[GRASS-SVN] r50882 - in
grass/branches/releasebranch_6_4/gui/wxpython: . core dbmgr
docs gcp gmodeler gui_core icons lmgr location_wizard mapdisp
modules nviz psmap tools vdigit wxplot xml
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Feb 19 15:31:20 EST 2012
Author: martinl
Date: 2012-02-19 12:31:20 -0800 (Sun, 19 Feb 2012)
New Revision: 50882
Added:
grass/branches/releasebranch_6_4/gui/wxpython/core/
grass/branches/releasebranch_6_4/gui/wxpython/core/debug.py
grass/branches/releasebranch_6_4/gui/wxpython/core/gcmd.py
grass/branches/releasebranch_6_4/gui/wxpython/core/globalvar.py
grass/branches/releasebranch_6_4/gui/wxpython/core/menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/core/render.py
grass/branches/releasebranch_6_4/gui/wxpython/core/settings.py
grass/branches/releasebranch_6_4/gui/wxpython/core/units.py
grass/branches/releasebranch_6_4/gui/wxpython/core/utils.py
grass/branches/releasebranch_6_4/gui/wxpython/core/workspace.py
grass/branches/releasebranch_6_4/gui/wxpython/create__init__.py
grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/
grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/manager.py
grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/sqlbuilder.py
grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/vinfo.py
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Components.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_light.jpg
grass/branches/releasebranch_6_4/gui/wxpython/gcp/
grass/branches/releasebranch_6_4/gui/wxpython/gcp/manager.py
grass/branches/releasebranch_6_4/gui/wxpython/gcp/mapdisplay.py
grass/branches/releasebranch_6_4/gui/wxpython/gcp/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/frame.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/model.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/forms.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/ghelp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/goutput.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/gselect.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapdisp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapwindow.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/menu.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/prompt.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_core/widgets.py
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/frame.py
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/layertree.py
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/pyshell.py
grass/branches/releasebranch_6_4/gui/wxpython/lmgr/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/
grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/base.py
grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/wizard.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/frame.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/gprint.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/main.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/mapwindow.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/statusbar.py
grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/
grass/branches/releasebranch_6_4/gui/wxpython/modules/colorrules.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/extensions.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/histogram.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/mcalc_builder.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/ogc_services.py
grass/branches/releasebranch_6_4/gui/wxpython/modules/vclean.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/
grass/branches/releasebranch_6_4/gui/wxpython/nviz/animation.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/main.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/mapwindow.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/tools.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/workspace.py
grass/branches/releasebranch_6_4/gui/wxpython/nviz/wxnviz.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/
grass/branches/releasebranch_6_4/gui/wxpython/psmap/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/frame.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/instructions.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/psmap/utils.py
grass/branches/releasebranch_6_4/gui/wxpython/states.txt
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/main.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/mapwindow.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdigit.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdisplay.py
grass/branches/releasebranch_6_4/gui/wxpython/wxplot/
grass/branches/releasebranch_6_4/gui/wxpython/wxplot/base.py
grass/branches/releasebranch_6_4/gui/wxpython/wxplot/dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/wxplot/profile.py
Removed:
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/
Modified:
grass/branches/releasebranch_6_4/gui/wxpython/Makefile
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Attribute_Table_Manager.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.GCP_Manager.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.PsMap.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizer.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_layer_manager.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_toolbar.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_surface.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_vector.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_view.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_volume.jpg
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_vector_digitizer_toolbar.jpg
grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py
grass/branches/releasebranch_6_4/gui/wxpython/icons/grass2_icons.py
grass/branches/releasebranch_6_4/gui/wxpython/icons/grass_icons.py
grass/branches/releasebranch_6_4/gui/wxpython/icons/icon.py
grass/branches/releasebranch_6_4/gui/wxpython/icons/silk_icons.py
grass/branches/releasebranch_6_4/gui/wxpython/tools/update_menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py
grass/branches/releasebranch_6_4/gui/wxpython/wxpythonlib.dox
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_modeler.xml
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_psmap.xml
Log:
wxGUI: major update from devbr6
Modified: grass/branches/releasebranch_6_4/gui/wxpython/Makefile
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/Makefile 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/Makefile 2012-02-19 20:31:20 UTC (rev 50882)
@@ -1,8 +1,7 @@
MODULE_TOPDIR = ../..
-SUBDIRS = docs scripts
+SUBDIRS = docs
EXTRA_CLEAN_FILES = menustrings.py build_ext.pyc
-CLEAN_SUBDIRS = scripts
include $(MODULE_TOPDIR)/include/Make/Dir.make
include $(MODULE_TOPDIR)/include/Make/Doxygen.make
@@ -10,29 +9,35 @@
ETCDIR = $(ETC)/wxpython
-SRCFILES := $(wildcard compat/* gui_modules/* icons/*.* icons/silk/* xml/*) gis_set.py wxgui.py README
+SRCFILES := $(wildcard compat/* icons/*.* scripts/* xml/*) \
+ $(wildcard core/* dbmgr/* gcp/* gmodeler/* gui_core/* lmgr/* location_wizard/* \
+ mapdisp/* modules/* nviz/* psmap/* vdigit/* wxplot/* ) \
+ gis_set.py wxgui.py README
DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
-default: install_scripts
+PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,core dbmgr gcp gmodeler gui_core lmgr location_wizard \
+ mapdisp modules nviz psmap vdigit wxplot)
+DSTDIRS := $(patsubst %,$(ETCDIR)/%,compat icons scripts xml)
+
+default: $(DSTFILES) menustrings.py
$(MAKE) parsubdirs
-clean: cleansubdirs
+$(ETCDIR)/%: % | $(PYDSTDIRS) $(DSTDIRS)
+ $(INSTALL_DATA) $< $@
-install_scripts:
- -for dir in '' compat gui_modules icons icons/silk xml; do \
- if [ ! -d $(ETCDIR)/$$dir ] ; then $(MKDIR) $(ETCDIR)/$$dir ; fi ; \
- done
- $(MAKE) $(DSTFILES)
- $(MAKE) menustrings.py
+menustrings.py: core/menudata.py $(ETCDIR)/xml/menudata.xml $(ETCDIR)/xml/menudata_modeler.xml
+ $(call run_grass,$(PYTHON) $< > $@)
+ $(call run_grass,$(PYTHON) $< "modeler" >> $@)
-$(ETCDIR)/%: %
- $(INSTALL_DATA) $< $@
+$(PYDSTDIRS): %: | $(ETCDIR)
+ $(MKDIR) $@
+ $(call run_grass,$(PYTHON) create__init__.py $@)
-menustrings.py: gui_modules/menudata.py $(ETCDIR)/xml/menudata.xml $(ETCDIR)/xml/menudata_modeler.xml
- GISBASE="$(GISBASE)" \
- $(PYTHON) $< > $@
- GISBASE="$(GISBASE)" \
- $(PYTHON) $< "modeler" >> $@
+$(DSTDIRS): %: | $(ETCDIR)
+ $(MKDIR) $@
+$(ETCDIR):
+ $(MKDIR) $@
+
#doxygen:
DOXNAME=wxpython
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/debug.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/debug.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/debug.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/debug.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/gcmd.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/gcmd.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/gcmd.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,683 @@
+"""!
+ 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 GetRealCmd(cmd):
+ """!Return real command name - only for MS Windows
+ """
+ if sys.platform == 'win32':
+ for ext in globalvar.grassScripts.keys():
+ if cmd in globalvar.grassScripts[ext]:
+ return cmd + ext
+
+ return cmd
+
+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 self.value
+
+class Popen(subprocess.Popen):
+ """!Subclass subprocess.Popen"""
+ def __init__(self, args, **kwargs):
+ if subprocess.mswindows:
+ args = map(EncodeString, args)
+
+ subprocess.Popen.__init__(self, args, **kwargs)
+
+ def recv(self, maxsize = None):
+ return self._recv('stdout', maxsize)
+
+ def recv_err(self, maxsize = None):
+ return self._recv('stderr', maxsize)
+
+ def send_recv(self, input = '', maxsize = None):
+ return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
+
+ def get_conn_maxsize(self, which, maxsize):
+ if maxsize is None:
+ maxsize = 1024
+ elif maxsize < 1:
+ maxsize = 1
+ return getattr(self, which), maxsize
+
+ def _close(self, which):
+ getattr(self, which).close()
+ setattr(self, which, None)
+
+ def kill(self):
+ """!Try to kill running process"""
+ if subprocess.mswindows:
+ import win32api
+ handle = win32api.OpenProcess(1, 0, self.pid)
+ return (0 != win32api.TerminateProcess(handle, 0))
+ else:
+ try:
+ os.kill(-self.pid, signal.SIGTERM) # kill whole group
+ except OSError:
+ pass
+
+ if subprocess.mswindows:
+ def send(self, input):
+ if not self.stdin:
+ return None
+
+ try:
+ x = msvcrt.get_osfhandle(self.stdin.fileno())
+ (errCode, written) = WriteFile(x, input)
+ except ValueError:
+ return self._close('stdin')
+ except (subprocess.pywintypes.error, Exception), why:
+ if why[0] in (109, errno.ESHUTDOWN):
+ return self._close('stdin')
+ raise
+
+ return written
+
+ def _recv(self, which, maxsize):
+ conn, maxsize = self.get_conn_maxsize(which, maxsize)
+ if conn is None:
+ return None
+
+ try:
+ x = msvcrt.get_osfhandle(conn.fileno())
+ (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
+ if maxsize < nAvail:
+ nAvail = maxsize
+ if nAvail > 0:
+ (errCode, read) = ReadFile(x, nAvail, None)
+ except ValueError:
+ return self._close(which)
+ except (subprocess.pywintypes.error, Exception), why:
+ if why[0] in (109, errno.ESHUTDOWN):
+ return self._close(which)
+ raise
+
+ if self.universal_newlines:
+ read = self._translate_newlines(read)
+ return read
+
+ else:
+ def send(self, input):
+ if not self.stdin:
+ return None
+
+ if not select.select([], [self.stdin], [], 0)[1]:
+ return 0
+
+ try:
+ written = os.write(self.stdin.fileno(), input)
+ except OSError, why:
+ if why[0] == errno.EPIPE: #broken pipe
+ return self._close('stdin')
+ raise
+
+ return written
+
+ def _recv(self, which, maxsize):
+ conn, maxsize = self.get_conn_maxsize(which, maxsize)
+ if conn is None:
+ return None
+
+ flags = fcntl.fcntl(conn, fcntl.F_GETFL)
+ if not conn.closed:
+ fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+
+ try:
+ if not select.select([conn], [], [], 0)[0]:
+ return ''
+
+ r = conn.read(maxsize)
+
+ if not r:
+ return self._close(which)
+
+ if self.universal_newlines:
+ r = self._translate_newlines(r)
+ return r
+ finally:
+ if not conn.closed:
+ fcntl.fcntl(conn, fcntl.F_SETFL, flags)
+
+message = "Other end disconnected!"
+
+def recv_some(p, t = .1, e = 1, tr = 5, stderr = 0):
+ if tr < 1:
+ tr = 1
+ x = time.time()+t
+ y = []
+ r = ''
+ pr = p.recv
+ if stderr:
+ pr = p.recv_err
+ while time.time() < x or r:
+ r = pr()
+ if r is None:
+ if e:
+ raise Exception(message)
+ else:
+ break
+ elif r:
+ y.append(r)
+ else:
+ time.sleep(max((x-time.time())/tr, 0))
+ return ''.join(y)
+
+def send_all(p, data):
+ while len(data):
+ sent = p.send(data)
+ if sent is None:
+ raise Exception(message)
+ data = buffer(data, sent)
+
+class Command:
+ """!Run command in separate thread. Used for commands launched
+ on the background.
+
+ If stdout/err is redirected, write() method is required for the
+ given classes.
+
+ @code
+ cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
+
+ if cmd.returncode == None:
+ print 'RUNNING?'
+ elif cmd.returncode == 0:
+ print 'SUCCESS'
+ else:
+ print 'FAILURE (%d)' % cmd.returncode
+ @endcode
+
+ @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(GetRealCmd(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(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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/gcmd.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/globalvar.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/globalvar.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/globalvar.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,173 @@
+"""!
+ 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")
+ETCSYMBOLDIR = os.path.join(ETCDIR, "gui", "images", "symbols")
+
+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 = (800, 600)
+GM_WINDOW_SIZE = (500, 600)
+
+def GetGRASSCommands():
+ """!Create list of available GRASS commands to use when parsing
+ string from the command line
+
+ @return list of commands (set) and directory of scripts (collected
+ by extension - MS Windows only)
+ """
+ gisbase = os.environ['GISBASE']
+ cmd = list()
+ if sys.platform == 'win32':
+ scripts = { '.bat' : list(),
+ '.py' : list()
+ }
+ else:
+ scripts = {}
+
+ # scan bin/
+ if os.path.exists(os.path.join(gisbase, 'bin')):
+ for fname in os.listdir(os.path.join(gisbase, 'bin')):
+ if scripts: # win32
+ name, ext = os.path.splitext(fname)
+ if ext != '.manifest':
+ cmd.append(name)
+ if ext in scripts.keys():
+ scripts[ext].append(name)
+ else:
+ cmd.append(fname)
+
+ # scan scripts/ (not on MS Windows)
+ if not scripts and os.path.exists(os.path.join(gisbase, 'scripts')):
+ for fname in os.listdir(os.path.join(gisbase, 'scripts')):
+ cmd.append(fname)
+
+ # scan gui/scripts/
+ if os.path.exists(os.path.join(gisbase, 'etc', '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')
+ cmd = cmd + os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts'))
+
+ # scan addons (path)
+ if os.getenv('GRASS_ADDON_PATH'):
+ for path in os.getenv('GRASS_ADDON_PATH').split(os.pathsep):
+ if not os.path.exists(path) or not os.path.isdir(path):
+ continue
+ for fname in os.listdir(path):
+ if scripts: # win32
+ name, ext = os.path.splitext(fname)
+ cmd.append(name)
+ if ext in scripts.keys():
+ scripts[ext].append(name)
+ else:
+ cmd.append(fname)
+
+ return set(cmd), scripts
+
+"""@brief Collected GRASS-relared binaries/scripts"""
+grassCmd, grassScripts = GetGRASSCommands()
+
+"""@Toolbar icon size"""
+toolbarSize = (24, 24)
+
+"""@Is g.mlist available?"""
+if 'g.mlist' in grassCmd:
+ have_mlist = True
+else:
+ have_mlist = False
+
+"""@Check version of wxPython, use agwStyle for 2.8.11+"""
+hasAgw = CheckWxVersion()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/globalvar.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/menudata.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/menudata.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/menudata.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/menudata.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/render.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/render.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/render.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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 sys.platform != 'win32':
+ mapstr = ",".join(maps)
+ maskstr = ",".join(masks)
+ mapoutstr = self.mapfile
+ else:
+ mapstr = ""
+ for item in maps:
+ mapstr += item.replace('\\', '/')
+ mapstr = mapstr.rstrip(',')
+ maskstr = ""
+ for item in masks:
+ maskstr += item.replace('\\', '/')
+ maskstr = maskstr.rstrip(',')
+ mapoutstr = self.mapfile.replace('\\', '/')
+
+ # 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 to 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 to 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])
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/render.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/settings.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/settings.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/settings.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,996 @@
+"""!
+ 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 = ';'
+
+ # define default settings
+ self._defaultSettings() # -> self.defaultSettings
+
+ # read settings from the file
+ self.userSettings = copy.deepcopy(self.defaultSettings)
+ try:
+ self.ReadSettingsFile()
+ except GException, e:
+ print >> sys.stderr, e.value
+
+ # define internal settings
+ self._internalSettings() # -> self.internalSettings
+
+ def _defaultSettings(self):
+ """!Define default settings
+ """
+ try:
+ projFile = PathJoin(os.environ["GRASS_PROJSHARE"], 'epsg')
+ except KeyError:
+ projFile = ''
+
+ 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),
+ },
+ 'mouseWheelZoom' : {
+ 'enabled' : True,
+ 'selection' : 0,
+ },
+ },
+ #
+ # 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' : True,
+ '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' : 125,
+ '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
+
+ def _internalSettings(self):
+ """!Define 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['display']['mouseWheelZoom']['choices'] = (_('Scroll forward to zoom in'),
+ _('Scroll back to zoom in'))
+
+ 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])
+
+UserSettings = Settings()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/settings.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/units.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/units.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/units.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/units.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/utils.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/utils.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/utils.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,766 @@
+"""!
+ 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
+import locale
+
+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(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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/utils.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/core/workspace.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/core/workspace.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/core/workspace.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1267 @@
+"""!
+ 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.main 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()
+
+ if NvizSettings:
+ self.nvizDefault = NvizSettings()
+ else:
+ self.nvizDefault = None
+
+ 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( {
+ "name" : display.get('name'),
+ "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()):
+ dispName = self.lmgr.gm_cb.GetPageText(page)
+ 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 '
+ 'name="%s" 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,
+ dispName.encode('utf8'),
+ 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())
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/core/workspace.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/create__init__.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/create__init__.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/create__init__.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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/releasebranch_6_4/gui/wxpython/create__init__.py
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,698 @@
+"""!
+ 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
+import types
+
+from core import globalvar
+import wx
+import wx.lib.scrolledpanel as scrolled
+
+from core.gcmd import RunCommand, GError
+from core.debug import Debug
+from core.settings import UserSettings
+from dbmgr.vinfo import VectorDBInfo
+from gui_core.widgets import IntegerValidator, FloatValidator
+
+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()
+ w += 50
+ if h < 200:
+ self.SetMinSize((w, 200))
+ else:
+ self.SetMinSize((w, h))
+
+ 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
+
+ Show error message when invalid values are entered.
+
+ 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
+ ctype = columns[name]['ctype']
+ value = columns[name]['values'][idx]
+ id = columns[name]['ids'][idx]
+ try:
+ newvalue = self.FindWindowById(id).GetValue()
+ except:
+ newvalue = self.FindWindowById(id).GetLabel()
+
+ if newvalue:
+ try:
+ if ctype == int:
+ newvalue = int(newvalue)
+ elif ctype == float:
+ newvalue = float(newvalue)
+ except ValueError:
+ GError(parent = self,
+ message = _("Column <%(col)s>: Value '%(value)s' needs to be entered as %(type)s.") % \
+ {'col' : name,
+ 'value' : str(newvalue),
+ 'type' : columns[name]['type'].lower()},
+ showTraceback = False)
+ sqlCommands.append(None)
+ continue
+ else:
+ if self.action == 'add':
+ continue
+
+ if newvalue != value:
+ updatedColumns.append(name)
+ if not newvalue:
+ updatedValues.append('NULL')
+ else:
+ if ctype != str:
+ updatedValues.append(str(newvalue))
+ else:
+ updatedValues.append("'" + str(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"""
+ close = 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']
+
+ for sql in self.GetSQLString(updateValues = True):
+ if not sql:
+ close = False
+ continue
+ if enc:
+ sql = sql.encode(enc)
+
+ RunCommand('db.execute',
+ parent = self,
+ quiet = True,
+ stdin = sql)
+
+ if close and 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 = 3, hgap = 3, vgap = 3)
+ flexSizer.AddGrowableCol(2)
+ # 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'].lower()
+ ctype = columns[name]['ctype']
+
+ if columns[name]['values'][idx] is not None:
+ if columns[name]['ctype'] != types.StringType:
+ 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 = "[%s]:" % vtype)
+ colValue = wx.TextCtrl(parent = panel, id = wx.ID_ANY, value = value)
+ colValue.SetName(name)
+ if ctype == int:
+ colValue.SetValidator(IntegerValidator())
+ elif ctype == float:
+ colValue.SetValidator(FloatValidator())
+
+ self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
+ if self.action == 'display':
+ colValue.SetWindowStyle(wx.TE_READONLY)
+
+ flexSizer.Add(colName, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(colType, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+ 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]
+
+ box = wx.StaticBox(parent = self, id = wx.ID_ANY)
+ box.Hide()
+ self.dataPanel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY,
+ style = wx.TAB_TRAVERSAL)
+ self.dataPanel.SetupScrolling(scroll_x = False)
+
+ # buttons
+ self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+ self.btnSubmit = wx.Button(self, wx.ID_OK, _("&Submit"))
+ self.btnSubmit.SetDefault()
+
+ # data area
+ self.widgets = []
+ cId = 0
+ self.usebox = False
+ self.cat = None
+ winFocus = False
+
+ for column, ctype, ctypeStr, 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 ctype == int:
+ valueWin.SetValidator(IntegerValidator())
+ elif ctype == float:
+ valueWin.SetValidator(FloatValidator())
+ if not winFocus:
+ wx.CallAfter(valueWin.SetFocus)
+ winFocus = True
+
+ label = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
+ label = column)
+ ctype = wx.StaticText(parent = self.dataPanel, id = wx.ID_ANY,
+ label = "[%s]:" % ctypeStr.lower())
+ self.widgets.append((label.GetId(), ctype.GetId(), valueWin.GetId()))
+
+ cId += 1
+
+ self._layout()
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # data area
+ dataSizer = wx.FlexGridSizer(cols = 3, hgap = 3, vgap = 3)
+ dataSizer.AddGrowableCol(2)
+
+ for labelId, ctypeId, valueId in self.widgets:
+ label = self.FindWindowById(labelId)
+ ctype = self.FindWindowById(ctypeId)
+ value = self.FindWindowById(valueId)
+
+ dataSizer.Add(label, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ dataSizer.Add(ctype, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
+ 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.GetBestSize()[0] + 25
+ self.SetMinSize((framewidth, 250))
+
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+
+ 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, ctypeId, 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/manager.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/manager.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/manager.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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', '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, GMessage, GWarning
+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:
+ GError(parent = self,
+ message = _("Column <%(column)s> not found in "
+ "in the table <%(table)s>.") % \
+ { 'column' : col, 'table' : tableName })
+ 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) == types.StringType or type(item2) == types.StringTypes:
+ 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:
+ GMessage(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)
+
+ #
+ # 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((700, 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.ComboBox(parent = panel, id = wx.ID_ANY,
+ size = (100,-1),
+ style = wx.CB_SIMPLE | wx.CB_READONLY,
+ choices = self.mapDBInfo.GetColumns(self.mapDBInfo.layers[layer]['table']))
+ sqlWhereColumn.SetSelection(0)
+ sqlWhereCond = wx.Choice(parent = panel, id = wx.ID_ANY,
+ size = (55,-1),
+ choices = ['=', '!=', '<', '<=', '>', '>='])
+ 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 = sqlWhereCond,
+ flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 3)
+ 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]['whereOperator'] = sqlWhereCond.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)
+
+ tlist = self._createTableDesc(panel, table)
+ tlist.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnTableRightUp) #wxMSW
+ tlist.Bind(wx.EVT_RIGHT_UP, self.OnTableRightUp) #wxGTK
+ self.layerPage[layer]['tableData'] = tlist.GetId()
+
+ # manage columns (add)
+ addBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+ label = " %s " % _("Add column"))
+ addSizer = wx.StaticBoxSizer(addBox, wx.HORIZONTAL)
+
+ 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 = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Column")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+ addSizer.Add(item = column, proportion = 1,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+
+ ctype = wx.Choice (parent = panel, id = wx.ID_ANY,
+ choices = ["integer",
+ "double",
+ "varchar",
+ "date"]) # FIXME
+ ctype.SetSelection(0)
+ ctype.Bind(wx.EVT_CHOICE, self.OnTableChangeType)
+ self.layerPage[layer]['addColType'] = ctype.GetId()
+ addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Type")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+ addSizer.Add(item = ctype,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+
+ 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()
+ addSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Length")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+ addSizer.Add(item = length,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+
+ btnAddCol = wx.Button(parent = panel, id = wx.ID_ADD)
+ btnAddCol.Bind(wx.EVT_BUTTON, self.OnTableItemAdd)
+ btnAddCol.Enable(False)
+ self.layerPage[layer]['addColButton'] = btnAddCol.GetId()
+ addSizer.Add(item = btnAddCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
+ border = 3)
+
+ # manage columns (rename)
+ renameBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
+ label = " %s " % _("Rename column"))
+ renameSizer = wx.StaticBoxSizer(renameBox, wx.HORIZONTAL)
+
+ 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()
+ renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Column")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+ renameSizer.Add(item = column, proportion = 1,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+
+ 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()
+ renameSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("To")),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+ renameSizer.Add(item = columnTo, proportion = 1,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT,
+ border = 5)
+
+ 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()
+ renameSizer.Add(item = btnRenameCol, flag = wx.ALL | wx.ALIGN_RIGHT | wx.EXPAND,
+ border = 3)
+
+ tableSizer.Add(item = tlist,
+ 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 = addSizer,
+ flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+ proportion = 0,
+ border = 3)
+ pageSizer.Add(item = renameSizer,
+ 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"""
+ tlist = TableListCtrl(parent = parent, id = wx.ID_ANY,
+ table = self.mapDBInfo.tables[table],
+ columns = self.mapDBInfo.GetColumns(table))
+ tlist.Populate()
+ # sorter
+ # itemDataMap = list.Populate()
+ # listmix.ColumnSorterMixin.__init__(self, 2)
+
+ return tlist
+
+ 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"""
+ tlist = LayerListCtrl(parent = parent, id = wx.ID_ANY,
+ layers = self.mapDBInfo.layers)
+
+ tlist.Populate()
+ # sorter
+ # itemDataMap = list.Populate()
+ # listmix.ColumnSorterMixin.__init__(self, 2)
+
+ return tlist
+
+ 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)
+
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ # generate popup-menu
+ menu = wx.Menu()
+ menu.Append(self.popupDataID1, _("Edit selected record"))
+ selected = tlist.GetFirstSelected()
+ if not self.editable or selected == -1 or tlist.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(tlist.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 tlist.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") % \
+ tlist.GetItemCount())
+
+ def OnDataItemDelete(self, event):
+ """!Delete selected item(s) from the tlist (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 be 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 be 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
+
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ cats = map(int, tlist.GetSelectedItems())
+
+ digitToolbar = self.mapdisplay.toolbars['vdigit']
+ if digitToolbar and digitToolbar.GetLayer() and \
+ digitToolbar.GetLayer().GetName() == self.vectorName:
+ display = self.mapdisplay.GetMapWindow().GetDisplay()
+ display.SetSelected(cats, layer = self.layer)
+ if zoom:
+ n, s, w, e = display.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"""
+ tlist = 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(tlist.GetColumnCount()):
+ columnName.append(tlist.GetColumn(i).GetText())
+
+ # maximal category number
+ if len(tlist.itemCatsMap.values()) > 0:
+ maxCat = max(tlist.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:
+ ctype = self.mapDBInfo.tables[table][col]['ctype']
+ ctypeStr = self.mapDBInfo.tables[table][col]['type']
+ if col == keyColumn: # key
+ if missingKey is False:
+ data.append((col, ctype, ctypeStr, str(maxCat + 1)))
+ keyId = colIdx
+ else:
+ data.append((col, ctype, ctypeStr, ''))
+
+ 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 tlist.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 tlist.columns[columnName[i]]['ctype'] == int:
+ # values[i] is stored as text.
+ value = float(values[i])
+ else:
+ value = values[i]
+ values[i] = tlist.columns[columnName[i]]['ctype'] (value)
+
+ except:
+ raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") %
+ {'value' : str(values[i]),
+ 'type' : tlist.columns[columnName[i]]['type']})
+ columnsString += '%s,' % columnName[i]
+ if tlist.columns[columnName[i]]['ctype'] == str:
+ valuesString += "'%s'," % values[i]
+ else:
+ valuesString += "%s," % values[i]
+
+ except ValueError, err:
+ GError(parent = self,
+ message = _("Unable to insert new record.\n%s") % err,
+ showTraceback = False)
+ self.OnDataItemAdd(event)
+ return
+
+ # remove category if need
+ if missingKey is True:
+ del values[0]
+
+ # add new item to the tlist
+ if len(tlist.itemIndexMap) > 0:
+ index = max(tlist.itemIndexMap) + 1
+ else:
+ index = 0
+
+ tlist.itemIndexMap.append(index)
+ tlist.itemDataMap[index] = values
+ tlist.itemCatsMap[index] = cat
+ tlist.SetItemCount(tlist.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"""
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ item = tlist.GetFirstSelected()
+ if item == -1:
+ return
+
+ table = self.mapDBInfo.layers[self.layer]['table']
+ keyColumn = self.mapDBInfo.layers[self.layer]['key']
+ cat = tlist.itemCatsMap[tlist.itemIndexMap[item]]
+
+ # (column name, value)
+ data = []
+
+ # collect names of all visible columns
+ columnName = []
+ for i in range(tlist.GetColumnCount()):
+ columnName.append(tlist.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)):
+ ctype = self.mapDBInfo.tables[table][columnName[i]]['ctype']
+ ctypeStr = self.mapDBInfo.tables[table][columnName[i]]['type']
+ if columnName[i] == keyColumn: # key
+ if missingKey is False:
+ data.append((columnName[i], ctype, ctypeStr, str(cat)))
+ keyId = i
+ else:
+ if missingKey is True:
+ value = tlist.GetItem(item, i-1).GetText()
+ else:
+ value = tlist.GetItem(item, i).GetText()
+ data.append((columnName[i], ctype, ctypeStr, 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 tlist.GetItem(item, i).GetText() != values[i]:
+ if len(values[i]) > 0:
+ try:
+ if missingKey is True:
+ idx = i - 1
+ else:
+ idx = i
+ if tlist.columns[columnName[i]]['ctype'] != types.StringType:
+ if tlist.columns[columnName[i]]['ctype'] == int:
+ value = float(values[i])
+ else:
+ value = values[i]
+ tlist.itemDataMap[item][idx] = \
+ tlist.columns[columnName[i]]['ctype'] (value)
+ else:
+ tlist.itemDataMap[item][idx] = values[i]
+ except:
+ raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") % \
+ {'value' : str(values[i]),
+ 'type' : tlist.columns[columnName[i]]['type']})
+
+ if tlist.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:
+ GError(parent = self,
+ message = _("Unable to update existing record.\n%s") % err,
+ showTraceback = False)
+ self.OnDataItemEdit(event)
+ return
+
+ if len(updateString) > 0:
+ self.listOfSQLStatements.append('UPDATE %s SET %s WHERE %s=%d' % \
+ (table, updateString.strip(','),
+ keyColumn, cat))
+ self.ApplyCommands()
+
+ tlist.Update(self.mapDBInfo)
+
+ def OnDataReload(self, event):
+ """!Reload tlist of records"""
+ self.OnApplySqlStatement(None)
+ self.listOfSQLStatements = []
+
+ def OnDataSelectAll(self, event):
+ """!Select all items"""
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ item = -1
+
+ while True:
+ item = tlist.GetNextItem(item)
+ if item == -1:
+ break
+ tlist.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
+
+ event.Skip()
+
+ def OnDataSelectNone(self, event):
+ """!Deselect items"""
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ item = -1
+
+ while True:
+ item = tlist.GetNextItem(item, wx.LIST_STATE_SELECTED)
+ if item == -1:
+ break
+ tlist.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"""
+ tlist = 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:
+ GError(parent = self,
+ message = _("Unable to rename column. "
+ "No column name defined."))
+ return
+ else:
+ item = tlist.FindItem(start = -1, str = name)
+ if item > -1:
+ if tlist.FindItem(start = -1, str = nameTo) > -1:
+ GError(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})
+ return
+ else:
+ tlist.SetItemText(item, nameTo)
+
+ self.listOfCommands.append(('v.db.renamecol',
+ { 'map' : self.vectorName,
+ 'layer' : self.layer,
+ 'column' : '%s,%s' % (name, nameTo) }
+ ))
+ else:
+ GError(parent = self,
+ message = _("Unable to rename column. "
+ "Column <%(column)s> doesn't exist in the table <%(table)s>.") %
+ {'column' : name, 'table' : table})
+ 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"""
+ tlist = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+
+ item = tlist.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?") % \
+ (tlist.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' : tlist.GetItemText(item) }
+ ))
+ tlist.DeleteItem(item)
+ item = tlist.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
+ tlist = self.FindWindowById(self.layerPage[self.layer]['tableData'])
+ tlist.Update(table = self.mapDBInfo.tables[table],
+ columns = self.mapDBInfo.GetColumns(table))
+ self.OnTableReload(None)
+
+ # update data tlist
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ tlist.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
+ win = self.FindWindowById(self.layerPage[self.layer]['simple'])
+ if not win:
+ return
+
+ wx.BeginBusyCursor()
+ if win.GetValue():
+ # simple sql statement
+ whereCol = self.FindWindowById(self.layerPage[self.layer]['whereColumn']).GetStringSelection()
+ whereOpe = self.FindWindowById(self.layerPage[self.layer]['whereOperator']).GetStringSelection()
+ whereVal = self.FindWindowById(self.layerPage[self.layer]['where']).GetValue().strip()
+ try:
+ if len(whereVal) > 0:
+ keyColumn = listWin.LoadData(self.layer, where = whereCol + whereOpe + 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:
+ GError(parent = self,
+ message = _("Loading attribute data failed.\n"
+ "Invalid SQL select statement.\n\n%s") % win.GetValue())
+ 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
+ """
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ # cats = tlist.selectedCats[:]
+ cats = tlist.GetSelectedItems()
+ if len(cats) == 0:
+ GMessage(parent = self,
+ message = _('Nothing to extract.'))
+ 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)
+ """
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ cats = tlist.GetSelectedItems()
+ if len(cats) == 0:
+ GMessage(parent = self,
+ message = _('Nothing to delete.'))
+
+ display = None
+ if 'vdigit' in self.mapdisplay.toolbars:
+ digitToolbar = self.mapdisplay.toolbars['vdigit']
+ if digitToolbar and digitToolbar.GetLayer() and \
+ digitToolbar.GetLayer().GetName() == self.vectorName:
+ display = self.mapdisplay.GetMapWindow().GetDisplay()
+ display.SetSelected(map(int, cats), layer = self.layer)
+ self.mapdisplay.MapWindow.UpdateMap(render = True, renderVector = True)
+
+ if self.OnDataItemDelete(None):
+ if display:
+ self.mapdisplay.GetMapWindow().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
+ """
+ tlist = self.FindWindowById(self.layerPage[self.layer]['data'])
+ cats = {
+ self.layer : tlist.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:
+ GWarning(parent = self.parent,
+ message = _("Unknown default DB connection. "
+ "Please define DB connection using db.connect module."))
+
+ 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)
+
+ layerSizer.SetVirtualSizeHints(self.addPanel)
+ 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:
+ GError(parent = self,
+ message = _("Unable to get list of tables.\n"
+ "Please use db.connect to set database parameters."))
+
+ 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:
+ GError(parent = self,
+ message = _("Unable to create new table. "
+ "Table name or key column name is missing."))
+ return
+
+ if table in self.addLayerWidgets['table'][1].GetItems():
+ GError(parent = self,
+ message = _("Unable to create new table. "
+ "Table <%s> already exists in the database.") % table)
+ 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():
+ GError(parent = self,
+ message = _("Unable to add new layer to vector map <%(vector)s>. "
+ "Layer %(layer)d already exists.") % \
+ {'vector' : self.mapDBInfo.map, 'layer' : layer})
+ 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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/manager.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/sqlbuilder.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/sqlbuilder.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/sqlbuilder.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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 = VectorDBInfo(self.vectmap)
+ self.tablename = self.dbInfo.GetTable(self.layer)
+ self.driver, self.database = self.dbInfo.GetDbSettings(self.layer)
+
+ self.qtype = qtype # type of query: SELECT, UPDATE, DELETE, ...
+ self.colvalues = [] # array with unique values in selected column
+
+ # set dialog title
+ self.SetTitle(_("GRASS SQL Builder (%(type)s): vector map <%(map)s>") % \
+ { 'type' : self.qtype.upper(), 'map' : self.vectmap })
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ # statusbar
+ self.statusbar = self.CreateStatusBar(number=1)
+ self.statusbar.SetStatusText(_("SQL statement not verified"), 0)
+
+ self._doLayout()
+
+ def _doLayout(self):
+ """!Do dialog layout"""
+
+ pagesizer = wx.BoxSizer(wx.VERTICAL)
+
+
+ # dbInfo
+ databasebox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Database connection"))
+ databaseboxsizer = wx.StaticBoxSizer(databasebox, wx.VERTICAL)
+ databaseboxsizer.Add(item=createDbInfoDesc(self.panel, self.dbInfo, layer = self.layer),
+ proportion=1,
+ flag=wx.EXPAND | wx.ALL,
+ border=3)
+
+ #
+ # text areas
+ #
+ # sql box
+ sqlbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Query"))
+ sqlboxsizer = wx.StaticBoxSizer(sqlbox, wx.VERTICAL)
+
+ self.text_sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+ value = '', size = (-1, 50),
+ style=wx.TE_MULTILINE)
+ if self.qtype.lower() == "select":
+ self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
+ self.text_sql.SetInsertionPointEnd()
+ self.text_sql.SetToolTipString(_("Example: %s") % "SELECT * FROM roadsmajor WHERE MULTILANE = 'no' OR OBJECTID < 10")
+ wx.CallAfter(self.text_sql.SetFocus)
+
+ sqlboxsizer.Add(item = self.text_sql, flag = wx.EXPAND)
+
+ #
+ # buttons
+ #
+ self.btn_clear = wx.Button(parent = self.panel, id = wx.ID_CLEAR)
+ self.btn_clear.SetToolTipString(_("Set SQL statement to default"))
+ self.btn_verify = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Verify"))
+ self.btn_verify.SetToolTipString(_("Verify SQL statement"))
+ self.btn_apply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
+ self.btn_apply.SetToolTipString(_("Apply SQL statement and close the dialog"))
+ self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+ self.btn_close.SetToolTipString(_("Close the dialog"))
+
+ self.btn_lv = { 'is' : ['=', ],
+ 'isnot' : ['!=', ],
+ 'like' : ['LIKE', ],
+ 'gt' : ['>', ],
+ 'ge' : ['>=', ],
+ 'lt' : ['<', ],
+ 'le' : ['<=', ],
+ 'or' : ['OR', ],
+ 'not' : ['NOT', ],
+ 'and' : ['AND', ],
+ 'brac' : ['()', ],
+ 'prc' : ['%', ] }
+
+ for key, value in self.btn_lv.iteritems():
+ btn = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = value[0])
+ self.btn_lv[key].append(btn.GetId())
+
+ buttonsizer = wx.FlexGridSizer(cols = 4, hgap = 5, vgap = 5)
+ buttonsizer.Add(item = self.btn_clear)
+ buttonsizer.Add(item = self.btn_verify)
+ buttonsizer.Add(item = self.btn_apply)
+ buttonsizer.Add(item = self.btn_close)
+
+ buttonsizer2 = wx.GridBagSizer(5, 5)
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['is'][1]), pos = (0,0))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['isnot'][1]), pos = (1,0))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['like'][1]), pos = (2, 0))
+
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['gt'][1]), pos = (0, 1))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['ge'][1]), pos = (1, 1))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['or'][1]), pos = (2, 1))
+
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['lt'][1]), pos = (0, 2))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['le'][1]), pos = (1, 2))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['not'][1]), pos = (2, 2))
+
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['brac'][1]), pos = (0, 3))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['prc'][1]), pos = (1, 3))
+ buttonsizer2.Add(item = self.FindWindowById(self.btn_lv['and'][1]), pos = (2, 3))
+
+ #
+ # list boxes (columns, values)
+ #
+ hsizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ columnsbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Columns"))
+ columnsizer = wx.StaticBoxSizer(columnsbox, wx.VERTICAL)
+ self.list_columns = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
+ choices = self.dbInfo.GetColumns(self.tablename),
+ style = wx.LB_MULTIPLE)
+ columnsizer.Add(item = self.list_columns, proportion = 1,
+ flag = wx.EXPAND)
+
+ radiosizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.radio_cv = wx.RadioBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Add on double-click"),
+ choices = [_("columns"), _("values")])
+ self.radio_cv.SetSelection(1) # default 'values'
+ radiosizer.Add(item = self.radio_cv, proportion = 1,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND, border = 5)
+
+ columnsizer.Add(item = radiosizer, proportion = 0,
+ flag = wx.TOP | wx.EXPAND, border = 5)
+ # self.list_columns.SetMinSize((-1,130))
+ # self.list_values.SetMinSize((-1,100))
+
+ valuesbox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Values"))
+ valuesizer = wx.StaticBoxSizer(valuesbox, wx.VERTICAL)
+ self.list_values = wx.ListBox(parent = self.panel, id = wx.ID_ANY,
+ choices = self.colvalues,
+ style = wx.LB_MULTIPLE)
+ valuesizer.Add(item = self.list_values, proportion = 1,
+ flag = wx.EXPAND)
+
+ self.btn_unique = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Get all values"))
+ self.btn_unique.Enable(False)
+ self.btn_uniquesample = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Get sample"))
+ self.btn_uniquesample.Enable(False)
+
+ buttonsizer3 = wx.BoxSizer(wx.HORIZONTAL)
+ buttonsizer3.Add(item = self.btn_uniquesample, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.RIGHT, border = 5)
+ buttonsizer3.Add(item = self.btn_unique, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL)
+
+ valuesizer.Add(item = buttonsizer3, proportion = 0,
+ flag = wx.TOP, border = 5)
+
+ # hsizer1.Add(wx.StaticText(self.panel,-1, "Unique values: "), border=0, proportion=1)
+
+ hsizer.Add(item = columnsizer, proportion = 1,
+ flag = wx.EXPAND)
+ hsizer.Add(item = valuesizer, proportion = 1,
+ flag = wx.EXPAND)
+
+ self.close_onapply = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+ label = _("Close dialog on apply"))
+ self.close_onapply.SetValue(True)
+
+ pagesizer.Add(item = databaseboxsizer,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+ pagesizer.Add(item = hsizer, proportion = 1,
+ flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+ # pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5)
+ # pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5)
+ pagesizer.Add(item = buttonsizer2, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL)
+ pagesizer.Add(item = sqlboxsizer, proportion = 0,
+ flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
+ pagesizer.Add(item = buttonsizer, proportion = 0,
+ flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+ pagesizer.Add(item = self.close_onapply, proportion = 0,
+ flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+ #
+ # bindings
+ #
+ self.btn_unique.Bind(wx.EVT_BUTTON, self.OnUniqueValues)
+ self.btn_uniquesample.Bind(wx.EVT_BUTTON, self.OnSampleValues)
+
+ for key, value in self.btn_lv.iteritems():
+ self.FindWindowById(value[1]).Bind(wx.EVT_BUTTON, self.OnAddMark)
+
+ self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
+ self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear)
+ self.btn_verify.Bind(wx.EVT_BUTTON, self.OnVerify)
+ self.btn_apply.Bind(wx.EVT_BUTTON, self.OnApply)
+
+ self.list_columns.Bind(wx.EVT_LISTBOX, self.OnAddColumn)
+ self.list_values.Bind(wx.EVT_LISTBOX, self.OnAddValue)
+
+ self.text_sql.Bind(wx.EVT_TEXT, self.OnText)
+
+ self.panel.SetAutoLayout(True)
+ self.panel.SetSizer(pagesizer)
+ pagesizer.Fit(self.panel)
+
+ self.Layout()
+ self.SetMinSize((660, 525))
+ self.SetClientSize(self.panel.GetSize())
+ self.CenterOnParent()
+
+ def OnUniqueValues(self, event, justsample = False):
+ """!Get unique values"""
+ vals = []
+ try:
+ idx = self.list_columns.GetSelections()[0]
+ column = self.list_columns.GetString(idx)
+ except:
+ self.list_values.Clear()
+ return
+
+ self.list_values.Clear()
+
+ querystring = "SELECT %s FROM %s" % (column, self.tablename)
+
+ data = grass.db_select(table = self.tablename,
+ sql = querystring,
+ database = self.database,
+ driver = self.driver)
+ if not data:
+ return
+
+ desc = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]
+
+ i = 0
+ for item in sorted(map(desc['ctype'], data)):
+ if justsample and i < 256 or \
+ not justsample:
+ if desc['type'] != 'character':
+ item = str(item)
+ self.list_values.Append(item)
+ else:
+ break
+ i += 1
+
+ def OnSampleValues(self, event):
+ """!Get sample values"""
+ self.OnUniqueValues(None, True)
+
+ def OnAddColumn(self, event):
+ """!Add column name to the query"""
+ idx = self.list_columns.GetSelections()
+ for i in idx:
+ column = self.list_columns.GetString(i)
+ self._add(element = 'column', value = column)
+
+ if not self.btn_uniquesample.IsEnabled():
+ self.btn_uniquesample.Enable(True)
+ self.btn_unique.Enable(True)
+
+ def OnAddValue(self, event):
+ """!Add value"""
+ selection = self.list_values.GetSelections()
+ if not selection:
+ event.Skip()
+ return
+
+ idx = selection[0]
+ value = self.list_values.GetString(idx)
+ idx = self.list_columns.GetSelections()[0]
+ column = self.list_columns.GetString(idx)
+
+ ctype = self.dbInfo.GetTableDesc(self.dbInfo.GetTable(self.layer))[column]['type']
+
+ if ctype == 'character':
+ value = "'%s'" % value
+
+ self._add(element = 'value', value = value)
+
+ def OnAddMark(self, event):
+ """!Add mark"""
+ mark = None
+ for key, value in self.btn_lv.iteritems():
+ if event.GetId() == value[1]:
+ mark = value[0]
+ break
+
+ self._add(element = 'mark', value = mark)
+
+ def _add(self, element, value):
+ """!Add element to the query
+
+ @param element element to add (column, value)
+ """
+ sqlstr = self.text_sql.GetValue()
+ newsqlstr = ''
+ if element == 'column':
+ if self.radio_cv.GetSelection() == 0: # -> column
+ idx1 = len('select')
+ idx2 = sqlstr.lower().find('from')
+ colstr = sqlstr[idx1:idx2].strip()
+ if colstr == '*':
+ cols = []
+ else:
+ cols = colstr.split(',')
+ if value in cols:
+ cols.remove(value)
+ else:
+ cols.append(value)
+
+ if len(cols) < 1:
+ cols = ['*',]
+
+ newsqlstr = 'SELECT ' + ','.join(cols) + ' ' + sqlstr[idx2:]
+ else: # -> where
+ newsqlstr = sqlstr
+ if sqlstr.lower().find('where') < 0:
+ newsqlstr += ' WHERE'
+
+ newsqlstr += ' ' + value
+
+ elif element == 'value':
+ newsqlstr = sqlstr + ' ' + value
+ elif element == 'mark':
+ newsqlstr = sqlstr + ' ' + value
+
+ if newsqlstr:
+ self.text_sql.SetValue(newsqlstr)
+
+ def GetSQLStatement(self):
+ """!Return SQL statement"""
+ return self.text_sql.GetValue().strip().replace("\n"," ")
+
+ def CloseOnApply(self):
+ """!Return True if the dialog will be close on apply"""
+ return self.close_onapply.IsChecked()
+
+ def OnText(self, event):
+ """Query string changed"""
+ if len(self.text_sql.GetValue()) > 0:
+ self.btn_verify.Enable(True)
+ else:
+ self.btn_verify.Enable(False)
+
+ def OnApply(self, event):
+ """Apply button pressed"""
+ if self.evtHeader:
+ self.evtHeader(event = 'apply')
+
+ if self.close_onapply.IsChecked():
+ self.Destroy()
+
+ event.Skip()
+
+ def OnVerify(self, event):
+ """!Verify button pressed"""
+ ret, msg = RunCommand('db.select',
+ getErrorMsg = True,
+ table = self.tablename,
+ sql = self.text_sql.GetValue(),
+ flags = 't',
+ driver = self.driver,
+ database = self.database)
+
+ if ret != 0 and msg:
+ self.statusbar.SetStatusText(_("SQL statement is not valid"), 0)
+ GError(parent = self,
+ message = _("SQL statement is not valid.\n\n%s") % msg)
+ else:
+ self.statusbar.SetStatusText(_("SQL statement is valid"), 0)
+
+ def OnClear(self, event):
+ """!Clear button pressed"""
+ if self.qtype.lower() == "select":
+ self.text_sql.SetValue("SELECT * FROM %s" % self.tablename)
+ else:
+ self.text_sql.SetValue("")
+
+ def OnClose(self, event):
+ """!Close button pressed"""
+ if self.evtHeader:
+ self.evtHeader(event = 'close')
+
+ self.Destroy()
+
+ event.Skip()
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ print >>sys.stderr, __doc__
+ sys.exit()
+
+ import gettext
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+
+ app = wx.App(0)
+ sqlb = SQLFrame(parent = None, title = _('SQL Builder'), vectmap = sys.argv[1])
+ sqlb.Show()
+
+ app.MainLoop()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/sqlbuilder.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/vinfo.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/vinfo.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/vinfo.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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(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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/dbmgr/vinfo.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Attribute_Table_Manager.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Attribute_Table_Manager.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Attribute_Table_Manager.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -17,21 +17,12 @@
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
<em>
-<a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
-<a href="wxGUI.Nviz.html">3D Viewer</a><br>
-<a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
-<a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
-<a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
-</em>
-
-<p>
-<em>
<a href="db.columns.html">db.columns</a>,
<a href="db.connect.html">db.connect</a>,
<a href="db.describe.html">db.describe</a>,
Added: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Components.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Components.html (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Components.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,14 @@
+<p>
+List of <em><a href="wxGUI.html">wxGUI</a></em> components:
+
+<ul>
+ <li><a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a></li>
+ <li><a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a></li>
+ <li><a href="wxGUI.Nviz.html">3D Viewer</a></li>
+ <li><a href="wxGUI.Modeler.html">Graphical Modeler</a></li>
+ <li><a href="wxGUI.GCP_Manager.html">Ground Control Points Manager</a></li>
+ <li><a href="wxGUI.PsMap.html">Cartographic Composer</a></li>
+</ul>
+
+<p>
+<i>$Date$</i>
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Components.html
___________________________________________________________________
Added: svn:mime-type
+ text/html
Added: svn:keywords
+ Author Date Id
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.GCP_Manager.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.GCP_Manager.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.GCP_Manager.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -292,21 +292,12 @@
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
<em>
- <a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
- <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
- <a href="wxGUI.Nviz.html">3D Viewer</a><br>
- <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
- <a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
-</em>
-
-<p>
-<em>
<a href="i.rectify.html">i.rectify</a>,
<a href="g.transform.html">g.transform</a>
</em>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -34,25 +34,15 @@
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
-<em>
-<a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
-<a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
-<a href="wxGUI.Nviz.html">3D Viewer</a><br>
-<a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
-<a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
-</em>
-
-<p>
See also
user <a href="http://grass.osgeo.org/wiki/WxGUI_Modeler">wiki</a> page
-which contains
-various <a href="http://grass.osgeo.org/wiki/WxGUI_Modeler#Video_Tutorials">video
-tutorials</a>.
+(especially various <a href="http://grass.osgeo.org/wiki/WxGUI_Modeler#Video_tutorials">video
+tutorials</a>).
<h2>AUTHORS</h2>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -13,7 +13,8 @@
<p>
To start the wxGUI 3D view mode, choose '3D view' from the map
-toolbar.
+toolbar. You can switch between 2D and 3D view. The region in
+3D view is updated according to displayed region in 2D view.
<p>
wxNviz is emphasized on the ease and speed of viewer positioning and
provided flexibility for using a wide range of data. A low resolution
@@ -38,30 +39,9 @@
</center>
<dl>
- <dt><img src="icons/3d-view.png">
- <em>Switch to view page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>view</b>
- control page.</dd>
- <dt><img src="icons/3d-raster.png">
- <em>Switch to surface page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>surface</b>
- control page (data properties).</dd>
- <dt><img src="icons/3d-vector.png">
- <em>Switch to vector page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>vector</b>
- control page (data properties).</dd>
- <dt><img src="icons/3d-volume.png">
- <em>Switch to volume page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>volume</b>
- control page (data properties).</dd>
- <dt><img src="icons/3d-light.png">
- <em>Switch to light page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>light</b>
- control page (appearance).</dd>
- <dt><img src="icons/3d-fringe.png">
- <em>Switch to fringe page</em></dt>
- <dd>Switch 3D Layer Manager Toolbox's page to the <b>fringe</b>
- control page (appearance).</dd>
+ <dt><img src="icons/script-save.png">
+ <em>Generate command for m.nviz.image</em></dt>
+ <dd>Generate command for m.nviz.image based on current state.</dd>
<dt><img src="icons/settings.png">
<em>Show 3D view mode settings</em></dt>
<dd>Show dialog with settings for wxGUI 3D view mode. The user
@@ -69,10 +49,6 @@
<dt><img src="icons/help.png">
<em>Show help</em></dt>
<dd>Show this help.</dd>
- <dt><img src="icons/quit.png">
- <em>Quit</em></dt>
- <dd>Quit 3D view mode and switch map display to the 2D view
- mode.</dd>
</dl>
<h2>3D View Layer Manager Toolbox</h2>
@@ -81,9 +57,11 @@
has several tabs:
<ul>
- <li><b>View</b> for view controling,</li>
+ <li><b>View</b> for view controlling,</li>
<li><b>Data</b> for data properties,</li>
<li><b>Appearance</b> for appearance settings (lighting, fringes, ...).</li>
+ <li><b>Analysis</b> for various data analyses (only cutting planes so far).</li>
+ <li><b>Animation</b> for creating simple animations.</li>
</ul>
<h3>View</h3>
@@ -92,15 +70,26 @@
perspective</em> of the view. The position box shows a puck with a
direction line pointing to the center. The direction line indicates
the look direction (azimuth). You click and drag the puck to change
- the current eye position. The box annotations are North, South,
- East, and West. You can also set exact position using <em>Look
- at</em> choice control.
+ the current eye position. Another way to change eye position is
+ to press the buttons around the position box representing cardinal
+ and ordinal directions.
+
+<p>
+There are four other buttons for view control in the bottom of this panel
+(following label <em>Look:</em>):
+<ul>
+ <li><em>here</em> requires you to click on Map Display Window to determine
+ the point to look at.</li>
+ <li><em>center</em> changes the point you are looking at to the center.</li>
+ <li><em>top</em> moves the current eye position above the map center.</li>
+ <li><em>reset</em> returns all current view settings to their default values.</li>
+</ul>
<center>
<br><img src="wxGUI_nviz_tools_view.jpg" border="1"><br><br>
</center>
-You can adjust the viewer's height above the scene, angle of view or
+You can adjust the viewer's height above the scene, perspective and
twist value to rotate the scene about the horizontal axis. An angle of
0 is flat. The scene rotates between -90 and 90 degrees.
@@ -109,43 +98,35 @@
example, if the easting and northing are in meters and the elevation
in feet, a vertical exaggeration of 0.305 would produce a true
(unexaggerated) surface.
-
<p>
-<em>Reset</em> returns all current settings to their default values.
+View parameters can be controlled by sliders or edited directly in text box.
+It's possible to enter values which are out of slider's range (and it will
+adjust then).
-<h3>Data properties - Surface</h3>
+<h4>Fly-through mode</h4>
+View can be changed in fly-through mode (can be activated in Map Display toolbar),
+which enables to change the view smoothly and therefore it is suitable
+for creating animation (see below). To start flying, press left mouse button
+and hold it down to continue flying. Flight direction is controlled by mouse cursor
+position on screen. Flight speed can be increased/decreased stepwise by keys
+PageUp/PageDown, Home/End or Up/Down arrows.
+Speed is increased multiple times while Shift key is held down. Holding down
+Ctrl key switches flight mode in the way that position of viewpoint is
+changed (not the direction).
-Each active raster map layer from the current layer tree is displayed
-as surface in the 3D space. Separate raster data or constants can be
-used for various attributes of the surface:
+<h3>Data properties</h3>
+This tab allows to control parameters related to map layers. It consists
+of four collapsible panels - <em>Surface</em>, <em>Constant surface</em>,
+<em>Vector</em> and <em>Volume</em>.
-<ul>
- <li><b>topography</b> - raster map or constant values used as elevation (z
- values) for the current surface.</li>
- <li><b>color</b> - raster map or constant color to drape over the current
- surface. This option is useful for draping imagery such as aerial
- photography over a DEM.</li>
- <li><b>mask</b> - raster map that controls the areas displayed from
- the current surface.</li>
- <li><b>transparency</b> - raster map or constant value that controls
- the transparency of the current surface. The default is completely
- opaque. Range from 0 (opaque) to 255 (transparent).</li>
- <li><b>shininess</b> - raster map or constant value that controls
- the shininess (reflectivity) of the current surface. Range from 0 to
- 255.</li>
- <li><b>emission</b> - raster map or constant value that controls the
- light emitted from the current surface. Range from 0 to 255.</li>
-</ul>
+<h4>Surface</h4>
-This panel controls how loaded surfaces are drawn. The top half of the
-panel has options to set, unset or modify attributes of the current
-surface. The bottom half has drawing style options, masking or
-changing surface position in the space.
-
-<center>
- <br><img src="wxGUI_nviz_tools_surface.jpg" border="1"><br><br>
-</center>
-
+Each active raster map layer from the current layer tree is displayed
+as surface in the 3D space. This panel controls how loaded surfaces are drawn.
+To change parameters of a surface, it must be selected in the very top part of the
+panel.
+<p>
+The top half of the panel has drawing style options.
Surface can be drawn as a wire mesh or using filled polygons (most
realistic). You can set draw <b>mode</b> to <em>coarse</em> (fast
display mode), <em>fine</em> (draws surface as filled polygons with
@@ -170,10 +151,43 @@
cells. The surface appears faceted.
<p>
-To set given draw settings for all loaded surfaces press button "All".
+To set given draw settings for all loaded surfaces press button "Set to all".
-<h3>Data properties - Vector</h3>
+<p>
+The bottom half of the panel has options to set, unset or modify attributes
+of the current surface. Separate raster data or constants can be
+used for various attributes of the surface:
+<ul>
+ <li><b>color</b> - raster map or constant color to drape over the current
+ surface. This option is useful for draping imagery such as aerial
+ photography over a DEM.</li>
+ <li><b>mask</b> - raster map that controls the areas displayed from
+ the current surface.</li>
+ <li><b>transparency</b> - raster map or constant value that controls
+ the transparency of the current surface. The default is completely
+ opaque. Range from 0 (opaque) to 100 (transparent).</li>
+ <li><b>shininess</b> - raster map or constant value that controls
+ the shininess (reflectivity) of the current surface. Range from 0 to
+ 100.</li>
+</ul>
+<p>
+In the very bottom part of the panel position of surface can be set.
+To move the surface right (looking from the south) choose <em>X</em> axis
+and set some positive value. To reset the surface position press
+<em>Reset</em> button.
+
+<center>
+ <br><img src="wxGUI_nviz_tools_surface.jpg" border="1"><br><br>
+</center>
+
+<h4>Constant surface</h4>
+It is possible to add constant surface and set its properties like
+fine resolution, value (height), color and transparency. It behaves
+similarly to surface but it has less options.
+
+<h4>Vector</h4>
+
2D vector data can be draped on the selected surfaces with various
markers to represent point data; you can use attribute of vector
features to determine size, color, shape of glyph.
@@ -186,14 +200,12 @@
You can define the width (in pixels) of the line features, the color
used for lines or point markers.
-<center>
- <br><img src="wxGUI_nviz_tools_vector.jpg" border="1"><br><br>
-</center>
-
+<p>
If vector map is 2D you can display vector features as flat at a
specified elevation or drape it over a surface(s) at a specified
height. Use the height control to set the flat elevation or the drape
-height above the surface(s).
+height above the surface(s). In case of multiple surfaces it is possible
+to specify which surfaces is the vector map draped over.
<p>
For display purposes, it is better to set the height slightly above
@@ -201,10 +213,10 @@
disappear into the surface(s).
<p>
-For 2D/3D vector points you can also set the size of the markers and
-the width (in pixels) of the line used to draw the point markers (only
-applies to wire-frame markers). Currently are implemented these
-markers:
+For 2D/3D vector points you can also set the size of the markers.
+<!-- and the width (in pixels) of the line used to draw the point markers (only
+applies to wire-frame markers). -->
+ Currently are implemented these markers:
<ul>
<li><b>x</b> sets the current points markers to a 2D "X",</li>
@@ -216,14 +228,40 @@
<li><b>asterisk</b> - 3D line-star.</li>
</ul>
-<h3>Data properties - Volume</h3>
+<p>
+Thematic mapping can be used to determine marker color and size
+(and line color and width).
-Volumes can be displayed either as isosurfaces or slices. Various
-attributes of the isosurface can be defined, similarly to surface
+<center>
+ <br><img src="wxGUI_nviz_tools_vector.jpg" border="1"><br><br>
+</center>
+
+<h4>Volume</h4>
+
+Volumes (3D raster maps) can be displayed either as isosurfaces or slices.
+Similarly to surface panel you can define draw <b>shading</b>
+- <em>gouraud</em> (draws the volumes with a smooth shading to blend
+individual cell colors together) and <em>flat</em> (draws the volumes
+with flat shading with one color for every two cells. The volume
+appears faceted). As mentioned above currently are supported two
+visualization modes:
+
+<ul>
+ <li><b>isosurface</b> - the levels of values for drawing the
+ volume(s) as isosurfaces,</li>
+ <li>and <b>slice</b> - drawing the volume
+ as cross-sections.</li>
+</ul>
+<p>
+The middle part of the panel has controls to add, delete, move up/down selected
+isosurface or slice. The bottom part differs for isosurface and slice.
+When choosing isosurface, this part the of panel has options to set, unset
+or modify attributes of the current isosurface.
+Various attributes of the isosurface can be defined, similarly to surface
attributes:
<ul>
- <li><b>level</b> - reference isosurface level (height in map
+ <li><b>isosurface value</b> - reference isosurface value (height in map
units).</li>
<li><b>color</b> - raster map or constant color to drape over the
current volume.</li>
@@ -231,40 +269,79 @@
the current volume.</li>
<li><b>transparency</b> - raster map or constant value that controls
the transparency of the current volume. The default is completely
- opaque. Range from 0 (opaque) to 255 (transparent).</li>
+ opaque. Range from 0 (opaque) to 100 (transparent).</li>
<li><b>shininess</b> - raster map or constant value that controls
the shininess (reflectivity) of the current volume. Range from 0 to
- 255.</li>
- <li><b>emission</b> - raster map or constant value that controls the
- light emitted from the current volume. Range from 0 to 255.</li>
+ 100.</li>
</ul>
+In case of volume slice the bottom part of the panel controls the slice
+attributes (which axis is slice parallel to, position of slice edges,
+transparency). Press button <em>Reset</em> to reset slice position
+attributes.
<p>
-This panel controls how loaded volumes are drawn. Volume can be drawn
-in two different modes: <b>isosurface</b> or <b>slice</b>. The top
-part of the panel has drawing style options. The middle part has
-controls to add, delete, move up/down selected isosurface or
-slices. The bottom part has options to set, unset or modify attributes
-of the current isosurface or slice.
+Volumes can be moved the same way like surfaces do.
<center>
<br><img src="wxGUI_nviz_tools_volume.jpg" border="1"><br><br>
</center>
-Similarly to surface panel you can define draw <b>shading</b>
-- <em>gouraud</em> (draws the volumes with a smooth shading to blend
-individual cell colors together) and <em>flat</em> (draws the volumes
-with flat shading with one color for every two cells. The volume
-appears faceted). As mentioned above currently are supported two
-visualization modes:
+<h3>Analysis</h3>
+<em>Analysis</em> tab contains <em>Cutting planes</em> panel.
+<h4>Cutting planes</h4>
+Cutting planes allow to cut surfaces along a plane. You can switch
+between six planes; to disable cutting planes switch to <em>None</em>.
+Initially the plane is vertical, you can change it to horizontal by setting
+<em>tilt</em> 90 degrees. The <em>X</em> and <em>Y</em> values specify
+the rotation center of plane. You can see better what <em>X</em> and <em>Y</em>
+do when changing <em>rotation</em>.
+<em>Height</em> parameter has sense only when changing
+<em>tilt</em> too. Press button <em>Reset</em> to reset current cutting plane.
+<p>
+In case of multiple surfaces you can visualize the cutting plane by
+<em>Shading</em>. Shading is visible only when more than one surface
+is loaded and these surfaces must have the same fine resolution set.
+
+
+
+<h3>Appearance</h3>
+Appearance tab consists of three collapsible panels:
+
<ul>
- <li><b>isosurface</b> - the levels of values for drawing the
- volume(s) as isosurfaces,</li>
- <li>and <b>slice</b> - the levels of values for drawing the volume
- as cross-sections.</li>
+ <li><em>Lighting</em> for adjusting light source</li>
+ <li><em>Fringe</em> for drawing fringes
+ <li><em>Decorations</em> to display north arrow and scale bar</li>
</ul>
+<p>
+The <em>lighting</em> panel enables to change the position of light
+source, light color, brightness and ambient. Light position is controlled
+similarly to eye position. If option <em>Show light model</em> is enabled
+light model is displayed to visualize the light settings.
+<center>
+ <br><img src="wxGUI_nviz_tools_light.jpg" border="1"><br><br>
+</center>
+<p>
+The <em>Fringe</em> panel allows to draw fringes in different directions
+(North & East, South & East, South & West, North & West). It is possible
+to set fringe color and height of the bottom edge.
+<p>
+The <em>Decorations</em> panel enables to display north arrow and simple
+scale bar. North arrow and scale bar length is determined in map units.
+You can display more than one scale bar.
+
+<h3>Animation</h3>
+Animation panel enables to create a simple animation as a sequence of images.
+Press 'Record' button and start changing the view. Views are
+recorded in given interval (FPS - Frames Per Second). After recording,
+the animation can be replayed. To save the animation, fill in the
+directory and file prefix, choose image format (PPM or TIF) and then
+press 'Save'. Now wait until the last image is generated.
+
+It is recommended to record animations using fly-through mode to achieve
+smooth motion.
+
<h2>Settings</h2>
This panel has controls which allows user to set default surface,
@@ -276,15 +353,9 @@
<h2>To be implement</h2>
<ul>
- <li>Improve intuitive navigation (mouse, fly mode)</li>
- <li>Animation capabilities</li>
- <li>Arbitrary cutting planes</li>
- <li>Labels, decoration, etc.</li>
- <li>Scripting capabilities</li>
- <li>Better workspace support (view settings, lighting)
+ <li>Labels, decoration, etc. (Implemented, but not fully functional)</li>
<li>Surface - mask by zero/elevation, more interactive positioning</li>
<li>Vector points - implement display mode flat/surface for 2D points</li>
- <li>Volume - slice draw mode</li>
<li>...</li>
</ul>
@@ -295,21 +366,15 @@
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
-<em>
- <a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
- <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
- <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
- <a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
- <a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
-</em>
+See also <a href="http://grass.osgeo.org/wiki/WxNVIZ">wiki</a> page
+(especially various <a href="http://grass.osgeo.org/wiki/WxNVIZ#Video_tutorials">video
+tutorials</a>).
-<p>
-See also <a href="http://grass.osgeo.org/wiki/WxNVIZ">wiki</a> page.
<br><br>
Command-line module <em><a href="m.nviz.image.html">m.nviz.image</a></em>.
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.PsMap.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.PsMap.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.PsMap.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -43,6 +43,9 @@
<li> text
<li> scalebar
<li> mapinfo
+ <li> point
+ <li> line
+ <li> rectangle
</ul>
@@ -184,19 +187,11 @@
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
-<em>
- <a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
- <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
- <a href="wxGUI.Nviz.html">3D Viewer</a><br>
- <a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
-</em>
-</p>
-<p>
See also <a href="http://grass.osgeo.org/wiki/WxGUI_Cartographic_Composer">wiki</a> page.
</p>
<h2>AUTHORS</h2>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizer.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizer.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizer.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -184,6 +184,10 @@
vector lines in bounding box. This is useful for labeling contour lines.</li>
</ul>
</dd>
+
+ <dt><img src="icons/undo.png">
+ <em>Undo</em></dt>
+ <dd>Undo previous operations.</dd>
<dt><img src="icons/settings.png">
<em>Settings</em></dt>
@@ -221,28 +225,15 @@
If the digitizer crashes for some reason you can repair the vector map
which was left open with the <em>v.build</em> module.
-<p>
-<b>Please note that vector digitizer is under active development and
-distributed as "Experimental Prototype".</b>
-
<h2>SEE ALSO</h2>
<em>
- <a href="wxGUI.html">wxGUI</a>
+ <a href="wxGUI.html">wxGUI</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-Other wxGUI components:<br>
<em>
- <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
- <a href="wxGUI.Nviz.html">3D Viewer</a><br>
- <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
- <a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
- <a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
-</em>
-
-<p>
-<em>
<a href="v.edit.html">v.edit</a>,
<a href="v.category.html">v.category</a>
</em>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html 2012-02-19 20:31:20 UTC (rev 50882)
@@ -1,41 +1,47 @@
<h2>DESCRIPTION</h2>
-<b>wxGUI</b> is a new generation of the GUI for GRASS GIS. It's a successor
-of the <em><a href="gis.m.html">Tcl/Tk GUI</a></em> from GRASS 6.
+<b>wxGUI</b> is a new generation of the <em>Graphical User
+Interface</em> (GUI) for GRASS GIS written
+in <a href="http://www.python.org">Python</a>
+using <a href="http://www.wxpython.org">wxPython</a> library. It's a
+successor of the <em><a href="gis.m.html">Tcl/Tk GUI</a></em> from
+GRASS 6.
<p>
If wxGUI is not your default GUI, you can define it as default by
-typing at GRASS command line prompt
+typing at GRASS command line prompt:
<div class="code"><pre>
- g.gui -u wxpython
+g.gui -u wxpython
</pre></div>
-or define in your <tt>.grassrc6</tt> file 'GRASS_GUI' variable
+Alternatively it may be defined in GISRC file
+(<tt>$HOME/.grassrc6</tt> on GNU/Linux, <tt>$APPDATA\GRASS6\grassrc6</tt>
+on MS Windows) by <tt>GRASS_GUI</tt> variable
<div class="code"><pre>
- GRASS_GUI: wxpython
+GRASS_GUI: wxpython
</pre></div>
The GUI can be quit by selecting the 'File->Exit' menu item. The GUI
can be restarted from the GRASS command line prompt by typing
<div class="code"><pre>
- g.gui wxpython
+g.gui wxpython
</pre></div>
-or to restart with previously saved workspace type:
+To restart with previously saved workspace file:
<div class="code"><pre>
- g.gui wxpython workspace=file.gxw
+g.gui wxpython workspace=file.gxw
</pre></div>
<p>
-You can also start GRASS from the shell command line with wxGUI
-defined by the <tt>-wxpython</tt> switch:
+The user can also start GRASS from the shell command line with the wxGUI
+specifying the <tt>-gui</tt> (or <tt>-wxpython</tt>) switch:
<div class="code"><pre>
- grass64 -wxpython
+grass65 -gui
</pre></div>
<p>
@@ -584,18 +590,15 @@
<h2>SEE ALSO</h2>
-wxGUI components:<br>
<em>
- <a href="wxGUI.Vector_Digitizer.html">Vector Digitizer</a><br>
- <a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
- <a href="wxGUI.Nviz.html">3D Viewer</a><br>
- <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
- <a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
- <a href="wxGUI.PsMap.html">Cartographic Composer</a><br>
+ <a href="wxGUI.Components.html">wxGUI components</a>
</em>
<p>
-See also wxGUI <a href="http://grass.osgeo.org/wiki/WxGUI">wiki</a> page,
+See also wxGUI <a href="http://grass.osgeo.org/wiki/WxGUI">wiki</a>
+page
+(especially various <a href="http://grass.osgeo.org/wiki/WxGUI#Video_tutorials">video
+tutorials</a>),
and <a href="http://grass.osgeo.org/wiki/Quick_wxGUI_tutorial">Quick
wxGUI Tutorial</a>.
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_layer_manager.jpg
===================================================================
(Binary files differ)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_toolbar.jpg
===================================================================
(Binary files differ)
Added: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_light.jpg
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_light.jpg
___________________________________________________________________
Added: svn:mime-type
+ image/jpeg
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_surface.jpg
===================================================================
(Binary files differ)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_vector.jpg
===================================================================
(Binary files differ)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_view.jpg
===================================================================
(Binary files differ)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_tools_volume.jpg
===================================================================
(Binary files differ)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_vector_digitizer_toolbar.jpg
===================================================================
(Binary files differ)
Added: grass/branches/releasebranch_6_4/gui/wxpython/gcp/manager.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gcp/manager.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gcp/manager.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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 canceled.") % minNumOfItems)
+ return
+
+ key = self.list.DeleteGCPItem()
+ del self.mapcoordlist[key]
+
+ # update key and GCP number
+ for newkey in range(key, len(self.mapcoordlist)):
+ index = self.list.FindItemData(-1, newkey + 1)
+ self.mapcoordlist[newkey][0] = newkey
+ self.list.SetStringItem(index, 0, str(newkey))
+ self.list.SetItemData(index, newkey)
+
+ # update selected
+ if self.list.GetItemCount() > 0:
+ if self.list.selected < self.list.GetItemCount():
+ self.list.selectedkey = self.list.GetItemData(self.list.selected)
+ else:
+ self.list.selected = self.list.GetItemCount() - 1
+ self.list.selectedkey = self.list.GetItemData(self.list.selected)
+
+ self.list.SetItemState(self.list.selected,
+ wx.LIST_STATE_SELECTED,
+ wx.LIST_STATE_SELECTED)
+ else:
+ self.list.selected = wx.NOT_FOUND
+ self.list.selectedkey = -1
+
+ self.UpdateColours()
+
+ if self.statusbarManager.GetMode() == 8: # go to
+ self.StatusbarUpdate()
+ if self.list.selectedkey > 0:
+ self.statusbarManager.SetProperty('gotoGCP', self.list.selectedkey)
+
+ def ClearGCP(self, event):
+ """
+ Clears all values in selected item of GCP list and unchecks it
+ """
+ index = self.list.GetSelected()
+
+ 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 canceled."))
+ else:
+ for i in range(len(values)):
+ if values[i] != coords[i]:
+ self.SetStringItem(index, i + 1, values[i])
+ changed = True
+
+ if changed:
+ # reset RMS and update mapcoordlist
+ self.SetStringItem(index, 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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gcp/manager.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gcp/mapdisplay.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gcp/mapdisplay.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gcp/mapdisplay.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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']
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gcp/mapdisplay.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gcp/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gcp/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gcp/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,152 @@
+"""!
+ 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, BaseIcons
+from icon import MetaIcon
+
+class GCPManToolbar(BaseToolbar):
+ """!Toolbar for managing ground control points
+
+ @param parent reference to GCP widget
+ """
+ def __init__(self, parent):
+ BaseToolbar.__init__(self, parent)
+
+ self.InitToolbar(self._toolbarData())
+
+ # realize the toolbar
+ self.Realize()
+
+ def _toolbarData(self):
+ icons = {
+ 'gcpSave' : MetaIcon(img = 'gcp-save',
+ label = _('Save GCPs to POINTS file')),
+ 'gcpReload' : MetaIcon(img = 'reload',
+ label = _('Reload GCPs from POINTS file')),
+ 'gcpAdd' : MetaIcon(img = 'gcp-add',
+ label = _('Add new GCP')),
+ 'gcpDelete' : MetaIcon(img = 'gcp-delete',
+ label = _('Delete selected GCP')),
+ 'gcpClear' : MetaIcon(img = 'gcp-remove',
+ label = _('Clear selected GCP')),
+ 'gcpRms' : MetaIcon(img = 'gcp-rms',
+ label = _('Recalculate RMS error')),
+ 'georectify' : MetaIcon(img = 'georectify',
+ label = _('Georectify')),
+ }
+
+ 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 '),
+ BaseIcons["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 = {
+ 'gcpSet' : MetaIcon(img = 'gcp-create',
+ label = _('Set GCP'),
+ desc = _('Define GCP (Ground Control Points)')),
+ 'quit' : BaseIcons['quit'].SetLabel(_('Quit georectification tool')),
+ 'settings' : BaseIcons['settings'].SetLabel( _('Georectifier settings')),
+ 'help' : BaseIcons['help'].SetLabel(_('Georectifier manual')),
+ }
+
+ return self._getToolbarData((("displaymap", BaseIcons["display"],
+ self.parent.OnDraw),
+ ("rendermap", BaseIcons["render"],
+ self.parent.OnRender),
+ ("erase", BaseIcons["erase"],
+ self.parent.OnErase),
+ (None, ),
+ ("gcpset", icons["gcpSet"],
+ self.parent.OnPointer),
+ ("pan", BaseIcons["pan"],
+ self.parent.OnPan),
+ ("zoomin", BaseIcons["zoomIn"],
+ self.parent.OnZoomIn),
+ ("zoomout", BaseIcons["zoomOut"],
+ self.parent.OnZoomOut),
+ ("zoommenu", BaseIcons["zoomMenu"],
+ self.parent.OnZoomMenuGCP),
+ (None, ),
+ ("zoomback", BaseIcons["zoomBack"],
+ self.parent.OnZoomBack),
+ ("zoomtomap", BaseIcons["zoomExtent"],
+ self.parent.OnZoomToMap),
+ (None, ),
+ ('settings', icons["settings"],
+ self.parent.OnSettings),
+ ('help', icons["help"],
+ self.parent.OnHelp),
+ (None, ),
+ ('quit', icons["quit"],
+ self.parent.OnQuit))
+ )
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gcp/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
@@ -146,8 +144,7 @@
style = wx.TE_PROCESS_ENTER)
# Locations
- self.lpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
- self.lblocations = GListBox(parent = self.lpanel,
+ self.lblocations = GListBox(parent = self.panel,
id = wx.ID_ANY, size = (180, 200),
choices = self.listOfLocations)
@@ -155,8 +152,7 @@
# TODO: sort; but keep PERMANENT on top of list
# Mapsets
- self.mpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
- self.lbmapsets = GListBox(parent = self.mpanel,
+ self.lbmapsets = GListBox(parent = self.panel,
id = wx.ID_ANY, size = (180, 200),
choices = self.listOfMapsets)
@@ -224,9 +220,8 @@
force = True)
self.lblocations.EnsureVisible(self.listOfLocations.index(location))
except ValueError:
- print >> sys.stderr, _("ERROR: Location <%s> not found") % \
- (utils.UnicodeString(location))
-
+ print >> sys.stderr, _("ERROR: Location <%s> not found") % location
+
# list of mapsets
self.UpdateMapsets(os.path.join(self.gisdbase, location))
mapset = self.GetRCValue("MAPSET")
@@ -237,89 +232,75 @@
self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
except ValueError:
self.lbmapsets.Clear()
- print >> sys.stderr, _("ERROR: Mapset <%s> not found") % \
- (utils.UnicodeString(mapset))
-
+ print >> sys.stderr, _("ERROR: Mapset <%s> not found") % mapset
+
def _do_layout(self):
- label_style = wx.ADJUST_MINSIZE | wx.ALIGN_CENTER_HORIZONTAL
-
sizer = wx.BoxSizer(wx.VERTICAL)
dbase_sizer = wx.BoxSizer(wx.HORIZONTAL)
- location_sizer = wx.FlexGridSizer(rows = 1, cols = 2, vgap = 4, hgap = 4)
+ location_sizer = wx.BoxSizer(wx.HORIZONTAL)
select_boxsizer = wx.StaticBoxSizer(self.select_box, wx.VERTICAL)
select_sizer = wx.FlexGridSizer(rows = 2, cols = 2, vgap = 4, hgap = 4)
- manage_boxsizer = wx.StaticBoxSizer(self.manage_box, wx.VERTICAL)
- manage_sizer = wx.BoxSizer(wx.VERTICAL)
+ select_sizer.AddGrowableRow(1)
+ select_sizer.AddGrowableCol(0)
+ select_sizer.AddGrowableCol(1)
+ manage_sizer = wx.StaticBoxSizer(self.manage_box, wx.VERTICAL)
btns_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
+
# gis data directory
dbase_sizer.Add(item = self.ldbase, proportion = 0,
flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
- dbase_sizer.Add(item = self.tgisdbase, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
+ dbase_sizer.Add(item = self.tgisdbase, proportion = 1,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL,
border = 3)
dbase_sizer.Add(item = self.bbrowse, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL,
border = 3)
-
+
# select sizer
select_sizer.Add(item = self.llocation, proportion = 0,
- flag = label_style | wx.ALL,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
select_sizer.Add(item = self.lmapset, proportion = 0,
- flag = label_style | wx.ALL,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
- select_sizer.Add(item = self.lpanel, proportion = 0,
- flag = wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL)
- select_sizer.Add(item = self.mpanel, proportion = 0,
- flag = wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL)
-
- select_boxsizer.Add(item = select_sizer, proportion = 0)
-
+ select_sizer.Add(item = self.lblocations, proportion = 1,
+ flag = wx.EXPAND)
+ select_sizer.Add(item = self.lbmapsets, proportion = 1,
+ flag = wx.EXPAND)
+
+ select_boxsizer.Add(item = select_sizer, proportion = 1,
+ flag = wx.EXPAND)
+
# define new location and mapset
manage_sizer.Add(item = self.ldefine, proportion = 0,
- flag = label_style | wx.ALL,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
manage_sizer.Add(item = self.bwizard, proportion = 0,
- flag = label_style | wx.BOTTOM,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
border = 5)
manage_sizer.Add(item = self.lcreate, proportion = 0,
- flag = label_style | wx.ALL,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
manage_sizer.Add(item = self.bmapset, proportion = 0,
- flag = label_style | wx.BOTTOM,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
border = 5)
manage_sizer.Add(item = self.lmanageloc, proportion = 0,
- flag = label_style | wx.ALL,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
border = 3)
manage_sizer.Add(item = self.manageloc, proportion = 0,
- flag = label_style | wx.BOTTOM,
+ flag = wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
border = 5)
-
- manage_boxsizer.Add(item = manage_sizer, proportion = 0)
-
+
# location sizer
- location_sizer.Add(item = select_boxsizer, proportion = 0,
- flag = wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL |
- wx.RIGHT | wx.LEFT | wx.EXPAND,
- border = 3) # GISDBASE setting
- location_sizer.Add(item = manage_boxsizer, proportion = 0,
- flag = wx.ADJUST_MINSIZE |
- wx.ALIGN_TOP |
- wx.ALIGN_CENTER_HORIZONTAL |
- wx.RIGHT | wx.EXPAND,
+ location_sizer.Add(item = select_boxsizer, proportion = 1,
+ flag = wx.LEFT | wx.RIGHT | wx.EXPAND,
+ border = 3)
+ location_sizer.Add(item = manage_sizer, proportion = 0,
+ flag = wx.RIGHT | wx.EXPAND,
border = 3)
-
+
# buttons
btns_sizer.Add(item = self.bstart, proportion = 0,
flag = wx.ALIGN_CENTER_HORIZONTAL |
@@ -336,7 +317,7 @@
wx.ALIGN_CENTER_VERTICAL |
wx.ALL,
border = 5)
-
+
# main sizer
sizer.Add(item = self.hbitmap,
proportion = 0,
@@ -356,24 +337,22 @@
wx.ALIGN_CENTER_HORIZONTAL)
sizer.Add(item = dbase_sizer, proportion = 0,
flag = wx.ALIGN_CENTER_HORIZONTAL |
- wx.RIGHT | wx.LEFT,
- border = 1) # GISDBASE setting
+ wx.RIGHT | wx.LEFT | wx.EXPAND,
+ border = 20) # GISDBASE setting
sizer.Add(item = location_sizer, proportion = 1,
- flag = wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL |
- wx.RIGHT | wx.LEFT,
+ flag = wx.RIGHT | wx.LEFT | wx.EXPAND,
border = 1)
sizer.Add(item = btns_sizer, proportion = 0,
flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL |
wx.RIGHT | wx.LEFT,
border = 1)
-
+
self.panel.SetAutoLayout(True)
self.panel.SetSizer(sizer)
sizer.Fit(self.panel)
sizer.SetSizeHints(self)
-
+
self.Layout()
def _readGisRC(self):
@@ -390,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()
@@ -406,9 +385,9 @@
def OnWizard(self, event):
"""!Location wizard started"""
- from gui_modules import location_wizard
- gWizard = location_wizard.LocationWizard(parent = self,
- grassdatabase = self.tgisdbase.GetValue())
+ from location_wizard.wizard import LocationWizard
+ gWizard = LocationWizard(parent = self,
+ grassdatabase = self.tgisdbase.GetValue())
if gWizard.location != None:
self.OnSetDatabase(event)
self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
@@ -433,8 +412,8 @@
def RenameMapset(self):
"""!Rename selected mapset
"""
- location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
- mapset = utils.UnicodeString(self.listOfMapsets[self.lbmapsets.GetSelection()])
+ location = self.listOfLocations[self.lblocations.GetSelection()]
+ mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
if mapset == 'PERMANENT':
GMessage(parent = self,
message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
@@ -474,7 +453,7 @@
def RenameLocation(self):
"""!Rename selected location
"""
- location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
+ location = self.listOfLocations[self.lblocations.GetSelection()]
dlg = wx.TextEntryDialog(parent = self,
message = _('Current name: %s\n\nEnter new name:') % location,
@@ -565,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. "
@@ -587,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)
@@ -711,6 +690,11 @@
if dlg.ShowModal() == wx.ID_OK:
mapset = dlg.GetValue()
+ if mapset in self.listOfMapsets:
+ GMessage(parent = self,
+ message = _("Mapset <%s> already exists.") % mapset)
+ return
+
try:
os.mkdir(os.path.join(self.gisdbase, location, mapset))
# copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r
@@ -775,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)
@@ -881,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/releasebranch_6_4/gui/wxpython/gmodeler/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,967 @@
+"""!
+ at package gmodeler.dialogs
+
+ at brief wxGUI Graphical Modeler - dialogs
+
+Classes:
+ - dialogs::ModelDataDialog
+ - dialogs::ModelSearchDialog
+ - dialogs::ModelRelationDialog
+ - dialogs::ModelItemDialog
+ - dialogs::ModelLoopDialog
+ - dialogs::ModelConditionDialog
+ - dialogs::ModelListCtrl
+ - dialogs::ValiableListCtrl
+ - dialogs::ItemListCtrl
+ - dialogs::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 wx
+import wx.lib.mixins.listctrl as listmix
+
+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 gui_core.gselect import Select
+from gmodeler.model import *
+
+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 = 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:
+ 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 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() }
+
+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 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 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/frame.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/frame.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/frame.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1471 @@
+"""!
+ at package gmodeler.frame
+
+ at brief wxGUI Graphical Modeler for creating, editing, and managing models
+
+Classes:
+ - frame::ModelFrame
+ - frame::ModelCanvas
+ - frame::ModelEvtHandler
+ - frame::VariablePanel
+ - frame::ItemPanel
+
+(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', 'wxpython'))
+from core import globalvar
+import wx
+from wx.lib import ogl
+import wx.lib.flatnotebook as FN
+
+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.menu import Menu
+from gmodeler.menudata import ModelerData
+from gui_core.forms import GUI
+from gmodeler.preferences import PreferencesDialog, PropertiesDialog
+from gmodeler.toolbars import ModelerToolbar
+
+from gmodeler.model import *
+from gmodeler.dialogs import *
+
+from grass.script import core as grass
+
+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 = ModelerToolbar(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"""
+ if not event.userData:
+ return
+
+ 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 = _('No intermediate data 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 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 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)
+
+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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/frame.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/menudata.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/menudata.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/menudata.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/menudata.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/model.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/model.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/model.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2249 @@
+"""!
+ 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
+ - model::ModelParamDialog
+
+(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 import globalvar
+from core import utils
+from core.gcmd import GMessage, GException, GError, RunCommand, EncodeString, GWarning
+from core.settings import UserSettings
+from gui_core.forms import GUI, CmdPanel
+from gui_core.widgets import GNotebook
+
+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 = 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(cmd[0] + ": " + _("undefined variable '%s'") % 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(cmd + ": " + _("undefined variable '%s'") % 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()
+ delInterData = False
+ if params:
+ dlg = ModelParamDialog(parent = parent,
+ params = params)
+ dlg.CenterOnParent()
+
+ ret = dlg.ShowModal()
+ if ret != wx.ID_OK:
+ dlg.Destroy()
+ return
+
+ err = dlg.GetErrors()
+ delInterData = dlg.DeleteIntermediateData()
+ 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)
+
+ if delInterData:
+ self.DeleteIntermediateData(log)
+
+ # 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(object):
+ 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.Recentre(self, dc) # re-center text
+ 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
+
+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)
+
+ # intermediate data?
+ self.interData = wx.CheckBox(parent = self, label = _("Delete intermediate data when finish"))
+ self.interData.SetValue(True)
+ rast, vect, rast3d, msg = self.parent.GetModel().GetIntermediateData()
+ if not rast and not vect and not rast3d:
+ self.interData.Hide()
+
+ 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)
+ if self.interData.IsShown():
+ mainSizer.Add(item = self.interData, proportion = 0,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+ 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 = 5)
+
+ 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:
+ 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
+
+ def DeleteIntermediateData(self):
+ """!Check if to detele intermediate data"""
+ if self.interData.IsShown() and self.interData.IsChecked():
+ return True
+
+ return False
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/model.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/preferences.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/preferences.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/preferences.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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'])
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/preferences.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,109 @@
+"""!
+ at package gmodeler.toolbars
+
+ at brief wxGUI Graphical Modeler toolbars classes
+
+Classes:
+ - toolbars::ModelerToolbar
+
+(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 wx
+
+from core import globalvar
+from gui_core.toolbars import BaseToolbar, BaseIcons
+
+from icons.icon import MetaIcon
+
+class ModelerToolbar(BaseToolbar):
+ """!Graphical modeler toolbaro (see gmodeler.py)
+ """
+ def __init__(self, parent):
+ BaseToolbar.__init__(self, parent)
+
+ self.InitToolbar(self._toolbarData())
+
+ # realize the toolbar
+ self.Realize()
+
+ def _toolbarData(self):
+ """!Toolbar data"""
+ icons = {
+ 'new' : MetaIcon(img = 'create',
+ label = _('Create new model (Ctrl+N)')),
+ 'open' : MetaIcon(img = 'open',
+ label = _('Load model from file (Ctrl+O)')),
+ 'save' : MetaIcon(img = 'save',
+ label = _('Save current model to file (Ctrl+S)')),
+ 'toImage' : MetaIcon(img = 'image-export',
+ label = _('Export model to image')),
+ 'toPython' : MetaIcon(img = 'python-export',
+ label = _('Export model to Python script')),
+ 'actionAdd' : MetaIcon(img = 'module-add',
+ label = _('Add command (GRASS module) to model')),
+ 'dataAdd' : MetaIcon(img = 'data-add',
+ label = _('Add data to model')),
+ 'relation' : MetaIcon(img = 'relation-create',
+ label = _('Manually define relation between data and commands')),
+ 'loop' : MetaIcon(img = 'loop-add',
+ label = _('Add loop/series')),
+ 'run' : MetaIcon(img = 'execute',
+ label = _('Run model')),
+ 'validate' : MetaIcon(img = 'check',
+ label = _('Validate model')),
+ 'settings' : BaseIcons['settings'].SetLabel(_('Modeler settings')),
+ 'properties' : MetaIcon(img = 'options',
+ label = _('Show model properties')),
+ 'variables' : MetaIcon(img = 'modeler-variables',
+ label = _('Manage model variables')),
+ 'redraw' : MetaIcon(img = 'redraw',
+ label = _('Redraw model canvas')),
+ 'quit' : BaseIcons['quit'].SetLabel(_('Quit Graphical 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", BaseIcons['help'],
+ self.parent.OnHelp),
+ (None, ),
+ ('quit', icons['quit'],
+ self.parent.OnCloseWindow))
+ )
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gmodeler/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2346 @@
+"""!
+ 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, GdalSelect
+from gui_core.forms import GUI
+from gui_core.widgets import SingleSymbolPanel, EVT_SYMBOL_SELECTION_CHANGED
+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, skipCurrent = True)
+
+ 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.UpdateItems(dbase = dbase, location = location)
+ 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, skipCurrent = True,
+ 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), flag = wx.EXPAND)
+
+ 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)
+
+ Valid mapType values:
+ - raster
+ - raster3d
+ - 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:
+ if self.mapType == 'raster':
+ self.layerType.SetSelection(0)
+ elif self.mapType == 'raster3d':
+ self.layerType.SetSelection(1)
+ elif self.mapType == 'vector':
+ self.layerType.SetSelection(2)
+ 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"""
+ if not self.add.IsChecked() or returncode != 0:
+ return
+
+ self.commandId += 1
+ 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)"""
+ self.commandId = -1
+ data = self.list.GetLayers()
+
+ 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)
+
+ 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 only on one item
+ if len(data) == 1:
+ 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)
+
+class SymbolDialog(wx.Dialog):
+ """!Dialog for GRASS symbols selection.
+
+ Dialog is called in gui_core::forms module.
+ """
+ def __init__(self, parent, symbolPath, currentSymbol = None, title = _("Symbols")):
+ """!Dialog constructor.
+
+ It is assumed that symbolPath contains folders with symbols.
+
+ @param parent dialog parent
+ @param symbolPath absolute path to symbols
+ @param currentSymbol currently selected symbol (e.g. 'basic/x')
+ @param title dialog title
+ """
+ wx.Dialog.__init__(self, parent = parent, title = title, id = wx.ID_ANY)
+
+ self.symbolPath = symbolPath
+ self.currentSymbol = currentSymbol # default basic/x
+ self.selected = None
+ self.selectedDir = None
+
+ self._layout()
+
+ def _layout(self):
+ mainPanel = wx.Panel(self, id = wx.ID_ANY)
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ vSizer = wx.BoxSizer( wx.VERTICAL)
+ fgSizer = wx.FlexGridSizer(rows = 2, vgap = 5, hgap = 5)
+ self.folderChoice = wx.Choice(mainPanel, id = wx.ID_ANY, choices = os.listdir(self.symbolPath))
+ self.folderChoice.Bind(wx.EVT_CHOICE, self.OnFolderSelect)
+
+ fgSizer.Add(item = wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol directory:")),
+ proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL)
+
+ fgSizer.Add(item = self.folderChoice, proportion = 0,
+ flag = wx.ALIGN_CENTER, border = 0)
+
+ self.infoLabel = wx.StaticText(mainPanel, id = wx.ID_ANY)
+ fgSizer.Add(wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol name:")),
+ flag = wx.ALIGN_CENTRE_VERTICAL)
+ fgSizer.Add(self.infoLabel, proportion = 0,
+ flag = wx.ALIGN_CENTRE_VERTICAL)
+ vSizer.Add(fgSizer, proportion = 0, flag = wx.ALL, border = 5)
+
+ self.panels = self._createSymbolPanels(mainPanel)
+ for panel in self.panels:
+ vSizer.Add(panel, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+ panel.Bind(EVT_SYMBOL_SELECTION_CHANGED, self.SelectionChanged)
+
+ mainSizer.Add(vSizer, proportion = 1, flag = wx.ALL| wx.EXPAND, border = 5)
+ self.btnCancel = wx.Button(parent = mainPanel, id = wx.ID_CANCEL)
+ self.btnOK = wx.Button(parent = mainPanel, id = wx.ID_OK)
+ self.btnOK.SetDefault()
+ self.btnOK.Enable(False)
+
+ # buttons
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnOK)
+ btnSizer.Realize()
+ mainSizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL, border = 5)
+
+ # show panel with the largest number of images and fit size
+ count = []
+ for folder in os.listdir(self.symbolPath):
+ count.append(len(os.listdir(os.path.join(self.symbolPath, folder))))
+
+ index = count.index(max(count))
+ self.folderChoice.SetSelection(index)
+ self.OnFolderSelect(None)
+ self.infoLabel.Show()
+
+ mainPanel.SetSizerAndFit(mainSizer)
+ self.SetSize(self.GetBestSize())
+
+ # show currently selected symbol
+ if self.currentSymbol:
+ # set directory
+ self.selectedDir, self.selected = os.path.split(self.currentSymbol)
+ self.folderChoice.SetStringSelection(self.selectedDir)
+ # select symbol
+ panelIdx = self.folderChoice.GetSelection()
+ for panel in self.symbolPanels[panelIdx]:
+ if panel.GetName() == self.selected:
+ panel.Select()
+ else:
+ self.folderChoice.SetSelection(0)
+
+ self.OnFolderSelect(None)
+
+ def _createSymbolPanels(self, parent):
+ """!Creates multiple panels with symbols.
+
+ Panels are shown/hidden according to selected folder."""
+ folders = os.listdir(self.symbolPath)
+
+ panels = []
+ self.symbolPanels = []
+ maxImages = 0
+
+ for folder in folders:
+ panel = wx.Panel(parent, style = wx.BORDER_RAISED)
+ sizer = wx.GridSizer(cols = 6, vgap = 3, hgap = 3)
+ images = self._getSymbols(path = os.path.join(self.symbolPath, folder))
+
+ symbolPanels = []
+ for img in images:
+ iP = SingleSymbolPanel(parent = panel, symbolPath = img)
+ sizer.Add(item = iP, proportion = 0, flag = wx.ALIGN_CENTER)
+ symbolPanels.append(iP)
+
+ panel.SetSizerAndFit(sizer)
+ panel.Hide()
+ panels.append(panel)
+ self.symbolPanels.append(symbolPanels)
+
+ return panels
+
+ def _getSymbols(self, path):
+ # we assume that images are in subfolders (1 level only)
+ imageList = []
+ for image in os.listdir(path):
+ imageList.append(os.path.join(path, image))
+
+ return sorted(imageList)
+
+ def OnFolderSelect(self, event):
+ """!Selected folder with symbols changed."""
+ idx = self.folderChoice.GetSelection()
+ for i in range(len(self.panels)):
+ sizer = self.panels[i].GetContainingSizer()
+ sizer.Show(self.panels[i], i == idx, recursive = True)
+ sizer.Layout()
+
+ if self.selectedDir == self.folderChoice.GetStringSelection():
+ self.btnOK.Enable()
+ self.infoLabel.SetLabel(self.selected)
+ else:
+ self.btnOK.Disable()
+ self.infoLabel.SetLabel('')
+
+ def SelectionChanged(self, event):
+ """!Selected symbol changed."""
+ if event.doubleClick:
+ self.EndModal(wx.ID_OK)
+ # deselect all
+ for i in range(len(self.panels)):
+ for panel in self.symbolPanels[i]:
+ if panel.GetName() != event.name:
+ panel.Deselect()
+
+ self.btnOK.Enable()
+
+ self.selected = event.name
+ self.selectedDir = self.folderChoice.GetStringSelection()
+
+ self.infoLabel.SetLabel(event.name)
+
+ def GetSelectedSymbol(self, fullPath = False):
+ """!Returns currently selected symbol.
+
+ @param fullPath true to return absolute path to symbol,
+ otherwise returns e.g. 'basic/x'
+ """
+ if fullPath:
+ return os.path.join(self.symbolPath, self.selectedDir, self.selected)
+
+ return os.path.join(self.selectedDir, self.selected)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/forms.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/forms.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2085 @@
+"""
+ 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', '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()
+ pBind = self.task.get_param(uid, element = 'wxId', raiseError = False)
+ if pBind:
+ pBind['value'] = ''
+
+ 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':
+ self.data[win.Insert] = { 'group' : p.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:
+ from gui_core.goutput import GMConsole
+ self.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:
+ title_txt.SetLabel(title + ':')
+ value = self._getValue(p)
+
+ if p['name'] == 'icon': # symbols
+ bitmap = wx.Bitmap(os.path.join(globalvar.ETCSYMBOLDIR, value) + '.png')
+ bb = wx.BitmapButton(parent = which_panel, id = wx.ID_ANY,
+ bitmap = bitmap)
+ iconLabel = wx.StaticText(parent = which_panel, id = wx.ID_ANY)
+ iconLabel.SetLabel(value)
+ p['value'] = value
+ p['wxId'] = [bb.GetId(), iconLabel.GetId()]
+ bb.Bind(wx.EVT_BUTTON, self.OnSetSymbol)
+ this_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ this_sizer.Add(item = bb, proportion = 0,
+ flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT, border = 5)
+ this_sizer.Add(item = iconLabel, proportion = 0,
+ flag = wx.ADJUST_MINSIZE | wx.BOTTOM | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border = 5)
+ which_sizer.Add(item = this_sizer, proportion = 0,
+ flag = wx.ADJUST_MINSIZE, border = 0)
+ else:
+ # list of values (combo)
+ 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)
+ 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)
+ selection.Bind(wx.EVT_TEXT, 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 OnSetSymbol(self, event):
+ """!Shows dialog for symbol selection"""
+ myId = event.GetId()
+
+ for p in self.task.params:
+ if 'wxId' in p and myId in p['wxId']:
+ from gui_core.dialogs import SymbolDialog
+ dlg = SymbolDialog(self, symbolPath = globalvar.ETCSYMBOLDIR,
+ currentSymbol = p['value'])
+ if dlg.ShowModal() == wx.ID_OK:
+ img = dlg.GetSelectedSymbol(fullPath = True)
+ p['value'] = dlg.GetSelectedSymbol(fullPath = False)
+
+ bitmapButton = wx.FindWindowById(p['wxId'][0])
+ label = wx.FindWindowById(p['wxId'][1])
+
+ bitmapButton.SetBitmapLabel(wx.Bitmap(img + '.png'))
+ label.SetLabel(p['value'])
+
+ self.OnUpdateValues(event)
+
+ dlg.Destroy()
+
+ 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(gcmd.GetRealCmd(cmd[0]),
+ blackList = _blackList)
+ except (grass.ScriptError, ValueError), e:
+ raise gcmd.GException(e)
+
+ # 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(gcmd.GetRealCmd(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()
+
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/forms.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/ghelp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/ghelp.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/ghelp.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,908 @@
+"""!
+ 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 sys
+import codecs
+import platform
+
+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 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, ScrolledPanel
+
+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, 450),
+ title = _('About GRASS GIS'), **kwargs):
+ wx.Frame.__init__(self, parent = parent, id = wx.ID_ANY, title = title, 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-64x64.png")
+ logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
+ bitmap = wx.Bitmap(name = logo,
+ type = wx.BITMAP_TYPE_PNG))
+ 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, ""))
+ info.SetForegroundColour(wx.Colour(35, 142, 35))
+ 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)
+
+ row += 2
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = _('Python:')),
+ pos = (row, 0),
+ flag = wx.ALIGN_RIGHT)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = platform.python_version()),
+ pos = (row, 1),
+ flag = wx.ALIGN_LEFT)
+
+ row += 1
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = _('wxPython:')),
+ pos = (row, 0),
+ flag = wx.ALIGN_RIGHT)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = wx.__version__),
+ pos = (row, 1),
+ flag = wx.ALIGN_LEFT)
+
+ infoSizer.Add(item = infoGridSizer,
+ proportion = 1,
+ flag = wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
+
+ # 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()
+ self.SetMinSize((500, 400))
+
+ 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 = ScrolledPanel(self)
+
+ 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 = ScrolledPanel(self)
+ 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 = ScrolledPanel(self)
+ authortxt = wx.StaticText(authorwin, id = wx.ID_ANY, label = authors)
+ authorwin.SetAutoLayout(True)
+ 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 = ScrolledPanel(self)
+ 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 = ScrolledPanel(self)
+ translatorswin.SetAutoLayout(True)
+ 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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/ghelp.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/goutput.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/goutput.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/goutput.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1151 @@
+"""!
+ 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()
+
+ if command[0] in globalvar.grassCmd:
+ # 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
+
+ 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|...)
+ hasParams = False
+ if command[0] != 'r.mapcalc':
+ try:
+ task = GUI(show = None).ParseCommand(command)
+ except GException, e:
+ GError(parent = self,
+ message = unicode(e),
+ showTraceback = False)
+ return
+
+ if task:
+ options = task.get_options()
+ hasParams = options['params'] and options['flags']
+ # check for <input>=-
+ for p in options['params']:
+ if p.get('prompt', '') == 'input' and \
+ p.get('element', '') == 'file' and \
+ p.get('age', 'new') == 'old' and \
+ p.get('value', '') == '-':
+ GError(parent = self,
+ message = _("Unable to run command:\n%(cmd)s\n\n"
+ "Option <%(opt)s>: read from standard input is not "
+ "supported by wxGUI") % { 'cmd': ' '.join(command),
+ 'opt': p.get('name', '') })
+ return
+ else:
+ task = None
+
+ if len(command) == 1 and hasParams and \
+ command[0] != 'v.krige.py':
+ # no arguments given
+ try:
+ GUI(parent = self).ParseCommand(command)
+ except GException, e:
+ print >> sys.stderr, e
+ return
+
+ # switch to 'Command output' if required
+ if switchPage:
+ self._notebook.SetSelectionByName('output')
+
+ self.parent.SetFocus()
+ self.parent.Raise()
+
+ # activate computational region (set with g.region)
+ # for all non-display commands.
+ if compReg:
+ tmpreg = os.getenv("GRASS_REGION")
+ if "GRASS_REGION" in os.environ:
+ del os.environ["GRASS_REGION"]
+
+ # process GRASS command with argument
+ self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
+ onDone = onDone, onPrepare = onPrepare, userData = userData)
+ self.cmdOutputTimer.Start(50)
+
+ # deactivate computational region and return to display settings
+ if compReg and tmpreg:
+ os.environ["GRASS_REGION"] = tmpreg
+ else:
+ # Send any other command to the shell. Send output to
+ # console output window
+ if len(command) == 1:
+ try:
+ task = gtask.parse_interface(command[0])
+ except:
+ task = None
+ else:
+ task = None
+
+ if task:
+ # process GRASS command without argument
+ GUI(parent = self).ParseCommand(command)
+ else:
+ self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
+ onDone = onDone, onPrepare = onPrepare, userData = userData)
+ self.cmdOutputTimer.Start(50)
+
+ 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)
+
+ # Process results here
+ try:
+ ctime = time.time() - event.time
+ if ctime < 60:
+ stime = _("%d sec") % int(ctime)
+ else:
+ mtime = int(ctime / 60)
+ stime = _("%(min)d min %(sec)d sec") % { 'min' : mtime,
+ 'sec' : int(ctime - (mtime * 60)) }
+ except KeyError:
+ # stopped deamon
+ stime = _("unknown")
+
+ 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)
+ msg = _('Command aborted')
+ else:
+ msg = _('Command finished')
+
+ self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime))
+ 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 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, e:
+ print >> sys.stderr, e
+ task = None
+ return
+
+ for p in task.get_options()['params']:
+ if p.get('prompt', '') not in ('raster', 'vector'):
+ continue
+ mapName = p.get('value', '')
+ if '@' not in mapName:
+ mapName = mapName + '@' + grass.gisenv()['MAPSET']
+ if mapName in mapLayers:
+ display.GetWindow().UpdateMap(render = True)
+ return
+ elif self.parent.GetName() == 'Modeler':
+ pass
+ else: # standalone dialogs
+ dialog = self.parent.parent
+ if hasattr(self.parent.parent, "btn_abort"):
+ dialog.btn_abort.Enable(False)
+
+ if hasattr(self.parent.parent, "btn_cancel"):
+ dialog.btn_cancel.Enable(True)
+
+ if hasattr(self.parent.parent, "btn_clipboard"):
+ dialog.btn_clipboard.Enable(True)
+
+ if hasattr(self.parent.parent, "btn_help"):
+ dialog.btn_help.Enable(True)
+
+ if hasattr(self.parent.parent, "btn_run"):
+ dialog.btn_run.Enable(True)
+
+ if event.returncode == 0 and not event.aborted:
+ try:
+ winName = self.parent.parent.parent.GetName()
+ except AttributeError:
+ winName = ''
+
+ if winName == 'LayerManager':
+ mapTree = self.parent.parent.parent.GetLayerTree()
+ elif winName == 'LayerTree':
+ mapTree = self.parent.parent.parent
+ elif winName: # GMConsole
+ mapTree = self.parent.parent.parent.parent.GetLayerTree()
+ else:
+ mapTree = None
+
+ cmd = dialog.notebookpanel.createCmd(ignoreErrors = True)
+ if hasattr(dialog, "addbox") and dialog.addbox.IsChecked():
+ # add created maps into layer tree
+ for p in dialog.task.get_options()['params']:
+ prompt = p.get('prompt', '')
+ if prompt in ('raster', 'vector', '3d-raster') and \
+ p.get('age', 'old') == 'new' and \
+ p.get('value', None):
+ name, found = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
+ param = p.get('name', ''))
+
+ if mapTree.GetMap().GetListOfLayers(l_name = name):
+ continue
+
+ if prompt == 'raster':
+ lcmd = ['d.rast',
+ 'map=%s' % name]
+ else:
+ lcmd = ['d.vect',
+ 'map=%s' % name]
+ mapTree.AddLayer(ltype = prompt,
+ lcmd = lcmd,
+ lname = name)
+
+ if hasattr(dialog, "get_dcmd") and \
+ dialog.get_dcmd is None and \
+ hasattr(dialog, "closebox") and \
+ dialog.closebox.IsChecked() and \
+ (event.returncode == 0 or event.aborted):
+ self.cmdOutput.Update()
+ time.sleep(2)
+ dialog.Close()
+
+ def OnProcessPendingOutputWindowEvents(self, event):
+ self.ProcessPendingEvents()
+
+ def ResetFocus(self):
+ """!Reset focus"""
+ self.cmdPrompt.SetFocus()
+
+class GMStdout:
+ """!GMConsole standard output
+
+ Based on FrameOutErr.py
+
+ Name: FrameOutErr.py
+ Purpose: Redirecting stdout / stderr
+ Author: Jean-Michel Fauth, Switzerland
+ Copyright: (c) 2005-2007 Jean-Michel Fauth
+ Licence: GPL
+ """
+ def __init__(self, parent):
+ self.parent = parent # GMConsole
+
+ def write(self, s):
+ if len(s) == 0 or s == '\n':
+ return
+
+ for line in s.splitlines():
+ if len(line) == 0:
+ continue
+
+ evt = wxCmdOutput(text = line + '\n',
+ type = '')
+ wx.PostEvent(self.parent.cmdOutput, evt)
+
+class GMStderr:
+ """!GMConsole standard error output
+
+ Based on FrameOutErr.py
+
+ Name: FrameOutErr.py
+ Purpose: Redirecting stdout / stderr
+ Author: Jean-Michel Fauth, Switzerland
+ Copyright: (c) 2005-2007 Jean-Michel Fauth
+ Licence: GPL
+ """
+ def __init__(self, parent):
+ self.parent = parent # GMConsole
+
+ self.type = ''
+ self.message = ''
+ self.printMessage = False
+
+ def flush(self):
+ pass
+
+ def write(self, s):
+ if "GtkPizza" in s:
+ return
+
+ # remove/replace escape sequences '\b' or '\r' from stream
+ progressValue = -1
+
+ for line in s.splitlines():
+ if len(line) == 0:
+ continue
+
+ if 'GRASS_INFO_PERCENT' in line:
+ value = int(line.rsplit(':', 1)[1].strip())
+ if value >= 0 and value < 100:
+ progressValue = value
+ else:
+ progressValue = 0
+ elif 'GRASS_INFO_MESSAGE' in line:
+ self.type = 'message'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_WARNING' in line:
+ self.type = 'warning'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_ERROR' in line:
+ self.type = 'error'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_END' in line:
+ self.printMessage = True
+ elif self.type == '':
+ if len(line) == 0:
+ continue
+ evt = wxCmdOutput(text = line,
+ type = '')
+ wx.PostEvent(self.parent.cmdOutput, evt)
+ elif len(line) > 0:
+ self.message += line.strip() + '\n'
+
+ if self.printMessage and len(self.message) > 0:
+ evt = wxCmdOutput(text = self.message,
+ type = self.type)
+ wx.PostEvent(self.parent.cmdOutput, evt)
+
+ self.type = ''
+ self.message = ''
+ self.printMessage = False
+
+ # update progress message
+ if progressValue > -1:
+ # self.gmgauge.SetValue(progressValue)
+ evt = wxCmdProgress(value = progressValue)
+ wx.PostEvent(self.parent.progressbar, evt)
+
+class GMStc(wx.stc.StyledTextCtrl):
+ """!Styled GMConsole
+
+ Based on FrameOutErr.py
+
+ Name: FrameOutErr.py
+ Purpose: Redirecting stdout / stderr
+ Author: Jean-Michel Fauth, Switzerland
+ Copyright: (c) 2005-2007 Jean-Michel Fauth
+ Licence: GPL
+ """
+ def __init__(self, parent, id, margin = False, wrap = None):
+ wx.stc.StyledTextCtrl.__init__(self, parent, id)
+ self.parent = parent
+ self.SetUndoCollection(True)
+ self.SetReadOnly(True)
+
+ #
+ # styles
+ #
+ self.SetStyle()
+
+ #
+ # line margins
+ #
+ # TODO print number only from cmdlog
+ self.SetMarginWidth(1, 0)
+ self.SetMarginWidth(2, 0)
+ if margin:
+ self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+ self.SetMarginWidth(0, 30)
+ else:
+ self.SetMarginWidth(0, 0)
+
+ #
+ # miscellaneous
+ #
+ self.SetViewWhiteSpace(False)
+ self.SetTabWidth(4)
+ self.SetUseTabs(False)
+ self.UsePopUp(True)
+ self.SetSelBackground(True, "#FFFF00")
+ self.SetUseHorizontalScrollBar(True)
+
+ #
+ # bindings
+ #
+ self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+ def OnTextSelectionChanged(self, event):
+ """!Copy selected text to clipboard and skip event.
+ The same function is in TextCtrlAutoComplete class (prompt.py).
+ """
+ self.Copy()
+ event.Skip()
+
+ def SetStyle(self):
+ """!Set styles for styled text output windows with type face
+ and point size selected by user (Courier New 10 is default)"""
+
+ settings = Settings()
+
+ typeface = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'type')
+ if typeface == "":
+ typeface = "Courier New"
+
+ typesize = settings.Get(group = 'appearance', key = 'outputfont', subkey = 'size')
+ if typesize == None or typesize <= 0:
+ typesize = 10
+ typesize = float(typesize)
+
+ self.StyleDefault = 0
+ self.StyleDefaultSpec = "face:%s,size:%d,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+ self.StyleCommand = 1
+ self.StyleCommandSpec = "face:%s,size:%d,,fore:#000000,back:#bcbcbc" % (typeface, typesize)
+ self.StyleOutput = 2
+ self.StyleOutputSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+ # fatal error
+ self.StyleError = 3
+ self.StyleErrorSpec = "face:%s,size:%d,,fore:#7F0000,back:#FFFFFF" % (typeface, typesize)
+ # warning
+ self.StyleWarning = 4
+ self.StyleWarningSpec = "face:%s,size:%d,,fore:#0000FF,back:#FFFFFF" % (typeface, typesize)
+ # message
+ self.StyleMessage = 5
+ self.StyleMessageSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+ # unknown
+ self.StyleUnknown = 6
+ self.StyleUnknownSpec = "face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
+
+ # default and clear => init
+ self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, self.StyleDefaultSpec)
+ self.StyleClearAll()
+ self.StyleSetSpec(self.StyleCommand, self.StyleCommandSpec)
+ self.StyleSetSpec(self.StyleOutput, self.StyleOutputSpec)
+ self.StyleSetSpec(self.StyleError, self.StyleErrorSpec)
+ self.StyleSetSpec(self.StyleWarning, self.StyleWarningSpec)
+ self.StyleSetSpec(self.StyleMessage, self.StyleMessageSpec)
+ self.StyleSetSpec(self.StyleUnknown, self.StyleUnknownSpec)
+
+ def OnDestroy(self, evt):
+ """!The clipboard contents can be preserved after
+ the app has exited"""
+
+ wx.TheClipboard.Flush()
+ evt.Skip()
+
+ def AddTextWrapped(self, txt, wrap = None):
+ """!Add string to text area.
+
+ String is wrapped and linesep is also added to the end
+ of the string"""
+ # allow writing to output window
+ self.SetReadOnly(False)
+
+ if wrap:
+ txt = textwrap.fill(txt, wrap) + '\n'
+ else:
+ if txt[-1] != '\n':
+ txt += '\n'
+
+ if '\r' in txt:
+ self.parent.linePos = -1
+ for seg in txt.split('\r'):
+ if self.parent.linePos > -1:
+ self.SetCurrentPos(self.parent.linePos)
+ self.ReplaceSelection(seg)
+ else:
+ self.parent.linePos = self.GetCurrentPos()
+ self.AddText(seg)
+ else:
+ self.parent.linePos = self.GetCurrentPos()
+ try:
+ self.AddText(txt)
+ except UnicodeDecodeError:
+ enc = UserSettings.Get(group = 'atm', key = 'encoding', subkey = 'value')
+ if enc:
+ txt = unicode(txt, enc)
+ elif 'GRASS_DB_ENCODING' in os.environ:
+ txt = unicode(txt, os.environ['GRASS_DB_ENCODING'])
+ else:
+ txt = EncodeString(txt)
+
+ self.AddText(txt)
+
+ # reset output window to read only
+ self.SetReadOnly(True)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/goutput.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/gselect.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/gselect.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/gselect.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1708 @@
+"""!
+ 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, GetVectorNumberOfLayers
+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:
+ value = self.param.get('value', '')
+ if value != '' and value in columns:
+ self.SetValue(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:
+ value = self.param.get('value', '')
+ if value != '' and value in columns:
+ self.SetValue(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, skipCurrent = False, **kwargs):
+ super(MapsetSelect, self).__init__(parent, id, size = size,
+ style = wx.CB_READONLY, **kwargs)
+ self.searchPath = searchPath
+ self.skipCurrent = skipCurrent
+
+ 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:
+ mlist = RunCommand('g.mapsets',
+ read = True, flags = 'p',
+ fs = 'newline').splitlines()
+ else:
+ mlist = GetListOfMapsets(self.gisdbase, self.location,
+ selectable = False)
+
+ gisenv = grass.gisenv()
+ if self.skipCurrent and \
+ gisenv['LOCATION_NAME'] == self.location and \
+ gisenv['MAPSET'] in mlist:
+ mlist.remove(gisenv['MAPSET'])
+
+ return mlist
+
+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,
+ **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,
+ **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,
+ **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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/gselect.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapdisp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapdisp.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapdisp.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,338 @@
+"""!
+ 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 sys
+
+import wx
+
+from core import globalvar
+from core.debug import Debug
+
+from grass.script import core as grass
+
+class MapFrameBase(wx.Frame):
+ """!Base class for map display window
+
+ Derived class must use statusbarManager or override
+ GetProperty, SetProperty and HasProperty methods.
+ If derived class enables and disables auto-rendering,
+ it should override IsAutoRendered method.
+ """
+ def __init__(self, parent = None, id = wx.ID_ANY, title = None,
+ style = wx.DEFAULT_FRAME_STYLE, toolbars = None,
+ Map = None, auimgr = None, name = None, **kwargs):
+ """!
+ @param toolbars array of activated toolbars, e.g. ['map', 'digit']
+ @param Map instance of render.Map
+ @param auimgs AUI manager
+ @param name frame name
+ @param kwargs wx.Frame attributes
+ """
+
+
+ self.Map = Map # instance of render.Map
+ self.parent = parent
+
+ wx.Frame.__init__(self, parent, id, title, style = style, name = name, **kwargs)
+
+ # available cursors
+ self.cursors = {
+ # default: cross
+ # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
+ "default" : wx.StockCursor(wx.CURSOR_ARROW),
+ "cross" : wx.StockCursor(wx.CURSOR_CROSS),
+ "hand" : wx.StockCursor(wx.CURSOR_HAND),
+ "pencil" : wx.StockCursor(wx.CURSOR_PENCIL),
+ "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
+ }
+
+ #
+ # set the size & system icon
+ #
+ self.SetClientSize(self.GetSize())
+ self.iconsize = (16, 16)
+
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
+
+ # toolbars
+ self.toolbars = {}
+
+ #
+ # Fancy gui
+ #
+ self._mgr = wx.aui.AuiManager(self)
+
+ def _initMap(self, map):
+ """!Initialize map display, set dimensions and map region
+ """
+ if not grass.find_program('g.region', ['--help']):
+ sys.exit(_("GRASS module '%s' not found. Unable to start map "
+ "display window.") % 'g.region')
+
+ self.width, self.height = self.GetClientSize()
+
+ Debug.msg(2, "MapFrame._initMap():")
+ map.ChangeMapSize(self.GetClientSize())
+ map.region = map.GetRegion() # g.region -upgc
+ # self.Map.SetRegion() # adjust region to match display window
+
+ def SetProperty(self, name, value):
+ """!Sets property"""
+ self.statusbarManager.SetProperty(name, value)
+
+ def GetProperty(self, name):
+ """!Returns property"""
+ return self.statusbarManager.GetProperty(name)
+
+ def HasProperty(self, name):
+ """!Checks whether object has property"""
+ return self.statusbarManager.HasProperty(name)
+
+ def GetPPM(self):
+ """! Get pixel per meter
+
+ @todo now computed every time, is it necessary?
+ @todo enable user to specify ppm (and store it in UserSettings)
+ """
+ # TODO: need to be fixed...
+ ### screen X region problem
+ ### user should specify ppm
+ dc = wx.ScreenDC()
+ dpSizePx = wx.DisplaySize() # display size in pixels
+ dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
+ dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
+ sysPpi = dc.GetPPI()
+ comPpi = (dpSizePx[0] / dpSizeIn[0],
+ dpSizePx[1] / dpSizeIn[1])
+
+ ppi = comPpi # pixel per inch
+ ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
+ (ppi[1] / 2.54) * 100)
+
+ Debug.msg(4, "MapFrameBase.GetPPM(): size: px=%d,%d mm=%f,%f "
+ "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
+ (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
+ dpSizeIn[0], dpSizeIn[1],
+ sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
+ ppm[0], ppm[1]))
+
+ return ppm
+
+ def SetMapScale(self, value, map = None):
+ """! Set current map scale
+
+ @param value scale value (n if scale is 1:n)
+ @param map Map instance (if none self.Map is used)
+ """
+ if not map:
+ map = self.Map
+
+ region = self.Map.region
+ dEW = value * (region['cols'] / self.GetPPM()[0])
+ dNS = value * (region['rows'] / self.GetPPM()[1])
+ region['n'] = region['center_northing'] + dNS / 2.
+ region['s'] = region['center_northing'] - dNS / 2.
+ region['w'] = region['center_easting'] - dEW / 2.
+ region['e'] = region['center_easting'] + dEW / 2.
+
+ # add to zoom history
+ self.GetWindow().ZoomHistory(region['n'], region['s'],
+ region['e'], region['w'])
+
+ def GetMapScale(self, map = None):
+ """! Get current map scale
+
+ @param map Map instance (if none self.Map is used)
+ """
+ if not map:
+ map = self.Map
+
+ region = map.region
+ ppm = self.GetPPM()
+
+ heightCm = region['rows'] / ppm[1] * 100
+ widthCm = region['cols'] / ppm[0] * 100
+
+ Debug.msg(4, "MapFrame.GetMapScale(): width_cm=%f, height_cm=%f" %
+ (widthCm, heightCm))
+
+ xscale = (region['e'] - region['w']) / (region['cols'] / ppm[0])
+ yscale = (region['n'] - region['s']) / (region['rows'] / ppm[1])
+ scale = (xscale + yscale) / 2.
+
+ Debug.msg(3, "MapFrame.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" % \
+ (xscale, yscale, scale))
+
+ return scale
+
+ def GetProgressBar(self):
+ """!Returns progress bar
+
+ Progress bar can be used by other classes.
+ """
+ return self.statusbarManager.GetProgressBar()
+
+ def GetMap(self):
+ """!Returns current Map instance
+ """
+ return self.Map
+
+ def GetWindow(self):
+ """!Get map window"""
+ return self.MapWindow
+
+ def GetMapToolbar(self):
+ """!Returns toolbar with zooming tools"""
+ raise NotImplementedError()
+
+ def GetToolbar(self, name):
+ """!Returns toolbar if exists else None.
+
+ Toolbars dictionary contains currently used toolbars only.
+ """
+ if name in self.toolbars:
+ return self.toolbars[name]
+
+ return None
+
+ def StatusbarUpdate(self):
+ """!Update statusbar content"""
+ self.statusbarManager.Update()
+
+ def IsAutoRendered(self):
+ """!Check if auto-rendering is enabled"""
+ return self.GetProperty('render')
+
+ def CoordinatesChanged(self):
+ """!Shows current coordinates on statusbar.
+
+ Used in BufferedWindow to report change of map coordinates (under mouse cursor).
+ """
+ self.statusbarManager.ShowItem('coordinates')
+
+ def StatusbarReposition(self):
+ """!Reposition items in statusbar"""
+ self.statusbarManager.Reposition()
+
+ def StatusbarEnableLongHelp(self, enable = True):
+ """!Enable/disable toolbars long help"""
+ for toolbar in self.toolbars.itervalues():
+ toolbar.EnableLongHelp(enable)
+
+ def IsStandalone(self):
+ """!Check if Map display is standalone"""
+ raise NotImplementedError("IsStandalone")
+
+ def OnRender(self, event):
+ """!Re-render map composition (each map layer)
+ """
+ raise NotImplementedError("OnRender")
+
+ def OnDraw(self, event):
+ """!Re-display current map composition
+ """
+ self.MapWindow.UpdateMap(render = False)
+
+ def OnErase(self, event):
+ """!Erase the canvas
+ """
+ self.MapWindow.EraseMap()
+
+ def OnZoomIn(self, event):
+ """!Zoom in the map.
+ Set mouse cursor, zoombox attributes, and zoom direction
+ """
+ toolbar = self.GetMapToolbar()
+ self._switchTool(toolbar, event)
+
+ win = self.GetWindow()
+ self._prepareZoom(mapWindow = win, zoomType = 1)
+
+ def OnZoomOut(self, event):
+ """!Zoom out the map.
+ Set mouse cursor, zoombox attributes, and zoom direction
+ """
+ toolbar = self.GetMapToolbar()
+ self._switchTool(toolbar, event)
+
+ win = self.GetWindow()
+ self._prepareZoom(mapWindow = win, zoomType = -1)
+
+ def _prepareZoom(self, mapWindow, zoomType):
+ """!Prepares MapWindow for zoom, toggles toolbar
+
+ @param mapWindow MapWindow to prepare
+ @param zoomType 1 for zoom in, -1 for zoom out
+ """
+ mapWindow.mouse['use'] = "zoom"
+ mapWindow.mouse['box'] = "box"
+ mapWindow.zoomtype = zoomType
+ mapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
+
+ # change the cursor
+ mapWindow.SetCursor(self.cursors["cross"])
+
+ def _switchTool(self, toolbar, event):
+ """!Helper function to switch tools"""
+ if toolbar:
+ toolbar.OnTool(event)
+ toolbar.action['desc'] = ''
+
+ def OnPan(self, event):
+ """!Panning, set mouse to drag
+ """
+ toolbar = self.GetMapToolbar()
+ self._switchTool(toolbar, event)
+
+ win = self.GetWindow()
+ self._preparePan(mapWindow = win)
+
+ def _preparePan(self, mapWindow):
+ """!Prepares MapWindow for pan, toggles toolbar
+
+ @param mapWindow MapWindow to prepare
+ """
+ mapWindow.mouse['use'] = "pan"
+ mapWindow.mouse['box'] = "pan"
+ mapWindow.zoomtype = 0
+
+ # change the cursor
+ mapWindow.SetCursor(self.cursors["hand"])
+
+ def OnZoomBack(self, event):
+ """!Zoom last (previously stored position)
+ """
+ self.MapWindow.ZoomBack()
+
+ def OnZoomToMap(self, event):
+ """!
+ Set display extents to match selected raster (including NULLs)
+ or vector map.
+ """
+ self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
+
+ def OnZoomToWind(self, event):
+ """!Set display geometry to match computational region
+ settings (set with g.region)
+ """
+ self.MapWindow.ZoomToWind()
+
+ def OnZoomToDefault(self, event):
+ """!Set display geometry to match default region settings
+ """
+ self.MapWindow.ZoomToDefault()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapdisp.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapwindow.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapwindow.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapwindow.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/mapwindow.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/menu.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/menu.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/menu.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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:
+ 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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/menu.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/preferences.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/preferences.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/preferences.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1565 @@
+"""!
+ 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 = UserSettings):
+
+ PreferencesBaseDialog.__init__(self, parent = parent, title = title,
+ settings = settings)
+
+ # create notebook pages
+ self._createGeneralPage(self.notebook)
+ self._createAppearancePage(self.notebook)
+ self._createDisplayPage(self.notebook)
+ self._createCmdPage(self.notebook)
+ self._createAttributeManagerPage(self.notebook)
+ self._createProjectionPage(self.notebook)
+
+ self.SetMinSize(self.GetBestSize())
+ self.SetSize(self.size)
+
+ def _createGeneralPage(self, notebook):
+ """!Create notebook page for general settings"""
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+ notebook.AddPage(page = panel, text = _("General"))
+
+ border = wx.BoxSizer(wx.VERTICAL)
+ #
+ # Layer Manager settings
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Layer Manager settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+ #
+ # ask when removing map layer from layer tree
+ #
+ row = 0
+ askOnRemoveLayer = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Ask when removing map layer from layer tree"),
+ name = 'IsChecked')
+ askOnRemoveLayer.SetValue(self.settings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'))
+ self.winId['manager:askOnRemoveLayer:enabled'] = askOnRemoveLayer.GetId()
+
+ gridSizer.Add(item = askOnRemoveLayer,
+ pos = (row, 0), span = (1, 2))
+
+ row += 1
+ askOnQuit = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Ask when quiting wxGUI or closing display"),
+ name = 'IsChecked')
+ askOnQuit.SetValue(self.settings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'))
+ self.winId['manager:askOnQuit:enabled'] = askOnQuit.GetId()
+
+ gridSizer.Add(item = askOnQuit,
+ pos = (row, 0), span = (1, 2))
+
+ row += 1
+ hideSearch = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Hide '%s' tab (requires GUI restart)") % _("Search module"),
+ name = 'IsChecked')
+ hideSearch.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'))
+ self.winId['manager:hideTabs:search'] = hideSearch.GetId()
+
+ gridSizer.Add(item = hideSearch,
+ pos = (row, 0), span = (1, 2))
+
+ row += 1
+ hidePyShell = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Hide '%s' tab (requires GUI restart)") % _("Python shell"),
+ name = 'IsChecked')
+ hidePyShell.SetValue(self.settings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'))
+ self.winId['manager:hideTabs:pyshell'] = hidePyShell.GetId()
+
+ gridSizer.Add(item = hidePyShell,
+ pos = (row, 0), span = (1, 2))
+
+ #
+ # Selected text is copied to clipboard
+ #
+ row += 1
+ copySelectedTextToClipboard = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Automatically copy selected text to clipboard (in Command console)"),
+ name = 'IsChecked')
+ copySelectedTextToClipboard.SetValue(self.settings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled'))
+ self.winId['manager:copySelectedTextToClipboard:enabled'] = copySelectedTextToClipboard.GetId()
+
+ gridSizer.Add(item = copySelectedTextToClipboard,
+ pos = (row, 0), span = (1, 2))
+
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+ #
+ # workspace
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Workspace settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+ row = 0
+ posDisplay = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Suppress positioning Map Display Window(s)"),
+ name = 'IsChecked')
+ posDisplay.SetValue(self.settings.Get(group = 'general', key = 'workspace',
+ subkey = ['posDisplay', 'enabled']))
+ self.winId['general:workspace:posDisplay:enabled'] = posDisplay.GetId()
+
+ gridSizer.Add(item = posDisplay,
+ pos = (row, 0), span = (1, 2))
+
+ row += 1
+
+ posManager = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Suppress positioning Layer Manager window"),
+ name = 'IsChecked')
+ posManager.SetValue(self.settings.Get(group = 'general', key = 'workspace',
+ subkey = ['posManager', 'enabled']))
+ self.winId['general:workspace:posManager:enabled'] = posManager.GetId()
+
+ gridSizer.Add(item = posManager,
+ pos = (row, 0), span = (1, 2))
+
+ row += 1
+ defaultPos = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Save current window layout as default"),
+ name = 'IsChecked')
+ defaultPos.SetValue(self.settings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'))
+ defaultPos.SetToolTip(wx.ToolTip (_("Save current position and size of Layer Manager window and opened "
+ "Map Display window(s) and use as default for next sessions.")))
+ self.winId['general:defWindowPos:enabled'] = defaultPos.GetId()
+
+ gridSizer.Add(item = defaultPos,
+ pos = (row, 0), span = (1, 2))
+
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+ panel.SetSizer(border)
+
+ return panel
+
+
+ panel.SetSizer(border)
+
+ return panel
+
+ def _createAppearancePage(self, notebook):
+ """!Create notebook page for display settings"""
+
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+ notebook.AddPage(page = panel, text = _("Appearance"))
+
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+ #
+ # font settings
+ #
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+ row = 0
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Font for command output:")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ outfontButton = wx.Button(parent = panel, id = wx.ID_ANY,
+ label = _("Set font"), size = (100, -1))
+ gridSizer.Add(item = outfontButton,
+ flag = wx.ALIGN_RIGHT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 1))
+
+ #
+ # appearence
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Appearance settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+ #
+ # element list
+ #
+ row = 0
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Element list:")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ elementList = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
+ choices = self.settings.Get(group = 'appearance', key = 'elementListExpand',
+ subkey = 'choices', internal = True),
+ name = "GetSelection")
+ elementList.SetSelection(self.settings.Get(group = 'appearance', key = 'elementListExpand',
+ subkey = 'selection'))
+ self.winId['appearance:elementListExpand:selection'] = elementList.GetId()
+
+ gridSizer.Add(item = elementList,
+ flag = wx.ALIGN_RIGHT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 1))
+
+ #
+ # menu style
+ #
+ row += 1
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Menu style (requires GUI restart):")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ listOfStyles = self.settings.Get(group = 'appearance', key = 'menustyle',
+ subkey = 'choices', internal = True)
+
+ menuItemText = wx.Choice(parent = panel, id = wx.ID_ANY, size = (325, -1),
+ choices = listOfStyles,
+ name = "GetSelection")
+ menuItemText.SetSelection(self.settings.Get(group = 'appearance', key = 'menustyle', subkey = 'selection'))
+
+ self.winId['appearance:menustyle:selection'] = menuItemText.GetId()
+
+ gridSizer.Add(item = menuItemText,
+ flag = wx.ALIGN_RIGHT,
+ pos = (row, 1))
+
+ #
+ # gselect.TreeCtrlComboPopup height
+ #
+ row += 1
+
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Height of map selection popup window (in pixels):")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ min = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'min', internal = True)
+ max = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'max', internal = True)
+ value = self.settings.Get(group = 'appearance', key = 'gSelectPopupHeight', subkey = 'value')
+
+ popupHeightSpin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1))
+ popupHeightSpin.SetRange(min,max)
+ popupHeightSpin.SetValue(value)
+
+ self.winId['appearance:gSelectPopupHeight:value'] = popupHeightSpin.GetId()
+
+ gridSizer.Add(item = popupHeightSpin,
+ flag = wx.ALIGN_RIGHT,
+ pos = (row, 1))
+
+
+ #
+ # icon theme
+ #
+ row += 1
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Icon theme (requires GUI restart):")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ iconTheme = wx.Choice(parent = panel, id = wx.ID_ANY, size = (100, -1),
+ choices = self.settings.Get(group = 'appearance', key = 'iconTheme',
+ subkey = 'choices', internal = True),
+ name = "GetStringSelection")
+ iconTheme.SetStringSelection(self.settings.Get(group = 'appearance', key = 'iconTheme', subkey = 'type'))
+ self.winId['appearance:iconTheme:type'] = iconTheme.GetId()
+
+ gridSizer.Add(item = iconTheme,
+ flag = wx.ALIGN_RIGHT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 1))
+
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+ panel.SetSizer(border)
+
+ # bindings
+ outfontButton.Bind(wx.EVT_BUTTON, self.OnSetOutputFont)
+
+ return panel
+
+ def _createDisplayPage(self, notebook):
+ """!Create notebook page for display settings"""
+
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY)
+ notebook.AddPage(page = panel, text = _("Map Display"))
+
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+ #
+ # font settings
+ #
+ row = 0
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Default font for GRASS displays:")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 0))
+ fontButton = wx.Button(parent = panel, id = wx.ID_ANY,
+ label = _("Set font"), size = (100, -1))
+ gridSizer.Add(item = fontButton,
+ flag = wx.ALIGN_RIGHT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos = (row, 1))
+
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
+
+ #
+ # display settings
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Default display settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(0)
+
+
+ #
+ # display driver
+ #
+ row = 0
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Display driver:")),
+ flag = wx.ALIGN_LEFT |
+ wx.ALIGN_CENTER_VERTICAL,
+ pos=(row, 0))
+ listOfDrivers = self.settings.Get(group='display', key='driver', subkey='choices', internal=True)
+ # 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))
+
+ #
+ # mouse wheel zoom
+ #
+ row += 1
+ wheelZooming = wx.CheckBox(parent = panel, id = wx.ID_ANY,
+ label = _("Enable zooming by mouse wheel"),
+ name = "IsChecked")
+ wheelZooming.SetValue(self.settings.Get(group = 'display', key = 'mouseWheelZoom',
+ subkey = 'enabled'))
+ self.winId['display:mouseWheelZoom:enabled'] = wheelZooming.GetId()
+
+ gridSizer.Add(item = wheelZooming,
+ pos = (row, 0), flag = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+
+ listOfModes = self.settings.Get(group = 'display', key = 'mouseWheelZoom', subkey = 'choices', internal = True)
+ zoomMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (200, -1),
+ choices = listOfModes,
+ name = "GetSelection")
+ zoomMode.SetSelection(self.settings.Get(group = 'display', key = 'mouseWheelZoom', subkey = 'selection'))
+ self.winId['display:mouseWheelZoom:selection'] = zoomMode.GetId()
+
+ gridSizer.Add(item = zoomMode,
+ 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.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
+
+ panel.SetSizer(border)
+
+ # bindings
+ fontButton.Bind(wx.EVT_BUTTON, self.OnSetFont)
+ wheelZooming.Bind(wx.EVT_CHECKBOX, self.OnEnableWheelZoom)
+
+ # enable/disable controls according to settings
+ self.OnEnableWheelZoom(None)
+
+ 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), flag = wx.ALIGN_RIGHT)
+
+ 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()
+
+ def OnEnableWheelZoom(self, event):
+ """!Enable/disable wheel zoom mode control"""
+ checkId = self.winId['display:mouseWheelZoom:enabled']
+ choiceId = self.winId['display:mouseWheelZoom:selection']
+ enable = self.FindWindowById(checkId).IsChecked()
+ self.FindWindowById(choiceId).Enable(enable)
+
+class DefaultFontDialog(wx.Dialog):
+ """
+ Opens a file selection dialog to select default font
+ to use in all GRASS displays
+ """
+ def __init__(self, parent, title, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE |
+ wx.RESIZE_BORDER,
+ settings = UserSettings,
+ type = 'font'):
+
+ self.settings = settings
+ self.type = type
+
+ wx.Dialog.__init__(self, parent, id, title, style = style)
+
+ panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.fontlist = self.GetFonts()
+
+ border = wx.BoxSizer(wx.VERTICAL)
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+ gridSizer.AddGrowableCol(0)
+
+ label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Select font:"))
+ gridSizer.Add(item = label,
+ flag = wx.ALIGN_TOP,
+ pos = (0,0))
+
+ self.fontlb = wx.ListBox(parent = panel, id = wx.ID_ANY, pos = wx.DefaultPosition,
+ choices = self.fontlist,
+ style = wx.LB_SINGLE|wx.LB_SORT)
+ self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.fontlb)
+ self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.fontlb)
+
+ gridSizer.Add(item = self.fontlb,
+ flag = wx.EXPAND, pos = (1, 0))
+
+ if self.type == 'font':
+ if "GRASS_FONT" in os.environ:
+ self.font = os.environ["GRASS_FONT"]
+ else:
+ self.font = self.settings.Get(group = 'display',
+ key = 'font', subkey = 'type')
+ self.encoding = self.settings.Get(group = 'display',
+ key = 'font', subkey = 'encoding')
+
+ label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Character encoding:"))
+ gridSizer.Add(item = label,
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (2, 0))
+
+ self.textentry = wx.TextCtrl(parent = panel, id = wx.ID_ANY,
+ value = self.encoding)
+ gridSizer.Add(item = self.textentry,
+ flag = wx.EXPAND, pos = (3, 0))
+
+ self.textentry.Bind(wx.EVT_TEXT, self.OnEncoding)
+
+ elif self.type == 'outputfont':
+ self.font = self.settings.Get(group = 'appearance',
+ key = 'outputfont', subkey = 'type')
+ self.fontsize = self.settings.Get(group = 'appearance',
+ key = 'outputfont', subkey = 'size')
+ label = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Font size:"))
+ gridSizer.Add(item = label,
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (2, 0))
+
+ self.spin = wx.SpinCtrl(parent = panel, id = wx.ID_ANY)
+ if self.fontsize:
+ self.spin.SetValue(int(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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/preferences.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/prompt.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/prompt.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/prompt.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1158 @@
+"""!
+ 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, GetRealCmd
+
+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
+ 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:
+ 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(GetRealCmd(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:
+ 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:
+ 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:
+ return
+
+ info = gtask.command_info(GetRealCmd(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() in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER] 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 and \
+ cmd != 'r.mapcalc' and \
+ (not self.cmdDesc or cmd != self.cmdDesc.get_name()):
+
+ try:
+ self.cmdDesc = gtask.parse_interface(GetRealCmd(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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/prompt.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,233 @@
+"""!
+ 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
+from icons.icon import MetaIcon
+
+BaseIcons = {
+ 'display' : MetaIcon(img = 'show',
+ label = _('Display map'),
+ desc = _('Re-render modified map layers only')),
+ 'render' : MetaIcon(img = 'layer-redraw',
+ label = _('Render map'),
+ desc = _('Force re-rendering all map layers')),
+ 'erase' : MetaIcon(img = 'erase',
+ label = _('Erase display'),
+ desc = _('Erase display canvas with given background color')),
+ 'pointer' : MetaIcon(img = 'pointer',
+ label = _('Pointer')),
+ 'zoomIn' : MetaIcon(img = 'zoom-in',
+ label = _('Zoom in'),
+ desc = _('Drag or click mouse to zoom')),
+ 'zoomOut' : MetaIcon(img = 'zoom-out',
+ label = _('Zoom out'),
+ desc = _('Drag or click mouse to unzoom')),
+ 'zoomBack' : MetaIcon(img = 'zoom-last',
+ label = _('Return to previous zoom')),
+ 'zoomMenu' : MetaIcon(img = 'zoom-more',
+ label = _('Various zoom options'),
+ desc = _('Zoom to computational, default, saved region, ...')),
+ 'zoomExtent' : MetaIcon(img = 'zoom-extent',
+ label = _('Zoom to selected map layer(s)')),
+ 'pan' : MetaIcon(img = 'pan',
+ label = _('Pan'),
+ desc = _('Drag with mouse to pan')),
+ 'saveFile' : MetaIcon(img = 'map-export',
+ label = _('Save display to graphic file')),
+ 'print' : MetaIcon(img = 'print',
+ label = _('Print display')),
+ 'font' : MetaIcon(img = 'font',
+ label = _('Select font')),
+ 'help' : MetaIcon(img = 'help',
+ label = _('Show manual')),
+ 'quit' : MetaIcon(img = 'quit',
+ label = _('Quit')),
+ 'addRast' : MetaIcon(img = 'layer-raster-add',
+ label = _('Add raster map layer')),
+ 'addVect' : MetaIcon(img = 'layer-vector-add',
+ label = _('Add vector map layer')),
+ 'overlay' : MetaIcon(img = 'overlay-add',
+ label = _('Add map elements'),
+ desc = _('Overlay elements like scale and legend onto map')),
+ 'histogramD' : MetaIcon(img = 'layer-raster-histogram',
+ label = _('Create histogram with d.histogram')),
+ 'settings' : MetaIcon(img = 'settings',
+ label = _("Settings")),
+ }
+
+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
+
+ def _onMenu(self, data):
+ """!Toolbar pop-up menu"""
+ menu = wx.Menu()
+
+ for icon, handler in data:
+ item = wx.MenuItem(menu, wx.ID_ANY, icon.GetLabel())
+ item.SetBitmap(icon.GetBitmap(self.parent.iconsize))
+ menu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, handler, item)
+
+ self.PopupMenu(menu)
+ menu.Destroy()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_core/widgets.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_core/widgets.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,470 @@
+"""!
+ at package gui_core.widgets
+
+ at brief Core GUI widgets
+
+Classes:
+ - widgets::GNotebook
+ - widgets::ScrolledPanel
+ - widgets::NumTextCtrl
+ - widgets::FloatSlider
+ - widgets::SymbolButton
+ - widgets::StaticWrapText
+ - widgets::BaseValidator
+ - widgets::IntegerValidator
+ - 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 os
+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
+
+from wx.lib.newevent import NewEvent
+wxSymbolSelectionChanged, EVT_SYMBOL_SELECTION_CHANGED = NewEvent()
+
+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, style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER):
+ SP.ScrolledPanel.__init__(self, parent = parent, id = wx.ID_ANY, style = style)
+
+ def OnChildFocus(self, event):
+ pass
+
+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 BaseValidator(wx.PyValidator):
+ def __init__(self):
+ wx.PyValidator.__init__(self)
+
+ self.Bind(wx.EVT_TEXT, self.OnText)
+
+ def OnText(self, event):
+ """!Do validation"""
+ self.Validate()
+
+ event.Skip()
+
+ def Validate(self):
+ """Validate input"""
+ textCtrl = self.GetWindow()
+ text = textCtrl.GetValue()
+
+ if text:
+ try:
+ self.type(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 TransferToWindow(self):
+ return True # Prevent wxDialog from complaining.
+
+ def TransferFromWindow(self):
+ return True # Prevent wxDialog from complaining.
+
+class IntegerValidator(BaseValidator):
+ """!Validator for floating-point input"""
+ def __init__(self):
+ BaseValidator.__init__(self)
+ self.type = int
+
+ def Clone(self):
+ """!Clone validator"""
+ return IntegerValidator()
+
+class FloatValidator(BaseValidator):
+ """!Validator for floating-point input"""
+ def __init__(self):
+ BaseValidator.__init__(self)
+ self.type = float
+
+ def Clone(self):
+ """!Clone validator"""
+ return FloatValidator()
+
+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 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 SingleSymbolPanel(wx.Panel):
+ """!Panel for displaying one symbol.
+
+ Changes background when selected. Assumes that parent will catch
+ events emitted on mouse click. Used in gui_core::dialog::SymbolDialog.
+ """
+ def __init__(self, parent, symbolPath):
+ """!Panel constructor
+
+ @param parent parent (gui_core::dialog::SymbolDialog)
+ @param symbolPath absolute path to symbol
+ """
+ wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.BORDER_RAISED)
+ self.SetName(os.path.splitext(os.path.basename(symbolPath))[0])
+ self.sBmp = wx.StaticBitmap(self, wx.ID_ANY, wx.Bitmap(symbolPath))
+
+ self.selected = False
+ self.selectColor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
+ self.deselectColor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
+
+ sizer = wx.BoxSizer()
+ sizer.Add(item = self.sBmp, proportion = 0, flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
+ self.SetBackgroundColour(self.deselectColor)
+ self.SetMinSize(self.GetBestSize())
+ self.SetSizerAndFit(sizer)
+
+ # binding to both (staticBitmap, Panel) necessary
+ self.sBmp.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+ self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
+ self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
+ self.sBmp.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
+
+ def OnLeftDown(self, event):
+ """!Panel selected, background changes"""
+ self.selected = True
+ self.SetBackgroundColour(self.selectColor)
+ event.Skip()
+
+ event = wxSymbolSelectionChanged(name = self.GetName(), doubleClick = False)
+ wx.PostEvent(self.GetParent(), event)
+
+ def OnDoubleClick(self, event):
+ event = wxSymbolSelectionChanged(name = self.GetName(), doubleClick = True)
+ wx.PostEvent(self.GetParent(), event)
+
+ def Deselect(self):
+ """!Panel deselected, background changes back to default"""
+ self.selected = False
+ self.SetBackgroundColour(self.deselectColor)
+
+ def Select(self):
+ """!Select panel, no event emitted"""
+ self.selected = True
+ self.SetBackgroundColour(self.selectColor)
+
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_core/widgets.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/icons/grass2_icons.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/icons/grass2_icons.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/icons/grass2_icons.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -7,7 +7,7 @@
import os
-from gui_modules import globalvar
+from core import globalvar
iconPath = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass2")
Modified: grass/branches/releasebranch_6_4/gui/wxpython/icons/grass_icons.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/icons/grass_icons.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/icons/grass_icons.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -4,7 +4,7 @@
import os
-from gui_modules import globalvar
+from core import globalvar
iconPath = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass")
iconPathVDigit = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass", "edit")
Modified: grass/branches/releasebranch_6_4/gui/wxpython/icons/icon.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/icons/icon.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/icons/icon.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -1,33 +1,28 @@
"""!
- at package icon
+ at package icons.icon
- at brief Icon themes
+ at brief Icon metadata
- at code
-from icons import Icons as Icons
- at endcode
-
Classes:
- MetaIcon
(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.
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
@author Martin Landa <landa.martin gmail.com>
- at author Anna Kratochvilova <anna.kratochvilova fsv.cvut.cz>
+ at author Anna Kratochvilova <kratochanna gmail.com>
"""
import os
import sys
import types
+import copy
-sys.path.append(os.path.join(os.getenv("GISBASE"), "etc", "wxpython", "gui_modules"))
-
import wx
-from gui_modules.preferences import globalSettings as UserSettings
+from core.settings import UserSettings
import grass2_icons # default icon set
iconPathDefault = grass2_icons.iconPath
@@ -83,14 +78,15 @@
iconSet[key] = os.path.join(iconPathVDigit, img)
else:
iconSet[key] = os.path.join(iconPath, img)
+
except StandardError, e:
sys.exit(_("Unable to load icon theme. Reason: %s") % e)
class MetaIcon:
"""!Handle icon metadata (image path, tooltip, ...)
"""
- def __init__(self, img, label, desc = None):
- self.imagepath = img
+ def __init__(self, img, label = None, desc = None):
+ self.imagepath = iconSet.get(img, wx.ART_MISSING_IMAGE)
if not self.imagepath:
self.type = 'unknown'
else:
@@ -107,11 +103,9 @@
self.description = ''
def __str__(self):
- """!Debugging"""
return "label=%s, img=%s, type=%s" % (self.label, self.imagepath, self.type)
def GetBitmap(self, size = None):
- """!Get bitmap"""
bmp = None
if self.type == 'wx':
@@ -129,347 +123,24 @@
def GetLabel(self):
return self.label
-
+
def GetDesc(self):
return self.description
def GetImageName(self):
return os.path.basename(self.imagepath)
-#
-# create list of icon instances
-#
-Icons = {
- 'displayWindow' : {
- 'display' : MetaIcon(img = iconSet.get('show', wx.ART_ERROR),
- label = _('Display map'),
- desc = _('Re-render modified map layers only')),
- 'render' : MetaIcon(img = iconSet.get('layer-redraw', wx.ART_ERROR),
- label = _('Render map'),
- desc = _('Force re-rendering all map layers')),
- 'erase' : MetaIcon(img = iconSet.get('erase', wx.ART_ERROR),
- label = _('Erase display'),
- desc = _('Erase display canvas with given background color')),
- 'pointer' : MetaIcon(img = iconSet.get('pointer', wx.ART_ERROR),
- label = _('Pointer')),
- 'zoomIn' : MetaIcon(img = iconSet.get('zoom-in', wx.ART_ERROR),
- label = _('Zoom in'),
- desc = _('Drag or click mouse to zoom')),
- 'zoomOut' : MetaIcon(img = iconSet.get('zoom-out', wx.ART_ERROR),
- label = _('Zoom out'),
- desc = _('Drag or click mouse to unzoom')),
- 'pan' : MetaIcon(img = iconSet.get('pan', wx.ART_ERROR),
- label = _('Pan'),
- desc = _('Drag with mouse to pan')),
- 'query' : MetaIcon(img = iconSet.get('info', wx.ART_ERROR),
- label = _('Query raster/vector map(s)'),
- desc = _('Query selected raster/vector map(s)')),
- 'zoomBack' : MetaIcon(img = iconSet.get('zoom-last', wx.ART_ERROR),
- label = _('Return to previous zoom')),
- 'zoomMenu' : MetaIcon(img = iconSet.get('zoom-more', wx.ART_ERROR),
- label = _('Various zoom options'),
- desc = _('Zoom to computational, default, saved region, ...')),
- 'zoomExtent' : MetaIcon(img = iconSet.get('zoom-extent', wx.ART_ERROR),
- label = _('Zoom to selected map layer(s)')),
- 'overlay' : MetaIcon(img = iconSet.get('overlay-add', wx.ART_ERROR),
- label = _('Add map elements'),
- desc = _('Overlay elements like scale and legend onto map')),
- 'addBarscale': MetaIcon(img = iconSet.get('scalebar-add', wx.ART_ERROR),
- label = _('Add scalebar and north arrow')),
- 'addLegend' : MetaIcon(img = iconSet.get('legend-add', wx.ART_ERROR),
- label = _('Add legend')),
- 'saveFile' : MetaIcon(img = iconSet.get('map-export', wx.ART_ERROR),
- label = _('Save display to graphic file')),
- 'print' : MetaIcon(img = iconSet.get('print', wx.ART_ERROR),
- label = _('Print display')),
- 'analyze' : MetaIcon(img = iconSet.get('layer-raster-analyze', wx.ART_ERROR),
- label = _('Analyze map'),
- desc = _('Measuring, profiling, histogramming, ...')),
- 'measure' : MetaIcon(img = iconSet.get('measure-length', wx.ART_ERROR),
- label = _('Measure distance')),
- 'profile' : MetaIcon(img = iconSet.get('layer-raster-profile', wx.ART_ERROR),
- label = _('Profile surface map')),
- 'addText' : MetaIcon(img = iconSet.get('text-add', wx.ART_ERROR),
- label = _('Add text layer')),
- 'histogram' : MetaIcon(img = iconSet.get('layer-raster-histogram', wx.ART_ERROR),
- label = _('Create histogram of raster map')),
- },
- 'layerManager' : {
- 'newdisplay' : MetaIcon(img = iconSet.get('monitor-create', wx.ART_ERROR),
- label = _('Start new map display')),
- 'workspaceNew' : MetaIcon(img = iconSet.get('create', wx.ART_ERROR),
- label = _('Create new workspace (Ctrl+N)')),
- 'workspaceOpen' : MetaIcon(img = iconSet.get('open', wx.ART_ERROR),
- label = _('Open existing workspace file (Ctrl+O)')),
- 'workspaceSave' : MetaIcon(img = iconSet.get('save', wx.ART_ERROR),
- label = _('Save current workspace to file (Ctrl+S)')),
- 'addMulti' : MetaIcon(img = iconSet.get('layer-open', wx.ART_ERROR),
- label = _('Add multiple raster or vector map layers (Ctrl+Shift+L)')),
- 'import' : MetaIcon(img = iconSet.get('layer-import', wx.ART_ERROR),
- label = _('Import/link raster or vector data')),
- 'rastImport' : MetaIcon(img = iconSet.get('layer-import', wx.ART_ERROR),
- label = _('Import raster data')),
- 'rastLink' : MetaIcon(img = iconSet.get('layer-import', wx.ART_ERROR),
- label = _('Link external raster data')),
- 'vectImport' : MetaIcon(img = iconSet.get('layer-import', wx.ART_ERROR),
- label = _('Import vector data')),
- 'vectLink' : MetaIcon(img = iconSet.get('layer-import', wx.ART_ERROR),
- label = _('Link external vector data')),
- 'addRast' : MetaIcon(img = iconSet.get('layer-raster-add', wx.ART_ERROR),
- label = _('Add raster map layer (Ctrl+Shift+R)')),
- 'rastMisc' : MetaIcon(img = iconSet.get('layer-raster-more', wx.ART_ERROR),
- label = _('Add various raster map layers (RGB, HIS, shaded relief...)')),
- 'addVect' : MetaIcon(img = iconSet.get('layer-vector-add', wx.ART_ERROR),
- label = _('Add vector map layer (Ctrl+Shift+V)')),
- 'vectMisc' : MetaIcon(img = iconSet.get('layer-vector-more', wx.ART_ERROR),
- label = _('Add various vector map layers (thematic, chart...)')),
- 'addCmd' : MetaIcon(img = iconSet.get('layer-command-add', wx.ART_ERROR),
- label = _('Add command layer')),
- 'addGroup' : MetaIcon(img = iconSet.get('layer-group-add', wx.ART_ERROR),
- label = _('Add group')),
- 'addOverlay' : MetaIcon(img = iconSet.get('layer-more', wx.ART_ERROR),
- label = _('Add grid or vector labels overlay')),
- 'delCmd' : MetaIcon(img = iconSet.get('layer-remove', wx.ART_ERROR),
- label = _('Delete selected map layer')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit')),
- 'attrTable' : MetaIcon(img = iconSet.get('table', wx.ART_ERROR),
- label = _('Show attribute table')),
- 'vdigit' : MetaIcon(img = iconSet.get('edit', wx.ART_ERROR),
- label = _('Edit vector maps')),
- 'addRgb' : MetaIcon(img = iconSet.get('layer-rgb-add', wx.ART_ERROR),
- label = _('Add RGB map layer')),
- 'addHis' : MetaIcon(img = iconSet.get('layer-his-add', wx.ART_ERROR),
- label = _('Add HIS map layer')),
- 'addShaded' : MetaIcon(img = iconSet.get('layer-shaded-relief-add', wx.ART_ERROR),
- label = _('Add shaded relief map layer')),
- 'addRArrow' : MetaIcon(img = iconSet.get('layer-aspect-arrow-add', wx.ART_ERROR),
- label = _('Add raster flow arrows')),
- 'addRNum' : MetaIcon(img = iconSet.get('layer-cell-cats-add', wx.ART_ERROR),
- label = _('Add raster cell numbers')),
- 'addThematic': MetaIcon(img = iconSet.get('layer-vector-thematic-add', wx.ART_ERROR),
- label = _('Add thematic area (choropleth) map layer')),
- 'addChart' : MetaIcon(img = iconSet.get('layer-vector-chart-add', wx.ART_ERROR),
- label = _('Add thematic chart layer')),
- 'addGrid' : MetaIcon(img = iconSet.get('layer-grid-add', wx.ART_ERROR),
- label = _('Add grid layer')),
- 'addGeodesic': MetaIcon(img = iconSet.get('shortest-distance', wx.ART_ERROR),
- label = _('Add geodesic line layer')),
- 'addRhumb' : MetaIcon(img = iconSet.get('shortest-distance', wx.ART_ERROR),
- label = _('Add rhumbline layer')),
- 'addLabels' : MetaIcon(img = iconSet.get('layer-label-add', wx.ART_ERROR),
- label = _('Add labels')),
- 'addRast3d' : MetaIcon(img = iconSet.get('layer-raster3d-add', wx.ART_ERROR),
- label = _('Add 3D raster map layer'),
- desc = _('Note that 3D raster data are rendered only in 3D view mode')),
- 'settings' : MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('Show GUI settings')),
- 'modeler' : MetaIcon(img = iconSet.get('modeler-main', wx.ART_ERROR),
- label = _('Graphical Modeler')),
- 'layerOptions' : MetaIcon(img = iconSet.get('options', wx.ART_ERROR),
- label = _('Set options')),
- 'mapOutput' : MetaIcon(img = iconSet.get('print-compose', wx.ART_ERROR),
- label = _('Cartographic Composer')),
- 'mapcalc' : MetaIcon(img = iconSet.get('calculator', wx.ART_ERROR),
- label = _('Raster Map Calculator')),
- },
- 'vdigit' : {
- 'addPoint' : MetaIcon(img = iconSet.get('point-create', wx.ART_ERROR),
- label = _('Digitize new point'),
- desc = _('Left: new point')),
- 'addLine' : MetaIcon(img = iconSet.get('line-create', wx.ART_ERROR),
- label = _('Digitize new line'),
- desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
- 'addBoundary' : MetaIcon(img = iconSet.get('boundary-create', wx.ART_ERROR),
- label = _('Digitize new boundary'),
- desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
- 'addCentroid' : MetaIcon(img = iconSet.get('centroid-create', wx.ART_ERROR),
- label = _('Digitize new centroid'),
- desc = _('Left: new point')),
- 'addArea' : MetaIcon(img = iconSet.get('polygon-create', wx.ART_ERROR),
- label = _('Digitize new area (composition of boundaries without category and one centroid with category)'),
- desc = _('Left: new point')),
- 'addVertex' : MetaIcon(img = iconSet.get('vertex-create', wx.ART_ERROR),
- label = _('Add new vertex'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'deleteLine' : MetaIcon(img = iconSet.get('line-delete', wx.ART_ERROR),
- label = _('Delete feature(s)'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'displayAttr' : MetaIcon(img = iconSet.get('attributes-display', wx.ART_ERROR),
- label = _('Display/update attributes'),
- desc = _('Left: Select')),
- 'displayCats' : MetaIcon(img = iconSet.get('cats-display', wx.ART_ERROR),
- label = _('Display/update categories'),
- desc = _('Left: Select')),
- 'editLine' : MetaIcon(img = iconSet.get('line-edit', wx.ART_ERROR),
- label = _('Edit line/boundary'),
- desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
- 'moveLine' : MetaIcon(img = iconSet.get('line-move', wx.ART_ERROR),
- label = _('Move feature(s)'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'moveVertex' : MetaIcon(img = iconSet.get('vertex-move', wx.ART_ERROR),
- label = _('Move vertex'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'removeVertex' : MetaIcon(img = iconSet.get('vertex-delete', wx.ART_ERROR),
- label = _('Remove vertex'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'settings' : MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('Digitization settings')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit digitizer'),
- desc = _('Quit digitizer and save changes')),
- 'additionalTools' : MetaIcon(img = iconSet.get('tools', wx.ART_ERROR),
- label = _('Additional tools ' \
- '(copy, flip, connect, etc.)'),
- desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
- 'undo' : MetaIcon(img = iconSet.get('undo', wx.ART_ERROR),
- label = _('Undo'),
- desc = _('Undo previous changes')),
- },
- 'profile' : {
- 'draw' : MetaIcon(img = iconSet.get('show', wx.ART_ERROR),
- label = _('Draw/re-draw profile')),
- 'transect' : MetaIcon(img = iconSet.get('layer-raster-profile', wx.ART_ERROR),
- label = _('Draw transect in map display window to profile')),
- 'options' : MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('Profile options')),
- 'save' : MetaIcon(img = iconSet.get('save', wx.ART_ERROR),
- label = _('Save profile data to CSV file')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit Profile Analysis Tool'))
- },
- 'georectify' : {
- 'gcpSet' : MetaIcon(img = iconSet.get('gcp-create', wx.ART_ERROR),
- label = _('Set GCP'),
- desc = _('Define GCP (Ground Control Points)')),
- 'georectify': MetaIcon(img = iconSet.get('georectify', wx.ART_ERROR),
- label = _('Georectify')),
- 'gcpRms' : MetaIcon(img = iconSet.get('gcp-rms', wx.ART_ERROR),
- label = _('Recalculate RMS error')),
- 'gcpSave' : MetaIcon(img = iconSet.get('gcp-save', wx.ART_ERROR),
- label = _('Save GCPs to POINTS file')),
- 'gcpAdd' : MetaIcon(img = iconSet.get('gcp-add', wx.ART_ERROR),
- label = _('Add new GCP')),
- 'gcpDelete' : MetaIcon(img = iconSet.get('gcp-delete', wx.ART_ERROR),
- label = _('Delete selected GCP')),
- 'gcpClear' : MetaIcon(img = iconSet.get('gcp-remove', wx.ART_ERROR),
- label = _('Clear selected GCP')),
- 'gcpReload' : MetaIcon(img = iconSet.get('reload', wx.ART_ERROR),
- label = _('Reload GCPs from POINTS file')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit georectification')),
- 'settings' : MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('Settings'),
- desc = _('Settings dialog for georectification tool')),
- },
- 'nviz' : {
- 'view' : MetaIcon(img = iconSet.get('3d-view', wx.ART_ERROR),
- label = _('Switch to view control page'),
- desc = _('Change view settings')),
- 'surface' : MetaIcon(img = iconSet.get('3d-raster', wx.ART_ERROR),
- label = _('Switch to surface (raster) control page'),
- desc = _('Change surface (loaded raster maps) settings')),
- 'vector' : MetaIcon(img = iconSet.get('3d-vector', wx.ART_ERROR),
- label = _('Switch to vector (2D/3D) control page'),
- desc = _('Change 2D/3D vector settings')),
- 'volume' : MetaIcon(img = iconSet.get('3d-volume', wx.ART_ERROR),
- label = _('Switch to volume (3D raster) control page'),
- desc = _('Change volume (loaded 3D raster maps) settings')),
- 'light' : MetaIcon(img = iconSet.get('3d-light', wx.ART_ERROR),
- label = _('Switch to lighting control page'),
- desc = _('Change lighting settings')),
- 'fringe' : MetaIcon(img = iconSet.get('3d-fringe', wx.ART_ERROR),
- label = _('Switch to fringe control page'),
- desc = _('Switch on/off fringes')),
- 'settings': MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('3D view mode tools'),
- desc = _('Show/hide 3D view mode settings dialog')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit 3D view mode'),
- desc = _('Switch back to 2D view mode')),
- },
- 'modeler' : {
- 'new' : MetaIcon(img = iconSet.get('create', wx.ART_ERROR),
- label = _('Create new model (Ctrl+N)')),
- 'open' : MetaIcon(img = iconSet.get('open', wx.ART_ERROR),
- label = _('Load model from file (Ctrl+O)')),
- 'save' : MetaIcon(img = iconSet.get('save', wx.ART_ERROR),
- label = _('Save current model to file (Ctrl+S)')),
- 'toImage' : MetaIcon(img = iconSet.get('image-export', wx.ART_ERROR),
- label = _('Export model to image')),
- 'toPython' : MetaIcon(img = iconSet.get('python-export', wx.ART_ERROR),
- label = _('Export model to Python script')),
- 'actionAdd' : MetaIcon(img = iconSet.get('module-add', wx.ART_ERROR),
- label = _('Add action (GRASS module) to model')),
- 'dataAdd' : MetaIcon(img = iconSet.get('data-add', wx.ART_ERROR),
- label = _('Add data item to model')),
- 'relation' : MetaIcon(img = iconSet.get('relation-create', wx.ART_ERROR),
- label = _('Define relation between data and action items')),
- 'run' : MetaIcon(img = iconSet.get('execute', wx.ART_ERROR),
- label = _('Run model')),
- 'validate' : MetaIcon(img = iconSet.get('check', wx.ART_ERROR),
- label = _('Validate model')),
- 'settings' : MetaIcon(img = iconSet.get('settings', wx.ART_ERROR),
- label = _('Show modeler settings')),
- 'properties' : MetaIcon(img = iconSet.get('options', wx.ART_ERROR),
- label = _('Show model properties')),
- 'variables' : MetaIcon(img = iconSet.get('modeler-variables', wx.ART_ERROR),
- label = _('Manage model variables')),
- 'redraw' : MetaIcon(img = iconSet.get('redraw', wx.ART_ERROR),
- label = _('Redraw model canvas')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit Graphical Modeler')),
- },
- 'misc' : {
- 'font' : MetaIcon(img = iconSet.get('font', wx.ART_ERROR),
- label = _('Select font')),
- 'help' : MetaIcon(img = iconSet.get('help', wx.ART_ERROR),
- label = _('Show manual')),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit')),
- },
- 'psMap' : {
- 'scriptSave' : MetaIcon(img = iconSet.get('script-save', wx.ART_ERROR),
- label = _('Generate text file with mapping instructions')),
- 'scriptLoad' : MetaIcon(img = iconSet.get('script-load', wx.ART_ERROR),
- label = _('Load text file with mapping instructions')),
- 'psExport' : MetaIcon(img = iconSet.get('ps-export', wx.ART_ERROR),
- label = _('Generate PostScript output')),
- 'pdfExport' : MetaIcon(img = iconSet.get('pdf-export', wx.ART_ERROR),
- label = _('Generate PDF output')),
- 'pageSetup' : MetaIcon(img = iconSet.get('page-settings', wx.ART_ERROR),
- label = _('Page setup'),
- desc = _('Specify paper size, margins and orientation')),
- 'fullExtent' : MetaIcon(img = iconSet.get('zoom-extent', wx.ART_ERROR),
- label = _("Full extent"),
- desc = _("Zoom to full extent")),
- 'addMap' : MetaIcon(img = iconSet.get('layer-add', wx.ART_ERROR),
- label = _("Map frame"),
- desc = _("Click and drag to place map frame")),
- 'addRast' : MetaIcon(img = iconSet.get('layer-raster-add', wx.ART_ERROR),
- label = _("Raster map"),
- desc = _("Add raster map")),
- 'addVect' : MetaIcon(img = iconSet.get('layer-vector-add', wx.ART_ERROR),
- label = _("Vector map"),
- desc = _("Add vector map")),
- 'deleteObj' : MetaIcon(img = iconSet.get('layer-remove', wx.ART_ERROR),
- label = _("Delete selected object")),
- 'preview' : MetaIcon(img = iconSet.get('execute', wx.ART_ERROR),
- label = _("Show preview")),
- 'quit' : MetaIcon(img = iconSet.get('quit', wx.ART_ERROR),
- label = _('Quit Cartographic Composer')),
- 'addText' : MetaIcon(img = iconSet.get('text-add', wx.ART_ERROR),
- label = _('Add text')),
- 'addMapinfo' : MetaIcon(img = iconSet.get('map-info', wx.ART_ERROR),
- label = _('Add map info')),
- 'addLegend' : MetaIcon(img = iconSet.get('legend-add', wx.ART_ERROR),
- label = _('Add legend')),
- 'addScalebar' : MetaIcon(img = iconSet.get('scalebar-add', wx.ART_ERROR),
- label = _('Add scale bar')),
- }
- }
-
-# testing ...
-if __name__ == '__main__':
- for k, v in iconSet.iteritems():
- print v.GetImageName()
+ def SetLabel(self, label = None, desc = None):
+ """!Set label/description for icon
+ @param label icon label (None for no change)
+ @param desc icon description (None for no change)
+
+ @return copy of original object
+ """
+ cobj = copy.copy(self)
+ if label:
+ cobj.label = label
+ if desc:
+ cobj.description = desc
+
+ return cobj
Modified: grass/branches/releasebranch_6_4/gui/wxpython/icons/silk_icons.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/icons/silk_icons.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/icons/silk_icons.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -10,7 +10,7 @@
import wx
-import globalvar
+from core import globalvar
iconPath = os.path.join(globalvar.ETCDIR, "gui", "icons", "silk")
Added: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/lmgr/frame.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/lmgr/frame.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1744 @@
+"""!
+ at package lmgr::frame
+
+ at brief Layer Manager - main menu, layer management toolbar, notebook
+control for display management and access to command console.
+
+Classes:
+ - frame::GMFrame
+
+(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 (Arizona State University)
+ at author Jachym Cepicky (Mendel University of Agriculture)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
+"""
+
+import sys
+import os
+import tempfile
+import stat
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree # Python <= 2.4
+
+from core import globalvar
+import wx
+import wx.aui
+try:
+ import wx.lib.agw.flatnotebook as FN
+except ImportError:
+ import wx.lib.flatnotebook as FN
+
+sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
+from grass.script import core as grass
+
+from core.gcmd import RunCommand, GError, GMessage
+from core.settings import UserSettings
+from gui_core.preferences import MapsetAccess, PreferencesDialog, EVT_SETTINGS_CHANGED
+from lmgr.layertree import LayerTree, LMIcons
+from lmgr.menudata import ManagerData
+from gui_core.widgets import GNotebook
+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 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 psmap.frame import PsMapFrame
+from core.debug import Debug
+from gui_core.ghelp import MenuTreeWindow, AboutWindow
+from modules.extensions import InstallExtensionWindow, UninstallExtensionWindow
+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
+from gcp.manager import GCPWizard
+from nviz.main import haveNviz
+
+class GMFrame(wx.Frame):
+ """!Layer Manager frame with notebook widget for controlling GRASS
+ GIS. Includes command console page for typing GRASS (and other)
+ commands, tree widget page for managing map layers.
+ """
+ def __init__(self, parent, id = wx.ID_ANY, title = _("GRASS GIS Layer Manager"),
+ workspace = None,
+ size = globalvar.GM_WINDOW_SIZE, style = wx.DEFAULT_FRAME_STYLE, **kwargs):
+ self.parent = parent
+ self.baseTitle = title
+ self.iconsize = (16, 16)
+
+ wx.Frame.__init__(self, parent = parent, id = id, size = size,
+ style = style, **kwargs)
+
+ self.SetTitle(self.baseTitle)
+ self.SetName("LayerManager")
+
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+ self._auimgr = wx.aui.AuiManager(self)
+
+ # initialize variables
+ self.disp_idx = 0 # index value for map displays and layer trees
+ self.curr_page = None # currently selected page for layer tree notebook
+ self.curr_pagenum = None # currently selected page number for layer tree notebook
+ self.workspaceFile = workspace # workspace file
+ self.workspaceChanged = False # track changes in workspace
+ self.georectifying = None # reference to GCP class or None
+ self.gcpmanagement = None # reference to GCP class or None
+
+ # list of open dialogs
+ self.dialogs = dict()
+ self.dialogs['preferences'] = None
+ self.dialogs['atm'] = list()
+
+ # creating widgets
+ self._createMenuBar()
+ self.statusbar = self.CreateStatusBar(number = 1)
+ self.notebook = self._createNoteBook()
+ self.toolbars = { 'workspace' : LMWorkspaceToolbar(parent = self),
+ 'data' : LMDataToolbar(parent = self),
+ 'tools' : LMToolsToolbar(parent = self),
+ 'misc' : LMMiscToolbar(parent = self),
+ 'vector' : LMVectorToolbar(parent = self),
+ 'nviz' : LMNvizToolbar(parent = self)}
+
+ self._toolbarsData = { 'workspace' : ("toolbarWorkspace", # name
+ _("Workspace Toolbar"), # caption
+ 1), # row
+ 'data' : ("toolbarData",
+ _("Data Toolbar"),
+ 1),
+ 'misc' : ("toolbarMisc",
+ _("Misc Toolbar"),
+ 2),
+ 'tools' : ("toolbarTools",
+ _("Tools Toolbar"),
+ 2),
+ 'vector' : ("toolbarVector",
+ _("Vector Toolbar"),
+ 2),
+ 'nviz' : ("toolbarNviz",
+ _("3D view Toolbar"),
+ 2),
+ }
+ if sys.platform == 'win32':
+ self._toolbarsList = ('workspace', 'data',
+ 'vector', 'tools', 'misc', 'nviz')
+ else:
+ self._toolbarsList = ('data', 'workspace',
+ 'nviz', 'misc', 'tools', 'vector')
+ for toolbar in self._toolbarsList:
+ name, caption, row = self._toolbarsData[toolbar]
+ self._auimgr.AddPane(self.toolbars[toolbar],
+ wx.aui.AuiPaneInfo().
+ Name(name).Caption(caption).
+ ToolbarPane().Top().Row(row).
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).
+ CloseButton(False).Layer(2).
+ BestSize((self.toolbars[toolbar].GetBestSize())))
+
+ self._auimgr.GetPane('toolbarNviz').Hide()
+ # bindings
+ self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+
+ # minimal frame size
+ self.SetMinSize((500, 400))
+
+ # AUI stuff
+ self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
+ Left().CentrePane().BestSize((-1,-1)).Dockable(False).
+ CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
+
+ self._auimgr.Update()
+
+ wx.CallAfter(self.notebook.SetSelectionByName, 'layers')
+
+ # use default window layout ?
+ if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
+ dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
+ try:
+ x, y = map(int, dim.split(',')[0:2])
+ w, h = map(int, dim.split(',')[2:4])
+ self.SetPosition((x, y))
+ self.SetSize((w, h))
+ except:
+ pass
+ else:
+ self.Centre()
+
+ self.Layout()
+ self.Show()
+
+ # load workspace file if requested
+ if self.workspaceFile:
+ # load given workspace file
+ if self.LoadWorkspaceFile(self.workspaceFile):
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
+ else:
+ self.workspaceFile = None
+ else:
+ # start default initial display
+ self.NewDisplay(show = False)
+
+ # show map display widnow
+ # -> OnSize() -> UpdateMap()
+ if self.curr_page and not self.curr_page.maptree.mapdisplay.IsShown():
+ self.curr_page.maptree.mapdisplay.Show()
+
+ # redirect stderr to log area
+ self.goutput.Redirect()
+
+ # fix goutput's pane size (required for Mac OSX)`
+ self.goutput.SetSashPosition(int(self.GetSize()[1] * .8))
+
+ self.workspaceChanged = False
+
+ # start with layer manager on top
+ if self.curr_page:
+ self.curr_page.maptree.mapdisplay.Raise()
+ wx.CallAfter(self.Raise)
+
+ def _createMenuBar(self):
+ """!Creates menu bar"""
+ self.menubar = Menu(parent = self, data = ManagerData())
+ self.SetMenuBar(self.menubar)
+ self.menucmd = self.menubar.GetCmd()
+
+ def _createTabMenu(self):
+ """!Creates context menu for display tabs.
+
+ Used to rename display.
+ """
+ menu = wx.Menu()
+ item = wx.MenuItem(menu, id = wx.ID_ANY, text = _("Rename Map Display"))
+ menu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnRenameDisplay, item)
+
+ return menu
+
+ def _setCopyingOfSelectedText(self):
+ copy = UserSettings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled')
+ self.goutput.SetCopyingOfSelectedText(copy)
+
+ def IsPaneShown(self, name):
+ """!Check if pane (toolbar, ...) of given name is currently shown"""
+ if self._auimgr.GetPane(name).IsOk():
+ return self._auimgr.GetPane(name).IsShown()
+ return False
+
+ def _createNoteBook(self):
+ """!Creates notebook widgets"""
+ 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:
+ self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, agwStyle = cbStyle)
+ else:
+ self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, style = cbStyle)
+ self.gm_cb.SetTabAreaColour(globalvar.FNPageColor)
+ menu = self._createTabMenu()
+ self.gm_cb.SetRightClickMenu(menu)
+ self.notebook.AddPage(page = self.gm_cb, text = _("Map layers"), name = 'layers')
+
+ # create 'command output' text area
+ self.goutput = GMConsole(self)
+ self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
+ self._setCopyingOfSelectedText()
+
+ # create 'search module' notebook page
+ if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'):
+ self.search = MenuTreeWindow(parent = self)
+ self.notebook.AddPage(page = self.search, text = _("Search module"), name = 'search')
+ else:
+ self.search = None
+
+ # create 'python shell' notebook page
+ if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'):
+ self.pyshell = PyShellWindow(parent = self)
+ self.notebook.AddPage(page = self.pyshell, text = _("Python shell"), name = 'pyshell')
+ else:
+ self.pyshell = None
+
+ # bindings
+ self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnCBPageChanged)
+ self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+ self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.OnCBPageClosed)
+
+ return self.notebook
+
+ def AddNvizTools(self):
+ """!Add nviz notebook page"""
+ Debug.msg(5, "GMFrame.AddNvizTools()")
+ if not haveNviz:
+ return
+
+ from nviz.main import NvizToolWindow
+
+ # show toolbar
+ self._auimgr.GetPane('toolbarNviz').Show()
+ # reorder other toolbars
+ for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc','toolbarNviz')):
+ self._auimgr.GetPane(toolbar).Row(2).Position(pos)
+ self._auimgr.Update()
+
+ # create nviz tools tab
+ 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')
+
+
+ def RemoveNvizTools(self):
+ """!Remove nviz notebook page"""
+ # if more mapwindow3D were possible, check here if nb page should be removed
+ self.notebook.SetSelectionByName('layers')
+ self.notebook.RemovePage(self.notebook.GetPageIndexByName('nviz'))
+ del self.nviz
+ # hide toolbar
+ self._auimgr.GetPane('toolbarNviz').Hide()
+ for pos, toolbar in enumerate(('toolbarVector', 'toolbarTools', 'toolbarMisc')):
+ self._auimgr.GetPane(toolbar).Row(2).Position(pos)
+ self._auimgr.Update()
+
+ def WorkspaceChanged(self):
+ """!Update window title"""
+ if not self.workspaceChanged:
+ self.workspaceChanged = True
+
+ if self.workspaceFile:
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile) + '*')
+
+ def OnLocationWizard(self, event):
+ """!Launch location wizard"""
+ from location_wizard.wizard import LocationWizard
+
+ gWizard = LocationWizard(parent = self,
+ grassdatabase = grass.gisenv()['GISDBASE'])
+ location = gWizard.location
+
+ if location != None:
+ dlg = wx.MessageDialog(parent = self,
+ message = _('Location <%s> created.\n\n'
+ 'Do you want to switch to the '
+ 'new location?') % location,
+ caption=_("Switch to new location?"),
+ style = wx.YES_NO | wx.NO_DEFAULT |
+ wx.ICON_QUESTION | wx.CENTRE)
+
+ ret = dlg.ShowModal()
+ dlg.Destroy()
+ if ret == wx.ID_YES:
+ if RunCommand('g.mapset', parent = self,
+ location = location,
+ mapset = 'PERMANENT') != 0:
+ return
+
+ GMessage(parent = self,
+ message = _("Current location is <%(loc)s>.\n"
+ "Current mapset is <%(mapset)s>.") % \
+ { 'loc' : location, 'mapset' : 'PERMANENT' })
+
+ def OnSettingsChanged(self, event):
+ """!Here can be functions which have to be called after EVT_SETTINGS_CHANGED.
+ Now only set copying of selected text to clipboard (in goutput).
+ """
+ ### self._createMenuBar() # bug when menu is re-created on the fly
+ self._setCopyingOfSelectedText()
+
+ def OnGCPManager(self, event):
+ """!Launch georectifier module
+ """
+ GCPWizard(self)
+
+ def OnGModeler(self, event):
+ """!Launch Graphical Modeler"""
+ win = ModelFrame(parent = self)
+ win.CentreOnScreen()
+
+ win.Show()
+
+ def OnPsMap(self, event):
+ """!Launch Cartographic Composer
+ """
+ win = PsMapFrame(parent = self)
+ win.CentreOnScreen()
+
+ win.Show()
+
+ def OnDone(self, cmd, returncode):
+ """Command execution finised"""
+ if hasattr(self, "model"):
+ self.model.DeleteIntermediateData(log = self.goutput)
+ del self.model
+ self.SetStatusText('')
+
+ def OnRunModel(self, event):
+ """!Run model"""
+ filename = ''
+ dlg = wx.FileDialog(parent = self, message =_("Choose model to run"),
+ defaultDir = os.getcwd(),
+ wildcard = _("GRASS Model File (*.gxm)|*.gxm"))
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+
+ if not filename:
+ dlg.Destroy()
+ return
+
+ self.model = Model()
+ self.model.LoadModel(filename)
+ self.model.Run(log = self.goutput, onDone = self.OnDone, parent = self)
+
+ dlg.Destroy()
+
+ def OnMapsets(self, event):
+ """!Launch mapset access dialog
+ """
+ dlg = MapsetAccess(parent = self, id = wx.ID_ANY)
+ dlg.CenterOnScreen()
+
+ if dlg.ShowModal() == wx.ID_OK:
+ ms = dlg.GetMapsets()
+ RunCommand('g.mapsets',
+ parent = self,
+ mapset = '%s' % ','.join(ms))
+
+ def OnCBPageChanged(self, event):
+ """!Page in notebook (display) changed"""
+ self.curr_page = self.gm_cb.GetCurrentPage()
+ self.curr_pagenum = self.gm_cb.GetSelection()
+ try:
+ self.curr_page.maptree.mapdisplay.SetFocus()
+ self.curr_page.maptree.mapdisplay.Raise()
+ except:
+ pass
+
+ event.Skip()
+
+ def OnPageChanged(self, event):
+ """!Page in notebook changed"""
+ page = event.GetSelection()
+ if page == self.notebook.GetPageIndexByName('output'):
+ # remove '(...)'
+ self.notebook.SetPageText(page, _("Command console"))
+ wx.CallAfter(self.goutput.ResetFocus)
+ self.SetStatusText('', 0)
+
+ event.Skip()
+
+ def OnCBPageClosed(self, event):
+ """!Page of notebook closed
+ Also close associated map display
+ """
+ if UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
+ maptree = self.curr_page.maptree
+
+ if self.workspaceFile:
+ message = _("Do you want to save changes in the workspace?")
+ else:
+ message = _("Do you want to store current settings "
+ "to workspace file?")
+
+ # ask user to save current settings
+ if maptree.GetCount() > 0:
+ name = self.gm_cb.GetPageText(self.curr_pagenum)
+ dlg = wx.MessageDialog(self,
+ message = message,
+ caption = _("Close Map Display %s") % name,
+ 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.workspaceFile:
+ self.OnWorkspaceSaveAs()
+ else:
+ self.SaveToWorkspaceFile(self.workspaceFile)
+ elif ret == wx.ID_CANCEL:
+ event.Veto()
+ dlg.Destroy()
+ return
+ dlg.Destroy()
+
+ self.gm_cb.GetPage(event.GetSelection()).maptree.Map.Clean()
+ self.gm_cb.GetPage(event.GetSelection()).maptree.Close(True)
+
+ self.curr_page = None
+
+ event.Skip()
+
+ def GetLayerTree(self):
+ """!Get current layer tree"""
+ return self.curr_page.maptree
+
+ def GetLogWindow(self):
+ """!Get widget for command output"""
+ return self.goutput
+
+ def GetMenuCmd(self, event):
+ """!Get GRASS command from menu item
+
+ Return command as a list"""
+ layer = None
+
+ if event:
+ cmd = self.menucmd[event.GetId()]
+
+ try:
+ cmdlist = cmd.split(' ')
+ except: # already list?
+ cmdlist = cmd
+
+ # check list of dummy commands for GUI modules that do not have GRASS
+ # bin modules or scripts.
+ if cmd in ['vcolors', 'r.mapcalc', 'r3.mapcalc']:
+ return cmdlist
+
+ try:
+ layer = self.curr_page.maptree.layer_selected
+ name = self.curr_page.maptree.GetPyData(layer)[0]['maplayer'].name
+ type = self.curr_page.maptree.GetPyData(layer)[0]['type']
+ except:
+ layer = None
+
+ 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 = GUI().GetCommandInputMapParamKey(cmdlist[0])
+ if input:
+ cmdlist.append("%s=%s" % (input, name))
+
+ return cmdlist
+
+ def RunMenuCmd(self, event = None, cmd = []):
+ """!Run command selected from menu"""
+ if event:
+ cmd = self.GetMenuCmd(event)
+ self.goutput.RunCmd(cmd, switchPage = False)
+
+ def OnMenuCmd(self, event = None, cmd = []):
+ """!Parse command selected from menu"""
+ if event:
+ cmd = self.GetMenuCmd(event)
+ GUI(parent = self).ParseCommand(cmd)
+
+ def OnVDigit(self, event):
+ """!Start vector digitizer
+ """
+ if not self.curr_page:
+ self.MsgNoLayerSelected()
+ return
+
+ tree = self.GetLayerTree()
+ layer = tree.layer_selected
+ # no map layer selected
+ if not layer:
+ self.MsgNoLayerSelected()
+ return
+
+ # available only for vector map layers
+ try:
+ mapLayer = tree.GetPyData(layer)[0]['maplayer']
+ except:
+ mapLayer = None
+
+ if not mapLayer or mapLayer.GetType() != 'vector':
+ GMessage(parent = self,
+ message = _("Selected map layer is not vector."))
+ return
+
+ if mapLayer.GetMapset() != grass.gisenv()['MAPSET']:
+ GMessage(parent = self,
+ message = _("Editing is allowed only for vector maps from the "
+ "current mapset."))
+ return
+
+ if not tree.GetPyData(layer)[0]:
+ return
+ dcmd = tree.GetPyData(layer)[0]['cmd']
+ if not dcmd:
+ return
+
+ tree.OnStartEditing(None)
+
+ def OnRunScript(self, event):
+ """!Run script"""
+ # open dialog and choose script file
+ dlg = wx.FileDialog(parent = self, message = _("Choose script file to run"),
+ defaultDir = os.getcwd(),
+ wildcard = _("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"))
+
+ filename = None
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+
+ if not filename:
+ return False
+
+ if not os.path.exists(filename):
+ GError(parent = self,
+ message = _("Script file '%s' doesn't exist. "
+ "Operation canceled.") % filename)
+ return
+
+ # check permission
+ if not os.access(filename, os.X_OK):
+ dlg = wx.MessageDialog(self,
+ message = _("Script <%s> is not executable. "
+ "Do you want to set the permissions "
+ "that allows you to run this script "
+ "(note that you must be the owner of the file)?" % \
+ os.path.basename(filename)),
+ caption = _("Set permission?"),
+ style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() != wx.ID_YES:
+ return
+ dlg.Destroy()
+ try:
+ mode = stat.S_IMODE(os.lstat(filename)[stat.ST_MODE])
+ os.chmod(filename, mode | stat.S_IXUSR)
+ except OSError:
+ GError(_("Unable to set permission. Operation canceled."), parent = self)
+ return
+
+ # check GRASS_ADDON_PATH
+ addonPath = os.getenv('GRASS_ADDON_PATH', [])
+ if addonPath:
+ addonPath = addonPath.split(os.pathsep)
+ dirName = os.path.dirname(filename)
+ if dirName not in addonPath:
+ addonPath.append(dirName)
+ dlg = wx.MessageDialog(self,
+ message = _("Directory '%s' is not defined in GRASS_ADDON_PATH. "
+ "Do you want add this directory to GRASS_ADDON_PATH?") % \
+ dirName,
+ caption = _("Update Addons path?"),
+ style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() == wx.ID_YES:
+ os.environ['GRASS_ADDON_PATH'] = os.pathsep.join(addonPath)
+ RunCommand('g.gisenv', set = 'ADDON_PATH=%s' % os.environ['GRASS_ADDON_PATH'])
+
+ self.goutput.WriteCmdLog(_("Launching script '%s'...") % filename)
+ self.goutput.RunCmd([filename], switchPage = True)
+
+ def OnChangeLocation(self, event):
+ """Change current location"""
+ dlg = LocationDialog(parent = self)
+ if dlg.ShowModal() == wx.ID_OK:
+ location, mapset = dlg.GetValues()
+ dlg.Destroy()
+
+ if not location or not mapset:
+ GError(parent = self,
+ message = _("No location/mapset provided. Operation canceled."))
+ return # this should not happen
+
+ if RunCommand('g.mapset', parent = self,
+ location = location,
+ mapset = mapset) != 0:
+ return # error reported
+
+ # close workspace
+ self.OnWorkspaceClose()
+ self.OnWorkspaceNew()
+ GMessage(parent = self,
+ message = _("Current location is <%(loc)s>.\n"
+ "Current mapset is <%(mapset)s>.") % \
+ { 'loc' : location, 'mapset' : mapset })
+
+ def OnCreateMapset(self, event):
+ """!Create new mapset"""
+ dlg = wx.TextEntryDialog(parent = self,
+ message = _('Enter name for new mapset:'),
+ caption = _('Create new mapset'))
+
+ if dlg.ShowModal() == wx.ID_OK:
+ mapset = dlg.GetValue()
+ if not mapset:
+ GError(parent = self,
+ message = _("No mapset provided. Operation canceled."))
+ return
+
+ ret = RunCommand('g.mapset',
+ parent = self,
+ flags = 'c',
+ mapset = mapset)
+ if ret == 0:
+ GMessage(parent = self,
+ message = _("Current mapset is <%s>.") % mapset)
+
+ def OnChangeMapset(self, event):
+ """Change current mapset"""
+ dlg = MapsetDialog(parent = self)
+
+ if dlg.ShowModal() == wx.ID_OK:
+ mapset = dlg.GetMapset()
+ dlg.Destroy()
+
+ if not mapset:
+ GError(parent = self,
+ message = _("No mapset provided. Operation canceled."))
+ return
+
+ if RunCommand('g.mapset',
+ parent = self,
+ mapset = mapset) == 0:
+ GMessage(parent = self,
+ message = _("Current mapset is <%s>.") % mapset)
+
+ def OnNewVector(self, event):
+ """!Create new vector map layer"""
+ dlg = CreateNewVector(self, log = self.goutput,
+ cmd = (('v.edit',
+ { 'tool' : 'create' },
+ 'map')))
+
+ if not dlg:
+ return
+
+ name = dlg.GetName(full = True)
+ if name and dlg.IsChecked('add'):
+ # add layer to map layer tree
+ self.curr_page.maptree.AddLayer(ltype = 'vector',
+ lname = name,
+ lcmd = ['d.vect', 'map=%s' % name])
+ dlg.Destroy()
+
+ def OnAboutGRASS(self, event):
+ """!Display 'About GRASS' dialog"""
+ win = AboutWindow(self)
+ win.CentreOnScreen()
+ win.Show(True)
+
+ def _popupMenu(self, data):
+ """!Create popup menu
+ """
+ point = wx.GetMousePosition()
+ menu = wx.Menu()
+
+ for key, handler in data:
+ if key is None:
+ menu.AppendSeparator()
+ continue
+ item = wx.MenuItem(menu, wx.ID_ANY, LMIcons[key].GetLabel())
+ item.SetBitmap(LMIcons[key].GetBitmap(self.iconsize))
+ menu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, handler, item)
+
+ # create menu
+ self.PopupMenu(menu)
+ menu.Destroy()
+
+ def OnImportMenu(self, event):
+ """!Import maps menu (import, link)
+ """
+ self._popupMenu((('rastImport', self.OnImportGdalLayers),
+ ('vectImport', self.OnImportOgrLayers)))
+
+ def OnWorkspaceNew(self, event = None):
+ """!Create new workspace file
+
+ Erase current workspace settings first
+ """
+ Debug.msg(4, "GMFrame.OnWorkspaceNew():")
+
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay()
+
+ maptree = self.curr_page.maptree
+
+ # ask user to save current settings
+ if self.workspaceFile and self.workspaceChanged:
+ self.OnWorkspaceSave()
+ elif self.workspaceFile is None and maptree.GetCount() > 0:
+ dlg = wx.MessageDialog(self, message = _("Current workspace is not empty. "
+ "Do you want to store current settings "
+ "to workspace file?"),
+ caption = _("Create new workspace?"),
+ style = wx.YES_NO | wx.YES_DEFAULT | \
+ wx.CANCEL | wx.ICON_QUESTION)
+ ret = dlg.ShowModal()
+ if ret == wx.ID_YES:
+ self.OnWorkspaceSaveAs()
+ elif ret == wx.ID_CANCEL:
+ dlg.Destroy()
+ return
+
+ dlg.Destroy()
+
+ # delete all items
+ maptree.DeleteAllItems()
+
+ # add new root element
+ maptree.root = maptree.AddRoot("Map Layers")
+ self.curr_page.maptree.SetPyData(maptree.root, (None,None))
+
+ # no workspace file loaded
+ self.workspaceFile = None
+ self.workspaceChanged = False
+ self.SetTitle(self.baseTitle)
+
+ def OnWorkspaceOpen(self, event = None):
+ """!Open file with workspace definition"""
+ dlg = wx.FileDialog(parent = self, message = _("Choose workspace file"),
+ defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"))
+
+ filename = ''
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+
+ if filename == '':
+ return
+
+ Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename)
+
+ # delete current layer tree content
+ self.OnWorkspaceClose()
+
+ self.LoadWorkspaceFile(filename)
+
+ self.workspaceFile = filename
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
+
+ def LoadWorkspaceFile(self, filename):
+ """!Load layer tree definition stored in GRASS Workspace XML file (gxw)
+
+ @todo Validate against DTD
+
+ @return True on success
+ @return False on error
+ """
+ # dtd
+ dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxw.dtd")
+
+ # parse workspace file
+ try:
+ gxwXml = ProcessWorkspaceFile(etree.parse(filename))
+ except Exception, e:
+ GError(parent = self,
+ message = _("Reading workspace file <%s> failed.\n"
+ "Invalid file, unable to parse XML document.") % filename)
+ return
+
+ busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
+ parent = self)
+ wx.Yield()
+
+ #
+ # load layer manager window properties
+ #
+ if not UserSettings.Get(group = 'general', key = 'workspace',
+ subkey = ['posManager', 'enabled']):
+ if gxwXml.layerManager['pos']:
+ self.SetPosition(gxwXml.layerManager['pos'])
+ if gxwXml.layerManager['size']:
+ self.SetSize(gxwXml.layerManager['size'])
+
+ #
+ # start map displays first (list of layers can be empty)
+ #
+ displayId = 0
+ mapdisplay = list()
+ for display in gxwXml.displays:
+ mapdisp = self.NewDisplay(name = display['name'], show = False)
+ mapdisplay.append(mapdisp)
+ maptree = self.gm_cb.GetPage(displayId).maptree
+
+ # set windows properties
+ mapdisp.SetProperties(render = display['render'],
+ mode = display['mode'],
+ showCompExtent = display['showCompExtent'],
+ alignExtent = display['alignExtent'],
+ constrainRes = display['constrainRes'],
+ projection = display['projection']['enabled'])
+
+ if display['projection']['enabled']:
+ if display['projection']['epsg']:
+ UserSettings.Set(group = 'display', key = 'projection', subkey = 'epsg',
+ value = display['projection']['epsg'])
+ if display['projection']['proj']:
+ UserSettings.Set(group = 'display', key = 'projection', subkey = 'proj4',
+ value = display['projection']['proj'])
+
+ # set position and size of map display
+ if not UserSettings.Get(group = 'general', key = 'workspace', subkey = ['posDisplay', 'enabled']):
+ if display['pos']:
+ mapdisp.SetPosition(display['pos'])
+ if display['size']:
+ mapdisp.SetSize(display['size'])
+
+ # set extent if defined
+ if display['extent']:
+ w, s, e, n = display['extent']
+ region = maptree.Map.region = maptree.Map.GetRegion(w = w, s = s, e = e, n = n)
+ mapdisp.GetWindow().ResetZoomHistory()
+ mapdisp.GetWindow().ZoomHistory(region['n'],
+ region['s'],
+ region['e'],
+ region['w'])
+
+ mapdisp.Show()
+
+ displayId += 1
+
+ maptree = None
+ selected = [] # list of selected layers
+ #
+ # load list of map layers
+ #
+ for layer in gxwXml.layers:
+ display = layer['display']
+ maptree = self.gm_cb.GetPage(display).maptree
+
+ newItem = maptree.AddLayer(ltype = layer['type'],
+ lname = layer['name'],
+ lchecked = layer['checked'],
+ lopacity = layer['opacity'],
+ lcmd = layer['cmd'],
+ lgroup = layer['group'],
+ lnviz = layer['nviz'],
+ lvdigit = layer['vdigit'])
+
+ if layer.has_key('selected'):
+ if layer['selected']:
+ selected.append((maptree, newItem))
+ else:
+ maptree.SelectItem(newItem, select = False)
+
+ for maptree, layer in selected:
+ if not maptree.IsSelected(layer):
+ maptree.SelectItem(layer, select = True)
+ maptree.layer_selected = layer
+
+ busy.Destroy()
+
+ for idx, mdisp in enumerate(mapdisplay):
+ mdisp.MapWindow2D.UpdateMap()
+ #nviz
+ if gxwXml.displays[idx]['viewMode'] == '3d':
+ mdisp.AddNviz()
+ self.nviz.UpdateState(view = gxwXml.nviz_state['view'],
+ iview = gxwXml.nviz_state['iview'],
+ light = gxwXml.nviz_state['light'])
+ mdisp.MapWindow3D.constants = gxwXml.nviz_state['constants']
+ for idx, constant in enumerate(mdisp.MapWindow3D.constants):
+ mdisp.MapWindow3D.AddConstant(constant, idx + 1)
+ for page in ('view', 'light', 'fringe', 'constant', 'cplane'):
+ self.nviz.UpdatePage(page)
+ self.nviz.UpdateSettings()
+ mapdisp.toolbars['map'].combo.SetSelection(1)
+
+
+ return True
+
+ def OnWorkspaceLoadGrcFile(self, event):
+ """!Load map layers from GRC file (Tcl/Tk GUI) into map layer tree"""
+ dlg = wx.FileDialog(parent = self, message = _("Choose GRC file to load"),
+ defaultDir = os.getcwd(), wildcard = _("Old GRASS Workspace File (*.grc)|*.grc"))
+
+ filename = ''
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+
+ if filename == '':
+ return
+
+ Debug.msg(4, "GMFrame.OnWorkspaceLoadGrcFile(): filename=%s" % filename)
+
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay()
+
+ busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
+ parent = self)
+ wx.Yield()
+
+ maptree = None
+ for layer in ProcessGrcFile(filename).read(self):
+ maptree = self.gm_cb.GetPage(layer['display']).maptree
+ newItem = maptree.AddLayer(ltype = layer['type'],
+ lname = layer['name'],
+ lchecked = layer['checked'],
+ lopacity = layer['opacity'],
+ lcmd = layer['cmd'],
+ lgroup = layer['group'])
+
+ busy.Destroy()
+
+ if maptree:
+ # reverse list of map layers
+ maptree.Map.ReverseListOfLayers()
+
+ def OnWorkspaceSaveAs(self, event = None):
+ """!Save workspace definition to selected file"""
+ dlg = wx.FileDialog(parent = self, message = _("Choose file to save current workspace"),
+ defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"), style = wx.FD_SAVE)
+
+ filename = ''
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+
+ if filename == '':
+ return False
+
+ # check for extension
+ if filename[-4:] != ".gxw":
+ filename += ".gxw"
+
+ if os.path.exists(filename):
+ dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
+ "Do you want to overwrite this file?") % filename,
+ caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() != wx.ID_YES:
+ dlg.Destroy()
+ return False
+
+ Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename)
+
+ self.SaveToWorkspaceFile(filename)
+ self.workspaceFile = filename
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
+
+ def OnWorkspaceSave(self, event = None):
+ """!Save file with workspace definition"""
+ if self.workspaceFile:
+ dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
+ "Do you want to overwrite this file?") % \
+ self.workspaceFile,
+ caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() == wx.ID_NO:
+ dlg.Destroy()
+ else:
+ Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile)
+ self.SaveToWorkspaceFile(self.workspaceFile)
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
+ self.workspaceChanged = False
+ else:
+ self.OnWorkspaceSaveAs()
+
+ def SaveToWorkspaceFile(self, filename):
+ """!Save layer tree layout to workspace file
+
+ Return True on success, False on error
+ """
+ tmpfile = tempfile.TemporaryFile(mode = 'w+b')
+ try:
+ WriteWorkspaceFile(lmgr = self, file = tmpfile)
+ except StandardError, e:
+ GError(parent = self,
+ message = _("Writing current settings to workspace file "
+ "failed."))
+ return False
+
+ try:
+ mfile = open(filename, "w")
+ tmpfile.seek(0)
+ for line in tmpfile.readlines():
+ mfile.write(line)
+ except IOError:
+ GError(parent = self,
+ message = _("Unable to open file <%s> for writing.") % filename)
+ return False
+
+ mfile.close()
+
+ return True
+
+ def OnWorkspaceClose(self, event = None):
+ """!Close file with workspace definition
+
+ If workspace has been modified ask user to save the changes.
+ """
+ Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile)
+
+ self.OnDisplayCloseAll()
+ self.workspaceFile = None
+ self.workspaceChanged = False
+ self.SetTitle(self.baseTitle)
+ self.disp_idx = 0
+ self.curr_page = None
+
+ def OnDisplayClose(self, event = None):
+ """!Close current map display window
+ """
+ if self.curr_page and self.curr_page.maptree.mapdisplay:
+ self.curr_page.maptree.mapdisplay.OnCloseWindow(event)
+
+ def OnDisplayCloseAll(self, event = None):
+ """!Close all open map display windows
+ """
+ displays = list()
+ for page in range(0, self.gm_cb.GetPageCount()):
+ displays.append(self.gm_cb.GetPage(page).maptree.mapdisplay)
+
+ for display in displays:
+ display.OnCloseWindow(event)
+
+ def OnRenameDisplay(self, event):
+ """!Change Map Display name"""
+ name = self.gm_cb.GetPageText(self.curr_pagenum)
+ dlg = wx.TextEntryDialog(self, message = _("Enter new name:"),
+ caption = _("Rename Map Display"), defaultValue = name)
+ if dlg.ShowModal() == wx.ID_OK:
+ name = dlg.GetValue()
+ self.gm_cb.SetPageText(page = self.curr_pagenum, text = name)
+ mapdisplay = self.curr_page.maptree.mapdisplay
+ mapdisplay.SetTitle(_("GRASS GIS Map Display: %(name)s - Location: %(loc)s") % \
+ { 'name' : name,
+ 'loc' : grass.gisenv()["LOCATION_NAME"] })
+ dlg.Destroy()
+
+ def RulesCmd(self, event):
+ """!Launches dialog for commands that need rules input and
+ processes rules
+ """
+ cmd = self.GetMenuCmd(event)
+
+ if cmd[0] == 'r.colors':
+ ctable = RasterColorTable(self)
+ else:
+ ctable = VectorColorTable(self, attributeType = 'color')
+ ctable.CentreOnScreen()
+ ctable.Show()
+
+ def OnXTermNoXMon(self, event):
+ """!
+ Run commands that need xterm
+ """
+ self.OnXTerm(event, need_xmon = False)
+
+ def OnXTerm(self, event, need_xmon = True):
+ """!
+ Run commands that need interactive xmon
+
+ @param need_xmon True to start X monitor
+ """
+ # unset display mode
+ del os.environ['GRASS_RENDER_IMMEDIATE']
+
+ if need_xmon:
+ # open next available xmon
+ xmonlist = []
+
+ # make list of xmons that are not running
+ ret = RunCommand('d.mon',
+ flags = 'L',
+ read = True)
+
+ for line in ret.split('\n'):
+ line = line.strip()
+ if line.startswith('x') and 'not running' in line:
+ xmonlist.append(line[0:2])
+
+ # find available xmon
+ xmon = xmonlist[0]
+
+ # bring up the xmon
+ cmdlist = ['d.mon', xmon]
+ p = Command(cmdlist, wait=False)
+
+ # run the command
+ command = self.GetMenuCmd(event)
+ command = ' '.join(command)
+
+ gisbase = os.environ['GISBASE']
+
+ if sys.platform == "win32":
+ runbat = os.path.join(gisbase,'etc','grass-run.bat')
+ cmdlist = ["start", runbat, runbat, command]
+ else:
+ if sys.platform == "darwin":
+ xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-mac')
+ else:
+ xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-wrapper')
+
+ grassrun = os.path.join(gisbase,'etc','grass-run.sh')
+ cmdlist = [xtermwrapper, '-e', grassrun, command]
+
+ p = Command(cmdlist, wait=False)
+
+ # reset display mode
+ os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE'
+
+ def OnEditImageryGroups(self, event, cmd = None):
+ """!Show dialog for creating and editing groups.
+ """
+ dlg = GroupDialog(self)
+ dlg.CentreOnScreen()
+ dlg.Show()
+
+ def OnInstallExtension(self, event):
+ """!Install extension from GRASS Addons SVN repository"""
+ win = InstallExtensionWindow(self, size = (650, 550))
+ win.CentreOnScreen()
+ win.Show()
+
+ def OnUninstallExtension(self, event):
+ """!Uninstall extension"""
+ win = UninstallExtensionWindow(self, size = (650, 300))
+ win.CentreOnScreen()
+ win.Show()
+
+ def OnPreferences(self, event):
+ """!General GUI preferences/settings
+ """
+ if not self.dialogs['preferences']:
+ dlg = PreferencesDialog(parent = self)
+ self.dialogs['preferences'] = dlg
+ self.dialogs['preferences'].CenterOnScreen()
+
+ dlg.Bind(EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
+
+ self.dialogs['preferences'].ShowModal()
+
+ def OnHelp(self, event):
+ """!Show help
+ """
+ self.goutput.RunCmd(['g.manual','-i'])
+
+ def OnHistogram(self, event):
+ """!Init histogram display canvas and tools
+ """
+ from modules.histogram import HistogramFrame
+ win = HistogramFrame(self)
+
+ win.CentreOnScreen()
+ win.Show()
+ win.Refresh()
+ win.Update()
+
+ def OnProfile(self, event):
+ """!Launch profile tool
+ """
+ win = profile.ProfileFrame(parent = self)
+
+ win.CentreOnParent()
+ win.Show()
+ win.Refresh()
+ win.Update()
+
+ def OnMapCalculator(self, event, cmd = ''):
+ """!Init map calculator for interactive creation of mapcalc statements
+ """
+ if event:
+ try:
+ cmd = self.GetMenuCmd(event)
+ except KeyError:
+ cmd = ['r.mapcalc']
+
+ win = MapCalcFrame(parent = self,
+ cmd = cmd[0])
+ win.CentreOnScreen()
+ win.Show()
+
+ def OnVectorCleaning(self, event, cmd = ''):
+ """!Init interactive vector cleaning
+ """
+ from modules.vclean import VectorCleaningFrame
+ win = VectorCleaningFrame(parent = self)
+ win.CentreOnScreen()
+ win.Show()
+
+ def OnImportDxfFile(self, event, cmd = None):
+ """!Convert multiple DXF layers to GRASS vector map layers"""
+ dlg = DxfImportDialog(parent = self)
+ dlg.CentreOnScreen()
+ dlg.Show()
+
+ def OnImportGdalLayers(self, event, cmd = None):
+ """!Convert multiple GDAL layers to GRASS raster map layers"""
+ dlg = GdalImportDialog(parent = self)
+ dlg.CentreOnScreen()
+ dlg.Show()
+
+ def OnLinkGdalLayers(self, event, cmd = None):
+ """!Link multiple GDAL layers to GRASS raster map layers"""
+ 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 = 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 = GdalImportDialog(parent = self, ogr = True, link = True)
+ dlg.CentreOnScreen()
+ dlg.Show()
+
+ def OnImportWMS(self, event):
+ """!Import data from OGC WMS server"""
+ dlg = WMSDialog(parent = self, service = 'wms')
+ dlg.CenterOnScreen()
+
+ if dlg.ShowModal() == wx.ID_OK: # -> import layers
+ layers = dlg.GetLayers()
+
+ if len(layers.keys()) > 0:
+ for layer in layers.keys():
+ cmd = ['r.in.wms',
+ 'mapserver=%s' % dlg.GetSettings()['server'],
+ 'layers=%s' % layer,
+ 'output=%s' % layer,
+ 'format=png',
+ '--overwrite']
+ styles = ','.join(layers[layer])
+ if styles:
+ cmd.append('styles=%s' % styles)
+ self.goutput.RunCmd(cmd, switchPage = True)
+
+ self.curr_page.maptree.AddLayer(ltype = 'raster',
+ lname = layer,
+ lcmd = ['d.rast', 'map=%s' % layer],
+ multiple = False)
+ else:
+ self.goutput.WriteWarning(_("Nothing to import. No WMS layer selected."))
+
+
+ dlg.Destroy()
+
+ def OnShowAttributeTable(self, event, selection = None):
+ """!Show attribute table of the given vector map layer
+ """
+ if not self.curr_page:
+ self.MsgNoLayerSelected()
+ return
+
+ tree = self.GetLayerTree()
+ layer = tree.layer_selected
+ # no map layer selected
+ if not layer:
+ self.MsgNoLayerSelected()
+ return
+
+ # available only for vector map layers
+ try:
+ maptype = tree.GetPyData(layer)[0]['maplayer'].type
+ except:
+ maptype = None
+
+ if not maptype or maptype != 'vector':
+ GMessage(parent = self,
+ message = _("Selected map layer is not vector."))
+ return
+
+ if not tree.GetPyData(layer)[0]:
+ return
+ dcmd = tree.GetPyData(layer)[0]['cmd']
+ if not dcmd:
+ return
+
+ busy = wx.BusyInfo(message = _("Please wait, loading attribute data..."),
+ parent = self)
+ wx.Yield()
+
+ dbmanager = AttributeManager(parent = self, id = wx.ID_ANY,
+ size = wx.Size(500, 300),
+ item = layer, log = self.goutput,
+ selection = selection)
+
+ busy.Destroy()
+
+ # register ATM dialog
+ self.dialogs['atm'].append(dbmanager)
+
+ # show ATM window
+ dbmanager.Show()
+
+ def OnNewDisplayWMS(self, event = None):
+ """!Create new layer tree and map display instance"""
+ self.NewDisplayWMS()
+
+ def OnNewDisplay(self, event = None):
+ """!Create new layer tree and map display instance"""
+ self.NewDisplay()
+
+ def NewDisplay(self, name = None, show = True):
+ """!Create new layer tree, which will
+ create an associated map display frame
+
+ @param name name of new map display
+ @param show show map display window if True
+
+ @return reference to mapdisplay intance
+ """
+ Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.disp_idx)
+
+ # make a new page in the bookcontrol for the layer tree (on page 0 of the notebook)
+ self.pg_panel = wx.Panel(self.gm_cb, id = wx.ID_ANY, style = wx.EXPAND)
+ if name:
+ dispName = name
+ else:
+ dispName = "Display " + str(self.disp_idx + 1)
+ self.gm_cb.AddPage(self.pg_panel, text = dispName, select = True)
+ 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(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)
+ cb_boxsizer.Add(self.curr_page.maptree, proportion = 1, flag = wx.EXPAND, border = 1)
+ self.curr_page.SetSizer(cb_boxsizer)
+ cb_boxsizer.Fit(self.curr_page.maptree)
+ self.curr_page.Layout()
+ self.curr_page.maptree.Layout()
+
+ # use default window layout
+ if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
+ dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
+ idx = 4 + self.disp_idx * 4
+ try:
+ x, y = map(int, dim.split(',')[idx:idx + 2])
+ w, h = map(int, dim.split(',')[idx + 2:idx + 4])
+ self.curr_page.maptree.mapdisplay.SetPosition((x, y))
+ self.curr_page.maptree.mapdisplay.SetSize((w, h))
+ except:
+ pass
+
+ self.disp_idx += 1
+
+ return self.curr_page.maptree.mapdisplay
+
+ def OnAddMaps(self, event = None):
+ """!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()
+ return
+
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay()
+
+ maptree = self.curr_page.maptree
+
+ for layerName in dialog.GetMapLayers():
+ ltype = dialog.GetLayerType(cmd = True)
+ if ltype == 'rast':
+ cmd = ['d.rast', 'map=%s' % layerName]
+ wxType = 'raster'
+ elif ltype == 'rast3d':
+ cmd = ['d.rast3d', 'map=%s' % layerName]
+ wxType = '3d-raster'
+ elif ltype == 'vect':
+ cmd = ['d.vect', 'map=%s' % layerName]
+ wxType = 'vector'
+ else:
+ GError(parent = self,
+ message = _("Unsupported map layer type <%s>.") % ltype)
+ return
+
+ newItem = maptree.AddLayer(ltype = wxType,
+ lname = layerName,
+ lchecked = False,
+ lopacity = 1.0,
+ lcmd = cmd,
+ lgroup = None)
+ dialog.Destroy()
+
+ def OnAddRaster(self, event):
+ """!Add raster map layer"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('raster')
+
+ def OnAddRaster3D(self, event):
+ """!Add 3D raster map layer"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.AddRaster3D(event)
+
+ def OnAddRasterMisc(self, event):
+ """!Create misc raster popup-menu"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self._popupMenu((('addRast3d', self.OnAddRaster3D),
+ (None, None),
+ ('addRgb', self.OnAddRasterRGB),
+ ('addHis', self.OnAddRasterHIS),
+ (None, None),
+ ('addShaded', self.OnAddRasterShaded),
+ (None, None),
+ ('addRArrow', self.OnAddRasterArrow),
+ ('addRNum', self.OnAddRasterNum)))
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnAddVector(self, event):
+ """!Add vector map to the current layer tree"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('vector')
+
+ def OnAddVectorMisc(self, event):
+ """!Create misc vector popup-menu"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self._popupMenu((('addThematic', self.OnAddVectorTheme),
+ ('addChart', self.OnAddVectorChart)))
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnAddVectorTheme(self, event):
+ """!Add thematic vector map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('thememap')
+
+ def OnAddVectorChart(self, event):
+ """!Add chart vector map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('themechart')
+
+ def OnAddOverlay(self, event):
+ """!Create decoration overlay menu"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self._popupMenu((('addGrid', self.OnAddGrid),
+ ('addLabels', self.OnAddLabels),
+ ('addGeodesic', self.OnAddGeodesic),
+ ('addRhumb', self.OnAddRhumb),
+ (None, None),
+ ('addCmd', self.OnAddCommand)))
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnAddRaster3D(self, event):
+ """!Add 3D raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('3d-raster')
+
+ def OnAddRasterRGB(self, event):
+ """!Add RGB raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('rgb')
+
+ def OnAddRasterHIS(self, event):
+ """!Add HIS raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('his')
+
+ def OnAddRasterShaded(self, event):
+ """!Add shaded relief raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('shaded')
+
+ def OnAddRasterArrow(self, event):
+ """!Add flow arrows raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('rastarrow')
+
+ def OnAddRasterNum(self, event):
+ """!Add cell number raster map to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('rastnum')
+
+ def OnAddCommand(self, event):
+ """!Add command line map layer to the current layer tree"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('command')
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnAddGroup(self, event):
+ """!Add layer group"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('group')
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnAddGrid(self, event):
+ """!Add grid map layer to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('grid')
+
+ def OnAddGeodesic(self, event):
+ """!Add geodesic line map layer to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('geodesic')
+
+ def OnAddRhumb(self, event):
+ """!Add rhumb map layer to the current layer tree"""
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('rhumb')
+
+ def OnAddLabels(self, event):
+ """!Add vector labels map layer to the current layer tree"""
+ # start new map display if no display is available
+ if not self.curr_page:
+ self.NewDisplay(show = True)
+
+ self.notebook.SetSelectionByName('layers')
+ self.curr_page.maptree.AddLayer('labels')
+
+ # show map display
+ self.curr_page.maptree.mapdisplay.Show()
+
+ def OnDeleteLayer(self, event):
+ """!Remove selected map layer from the current layer Tree
+ """
+ if not self.curr_page or not self.curr_page.maptree.layer_selected:
+ self.MsgNoLayerSelected()
+ return
+
+ if UserSettings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'):
+ layerName = ''
+ for item in self.curr_page.maptree.GetSelections():
+ name = str(self.curr_page.maptree.GetItemText(item))
+ idx = name.find('(opacity')
+ if idx > -1:
+ layerName += '<' + name[:idx].strip(' ') + '>,\n'
+ else:
+ layerName += '<' + name + '>,\n'
+ layerName = layerName.rstrip(',\n')
+
+ if len(layerName) > 2: # <>
+ message = _("Do you want to remove map layer(s)\n%s\n"
+ "from layer tree?") % layerName
+ else:
+ message = _("Do you want to remove selected map layer(s) "
+ "from layer tree?")
+
+ dlg = wx.MessageDialog (parent = self, message = message,
+ caption = _("Remove map layer"),
+ style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+
+ if dlg.ShowModal() != wx.ID_YES:
+ dlg.Destroy()
+ return
+
+ dlg.Destroy()
+
+ for layer in self.curr_page.maptree.GetSelections():
+ if self.curr_page.maptree.GetPyData(layer)[0]['type'] == 'group':
+ self.curr_page.maptree.DeleteChildren(layer)
+ self.curr_page.maptree.Delete(layer)
+
+ def OnKeyDown(self, event):
+ """!Key pressed"""
+ kc = event.GetKeyCode()
+
+ if event.ControlDown():
+ if kc == wx.WXK_TAB:
+ # switch layer list / command output
+ if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('layers'):
+ self.notebook.SetSelectionByName('output')
+ else:
+ self.notebook.SetSelectionByName('layers')
+
+ try:
+ ckc = chr(kc)
+ except ValueError:
+ event.Skip()
+ return
+
+ if event.CtrlDown():
+ if kc == 'R':
+ self.OnAddRaster(None)
+ elif kc == 'V':
+ self.OnAddVector(None)
+
+ event.Skip()
+
+ def OnCloseWindow(self, event):
+ """!Cleanup when wxGUI is quitted"""
+ if not self.curr_page:
+ self._auimgr.UnInit()
+ self.Destroy()
+ return
+
+ maptree = self.curr_page.maptree
+ if self.workspaceChanged and \
+ UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
+ if self.workspaceFile:
+ message = _("Do you want to save changes in the workspace?")
+ else:
+ message = _("Do you want to store current settings "
+ "to workspace file?")
+
+ # ask user to save current settings
+ if maptree.GetCount() > 0:
+ dlg = wx.MessageDialog(self,
+ message = message,
+ caption = _("Quit GRASS GUI"),
+ 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.workspaceFile:
+ self.OnWorkspaceSaveAs()
+ else:
+ self.SaveToWorkspaceFile(self.workspaceFile)
+ elif ret == wx.ID_CANCEL:
+ event.Veto()
+ dlg.Destroy()
+ return
+ dlg.Destroy()
+
+ # don't ask any more...
+ UserSettings.Set(group = 'manager', key = 'askOnQuit', subkey = 'enabled',
+ value = False)
+
+ self.OnDisplayCloseAll()
+
+ self.gm_cb.DeleteAllPages()
+
+ self._auimgr.UnInit()
+ self.Destroy()
+
+ def MsgNoLayerSelected(self):
+ """!Show dialog message 'No layer selected'"""
+ wx.MessageBox(parent = self,
+ message = _("No map layer selected. Operation canceled."),
+ caption = _("Message"),
+ style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/frame.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/layertree.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/lmgr/layertree.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/lmgr/layertree.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1587 @@
+"""!
+ at package lmgr.layertree
+
+ at brief Utility classes for map layer management.
+
+Classes:
+ - layertree::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 core.settings import UserSettings
+from core.gcmd import GWarning
+from gui_core.toolbars import BaseIcons
+from icons.icon import MetaIcon
+
+TREE_ITEM_HEIGHT = 25
+
+LMIcons = {
+ 'rastImport' : MetaIcon(img = 'layer-import',
+ label = _('Import raster data')),
+ 'rastLink' : MetaIcon(img = 'layer-import',
+ label = _('Link external raster data')),
+ 'rastOut' : MetaIcon(img = 'layer-export',
+ label = _('Set raster output format')),
+ 'vectImport' : MetaIcon(img = 'layer-import',
+ label = _('Import vector data')),
+ 'vectLink' : MetaIcon(img = 'layer-import',
+ label = _('Link external vector data')),
+ 'vectOut' : MetaIcon(img = 'layer-export',
+ label = _('Set vector output format')),
+ 'addCmd' : MetaIcon(img = 'layer-command-add',
+ label = _('Add command layer')),
+ 'quit' : MetaIcon(img = 'quit',
+ label = _('Quit')),
+ 'addRgb' : MetaIcon(img = 'layer-rgb-add',
+ label = _('Add RGB map layer')),
+ 'addHis' : MetaIcon(img = 'layer-his-add',
+ label = _('Add HIS map layer')),
+ 'addShaded' : MetaIcon(img = 'layer-shaded-relief-add',
+ label = _('Add shaded relief map layer')),
+ 'addRArrow' : MetaIcon(img = 'layer-aspect-arrow-add',
+ label = _('Add raster flow arrows')),
+ 'addRNum' : MetaIcon(img = 'layer-cell-cats-add',
+ label = _('Add raster cell numbers')),
+ 'addThematic': MetaIcon(img = 'layer-vector-thematic-add',
+ label = _('Add thematic area (choropleth) map layer')),
+ 'addChart' : MetaIcon(img = 'layer-vector-chart-add',
+ label = _('Add thematic chart layer')),
+ 'addGrid' : MetaIcon(img = 'layer-grid-add',
+ label = _('Add grid layer')),
+ 'addGeodesic': MetaIcon(img = 'shortest-distance',
+ label = _('Add geodesic line layer')),
+ 'addRhumb' : MetaIcon(img = 'shortest-distance',
+ label = _('Add rhumbline layer')),
+ 'addLabels' : MetaIcon(img = 'layer-label-add',
+ label = _('Add labels')),
+ 'addRast3d' : MetaIcon(img = 'layer-raster3d-add',
+ label = _('Add 3D raster map layer'),
+ desc = _('Note that 3D raster data are rendered only in 3D view mode')),
+ 'layerOptions' : MetaIcon(img = 'options',
+ label = _('Set options')),
+ }
+
+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)
+ trgif = BaseIcons["addRast"].GetBitmap(bmpsize)
+ self.rast_icon = il.Add(trgif)
+
+ trgif = LMIcons["addRast3d"].GetBitmap(bmpsize)
+ self.rast3d_icon = il.Add(trgif)
+
+ trgif = LMIcons["addRgb"].GetBitmap(bmpsize)
+ self.rgb_icon = il.Add(trgif)
+
+ trgif = LMIcons["addHis"].GetBitmap(bmpsize)
+ self.his_icon = il.Add(trgif)
+
+ trgif = LMIcons["addShaded"].GetBitmap(bmpsize)
+ self.shaded_icon = il.Add(trgif)
+
+ trgif = LMIcons["addRArrow"].GetBitmap(bmpsize)
+ self.rarrow_icon = il.Add(trgif)
+
+ trgif = LMIcons["addRNum"].GetBitmap(bmpsize)
+ self.rnum_icon = il.Add(trgif)
+
+ trgif = BaseIcons["addVect"].GetBitmap(bmpsize)
+ self.vect_icon = il.Add(trgif)
+
+ trgif = LMIcons["addThematic"].GetBitmap(bmpsize)
+ self.theme_icon = il.Add(trgif)
+
+ trgif = LMIcons["addChart"].GetBitmap(bmpsize)
+ self.chart_icon = il.Add(trgif)
+
+ trgif = LMIcons["addGrid"].GetBitmap(bmpsize)
+ self.grid_icon = il.Add(trgif)
+
+ trgif = LMIcons["addGeodesic"].GetBitmap(bmpsize)
+ self.geodesic_icon = il.Add(trgif)
+
+ trgif = LMIcons["addRhumb"].GetBitmap(bmpsize)
+ self.rhumb_icon = il.Add(trgif)
+
+ trgif = LMIcons["addLabels"].GetBitmap(bmpsize)
+ self.labels_icon = il.Add(trgif)
+
+ trgif = LMIcons["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, compReg = False)
+
+ 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
+
+ win = HistogramFrame(parent = self)
+
+ win.CentreOnScreen()
+ win.Show()
+ win.SetHistLayer(mapLayer.GetName())
+ win.HistWindow.UpdateHist()
+ win.Refresh()
+ win.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 = LMIcons["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 = LMIcons["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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/layertree.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/menudata.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/lmgr/menudata.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/lmgr/menudata.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/menudata.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/pyshell.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/lmgr/pyshell.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/lmgr/pyshell.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/pyshell.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/lmgr/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/lmgr/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,266 @@
+"""!
+ 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, BaseIcons
+from icons.icon import MetaIcon
+
+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 = {
+ 'newdisplay' : MetaIcon(img = 'monitor-create',
+ label = _('Start new map display')),
+ 'workspaceNew' : MetaIcon(img = 'create',
+ label = _('Create new workspace (Ctrl+N)')),
+ 'workspaceOpen' : MetaIcon(img = 'open',
+ label = _('Open existing workspace file (Ctrl+O)')),
+ 'workspaceSave' : MetaIcon(img = 'save',
+ label = _('Save current workspace to file (Ctrl+S)')),
+ }
+ 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 = {
+ 'addMulti' : MetaIcon(img = 'layer-open',
+ label = _('Add multiple raster or vector map layers (Ctrl+Shift+L)')),
+ 'addRast' : BaseIcons['addRast'].SetLabel(_("Add raster map layer (Ctrl+Shift+R)")),
+ 'rastMisc' : MetaIcon(img = 'layer-raster-more',
+ label = _('Add various raster map layers (RGB, HIS, shaded relief...)')),
+ 'addVect' : BaseIcons['addVect'].SetLabel(_("Add vector map layer (Ctrl+Shift+V)")),
+ 'vectMisc' : MetaIcon(img = 'layer-vector-more',
+ label = _('Add various vector map layers (thematic, chart...)')),
+ 'addGroup' : MetaIcon(img = 'layer-group-add',
+ label = _('Add group')),
+ 'addOverlay' : MetaIcon(img = 'layer-more',
+ label = _('Add grid or vector labels overlay')),
+ 'delCmd' : MetaIcon(img = 'layer-remove',
+ label = _('Delete selected map layer')),
+ }
+
+ 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 = {
+ 'import' : MetaIcon(img = 'layer-import',
+ label = _('Import/link raster or vector data')),
+ 'mapcalc' : MetaIcon(img = 'calculator',
+ label = _('Raster Map Calculator')),
+ 'modeler' : MetaIcon(img = 'modeler-main',
+ label = _('Graphical Modeler')),
+ 'georectify' : MetaIcon(img = 'georectify',
+ label = _('Georectifier')),
+ 'composer': MetaIcon(img = 'print-compose',
+ label = _('Cartographic Composer')),
+ }
+
+ return self._getToolbarData((('importMap', icons["import"],
+ self.parent.OnImportMenu),
+ (None, ),
+ ('mapCalc', icons["mapcalc"],
+ self.parent.OnMapCalculator),
+ ('georect', icons["georectify"],
+ self.parent.OnGCPManager),
+ ('modeler', icons["modeler"],
+ self.parent.OnGModeler),
+ ('mapOutput', icons['composer'],
+ 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 = {
+ 'settings' : BaseIcons['settings'].SetLabel(_('GUI settings')),
+ 'help' : BaseIcons['help'].SetLabel(_('GRASS manual')),
+ }
+
+ return self._getToolbarData((('settings', icons["settings"],
+ self.parent.OnPreferences),
+ ('help', icons["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 = {
+ 'vdigit' : MetaIcon(img = 'edit',
+ label = _('Edit vector maps')),
+ 'attrTable' : MetaIcon(img = 'table',
+ label = _('Show attribute table')),
+ }
+
+ 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 = {
+ 'cmd' : MetaIcon(img = 'script-save',
+ label = _('Generate command for m.nviz.image'),
+ desc = _('Generate command for m.nviz.image based on current state')),
+ 'settings' : MetaIcon(img = '3d-settings',
+ label = _('3D view mode settings'),
+ desc = _('Show 3D view mode settings dialog')),
+ 'help' : MetaIcon(img = '3d-help',
+ label = _('Show 3D view mode manual')),
+ }
+
+ return self._getToolbarData((("nvizCmd", icons['cmd'],
+ self.OnNvizCmd),
+ (None, ),
+ ("settings", icons["settings"],
+ self.OnSettings),
+ ("help", icons["help"],
+ self.OnHelp))
+ )
+
+ def OnNvizCmd(self, event):
+ """!Show m.nviz.image command"""
+ self.lmgr.GetLayerTree().GetMapDisplay().GetWindow().OnNvizCmd()
+
+ def OnHelp(self, event):
+ """!Show 3D view mode help"""
+ if not self.lmgr:
+ RunCommand('g.manual',
+ entry = 'wxGUI.Nviz')
+ else:
+ log = self.lmgr.GetLogWindow()
+ log.RunCmd(['g.manual',
+ 'entry=wxGUI.Nviz'])
+
+ def OnSettings(self, event):
+ """!Show nviz notebook page"""
+ if not self.settingsDialog:
+ self.settingsDialog = NvizPreferencesDialog(parent = self.parent)
+ self.settingsDialog.Show()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/lmgr/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/base.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/base.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/base.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/base.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/wizard.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/wizard.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/wizard.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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 a generic Cartesian 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: # -> canceled
+ 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/location_wizard/wizard.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/frame.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/frame.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1276 @@
+"""!
+ 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, NvizIcons
+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 core.settings import UserSettings
+from gui_core.mapdisp import MapFrameBase
+from mapdisp.mapwindow import BufferedWindow
+from modules.histogram import HistogramFrame
+from wxplot.profile import ProfileFrame
+
+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 GetMapWindow(self):
+ return self.MapWindow
+
+ def _addToolbarVDigit(self):
+ """!Add vector digitizer toolbar
+ """
+ from vdigit.main 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 vdigit.mapwindow 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
+ """
+ from nviz.main import haveNviz, GLWindow
+
+ # 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', NvizIcons['rotate'],
+ self.OnRotate, wx.ITEM_CHECK, 7),)) # 7 is position
+ self.toolbars['map'].InsertTool((('flyThrough', NvizIcons['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 OnMeasure(self, event):
+ """!Init measurement routine that calculates map distance
+ along transect drawn on map display
+ """
+ self.totaldist = 0.0 # total measured distance
+
+ # switch Layer Manager to output console to show measure results
+ self._layerManager.notebook.SetSelectionByName('output')
+
+ # change mouse to draw line for measurement
+ self.MapWindow.mouse['use'] = "measure"
+ self.MapWindow.mouse['box'] = "line"
+ self.MapWindow.zoomtype = 0
+ self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
+ self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
+
+ # change the cursor
+ self.MapWindow.SetCursor(self.cursors["pencil"])
+
+ # initiating output
+ style = self._layerManager.goutput.cmd_output.StyleWarning
+ self._layerManager.goutput.WriteLog(_('Click and drag with left mouse button '
+ 'to measure.%s'
+ 'Double click with left button to clear.') % \
+ (os.linesep), style)
+ if self.Map.projinfo['proj'] != 'xy':
+ units = self.Map.projinfo['units']
+ self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
+ + units + '):')
+ else:
+ self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
+
+ if self.Map.projinfo['proj'] == 'll':
+ try:
+ import grass.lib.gis as gislib
+ global haveCtypes
+ haveCtypes = True
+
+ gislib.G_begin_distance_calculations()
+ except ImportError, e:
+ self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
+ 'supported by this tool.\n'
+ 'Reason: %s' % e))
+
+ def MeasureDist(self, beginpt, endpt):
+ """!Calculate map distance from screen distance
+ and print to output window
+ """
+ self._layerManager.notebook.SetSelectionByName('output')
+
+ dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
+
+ dist = round(dist, 3)
+ d, dunits = self.FormatDist(dist)
+
+ self.totaldist += dist
+ td, tdunits = self.FormatDist(self.totaldist)
+
+ strdist = str(d)
+ strtotdist = str(td)
+
+ if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
+ angle = int(math.degrees(math.atan2(north,east)) + 0.5)
+ angle = 180 - angle
+ if angle < 0:
+ angle = 360 + angle
+
+ mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
+ % (_('segment'), strdist, dunits,
+ _('total distance'), strtotdist, tdunits,
+ _('bearing'), angle, _('deg'),
+ '-' * 60)
+ else:
+ mstring = '%s = %s %s\n%s = %s %s\n%s' \
+ % (_('segment'), strdist, dunits,
+ _('total distance'), strtotdist, tdunits,
+ '-' * 60)
+
+ self._layerManager.goutput.WriteLog(mstring)
+
+ return dist
+
+ def OnProfile(self, event):
+ """!Launch profile tool
+ """
+ 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)
+
+ win = ProfileFrame(parent = self, rasterList = raster)
+
+ win.CentreOnParent()
+ win.Show()
+ # Open raster select dialog to make sure that a raster (and
+ # the desired raster) is selected to be profiled
+ win.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 OnHistogram(self, event):
+ """!Init histogram display canvas and tools
+ """
+ win = HistogramFrame(self)
+
+ win.CentreOnParent()
+ win.Show()
+ win.Refresh()
+ win.Update()
+
+ 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']
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/frame.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/gprint.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/gprint.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/gprint.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/gprint.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/main.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/main.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/main.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/main.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/mapwindow.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/mapwindow.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/mapwindow.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1721 @@
+"""!
+ 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.pdc.RemoveAll()
+ self.Draw(self.pdc, img, drawid = 99)
+
+ # compute size ratio to move overlay accordingly
+ cSize = self.GetClientSizeTuple()
+ ratio = float(width) / cSize[0], float(height) / cSize[1]
+
+ # redraw lagend, scalebar
+ for img in self.GetOverlay():
+ # draw any active and defined overlays
+ if self.imagedict[img]['layer'].IsActive():
+ id = self.imagedict[img]['id']
+ coords = int(ratio[0] * self.overlays[id]['coords'][0]),\
+ int(ratio[1] * self.overlays[id]['coords'][1])
+ self.Draw(self.pdc, img = img, drawid = id,
+ pdctype = self.overlays[id]['pdcType'], coords = coords)
+
+ # redraw text labels
+ for id in self.textdict.keys():
+ textinfo = self.textdict[id]
+ oldCoords = textinfo['coords']
+ textinfo['coords'] = ratio[0] * textinfo['coords'][0],\
+ ratio[1] * textinfo['coords'][1]
+ self.Draw(self.pdc, img = self.textdict[id], drawid = id,
+ pdctype = 'text')
+ # set back old coordinates
+ textinfo['coords'] = oldCoords
+
+ 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
+ """
+ if not UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'enabled'):
+ event.Skip()
+ return
+
+ 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
+
+ if UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'selection'):
+ 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))
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/mapwindow.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/statusbar.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/statusbar.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/statusbar.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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/releasebranch_6_4/gui/wxpython/mapdisp/statusbar.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,267 @@
+"""!
+ 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, BaseIcons
+from nviz.main import haveNviz
+from vdigit.main import haveVDigit
+from icons.icon import MetaIcon
+
+MapIcons = {
+ 'query' : MetaIcon(img = 'info',
+ label = _('Query raster/vector map(s)'),
+ desc = _('Query selected raster/vector map(s)')),
+ 'addBarscale': MetaIcon(img = 'scalebar-add',
+ label = _('Add scalebar and north arrow')),
+ 'addLegend' : MetaIcon(img = 'legend-add',
+ label = _('Add legend')),
+ 'addNorthArrow': MetaIcon(img = 'north-arrow-add',
+ label = _('North Arrow')),
+ 'analyze' : MetaIcon(img = 'layer-raster-analyze',
+ label = _('Analyze map'),
+ desc = _('Measuring, profiling, histogramming, ...')),
+ 'measure' : MetaIcon(img = 'measure-length',
+ label = _('Measure distance')),
+ 'profile' : MetaIcon(img = 'layer-raster-profile',
+ label = _('Profile surface map')),
+ 'scatter' : MetaIcon(img = 'layer-raster-profile',
+ label = _("Create bivariate scatterplot of raster maps")),
+ 'addText' : MetaIcon(img = 'text-add',
+ label = _('Add text layer')),
+ 'histogram' : MetaIcon(img = 'layer-raster-histogram',
+ label = _('Create histogram of raster map')),
+ }
+
+NvizIcons = {
+ 'rotate' : MetaIcon(img = '3d-rotate',
+ label = _('Rotate 3D scene'),
+ desc = _('Drag with mouse to rotate 3D scene')),
+ 'flyThrough': MetaIcon(img = 'flythrough',
+ label = _('Fly-through mode'),
+ desc = _('Drag with mouse, hold Ctrl down for different mode'
+ ' or Shift to accelerate')),
+ 'zoomIn' : BaseIcons['zoomIn'].SetLabel(desc = _('Click mouse to zoom')),
+ 'zoomOut' : BaseIcons['zoomOut'].SetLabel(desc = _('Click mouse to unzoom'))
+ }
+
+class MapToolbar(BaseToolbar):
+ """!Map Display toolbar
+ """
+ def __init__(self, parent, mapcontent):
+ """!Map Display constructor
+
+ @param parent reference to MapFrame
+ @param mapcontent reference to render.Map (registred by MapFrame)
+ """
+ self.mapcontent = mapcontent # render.Map
+ BaseToolbar.__init__(self, parent = parent) # MapFrame
+
+ self.InitToolbar(self._toolbarData())
+
+ # optional tools
+ choices = [ _('2D view'), ]
+ self.toolId = { '2d' : 0 }
+ if self.parent.GetLayerManager():
+ log = self.parent.GetLayerManager().GetLogWindow()
+
+ if haveNviz:
+ choices.append(_('3D view'))
+ self.toolId['3d'] = 1
+ else:
+ from nviz.main import errorMsg
+ log.WriteCmdLog(_('3D view mode not available'))
+ log.WriteWarning(_('Reason: %s') % str(errorMsg))
+ log.WriteLog(_('Note that the wxGUI\'s 3D view mode is currently disabled '
+ 'on MS Windows (hopefully this will be fixed soon). '
+ 'Please keep an eye out for updated versions of GRASS. '
+ 'In the meantime you can use "NVIZ" from the File menu.'), wrap = 60)
+
+ self.toolId['3d'] = -1
+
+ if haveVDigit:
+ choices.append(_('Digitize'))
+ if self.toolId['3d'] > -1:
+ self.toolId['vdigit'] = 2
+ else:
+ self.toolId['vdigit'] = 1
+ else:
+ from vdigit.main import errorMsg
+ log.WriteCmdLog(_('Vector digitizer not available'))
+ log.WriteWarning(_('Reason: %s') % errorMsg)
+ log.WriteLog(_('Note that the wxGUI\'s vector digitizer is currently disabled '
+ '(hopefully this will be fixed soon). '
+ 'Please keep an eye out for updated versions of GRASS. '
+ 'In the meantime you can use "v.digit" from the Develop Vector menu.'), wrap = 60)
+
+ self.toolId['vdigit'] = -1
+
+ self.combo = wx.ComboBox(parent = self, id = wx.ID_ANY,
+ choices = choices,
+ style = wx.CB_READONLY, size = (110, -1))
+ self.combo.SetSelection(0)
+
+ self.comboid = self.AddControl(self.combo)
+ self.parent.Bind(wx.EVT_COMBOBOX, self.OnSelectTool, self.comboid)
+
+ # realize the toolbar
+ self.Realize()
+
+ # workaround for Mac bug. May be fixed by 2.8.8, but not before then.
+ self.combo.Hide()
+ self.combo.Show()
+
+ self.action = { 'id' : self.pointer }
+ self.defaultAction = { 'id' : self.pointer,
+ 'bind' : self.parent.OnPointer }
+
+ self.OnTool(None)
+
+ self.EnableTool(self.zoomBack, False)
+
+ self.FixSize(width = 90)
+
+ def _toolbarData(self):
+ """!Toolbar data"""
+ return self._getToolbarData((('displayMap', BaseIcons['display'],
+ self.parent.OnDraw),
+ ('renderMap', BaseIcons['render'],
+ self.parent.OnRender),
+ ('erase', BaseIcons['erase'],
+ self.parent.OnErase),
+ (None, ),
+ ('pointer', BaseIcons['pointer'],
+ self.parent.OnPointer,
+ wx.ITEM_CHECK),
+ ('query', MapIcons['query'],
+ self.parent.OnQuery,
+ wx.ITEM_CHECK),
+ ('pan', BaseIcons['pan'],
+ self.parent.OnPan,
+ wx.ITEM_CHECK),
+ ('zoomIn', BaseIcons['zoomIn'],
+ self.parent.OnZoomIn,
+ wx.ITEM_CHECK),
+ ('zoomOut', BaseIcons['zoomOut'],
+ self.parent.OnZoomOut,
+ wx.ITEM_CHECK),
+ ('zoomExtent', BaseIcons['zoomExtent'],
+ self.parent.OnZoomToMap),
+ ('zoomBack', BaseIcons['zoomBack'],
+ self.parent.OnZoomBack),
+ ('zoomMenu', BaseIcons['zoomMenu'],
+ self.parent.OnZoomMenu),
+ (None, ),
+ ('analyze', MapIcons['analyze'],
+ self.OnAnalyze),
+ (None, ),
+ ('overlay', BaseIcons['overlay'],
+ self.OnDecoration),
+ (None, ),
+ ('saveFile', BaseIcons['saveFile'],
+ self.parent.SaveToFile),
+ ('printMap', BaseIcons['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:
+ icons = BaseIcons
+ else:
+ icons = NvizIcons
+ for i, data in enumerate(self._data):
+ for tool in (('zoomIn', 'zoomOut')):
+ if data[0] == tool:
+ tmp = list(data)
+ tmp[4] = icons[tool].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 OnAnalyze(self, event):
+ """!Analysis tools menu
+ """
+ self._onMenu(((MapIcons["measure"], self.parent.OnMeasure),
+ (MapIcons["profile"], self.parent.OnProfile),
+ (MapIcons["histogram"], self.parent.OnHistogram)))
+
+ def OnDecoration(self, event):
+ """!Decorations overlay menu
+ """
+ if self.parent.IsPaneShown('3d'):
+ self._onMenu(((MapIcons["addNorthArrow"], self.parent.OnAddArrow),
+ (MapIcons["addLegend"], self.parent.OnAddLegend),
+ (MapIcons["addText"], self.parent.OnAddText)))
+ else:
+ self._onMenu(((MapIcons["addBarscale"], self.parent.OnAddBarscale),
+ (MapIcons["addLegend"], self.parent.OnAddLegend),
+ (MapIcons["addText"], self.parent.OnAddText)))
+
+ def ExitToolbars(self):
+ if self.parent.GetToolbar('vdigit'):
+ self.parent.toolbars['vdigit'].OnExit()
+ if self.parent.GetLayerManager().IsPaneShown('toolbarNviz'):
+ self.parent.RemoveNviz()
+
+ def Enable2D(self, enabled):
+ """!Enable/Disable 2D display mode specific tools"""
+ for tool in (self.zoomMenu,
+ self.analyze,
+ self.printMap):
+ self.EnableTool(tool, enabled)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/mapdisp/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/colorrules.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/colorrules.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/colorrules.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1796 @@
+"""
+ 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, GError
+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, initial = 1)
+ # 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 panel/scrollpanel in vector dialog
+ if isinstance(self.parent.GetParent(), RasterColorTable):
+ table = self.parent.GetParent().colorTable
+ else:
+ table = self.parent.GetParent().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))
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ # 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 = 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, parent):
+ """!Create buttons for leaving dialog"""
+ self.btnHelp = wx.Button(parent, id = wx.ID_HELP)
+ self.btnCancel = wx.Button(parent, id = wx.ID_CANCEL)
+ self.btnApply = wx.Button(parent, id = wx.ID_APPLY)
+ self.btnOK = wx.Button(parent, 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.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER)
+
+ 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."))
+ else:
+ # re-render preview and current map window
+ self.OnPreview(None)
+ 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.SetMinSize((650, 700))
+
+ self.CentreOnScreen()
+ self.Show()
+
+ def _doLayout(self):
+ """!Do main layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ #
+ # map selection
+ #
+ mapSelection = self._createMapSelection(parent = self.panel)
+ sizer.Add(item = mapSelection, proportion = 0,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+ #
+ # manage extern tables
+ #
+ fileSelection = self._createFileSelection(parent = self.panel)
+ sizer.Add(item = fileSelection, proportion = 0,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+ #
+ # body & preview
+ #
+ bodySizer = self._createBody(parent = self.panel)
+ sizer.Add(item = bodySizer, proportion = 1,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+ #
+ # buttons
+ #
+ btnSizer = self._createButtons(parent = self.panel)
+ sizer.Add(item = wx.StaticLine(parent = self.panel, 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.panel.SetSizer(sizer)
+ sizer.Layout()
+ sizer.Fit(self.panel)
+ 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.SetMinSize((650, 700))
+
+ self.CentreOnScreen()
+ 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(parent = self.panel, id = wx.ID_ANY,
+ 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(self.panel)
+
+ mainsizer = wx.BoxSizer(wx.VERTICAL)
+ mainsizer.Add(scrollPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ mainsizer.Add(item = wx.StaticLine(parent = self.panel, 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.panel.SetSizer(mainsizer)
+ mainsizer.Layout()
+ mainsizer.Fit(self.panel)
+ self.Layout()
+
+ 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 <%(map)s> is not in current mapset <%(mapset)s>. "
+ "Color rules cannot be edited.") % \
+ { 'map' : self.inmap,
+ 'mapset' : grass.gisenv()['MAPSET'] }
+ else:
+ message = _("Selected map <%(map)s> is not in current mapset <%(mapset)s>. "
+ "Attribute table cannot be edited.") % \
+ { 'map' : self.inmap,
+ 'mapset' : 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']
+
+ sep = ';'
+ if self.inmap:
+ outFile = tempfile.NamedTemporaryFile(mode = 'w+b')
+ 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 = "%s: %.1f - %.1f)" % (_("range"),
+ self.properties['min'], self.properties['max'])
+ elif ctype == int:
+ range = "%s: %d - %d)" % (_("range"),
+ 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(parent = 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:
+ if not self.properties['storeColumn']:
+ GError(_("No color column defined. Operation canceled."),
+ parent = self)
+ return
+
+ 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')
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/colorrules.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/extensions.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/extensions.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/extensions.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,508 @@
+"""!
+ at package modules.extensions
+
+ at brief GRASS Addons extensions management classes
+
+Classes:
+ - extensions::InstallExtensionWindow
+ - extensions::ExtensionTree
+ - extensions::UninstallExtensionWindow
+ - extensions::CheckListExtension
+
+(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 sys
+
+import wx
+import wx.lib.mixins.listctrl as listmix
+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"))
+ 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')
+
+ ignoreFlags = ['l', 'c', 'g', 'a', 'f', 'quiet', 'verbose']
+ if sys.platform == 'win32':
+ ignoreFlags.append('d')
+ ignoreFlags.append('i')
+
+ 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 ignoreFlags:
+ 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.add(name)
+
+ def OnItemSelected(self, event):
+ """!Item selected"""
+ item = event.GetItem()
+ self.tree.itemSelected = item
+ data = self.tree.GetPyData(item)
+ if data is None:
+ 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:
+ try:
+ key, value = line.split('=', 1)
+ except ValueError:
+ key = 'name'
+ value = line
+
+ 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 UninstallExtensionWindow(wx.Frame):
+ def __init__(self, parent, id = wx.ID_ANY,
+ title = _("Uninstall GRASS Addons extensions"), **kwargs):
+ self.parent = parent
+
+ 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.extBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("List of installed extensions"))
+
+ self.extList = CheckListExtension(parent = self.panel)
+
+ # buttons
+ self.btnUninstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("&Uninstall"))
+ self.btnUninstall.SetToolTipString(_("Uninstall selected AddOns extensions"))
+ self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Command dialog"))
+ self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
+ self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+
+ self.btnUninstall.Bind(wx.EVT_BUTTON, self.OnUninstall)
+ self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
+ self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+
+ self._layout()
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ extSizer = wx.StaticBoxSizer(self.extBox, wx.HORIZONTAL)
+ extSizer.Add(item = self.extList, proportion = 1,
+ flag = wx.ALL | wx.EXPAND, border = 1)
+
+ 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.btnUninstall, proportion = 0)
+
+ sizer.Add(item = extSizer, proportion = 1,
+ flag = wx.ALL | 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 OnCloseWindow(self, event):
+ """!Close window"""
+ self.Destroy()
+
+ def OnUninstall(self, event):
+ """!Uninstall selected extensions"""
+ log = self.parent.GetLogWindow()
+ eList = self.extList.GetExtensions()
+ if not eList:
+ GError(_("No extension selected for removal. "
+ "Operation canceled."),
+ parent = self)
+ return
+
+ for ext in eList:
+ files = RunCommand('g.extension.py', parent = self, read = True, quiet = True,
+ extension = ext, operation = 'remove').splitlines()
+ dlg = wx.MessageDialog(parent = self,
+ message = _("List of files to be removed:\n%(files)s\n\n"
+ "Do you want really to remove <%(ext)s> extension?") % \
+ { 'files' : os.linesep.join(files), 'ext' : ext },
+ caption = _("Remove extension"),
+ style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+
+ if dlg.ShowModal() == wx.ID_YES:
+ RunCommand('g.extension.py', flags = 'f', parent = self, quiet = True,
+ extension = ext, operation = 'remove')
+
+ self.extList.LoadData()
+
+ def OnCmdDialog(self, event):
+ """!Shows command dialog"""
+ GUI(parent = self).ParseCommand(cmd = ['g.extension.py'])
+
+class CheckListExtension(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
+ """!List of mapset/owner/group"""
+ def __init__(self, parent):
+ self.parent = parent
+
+ wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY,
+ style = wx.LC_REPORT)
+ listmix.CheckListCtrlMixin.__init__(self)
+
+ # setup mixins
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+ self.InsertColumn(0, _('Extension'))
+ self.LoadData()
+
+ def LoadData(self):
+ """!Load data into list"""
+ self.DeleteAllItems()
+ for ext in RunCommand('g.extension.py',
+ quiet = True, parent = self, read = True,
+ flags = 'a').splitlines():
+ if ext:
+ self.InsertStringItem(sys.maxint, ext)
+
+ def GetExtensions(self):
+ """!Get extensions to be un-installed
+ """
+ extList = list()
+ for i in range(self.GetItemCount()):
+ if self.IsChecked(i):
+ name = self.GetItemText(i)
+ if name:
+ extList.append(name)
+
+ return extList
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/extensions.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/histogram.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/histogram.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/histogram.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,493 @@
+"""!
+ 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 core.gcmd import GError
+from gui_core.toolbars import BaseToolbar, BaseIcons
+
+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 Histogramming Tool (d.histogram)"),
+ size = wx.Size(500, 350),
+ style = wx.DEFAULT_FRAME_STYLE, **kwargs):
+ wx.Frame.__init__(self, parent, id, title, size = size, 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"""
+ return self._getToolbarData((('histogram', BaseIcons["histogramD"],
+ self.parent.OnOptions),
+ ('render', BaseIcons["display"],
+ self.parent.OnRender),
+ ('erase', BaseIcons["erase"],
+ self.parent.OnErase),
+ ('font', BaseIcons["font"],
+ self.parent.SetHistFont),
+ (None, ),
+ ('save', BaseIcons["saveFile"],
+ self.parent.SaveToFile),
+ ('hprint', BaseIcons["print"],
+ self.parent.PrintMenu),
+ (None, ),
+ ('quit', BaseIcons["quit"],
+ self.parent.OnQuit))
+ )
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/histogram.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/mcalc_builder.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/mcalc_builder.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/mcalc_builder.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/mcalc_builder.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/ogc_services.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/ogc_services.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/ogc_services.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/ogc_services.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/modules/vclean.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/modules/vclean.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/modules/vclean.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,555 @@
+"""
+ 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 = 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 = len(self.ftype)
+
+ self.tools_string = ''
+ self.thresh_string = ''
+ self.ftype_string = ''
+
+ 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.panel, id = wx.ID_ANY,
+ label= _('Select input vector map:'))
+ self.selectionInput = Select(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE,
+ type = 'vector')
+ self.ftype_check = {}
+ ftypeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = _(' Feature type: '))
+ self.ftypeSizer = wx.StaticBoxSizer(ftypeBox, wx.HORIZONTAL)
+
+ self.outmaplabel = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _('Select output vector map:'))
+ self.selectionOutput = Select(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE,
+ type = 'vector')
+
+ 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'))
+
+ # cleaning tools
+ self.ct_label = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = self.ctlabel)
+
+ self.ct_panel = self._toolsPanel()
+
+ # buttons to manage cleaning tools
+ self.btn_add = wx.Button(parent = self.panel, id = wx.ID_ADD)
+ self.btn_remove = wx.Button(parent = self.panel, id = wx.ID_REMOVE)
+ self.btn_moveup = wx.Button(parent = self.panel, id = wx.ID_UP)
+ self.btn_movedown = wx.Button(parent = self.panel, id = wx.ID_DOWN)
+
+ # add one tool as default
+ self.AddTool()
+ self.selected = -1
+
+ # Buttons
+ self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
+ self.btn_run = wx.Button(parent = self.panel, id = wx.ID_ANY, label = _("&Run"))
+ self.btn_run.SetDefault()
+ 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)"))
+ self.btn_help = wx.Button(parent = self.panel, 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)
+
+ # layout
+ self._layout()
+
+ self.SetMinSize(self.GetBestSize())
+
+ self.CentreOnScreen()
+
+ 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.panel, id = wx.ID_ANY, label = _('point')),
+ wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('line')),
+ wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('boundary')),
+ wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('centroid')),
+ wx.CheckBox(parent = self.panel, id = wx.ID_ANY, label = _('area')),
+ wx.CheckBox(parent = self.panel, 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.panel.SetAutoLayout(True)
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+
+ self.Layout()
+
+ def _toolsPanel(self):
+ ct_panel = scrolled.ScrolledPanel(parent = self.panel, 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 "
+ "canceled.\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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/modules/vclean.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/animation.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/animation.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/animation.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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/releasebranch_6_4/gui/wxpython/nviz/animation.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/main.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/main.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/main.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,40 @@
+"""!
+ 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
+ from nviz import mapwindow
+ from nviz import tools
+ from nviz import workspace
+ import wxnviz
+ haveNviz = True
+except (ImportError, NameError), err:
+ haveNviz = False
+ errorMsg = err
+
+if haveNviz:
+ GLWindow = mapwindow.GLWindow
+ NvizToolWindow = tools.NvizToolWindow
+ NvizSettings = workspace.NvizSettings
+else:
+ GLWindow = None
+ NvizToolWindow = None
+ NvizSettings = None
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/main.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/mapwindow.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/mapwindow.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/mapwindow.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2481 @@
+"""!
+ 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"""
+ if not UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'enabled'):
+ event.Skip()
+ return
+
+ 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:
+ if UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'selection'):
+ wheel *= -1
+ 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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/mapwindow.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/preferences.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/preferences.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/preferences.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,630 @@
+"""
+ 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 os
+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.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_nviz.ico'), wx.BITMAP_TYPE_ICO))
+
+ 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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/preferences.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/tools.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/tools.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/tools.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/tools.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/workspace.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/workspace.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/workspace.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,325 @@
+"""!
+ 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):
+ pass
+
+ 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/workspace.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/nviz/wxnviz.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/nviz/wxnviz.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/nviz/wxnviz.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2042 @@
+"""!
+ 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.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 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/nviz/wxnviz.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,4969 @@
+"""!
+ at package psmap.dialogs
+
+ at brief dialogs for wxPsMap
+
+Classes:
+ - dialogs::TCValidator
+ - dialogs::PenStyleComboBox
+ - dialogs::CheckListCtrl
+ - 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
+ - dialogs::PointDialog
+ - dialogs::RectangleDialog
+
+(C) 2011-2012 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 copy import deepcopy
+
+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 gui_core.gselect import Select
+from core.gcmd import RunCommand, GError, GMessage
+from gui_core.dialogs import SymbolDialog
+from psmap.utils import *
+from psmap.instructions import *
+
+# 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 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 PsmapDialog(wx.Dialog):
+ def __init__(self, parent, id, title, settings, apply = True):
+ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY,
+ title = title, size = wx.DefaultSize,
+ style = wx.CAPTION|wx.MINIMIZE_BOX|wx.CLOSE_BOX)
+ self.apply = apply
+ self.id = id
+ self.parent = parent
+ self.instruction = settings
+ self.objectType = None
+ self.unitConv = UnitConversion(self)
+ self.spinCtrlSize = (65, -1)
+
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+
+
+ def AddUnits(self, parent, dialogDict):
+ parent.units = dict()
+ parent.units['unitsLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Units:"))
+ choices = self.unitConv.getPageUnitsNames()
+ parent.units['unitsCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = choices)
+ parent.units['unitsCtrl'].SetStringSelection(self.unitConv.findName(dialogDict['unit']))
+
+ def AddPosition(self, parent, dialogDict):
+ if not hasattr(parent, "position"):
+ parent.position = dict()
+ parent.position['comment'] = wx.StaticText(parent, id = wx.ID_ANY,\
+ label = _("Position of the top left corner\nfrom the top left edge of the paper"))
+ parent.position['xLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("X:"))
+ parent.position['yLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Y:"))
+ parent.position['xCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][0]), validator = TCValidator(flag = 'DIGIT_ONLY'))
+ parent.position['yCtrl'] = wx.TextCtrl(parent, id = wx.ID_ANY, value = str(dialogDict['where'][1]), validator = TCValidator(flag = 'DIGIT_ONLY'))
+ if dialogDict.has_key('unit'):
+ x = self.unitConv.convert(value = dialogDict['where'][0], fromUnit = 'inch', toUnit = dialogDict['unit'])
+ y = self.unitConv.convert(value = dialogDict['where'][1], fromUnit = 'inch', toUnit = dialogDict['unit'])
+ parent.position['xCtrl'].SetValue("%5.3f" % x)
+ parent.position['yCtrl'].SetValue("%5.3f" % y)
+
+ def AddExtendedPosition(self, panel, gridBagSizer, dialogDict):
+ """!Add widgets for setting position relative to paper and to map"""
+ panel.position = dict()
+ positionLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Position is given:"))
+ panel.position['toPaper'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("relatively to paper"), style = wx.RB_GROUP)
+ panel.position['toMap'] = wx.RadioButton(panel, id = wx.ID_ANY, label = _("by map coordinates"))
+ panel.position['toPaper'].SetValue(dialogDict['XY'])
+ panel.position['toMap'].SetValue(not dialogDict['XY'])
+
+ gridBagSizer.Add(positionLabel, pos = (0,0), span = (1,3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+ gridBagSizer.Add(panel.position['toPaper'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+ gridBagSizer.Add(panel.position['toMap'], pos = (1,1),flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT, border = 0)
+
+ # first box - paper coordinates
+ box1 = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+ sizerP = wx.StaticBoxSizer(box1, wx.VERTICAL)
+ self.gridBagSizerP = wx.GridBagSizer (hgap = 5, vgap = 5)
+ self.gridBagSizerP.AddGrowableCol(1)
+ self.gridBagSizerP.AddGrowableRow(3)
+
+ self.AddPosition(parent = panel, dialogDict = dialogDict)
+ panel.position['comment'].SetLabel(_("Position from the top left\nedge of the paper"))
+ self.AddUnits(parent = panel, dialogDict = dialogDict)
+ self.gridBagSizerP.Add(panel.units['unitsLabel'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.units['unitsCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.position['xLabel'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.position['xCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.position['yLabel'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.position['yCtrl'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerP.Add(panel.position['comment'], pos = (3,0), span = (1,2), flag = wx.ALIGN_BOTTOM, border = 0)
+
+ sizerP.Add(self.gridBagSizerP, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ gridBagSizer.Add(sizerP, pos = (2,0),span = (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+
+ # second box - map coordinates
+ box2 = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = "")
+ sizerM = wx.StaticBoxSizer(box2, wx.VERTICAL)
+ self.gridBagSizerM = wx.GridBagSizer (hgap = 5, vgap = 5)
+ self.gridBagSizerM.AddGrowableCol(0)
+ self.gridBagSizerM.AddGrowableCol(1)
+
+ eastingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "E:")
+ northingLabel = wx.StaticText(panel, id = wx.ID_ANY, label = "N:")
+ panel.position['eCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+ panel.position['nCtrl'] = wx.TextCtrl(panel, id = wx.ID_ANY, value = "")
+ east, north = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = dialogDict['where'][0], y = dialogDict['where'][1], paperToMap = True)
+ panel.position['eCtrl'].SetValue(str(east))
+ panel.position['nCtrl'].SetValue(str(north))
+
+ self.gridBagSizerM.Add(eastingLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(northingLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(panel.position['eCtrl'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.gridBagSizerM.Add(panel.position['nCtrl'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizerM.Add(self.gridBagSizerM, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ gridBagSizer.Add(sizerM, pos = (2,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+
+ def AddFont(self, parent, dialogDict, color = True):
+ parent.font = dict()
+## parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose font:"))
+## parent.font['fontCtrl'] = wx.FontPickerCtrl(parent, id = wx.ID_ANY)
+##
+## parent.font['fontCtrl'].SetSelectedFont(
+## wx.FontFromNativeInfoString(dialogDict['font'] + " " + str(dialogDict['fontsize'])))
+## parent.font['fontCtrl'].SetMaxPointSize(50)
+##
+## if color:
+## parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
+## parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY, style=wx.FNTP_FONTDESC_AS_LABEL)
+## parent.font['colorCtrl'].SetColour(dialogDict['color'])
+
+## parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color']))
+
+ parent.font['fontLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font:"))
+ parent.font['fontSizeLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Font size:"))
+ fontChoices = [ 'Times-Roman', 'Times-Italic', 'Times-Bold', 'Times-BoldItalic', 'Helvetica',\
+ 'Helvetica-Oblique', 'Helvetica-Bold', 'Helvetica-BoldOblique', 'Courier',\
+ 'Courier-Oblique', 'Courier-Bold', 'Courier-BoldOblique']
+ parent.font['fontCtrl'] = wx.Choice(parent, id = wx.ID_ANY, choices = fontChoices)
+ if dialogDict['font'] in fontChoices:
+ parent.font['fontCtrl'].SetStringSelection(dialogDict['font'])
+ else:
+ parent.font['fontCtrl'].SetStringSelection('Helvetica')
+ parent.font['fontSizeCtrl'] = wx.SpinCtrl(parent, id = wx.ID_ANY, min = 4, max = 50, initial = 10)
+ parent.font['fontSizeCtrl'].SetValue(dialogDict['fontsize'])
+
+ if color:
+ parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Choose color:"))
+ parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
+ parent.font['colorCtrl'].SetColour(convertRGB(dialogDict['color']))
+## parent.font['colorLabel'] = wx.StaticText(parent, id = wx.ID_ANY, label = _("Color:"))
+## colorChoices = [ 'aqua', 'black', 'blue', 'brown', 'cyan', 'gray', 'green', 'indigo', 'magenta',\
+## 'orange', 'purple', 'red', 'violet', 'white', 'yellow']
+## parent.colorCtrl = wx.Choice(parent, id = wx.ID_ANY, choices = colorChoices)
+## parent.colorCtrl.SetStringSelection(parent.rLegendDict['color'])
+## parent.font['colorCtrl'] = wx.ColourPickerCtrl(parent, id = wx.ID_ANY)
+## parent.font['colorCtrl'].SetColour(dialogDict['color'])
+ def OnApply(self, event):
+ ok = self.update()
+ if ok:
+ self.parent.DialogDataChanged(id = self.id)
+ return True
+ else:
+ return False
+
+ def OnOK(self, event):
+ """!Apply changes, close dialog"""
+ ok = self.OnApply(event)
+ if ok:
+ self.Close()
+
+ def OnCancel(self, event):
+ """!Close dialog"""
+ self.Close()
+
+ def OnClose(self, event):
+ """!Destroy dialog and delete it from open dialogs"""
+ if self.objectType:
+ for each in self.objectType:
+ if each in self.parent.openDialogs:
+ del self.parent.openDialogs[each]
+ event.Skip()
+ self.Destroy()
+
+ def _layout(self, panel):
+ #buttons
+ btnCancel = wx.Button(self, wx.ID_CANCEL)
+ btnOK = wx.Button(self, wx.ID_OK)
+ btnOK.SetDefault()
+ if self.apply:
+ btnApply = wx.Button(self, wx.ID_APPLY)
+
+
+ # bindigs
+ btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
+ btnOK.SetToolTipString(_("Close dialog and apply changes"))
+ #btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+ btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
+ btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+ if self.apply:
+ btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
+ btnApply.SetToolTipString(_("Apply changes"))
+
+ # sizers
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(btnCancel)
+ if self.apply:
+ btnSizer.AddButton(btnApply)
+ btnSizer.AddButton(btnOK)
+ btnSizer.Realize()
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = panel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ mainSizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+
+ self.SetSizer(mainSizer)
+ mainSizer.Layout()
+ mainSizer.Fit(self)
+
+class PageSetupDialog(PsmapDialog):
+ def __init__(self, parent, id, settings):
+ PsmapDialog.__init__(self, parent = parent, id = id, title = "Page setup", settings = settings)
+
+ self.cat = ['Units', 'Format', 'Orientation', 'Width', 'Height', 'Left', 'Right', 'Top', 'Bottom']
+ labels = [_('Units'), _('Format'), _('Orientation'), _('Width'), _('Height'),
+ _('Left'), _('Right'), _('Top'), _('Bottom')]
+ self.catsLabels = dict(zip(self.cat, labels))
+ paperString = RunCommand('ps.map', flags = 'p', read = True, quiet = True)
+ self.paperTable = self._toList(paperString)
+ self.unitsList = self.unitConv.getPageUnitsNames()
+ self.pageSetupDict = settings[id].GetInstruction()
+
+ self._layout()
+
+ if self.pageSetupDict:
+ self.getCtrl('Units').SetStringSelection(self.unitConv.findName(self.pageSetupDict['Units']))
+ if self.pageSetupDict['Format'] == 'custom':
+ self.getCtrl('Format').SetSelection(self.getCtrl('Format').GetCount() - 1)
+ else:
+ self.getCtrl('Format').SetStringSelection(self.pageSetupDict['Format'])
+ if self.pageSetupDict['Orientation'] == 'Portrait':
+ self.getCtrl('Orientation').SetSelection(0)
+ else:
+ self.getCtrl('Orientation').SetSelection(1)
+
+ for item in self.cat[3:]:
+ val = self.unitConv.convert(value = self.pageSetupDict[item],
+ fromUnit = 'inch', toUnit = self.pageSetupDict['Units'])
+ self.getCtrl(item).SetValue("%4.3f" % val)
+
+
+ if self.getCtrl('Format').GetSelection() != self.getCtrl('Format').GetCount() - 1: # custom
+ self.getCtrl('Width').Disable()
+ self.getCtrl('Height').Disable()
+ else:
+ self.getCtrl('Orientation').Disable()
+ # events
+ self.getCtrl('Units').Bind(wx.EVT_CHOICE, self.OnChoice)
+ self.getCtrl('Format').Bind(wx.EVT_CHOICE, self.OnChoice)
+ self.getCtrl('Orientation').Bind(wx.EVT_CHOICE, self.OnChoice)
+ self.btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
+
+
+ def update(self):
+ self.pageSetupDict['Units'] = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
+ self.pageSetupDict['Format'] = self.paperTable[self.getCtrl('Format').GetSelection()]['Format']
+ if self.getCtrl('Orientation').GetSelection() == 0:
+ self.pageSetupDict['Orientation'] = 'Portrait'
+ else:
+ self.pageSetupDict['Orientation'] = 'Landscape'
+ for item in self.cat[3:]:
+ self.pageSetupDict[item] = self.unitConv.convert(value = float(self.getCtrl(item).GetValue()),
+ fromUnit = self.pageSetupDict['Units'], toUnit = 'inch')
+
+
+
+ def OnOK(self, event):
+ try:
+ self.update()
+ except ValueError:
+ wx.MessageBox(message = _("Literal is not allowed!"), caption = _('Invalid input'),
+ style = wx.OK|wx.ICON_ERROR)
+ else:
+ event.Skip()
+
+ def _layout(self):
+ size = (110,-1)
+ #sizers
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ pageBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Page size"))
+ pageSizer = wx.StaticBoxSizer(pageBox, wx.VERTICAL)
+ marginBox = wx.StaticBox(self, id = wx.ID_ANY, label = " %s " % _("Margins"))
+ marginSizer = wx.StaticBoxSizer(marginBox, wx.VERTICAL)
+ horSizer = wx.BoxSizer(wx.HORIZONTAL)
+ #staticText + choice
+ choices = [self.unitsList, [item['Format'] for item in self.paperTable], [_('Portrait'), _('Landscape')]]
+ propor = [0,1,1]
+ border = [5,3,3]
+ self.hBoxDict={}
+ for i, item in enumerate(self.cat[:3]):
+ hBox = wx.BoxSizer(wx.HORIZONTAL)
+ stText = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
+ choice = wx.Choice(self, id = wx.ID_ANY, choices = choices[i], size = size)
+ hBox.Add(stText, proportion = propor[i], flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = border[i])
+ hBox.Add(choice, proportion = 0, flag = wx.ALL, border = border[i])
+ if item == 'Units':
+ hBox.Add(size,1)
+ self.hBoxDict[item] = hBox
+
+ #staticText + TextCtrl
+ for item in self.cat[3:]:
+ hBox = wx.BoxSizer(wx.HORIZONTAL)
+ label = wx.StaticText(self, id = wx.ID_ANY, label = self.catsLabels[item] + ':')
+ textctrl = wx.TextCtrl(self, id = wx.ID_ANY, size = size, value = '')
+ hBox.Add(label, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 3)
+ hBox.Add(textctrl, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 3)
+ self.hBoxDict[item] = hBox
+
+ sizer = list([mainSizer] + [pageSizer]*4 + [marginSizer]*4)
+ for i, item in enumerate(self.cat):
+ sizer[i].Add(self.hBoxDict[item], 0, wx.GROW|wx.RIGHT|wx.LEFT,5)
+ # OK button
+ btnSizer = wx.StdDialogButtonSizer()
+ self.btnOk = wx.Button(self, wx.ID_OK)
+ self.btnOk.SetDefault()
+ btnSizer.AddButton(self.btnOk)
+ btn = wx.Button(self, wx.ID_CANCEL)
+ btnSizer.AddButton(btn)
+ btnSizer.Realize()
+
+
+ horSizer.Add(pageSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM, border = 10)
+ horSizer.Add(marginSizer, proportion = 0, flag = wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND, border = 10)
+ mainSizer.Add(horSizer, proportion = 0, border = 10)
+ mainSizer.Add(btnSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT|wx.ALL, border = 10)
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def OnChoice(self, event):
+ currPaper = self.paperTable[self.getCtrl('Format').GetSelection()]
+ currUnit = self.unitConv.findUnit(self.getCtrl('Units').GetStringSelection())
+ currOrientIdx = self.getCtrl('Orientation').GetSelection()
+ newSize = dict()
+ for item in self.cat[3:]:
+ newSize[item] = self.unitConv.convert(float(currPaper[item]), fromUnit = 'inch', toUnit = currUnit)
+
+ enable = True
+ if currPaper['Format'] != _('custom'):
+ if currOrientIdx == 1: # portrait
+ newSize['Width'], newSize['Height'] = newSize['Height'], newSize['Width']
+ for item in self.cat[3:]:
+ self.getCtrl(item).ChangeValue("%4.3f" % newSize[item])
+ enable = False
+ self.getCtrl('Width').Enable(enable)
+ self.getCtrl('Height').Enable(enable)
+ self.getCtrl('Orientation').Enable(not enable)
+
+
+ def getCtrl(self, item):
+ return self.hBoxDict[item].GetItem(1).GetWindow()
+
+ def _toList(self, paperStr):
+
+ sizeList = list()
+ for line in paperStr.strip().split('\n'):
+ d = dict(zip([self.cat[1]]+ self.cat[3:],line.split()))
+ sizeList.append(d)
+ d = {}.fromkeys([self.cat[1]]+ self.cat[3:], 100)
+ d.update(Format = _('custom'))
+ sizeList.append(d)
+ return sizeList
+
+class MapDialog(PsmapDialog):
+ """!Dialog for map frame settings and optionally raster and vector map selection"""
+ def __init__(self, parent, id, settings, rect = None, notebook = False):
+ PsmapDialog.__init__(self, parent = parent, id = id, title = "", settings = settings)
+
+ self.isNotebook = notebook
+ if self.isNotebook:
+ self.objectType = ('mapNotebook',)
+ else:
+ self.objectType = ('map',)
+
+
+ #notebook
+ if self.isNotebook:
+ self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+ self.mPanel = MapFramePanel(parent = self.notebook, id = self.id[0], settings = self.instruction,
+ rect = rect, notebook = True)
+ self.id[0] = self.mPanel.getId()
+ self.rPanel = RasterPanel(parent = self.notebook, id = self.id[1], settings = self.instruction,
+ notebook = True)
+ self.id[1] = self.rPanel.getId()
+ self.vPanel = VectorPanel(parent = self.notebook, id = self.id[2], settings = self.instruction,
+ notebook = True)
+ self.id[2] = self.vPanel.getId()
+ self._layout(self.notebook)
+ self.SetTitle(_("Map settings"))
+ else:
+ self.mPanel = MapFramePanel(parent = self, id = self.id[0], settings = self.instruction,
+ rect = rect, notebook = False)
+ self.id[0] = self.mPanel.getId()
+ self._layout(self.mPanel)
+ self.SetTitle(_("Map frame settings"))
+
+
+ def OnApply(self, event):
+ """!Apply changes"""
+ if self.isNotebook:
+ okV = self.vPanel.update()
+ okR = self.rPanel.update()
+ if okV and self.id[2] in self.instruction:
+ self.parent.DialogDataChanged(id = self.id[2])
+ if okR and self.id[1] in self.instruction:
+ self.parent.DialogDataChanged(id = self.id[1])
+ if not okR or not okV:
+ return False
+
+ ok = self.mPanel.update()
+ if ok:
+ self.parent.DialogDataChanged(id = self.id[0])
+ return True
+
+ return False
+
+ def OnCancel(self, event):
+ """!Close dialog and remove tmp red box"""
+ self.parent.canvas.pdcTmp.RemoveId(self.parent.canvas.idZoomBoxTmp)
+ self.parent.canvas.Refresh()
+ self.Close()
+
+ def updateDialog(self):
+ """!Update raster and vector information"""
+ if self.mPanel.scaleChoice.GetSelection() == 0:
+ if self.mPanel.rasterTypeRadio.GetValue():
+ if 'raster' in self.parent.openDialogs:
+ if self.parent.openDialogs['raster'].rPanel.rasterYesRadio.GetValue() and \
+ self.parent.openDialogs['raster'].rPanel.rasterSelect.GetValue() == self.mPanel.select.GetValue():
+ self.mPanel.drawMap.SetValue(True)
+ else:
+ self.mPanel.drawMap.SetValue(False)
+ else:
+ if 'vector' in self.parent.openDialogs:
+ found = False
+ for each in self.parent.openDialogs['vector'].vPanel.vectorList:
+ if each[0] == self.mPanel.select.GetValue():
+ found = True
+ self.mPanel.drawMap.SetValue(found)
+
+class MapFramePanel(wx.Panel):
+ """!wx.Panel with map (scale, region, border) settings"""
+ def __init__(self, parent, id, settings, rect, notebook = True):
+ wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+
+ self.id = id
+ self.instruction = settings
+
+ if notebook:
+ self.book = parent
+ self.book.AddPage(page = self, text = _("Map frame"))
+ self.mapDialog = self.book.GetParent()
+ else:
+ self.mapDialog = parent
+
+ if self.id is not None:
+ self.mapFrameDict = self.instruction[self.id].GetInstruction()
+ else:
+ self.id = wx.NewId()
+ mapFrame = MapFrame(self.id)
+ self.mapFrameDict = mapFrame.GetInstruction()
+ self.mapFrameDict['rect'] = rect
+
+
+ self._layout()
+
+ self.scale = [None]*4
+ self.center = [None]*4
+
+
+
+ self.selectedMap = self.mapFrameDict['map']
+ self.selectedRegion = self.mapFrameDict['region']
+ self.scaleType = self.mapFrameDict['scaleType']
+ self.mapType = self.mapFrameDict['mapType']
+ self.scaleChoice.SetSelection(self.mapFrameDict['scaleType'])
+ if self.instruction[self.id]:
+ self.drawMap.SetValue(self.mapFrameDict['drawMap'])
+ else:
+ self.drawMap.SetValue(True)
+ if self.mapFrameDict['scaleType'] == 0 and self.mapFrameDict['map']:
+ self.select.SetValue(self.mapFrameDict['map'])
+ if self.mapFrameDict['mapType'] == 'raster':
+ self.rasterTypeRadio.SetValue(True)
+ self.vectorTypeRadio.SetValue(False)
+ else:
+ self.rasterTypeRadio.SetValue(False)
+ self.vectorTypeRadio.SetValue(True)
+ elif self.mapFrameDict['scaleType'] == 1 and self.mapFrameDict['region']:
+ self.select.SetValue(self.mapFrameDict['region'])
+
+
+ self.OnMap(None)
+ self.scale[self.mapFrameDict['scaleType']] = self.mapFrameDict['scale']
+ self.center[self.mapFrameDict['scaleType']] = self.mapFrameDict['center']
+ self.OnScaleChoice(None)
+ self.OnElementType(None)
+ self.OnBorder(None)
+
+
+
+ def _layout(self):
+ """!Do layout"""
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map frame"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+ gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+
+ #scale options
+ frameText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map frame options:"))
+ scaleChoices = [_("fit frame to match selected map"),
+ _("fit frame to match saved region"),
+ _("fit frame to match current computational region"),
+ _("fixed scale and map center")]
+ self.scaleChoice = wx.Choice(self, id = wx.ID_ANY, choices = scaleChoices)
+
+
+ gridBagSizer.Add(frameText, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.scaleChoice, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+ #map and region selection
+ self.staticBox = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map selection"))
+ sizerM = wx.StaticBoxSizer(self.staticBox, wx.HORIZONTAL)
+ self.mapSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+ self.rasterTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("raster"), style = wx.RB_GROUP)
+ self.vectorTypeRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("vector"))
+ self.drawMap = wx.CheckBox(self, id = wx.ID_ANY, label = "add selected map")
+
+ self.mapOrRegionText = [_("Map:"), _("Region:")]
+ dc = wx.ClientDC(self)# determine size of labels
+ width = max(dc.GetTextExtent(self.mapOrRegionText[0])[0], dc.GetTextExtent(self.mapOrRegionText[1])[0])
+ self.mapText = wx.StaticText(self, id = wx.ID_ANY, label = self.mapOrRegionText[0], size = (width, -1))
+ self.select = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+ type = 'raster', multiple = False,
+ updateOnPopup = True, onPopup = None)
+
+ self.mapSizer.Add(self.rasterTypeRadio, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.mapSizer.Add(self.vectorTypeRadio, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.mapSizer.Add(self.drawMap, pos = (0, 3), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+ self.mapSizer.Add(self.mapText, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.mapSizer.Add(self.select, pos = (1, 1), span = (1, 3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizerM.Add(self.mapSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ gridBagSizer.Add(sizerM, pos = (2, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+
+ #map scale and center
+ boxC = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Map scale and center"))
+ sizerC = wx.StaticBoxSizer(boxC, wx.HORIZONTAL)
+ self.centerSizer = wx.FlexGridSizer(rows = 2, cols = 5, hgap = 5, vgap = 5)
+
+
+ centerText = wx.StaticText(self, id = wx.ID_ANY, label = _("Center:"))
+ self.eastingText = wx.StaticText(self, id = wx.ID_ANY, label = _("E:"))
+ self.northingText = wx.StaticText(self, id = wx.ID_ANY, label = _("N:"))
+ self.eastingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
+ self.northingTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, style = wx.TE_RIGHT, validator = TCValidator(flag = 'DIGIT_ONLY'))
+ scaleText = wx.StaticText(self, id = wx.ID_ANY, label = _("Scale:"))
+ scalePrefixText = wx.StaticText(self, id = wx.ID_ANY, label = _("1 :"))
+ self.scaleTextCtrl = wx.TextCtrl(self, id = wx.ID_ANY, value = "", style = wx.TE_RIGHT, validator = TCValidator('DIGIT_ONLY'))
+
+ self.centerSizer.Add(centerText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
+ self.centerSizer.Add(self.eastingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+ self.centerSizer.Add(self.eastingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.centerSizer.Add(self.northingText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+ self.centerSizer.Add(self.northingTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ self.centerSizer.Add(scaleText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border = 10)
+ self.centerSizer.Add(scalePrefixText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, border = 0)
+ self.centerSizer.Add(self.scaleTextCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizerC.Add(self.centerSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ gridBagSizer.Add(sizerC, pos = (3, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+
+ #resolution
+ flexSizer = wx.FlexGridSizer(rows = 1, cols = 2, hgap = 5, vgap = 5)
+
+ resolutionText = wx.StaticText(self, id = wx.ID_ANY, label = _("Map max resolution (dpi):"))
+ self.resolutionSpin = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 1000, initial = 300)
+
+ flexSizer.Add(resolutionText, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexSizer.Add(self.resolutionSpin, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ self.resolutionSpin.SetValue(self.mapFrameDict['resolution'])
+
+ gridBagSizer.Add(flexSizer, pos = (4, 0), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ # border
+ box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Border"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+ gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+ self.borderCheck = wx.CheckBox(self, id = wx.ID_ANY, label = (_("draw border around map frame")))
+ if self.mapFrameDict['border'] == 'y':
+ self.borderCheck.SetValue(True)
+ else:
+ self.borderCheck.SetValue(False)
+
+ self.borderColorText = wx.StaticText(self, id = wx.ID_ANY, label = _("border color:"))
+ self.borderWidthText = wx.StaticText(self, id = wx.ID_ANY, label = _("border width (pts):"))
+ self.borderColourPicker = wx.ColourPickerCtrl(self, id = wx.ID_ANY)
+ self.borderWidthCtrl = wx.SpinCtrl(self, id = wx.ID_ANY, min = 1, max = 100, initial = 1)
+
+ if self.mapFrameDict['border'] == 'y':
+ self.borderWidthCtrl.SetValue(int(self.mapFrameDict['width']))
+ self.borderColourPicker.SetColour(convertRGB(self.mapFrameDict['color']))
+
+
+ gridBagSizer.Add(self.borderCheck, pos = (0, 0), span = (1,2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+ gridBagSizer.Add(self.borderColorText, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.borderWidthText, pos = (2, 1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.borderColourPicker, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+ gridBagSizer.Add(self.borderWidthCtrl, pos = (2, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ self.SetSizer(border)
+ self.Fit()
+
+
+ if projInfo()['proj'] == 'll':
+ self.scaleChoice.SetItems(self.scaleChoice.GetItems()[0:3])
+ boxC.Hide()
+ for each in self.centerSizer.GetChildren():
+ each.GetWindow().Hide()
+
+
+ # bindings
+ self.scaleChoice.Bind(wx.EVT_CHOICE, self.OnScaleChoice)
+ self.select.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnMap)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.vectorTypeRadio)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnElementType, self.rasterTypeRadio)
+ self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.borderCheck)
+
+
+
+ def OnMap(self, event):
+ """!Selected map or region changing"""
+
+ if self.select.GetValue():
+ self.selected = self.select.GetValue()
+ else:
+ self.selected = None
+
+ if self.scaleChoice.GetSelection() == 0:
+ self.selectedMap = self.selected
+ if self.rasterTypeRadio.GetValue():
+ mapType = 'raster'
+ else:
+ mapType = 'vector'
+
+ self.scale[0], self.center[0], foo = AutoAdjust(self, scaleType = 0, map = self.selected,
+ mapType = mapType, rect = self.mapFrameDict['rect'])
+ #self.center[0] = self.RegionCenter(self.RegionDict(scaleType = 0))
+
+ elif self.scaleChoice.GetSelection() == 1:
+ self.selectedRegion = self.selected
+ self.scale[1], self.center[1], foo = AutoAdjust(self, scaleType = 1, region = self.selected, rect = self.mapFrameDict['rect'])
+ #self.center[1] = self.RegionCenter(self.RegionDict(scaleType = 1))
+ elif self.scaleChoice.GetSelection() == 2:
+ self.scale[2], self.center[2], foo = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
+ #self.center[2] = self.RegionCenter(self.RegionDict(scaleType = 2))
+
+ else:
+ self.scale[3] = None
+ self.center[3] = None
+
+ self.OnScaleChoice(None)
+
+
+ def OnScaleChoice(self, event):
+ """!Selected scale type changing"""
+
+ scaleType = self.scaleChoice.GetSelection()
+ if self.scaleType != scaleType:
+ self.scaleType = scaleType
+ self.select.SetValue("")
+
+ if scaleType in (0, 1): # automatic - region from raster map, saved region
+ if scaleType == 0:
+ # set map selection
+ self.rasterTypeRadio.Show()
+ self.vectorTypeRadio.Show()
+ self.drawMap.Show()
+ self.staticBox.SetLabel(" %s " % _("Map selection"))
+ if self.rasterTypeRadio.GetValue():
+ stype = 'raster'
+ else:
+ stype = 'vector'
+
+ self.select.SetElementList(type = stype)
+ self.mapText.SetLabel(self.mapOrRegionText[0])
+ self.select.SetToolTipString(_("Region is set to match this map,\nraster or vector map must be added later"))
+
+ if scaleType == 1:
+ # set region selection
+ self.rasterTypeRadio.Hide()
+ self.vectorTypeRadio.Hide()
+ self.drawMap.Hide()
+ self.staticBox.SetLabel(" %s " % _("Region selection"))
+ stype = 'region'
+ self.select.SetElementList(type = stype)
+ self.mapText.SetLabel(self.mapOrRegionText[1])
+ self.select.SetToolTipString("")
+
+ for each in self.mapSizer.GetChildren():
+ each.GetWindow().Enable()
+ for each in self.centerSizer.GetChildren():
+ each.GetWindow().Disable()
+
+ if self.scale[scaleType]:
+
+ self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+ if self.center[scaleType]:
+ self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+ self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+ elif scaleType == 2:
+ for each in self.mapSizer.GetChildren():
+ each.GetWindow().Disable()
+ for each in self.centerSizer.GetChildren():
+ each.GetWindow().Disable()
+
+ if self.scale[scaleType]:
+ self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+ if self.center[scaleType]:
+ self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+ self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+ else: # fixed
+ for each in self.mapSizer.GetChildren():
+ each.GetWindow().Disable()
+ for each in self.centerSizer.GetChildren():
+ each.GetWindow().Enable()
+
+ if self.scale[scaleType]:
+ self.scaleTextCtrl.SetValue("%.0f" % (1/self.scale[scaleType]))
+ if self.center[scaleType]:
+ self.eastingTextCtrl.SetValue(str(self.center[scaleType][0]))
+ self.northingTextCtrl.SetValue(str(self.center[scaleType][1]))
+
+ def OnElementType(self, event):
+ """!Changes data in map selection tree ctrl popup"""
+ if self.rasterTypeRadio.GetValue():
+ mapType = 'raster'
+ else:
+ mapType = 'vector'
+ self.select.SetElementList(type = mapType)
+ if self.mapType != mapType and event is not None:
+ self.mapType = mapType
+ self.select.SetValue('')
+ self.mapType = mapType
+
+ def OnBorder(self, event):
+ """!Enables/disable the part relating to border of map frame"""
+ for each in (self.borderColorText, self.borderWidthText, self.borderColourPicker, self.borderWidthCtrl):
+ each.Enable(self.borderCheck.GetValue())
+
+ def getId(self):
+ """!Returns id of raster map"""
+ return self.id
+
+ def update(self):
+ """!Save changes"""
+ mapFrameDict = dict(self.mapFrameDict)
+ # resolution
+ mapFrameDict['resolution'] = self.resolutionSpin.GetValue()
+ #scale
+ scaleType = self.scaleType
+ mapFrameDict['scaleType'] = scaleType
+
+ if mapFrameDict['scaleType'] == 0:
+ if self.select.GetValue():
+ mapFrameDict['drawMap'] = self.drawMap.GetValue()
+ mapFrameDict['map'] = self.select.GetValue()
+ mapFrameDict['mapType'] = self.mapType
+ mapFrameDict['region'] = None
+
+ if mapFrameDict['drawMap']:
+
+ if mapFrameDict['mapType'] == 'raster':
+ mapFile = grass.find_file(mapFrameDict['map'], element = 'cell')
+ if mapFile['file'] == '':
+ GMessage("Raster %s not found" % mapFrameDict['map'])
+ return False
+ raster = self.instruction.FindInstructionByType('raster')
+ if raster:
+ raster['raster'] = mapFrameDict['map']
+ else:
+ raster = Raster(wx.NewId())
+ raster['raster'] = mapFrameDict['map']
+ raster['isRaster'] = True
+ self.instruction.AddInstruction(raster)
+
+ elif mapFrameDict['mapType'] == 'vector':
+
+ mapFile = grass.find_file(mapFrameDict['map'], element = 'vector')
+ if mapFile['file'] == '':
+ GMessage("Vector %s not found" % mapFrameDict['map'])
+ return False
+
+ vector = self.instruction.FindInstructionByType('vector')
+ isAdded = False
+ if vector:
+ for each in vector['list']:
+ if each[0] == mapFrameDict['map']:
+ isAdded = True
+ if not isAdded:
+ topoInfo = grass.vector_info_topo(map = mapFrameDict['map'])
+ if topoInfo:
+ if bool(topoInfo['areas']):
+ topoType = 'areas'
+ elif bool(topoInfo['lines']):
+ topoType = 'lines'
+ else:
+ topoType = 'points'
+ label = '('.join(mapFrameDict['map'].split('@')) + ')'
+
+ if not vector:
+ vector = Vector(wx.NewId())
+ vector['list'] = []
+ self.instruction.AddInstruction(vector)
+ id = wx.NewId()
+ vector['list'].insert(0, [mapFrameDict['map'], topoType, id, 1, label])
+ vProp = VProperties(id, topoType)
+ vProp['name'], vProp['label'], vProp['lpos'] = mapFrameDict['map'], label, 1
+ self.instruction.AddInstruction(vProp)
+ else:
+ return False
+
+ self.scale[0], self.center[0], self.rectAdjusted = AutoAdjust(self, scaleType = 0, map = mapFrameDict['map'],
+ mapType = self.mapType, rect = self.mapFrameDict['rect'])
+
+ if self.rectAdjusted:
+ mapFrameDict['rect'] = self.rectAdjusted
+ else:
+ mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+ mapFrameDict['scale'] = self.scale[0]
+
+ mapFrameDict['center'] = self.center[0]
+ # set region
+ if self.mapType == 'raster':
+ RunCommand('g.region', rast = mapFrameDict['map'])
+ if self.mapType == 'vector':
+ raster = self.instruction.FindInstructionByType('raster')
+ if raster:
+ rasterId = raster.id
+ else:
+ rasterId = None
+
+ if rasterId:
+
+ RunCommand('g.region', vect = mapFrameDict['map'], rast = self.instruction[rasterId]['raster'])
+ else:
+ RunCommand('g.region', vect = mapFrameDict['map'])
+
+
+
+ else:
+ wx.MessageBox(message = _("No map selected!"),
+ caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+ return False
+
+ elif mapFrameDict['scaleType'] == 1:
+ if self.select.GetValue():
+ mapFrameDict['drawMap'] = False
+ mapFrameDict['map'] = None
+ mapFrameDict['mapType'] = None
+ mapFrameDict['region'] = self.select.GetValue()
+ self.scale[1], self.center[1], self.rectAdjusted = AutoAdjust(self, scaleType = 1, region = mapFrameDict['region'],
+ rect = self.mapFrameDict['rect'])
+ if self.rectAdjusted:
+ mapFrameDict['rect'] = self.rectAdjusted
+ else:
+ mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+ mapFrameDict['scale'] = self.scale[1]
+ mapFrameDict['center'] = self.center[1]
+ # set region
+ RunCommand('g.region', region = mapFrameDict['region'])
+ else:
+ wx.MessageBox(message = _("No region selected!"),
+ caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+ return False
+
+ elif scaleType == 2:
+ mapFrameDict['drawMap'] = False
+ mapFrameDict['map'] = None
+ mapFrameDict['mapType'] = None
+ mapFrameDict['region'] = None
+ self.scale[2], self.center[2], self.rectAdjusted = AutoAdjust(self, scaleType = 2, rect = self.mapFrameDict['rect'])
+ if self.rectAdjusted:
+ mapFrameDict['rect'] = self.rectAdjusted
+ else:
+ mapFrameDict['rect'] = self.mapFrameDict['rect']
+
+ mapFrameDict['scale'] = self.scale[2]
+ mapFrameDict['center'] = self.center[2]
+
+ env = grass.gisenv()
+ windFilePath = os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'], 'WIND')
+ try:
+ windFile = open(windFilePath, 'r').read()
+ region = grass.parse_key_val(windFile, sep = ':', val_type = float)
+ except IOError:
+ region = grass.region()
+
+ raster = self.instruction.FindInstructionByType('raster')
+ if raster:
+ rasterId = raster.id
+ else:
+ rasterId = None
+
+ if rasterId: # because of resolution
+ RunCommand('g.region', n = region['north'], s = region['south'],
+ e = region['east'], w = region['west'], rast = self.instruction[rasterId]['raster'])
+ else:
+ RunCommand('g.region', n = region['north'], s = region['south'],
+ e = region['east'], w = region['west'])
+
+ elif scaleType == 3:
+ mapFrameDict['drawMap'] = False
+ mapFrameDict['map'] = None
+ mapFrameDict['mapType'] = None
+ mapFrameDict['region'] = None
+ mapFrameDict['rect'] = self.mapFrameDict['rect']
+ try:
+ scaleNumber = float(self.scaleTextCtrl.GetValue())
+ centerE = float(self.eastingTextCtrl.GetValue())
+ centerN = float(self.northingTextCtrl.GetValue())
+ except (ValueError, SyntaxError):
+ wx.MessageBox(message = _("Invalid scale or map center!"),
+ caption = _('Invalid input'), style = wx.OK|wx.ICON_ERROR)
+ return False
+ mapFrameDict['scale'] = 1/scaleNumber
+ mapFrameDict['center'] = centerE, centerN
+
+ ComputeSetRegion(self, mapDict = mapFrameDict)
+
+ # check resolution
+ SetResolution(dpi = mapFrameDict['resolution'], width = mapFrameDict['rect'].width,
+ height = mapFrameDict['rect'].height)
+ # border
+ if self.borderCheck.GetValue():
+ mapFrameDict['border'] = 'y'
+ else:
+ mapFrameDict['border'] = 'n'
+
+ if mapFrameDict['border'] == 'y':
+ mapFrameDict['width'] = self.borderWidthCtrl.GetValue()
+ mapFrameDict['color'] = convertRGB(self.borderColourPicker.GetColour())
+
+ if self.id not in self.instruction:
+ mapFrame = MapFrame(self.id)
+ self.instruction.AddInstruction(mapFrame)
+ self.instruction[self.id].SetInstruction(mapFrameDict)
+
+ if self.id not in self.mapDialog.parent.objectId:
+ self.mapDialog.parent.objectId.insert(0, self.id)# map frame is drawn first
+ return True
+
+class RasterPanel(wx.Panel):
+ """!Panel for raster map settings"""
+ def __init__(self, parent, id, settings, notebook = True):
+ wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+ self.instruction = settings
+
+ if notebook:
+ self.book = parent
+ self.book.AddPage(page = self, text = _("Raster map"))
+ self.mainDialog = self.book.GetParent()
+ else:
+ self.mainDialog = parent
+ if id:
+ self.id = id
+ self.rasterDict = self.instruction[self.id].GetInstruction()
+ else:
+ self.id = wx.NewId()
+ raster = Raster(self.id)
+ self.rasterDict = raster.GetInstruction()
+
+
+ self._layout()
+ self.OnRaster(None)
+
+ def _layout(self):
+ """!Do layout"""
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ # choose raster map
+
+ box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Choose raster map"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+ self.rasterNoRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("no raster map"), style = wx.RB_GROUP)
+ self.rasterYesRadio = wx.RadioButton(self, id = wx.ID_ANY, label = _("raster:"))
+
+ self.rasterSelect = Select(self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
+ type = 'raster', multiple = False,
+ updateOnPopup = True, onPopup = None)
+ if self.rasterDict['isRaster']:
+ self.rasterYesRadio.SetValue(True)
+ self.rasterNoRadio.SetValue(False)
+ self.rasterSelect.SetValue(self.rasterDict['raster'])
+ else:
+ self.rasterYesRadio.SetValue(False)
+ self.rasterNoRadio.SetValue(True)
+ mapId = self.instruction.FindInstructionByType('map').id
+
+ if self.instruction[mapId]['map'] and self.instruction[mapId]['mapType'] == 'raster':
+ self.rasterSelect.SetValue(self.instruction[mapId]['map'])# raster map from map frame dialog if possible
+ else:
+ self.rasterSelect.SetValue('')
+ gridBagSizer.Add(self.rasterNoRadio, pos = (0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.rasterYesRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.rasterSelect, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #self.rasterSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnRaster)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterNoRadio)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnRaster, self.rasterYesRadio)
+
+ self.SetSizer(border)
+ self.Fit()
+
+ def OnRaster(self, event):
+ """!Enable/disable raster selection"""
+ self.rasterSelect.Enable(self.rasterYesRadio.GetValue())
+
+ def update(self):
+ #draw raster
+ mapInstr = self.instruction.FindInstructionByType('map')
+ if not mapInstr: # no map frame
+ GMessage(message = _("Please, create map frame first."))
+ return
+
+ if self.rasterNoRadio.GetValue() or not self.rasterSelect.GetValue():
+ self.rasterDict['isRaster'] = False
+ self.rasterDict['raster'] = None
+ mapInstr['drawMap'] = False
+ if self.id in self.instruction:
+ del self.instruction[self.id]
+
+ else:
+ self.rasterDict['isRaster'] = True
+ self.rasterDict['raster'] = self.rasterSelect.GetValue()
+ if self.rasterDict['raster'] != mapInstr['drawMap']:
+ mapInstr['drawMap'] = False
+
+ raster = self.instruction.FindInstructionByType('raster')
+ if not raster:
+ raster = Raster(self.id)
+ self.instruction.AddInstruction(raster)
+ self.instruction[self.id].SetInstruction(self.rasterDict)
+ else:
+ self.instruction[raster.id].SetInstruction(self.rasterDict)
+
+ if 'map' in self.mainDialog.parent.openDialogs:
+ self.mainDialog.parent.openDialogs['map'].updateDialog()
+ return True
+
+ def getId(self):
+ return self.id
+
+class VectorPanel(wx.Panel):
+ """!Panel for vector maps settings"""
+ def __init__(self, parent, id, settings, notebook = True):
+ wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+
+ self.parent = parent
+ self.instruction = settings
+ self.tmpDialogDict = {}
+ vectors = self.instruction.FindInstructionByType('vProperties', list = True)
+ for vector in vectors:
+ self.tmpDialogDict[vector.id] = dict(self.instruction[vector.id].GetInstruction())
+
+ if id:
+ self.id = id
+ self.vectorList = deepcopy(self.instruction[id]['list'])
+ else:
+ self.id = wx.NewId()
+ self.vectorList = []
+
+ vLegend = self.instruction.FindInstructionByType('vectorLegend')
+ if vLegend:
+ self.vLegendId = vLegend.id
+ else:
+ self.vLegendId = None
+
+
+ self._layout()
+
+ if notebook:
+ self.parent.AddPage(page = self, text = _("Vector maps"))
+ self.parent = self.parent.GetParent()
+
+ def _layout(self):
+ """!Do layout"""
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ # choose vector map
+
+ box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Add map"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+ text = wx.StaticText(self, id = wx.ID_ANY, label = _("Map:"))
+ self.select = Select(self, id = wx.ID_ANY,# size = globalvar.DIALOG_GSELECT_SIZE,
+ type = 'vector', multiple = False,
+ updateOnPopup = True, onPopup = None)
+ topologyTypeTr = [_("points"), _("lines"), _("areas")]
+ self.topologyTypeList = ["points", "lines", "areas"]
+ self.vectorType = wx.RadioBox(self, id = wx.ID_ANY, label = " %s " % _("Data Type"), choices = topologyTypeTr,
+ 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 = ''
+ idx = self.vectorType.GetSelection()
+ ttype = self.topologyTypeList[idx]
+ record = "%s - %s" % (vmap, ttype)
+ id = wx.NewId()
+ lpos = 1
+ label = mapname + mapset
+ self.vectorList.insert(0, [vmap, ttype, id, lpos, label])
+ self.reposition()
+ self.listbox.InsertItems([record], 0)
+
+ vector = VProperties(id, ttype)
+ 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(_("%s properties") % self.vectorName)
+
+ #vector map info
+ self.connection = True
+ try:
+ self.mapDBInfo = VectorDBInfo(self.vectorName)
+ self.layers = self.mapDBInfo.layers.keys()
+ except grass.ScriptError:
+ self.connection = False
+ self.layers = []
+ if not self.layers:
+ self.connection = False
+ self.layers = []
+
+ self.currLayer = self.vPropertiesDict['layer']
+
+ #path to symbols, patterns
+ gisbase = os.getenv("GISBASE")
+ self.symbolPath = os.path.join(gisbase, 'etc', 'symbol')
+ self.symbols = []
+ for dir in os.listdir(self.symbolPath):
+ for symbol in os.listdir(os.path.join(self.symbolPath, dir)):
+ self.symbols.append(os.path.join(dir, symbol))
+ self.patternPath = os.path.join(gisbase, 'etc', 'paint', 'patterns')
+
+ #notebook
+ notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+ self.DSpanel = self._DataSelectionPanel(notebook)
+ self.EnableLayerSelection(enable = self.connection)
+ selectPanel = { 'points': [self._ColorsPointAreaPanel, self._StylePointPanel],
+ 'lines': [self._ColorsLinePanel, self._StyleLinePanel],
+ 'areas': [self._ColorsPointAreaPanel, self._StyleAreaPanel]}
+ self.ColorsPanel = selectPanel[self.type][0](notebook)
+
+ self.OnOutline(None)
+ if self.type in ('points', 'areas'):
+ self.OnFill(None)
+ self.OnColor(None)
+
+ self.StylePanel = selectPanel[self.type][1](notebook)
+ if self.type == 'points':
+ self.OnSize(None)
+ self.OnRotation(None)
+ self.OnSymbology(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.symbolName = wx.StaticText(panel, id = wx.ID_ANY)
+ self.symbolName.SetLabel(self.vPropertiesDict['symbol'])
+ bitmap = wx.Bitmap(os.path.join(globalvar.ETCSYMBOLDIR,
+ self.vPropertiesDict['symbol']) + '.png')
+ self.symbolButton = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bitmap)
+
+ 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 not self.vPropertiesDict['eps']:
+ self.epsFileCtrl.SetValue('')
+ else: #eps chosen
+ self.epsFileCtrl.SetValue(self.vPropertiesDict['eps'])
+
+ gridBagSizer.AddGrowableCol(2)
+ gridBagSizer.Add(self.symbolRadio, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.symbolName, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border = 10)
+ gridBagSizer.Add(self.symbolButton, pos = (0, 2), flag = wx.ALIGN_RIGHT , border = 0)
+ gridBagSizer.Add(self.epsRadio, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.epsFileCtrl, pos = (1, 1), span = (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)
+
+ self.Bind(wx.EVT_BUTTON, self.OnSymbolSelection, self.symbolButton)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnSymbology, self.symbolRadio)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnSymbology, self.epsRadio)
+
+ #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 OnSymbology(self, event):
+ useSymbol = self.symbolRadio.GetValue()
+
+ self.symbolButton.Enable(useSymbol)
+ self.symbolName.Enable(useSymbol)
+ self.epsFileCtrl.Enable(not useSymbol)
+
+ def OnSymbolSelection(self, event):
+ dlg = SymbolDialog(self, symbolPath = globalvar.ETCSYMBOLDIR,
+ currentSymbol = self.symbolName.GetLabel())
+ if dlg.ShowModal() == wx.ID_OK:
+ img = dlg.GetSelectedSymbol(fullPath = True)
+ name = dlg.GetSelectedSymbol(fullPath = False)
+ self.symbolButton.SetBitmapLabel(wx.Bitmap(img + '.png'))
+ self.symbolName.SetLabel(name)
+
+ dlg.Destroy()
+
+ 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.symbolName.GetLabel()
+ self.vPropertiesDict['eps'] = None
+ else:
+ self.vPropertiesDict['eps'] = self.epsFileCtrl.GetValue()
+ #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'] = Rect2D(x = x, y = y, width = drawWidth, height = 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.ClientDC(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'] = 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'] = Rect2D(x = x, y = y, width = rectSize[0], height = 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(mapInstr = map, x = self.textDict['where'][0], y = self.textDict['where'][1], paperToMap = True)
+
+ notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+ self.textPanel = self._textPanel(notebook)
+ self.positionPanel = self._positionPanel(notebook)
+ self.OnBackground(None)
+ self.OnHighlight(None)
+ self.OnBorder(None)
+ self.OnPositionType(None)
+ self.OnRotation(None)
+
+ self._layout(notebook)
+
+ def _textPanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = _("Text"))
+
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ # text entry
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+ textLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Enter text:"))
+ self.textCtrl = ExpandoTextCtrl(panel, id = wx.ID_ANY, value = self.textDict['text'])
+
+ sizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+ sizer.Add(self.textCtrl, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #font
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Font settings"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ flexGridSizer = wx.FlexGridSizer (rows = 3, cols = 2, hgap = 5, vgap = 5)
+ flexGridSizer.AddGrowableCol(1)
+
+ self.AddFont(parent = panel, dialogDict = self.textDict)
+
+ flexGridSizer.Add(panel.font['fontLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexGridSizer.Add(panel.font['fontCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexGridSizer.Add(panel.font['fontSizeLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexGridSizer.Add(panel.font['fontSizeCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexGridSizer.Add(panel.font['colorLabel'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ flexGridSizer.Add(panel.font['colorCtrl'], proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizer.Add(item = flexGridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #text effects
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text effects"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+ self.effect = {}
+ self.effect['backgroundCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text background"))
+ self.effect['backgroundColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+
+ self.effect['highlightCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("highlight"))
+ self.effect['highlightColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.effect['highlightWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 0, max = 5, initial = 1)
+ self.effect['highlightWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+
+ self.effect['borderCtrl'] = wx.CheckBox(panel, id = wx.ID_ANY, label = _("text border"))
+ self.effect['borderColor'] = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.effect['borderWidth'] = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize, min = 1, max = 25, initial = 1)
+ self.effect['borderWidthLabel'] = wx.StaticText(panel, id = wx.ID_ANY, label = _("Width (pts):"))
+
+ #set values
+ if self.textDict['background'] == None:
+ self.textDict['background'] = 'none'
+ if self.textDict['background'] != 'none':
+ self.effect['backgroundCtrl'].SetValue(True)
+ self.effect['backgroundColor'].SetColour(convertRGB(self.textDict['background']))
+ else:
+ self.effect['backgroundCtrl'].SetValue(False)
+ self.effect['backgroundColor'].SetColour(convertRGB('white'))
+
+ if self.textDict['hcolor'] == None:
+ self.textDict['hcolor'] = 'none'
+ if self.textDict['hcolor'] != 'none':
+ self.effect['highlightCtrl'].SetValue(True)
+ self.effect['highlightColor'].SetColour(convertRGB(self.textDict['hcolor']))
+ else:
+ self.effect['highlightCtrl'].SetValue(False)
+ self.effect['highlightColor'].SetColour(convertRGB('grey'))
+
+ self.effect['highlightWidth'].SetValue(float(self.textDict['hwidth']))
+
+ if self.textDict['border'] == None:
+ self.textDict['border'] = 'none'
+ if self.textDict['border'] != 'none':
+ self.effect['borderCtrl'].SetValue(True)
+ self.effect['borderColor'].SetColour(convertRGB(self.textDict['border']))
+ else:
+ self.effect['borderCtrl'].SetValue(False)
+ self.effect['borderColor'].SetColour(convertRGB('black'))
+
+ self.effect['borderWidth'].SetValue(float(self.textDict['width']))
+
+ gridBagSizer.Add(self.effect['backgroundCtrl'], pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['backgroundColor'], pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['highlightCtrl'], pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['highlightColor'], pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['highlightWidthLabel'], pos = (1,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['highlightWidth'], pos = (1,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['borderCtrl'], pos = (2,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['borderColor'], pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['borderWidthLabel'], pos = (2,2), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizer.Add(self.effect['borderWidth'], pos = (2,3), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizer.Add(item = gridBagSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textCtrl)
+ self.Bind(wx.EVT_CHECKBOX, self.OnBackground, self.effect['backgroundCtrl'])
+ self.Bind(wx.EVT_CHECKBOX, self.OnHighlight, self.effect['highlightCtrl'])
+ self.Bind(wx.EVT_CHECKBOX, self.OnBorder, self.effect['borderCtrl'])
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ return panel
+
+ def _positionPanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = _("Position"))
+
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+ gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridBagSizer.AddGrowableCol(0)
+ gridBagSizer.AddGrowableCol(1)
+
+ #Position
+ self.AddExtendedPosition(panel, gridBagSizer, self.textDict)
+
+ #offset
+ box3 = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_("Offset"))
+ sizerO = wx.StaticBoxSizer(box3, wx.VERTICAL)
+ gridBagSizerO = wx.GridBagSizer (hgap = 5, vgap = 5)
+ self.xoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("horizontal (pts):"))
+ self.yoffLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("vertical (pts):"))
+ self.xoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0)
+ self.yoffCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = (50, -1), min = -50, max = 50, initial = 0)
+ self.xoffCtrl.SetValue(self.textDict['xoffset'])
+ self.yoffCtrl.SetValue(self.textDict['yoffset'])
+ gridBagSizerO.Add(self.xoffLabel, pos = (0,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizerO.Add(self.yoffLabel, pos = (1,0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizerO.Add(self.xoffCtrl, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridBagSizerO.Add(self.yoffCtrl, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+
+ sizerO.Add(gridBagSizerO, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ gridBagSizer.Add(sizerO, pos = (3,0), flag = wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, border = 0)
+ # reference point
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " %_(" Reference point"))
+ sizerR = wx.StaticBoxSizer(box, wx.VERTICAL)
+ flexSizer = wx.FlexGridSizer(rows = 3, cols = 3, hgap = 5, vgap = 5)
+ flexSizer.AddGrowableCol(0)
+ flexSizer.AddGrowableCol(1)
+ flexSizer.AddGrowableCol(2)
+ ref = []
+ for row in ["upper", "center", "lower"]:
+ for col in ["left", "center", "right"]:
+ ref.append(row + " " + col)
+ self.radio = [wx.RadioButton(panel, id = wx.ID_ANY, label = '', style = wx.RB_GROUP, name = ref[0])]
+ self.radio[0].SetValue(False)
+ flexSizer.Add(self.radio[0], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+ for i in range(1,9):
+ self.radio.append(wx.RadioButton(panel, id = wx.ID_ANY, label = '', name = ref[i]))
+ self.radio[-1].SetValue(False)
+ flexSizer.Add(self.radio[-1], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+ self.FindWindowByName(self.textDict['ref']).SetValue(True)
+
+ sizerR.Add(flexSizer, proportion = 1, flag = wx.EXPAND, border = 0)
+ gridBagSizer.Add(sizerR, pos = (3,1), flag = wx.ALIGN_LEFT|wx.EXPAND, border = 0)
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #rotation
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Text rotation"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+ self.rotCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("rotate text (counterclockwise)"))
+ self.rotValue = wx.SpinCtrl(panel, wx.ID_ANY, size = (50, -1), min = 0, max = 360, initial = 0)
+ if self.textDict['rotate']:
+ self.rotValue.SetValue(int(self.textDict['rotate']))
+ self.rotCtrl.SetValue(True)
+ else:
+ self.rotValue.SetValue(0)
+ self.rotCtrl.SetValue(False)
+ sizer.Add(self.rotCtrl, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
+ sizer.Add(self.rotValue, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.ALL, border = 5)
+
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper'])
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+ self.Bind(wx.EVT_CHECKBOX, self.OnRotation, self.rotCtrl)
+
+ return panel
+
+ def OnRefit(self, event):
+ self.Fit()
+
+ def OnRotation(self, event):
+ if self.rotCtrl.GetValue():
+ self.rotValue.Enable()
+ else:
+ self.rotValue.Disable()
+
+ def OnPositionType(self, event):
+ if self.positionPanel.position['toPaper'].GetValue():
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Disable()
+ else:
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Disable()
+
+ def OnBackground(self, event):
+ if self.effect['backgroundCtrl'].GetValue():
+ self.effect['backgroundColor'].Enable()
+ self.update()
+ else:
+ self.effect['backgroundColor'].Disable()
+
+ def OnHighlight(self, event):
+ if self.effect['highlightCtrl'].GetValue():
+ self.effect['highlightColor'].Enable()
+ self.effect['highlightWidth'].Enable()
+ self.effect['highlightWidthLabel'].Enable()
+ self.update()
+ else:
+ self.effect['highlightColor'].Disable()
+ self.effect['highlightWidth'].Disable()
+ self.effect['highlightWidthLabel'].Disable()
+
+ def OnBorder(self, event):
+ if self.effect['borderCtrl'].GetValue():
+ self.effect['borderColor'].Enable()
+ self.effect['borderWidth'].Enable()
+ self.effect['borderWidthLabel'].Enable()
+ self.update()
+ else:
+ self.effect['borderColor'].Disable()
+ self.effect['borderWidth'].Disable()
+ self.effect['borderWidthLabel'].Disable()
+
+ def update(self):
+ #text
+ self.textDict['text'] = self.textCtrl.GetValue()
+ if not self.textDict['text']:
+ wx.MessageBox(_("No text entered!"), _("Error"))
+ return False
+
+ #font
+ self.textDict['font'] = self.textPanel.font['fontCtrl'].GetStringSelection()
+ self.textDict['fontsize'] = self.textPanel.font['fontSizeCtrl'].GetValue()
+ color = self.textPanel.font['colorCtrl'].GetColour()
+ self.textDict['color'] = convertRGB(color)
+
+ #effects
+ if self.effect['backgroundCtrl'].GetValue():
+ background = self.effect['backgroundColor'].GetColour()
+ self.textDict['background'] = convertRGB(background)
+ else:
+ self.textDict['background'] = 'none'
+
+ if self.effect['borderCtrl'].GetValue():
+ border = self.effect['borderColor'].GetColour()
+ self.textDict['border'] = convertRGB(border)
+ else:
+ self.textDict['border'] = 'none'
+
+ self.textDict['width'] = self.effect['borderWidth'].GetValue()
+
+ if self.effect['highlightCtrl'].GetValue():
+ highlight = self.effect['highlightColor'].GetColour()
+ self.textDict['hcolor'] = convertRGB(highlight)
+ else:
+ self.textDict['hcolor'] = 'none'
+
+ self.textDict['hwidth'] = self.effect['highlightWidth'].GetValue()
+
+ #offset
+ self.textDict['xoffset'] = self.xoffCtrl.GetValue()
+ self.textDict['yoffset'] = self.yoffCtrl.GetValue()
+
+ #position
+ if self.positionPanel.position['toPaper'].GetValue():
+ self.textDict['XY'] = True
+ currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+ self.textDict['unit'] = currUnit
+ if self.positionPanel.position['xCtrl'].GetValue():
+ x = self.positionPanel.position['xCtrl'].GetValue()
+ else:
+ x = self.textDict['where'][0]
+
+ if self.positionPanel.position['yCtrl'].GetValue():
+ y = self.positionPanel.position['yCtrl'].GetValue()
+ else:
+ y = self.textDict['where'][1]
+
+ x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+ y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+ self.textDict['where'] = x, y
+ self.textDict['east'], self.textDict['north'] = PaperMapCoordinates(self.instruction[self.mapId], x, y, paperToMap = True)
+ else:
+ self.textDict['XY'] = False
+ if self.positionPanel.position['eCtrl'].GetValue():
+ self.textDict['east'] = self.positionPanel.position['eCtrl'].GetValue()
+ else:
+ self.textDict['east'] = self.textDict['east']
+
+ if self.positionPanel.position['nCtrl'].GetValue():
+ self.textDict['north'] = self.positionPanel.position['nCtrl'].GetValue()
+ else:
+ self.textDict['north'] = self.textDict['north']
+
+ self.textDict['where'] = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.textDict['east']),
+ y = float(self.textDict['north']), paperToMap = False)
+ #rotation
+ if self.rotCtrl.GetValue():
+ self.textDict['rotate'] = self.rotValue.GetValue()
+ else:
+ self.textDict['rotate'] = None
+ #reference point
+ for radio in self.radio:
+ if radio.GetValue() == True:
+ self.textDict['ref'] = radio.GetName()
+
+ if self.id not in self.instruction:
+ text = Text(self.id)
+ self.instruction.AddInstruction(text)
+ self.instruction[self.id].SetInstruction(self.textDict)
+
+ if self.id not in self.parent.objectId:
+ self.parent.objectId.append(self.id)
+
+# self.updateDialog()
+
+ return True
+
+ def updateDialog(self):
+ """!Update text coordinates, after moving"""
+ # XY coordinates
+ x, y = self.textDict['where'][:2]
+ currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+ x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+ y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+ self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+ self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+ # EN coordinates
+ e, n = self.textDict['east'], self.textDict['north']
+ self.positionPanel.position['eCtrl'].SetValue(str(self.textDict['east']))
+ self.positionPanel.position['nCtrl'].SetValue(str(self.textDict['north']))
+
+class ImageDialog(PsmapDialog):
+ """!Dialog for setting image properties.
+
+ It's base dialog for North Arrow dialog.
+ """
+ def __init__(self, parent, id, settings, imagePanelName = _("Image")):
+ PsmapDialog.__init__(self, parent = parent, id = id, title = "Image settings",
+ settings = settings)
+
+ self.objectType = ('image',)
+ if self.id is not None:
+ self.imageObj = self.instruction[self.id]
+ self.imageDict = self.instruction[id].GetInstruction()
+ else:
+ self.id = wx.NewId()
+ self.imageObj = self._newObject()
+ self.imageDict = self.imageObj.GetInstruction()
+ page = self.instruction.FindInstructionByType('page').GetInstruction()
+ self.imageDict['where'] = page['Left'], page['Top']
+
+ map = self.instruction.FindInstructionByType('map')
+ if not map:
+ map = self.instruction.FindInstructionByType('initMap')
+ self.mapId = map.id
+
+ self.imageDict['east'], self.imageDict['north'] = PaperMapCoordinates(mapInstr = map, x = self.imageDict['where'][0], y = self.imageDict['where'][1], paperToMap = True)
+
+ notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+ self.imagePanelName = imagePanelName
+ self.imagePanel = self._imagePanel(notebook)
+ self.positionPanel = self._positionPanel(notebook)
+ self.OnPositionType(None)
+
+ if self.imageDict['epsfile']:
+ self.imagePanel.image['dir'].SetValue(os.path.dirname(self.imageDict['epsfile']))
+ else:
+ self.imagePanel.image['dir'].SetValue(self._getImageDirectory())
+ self.OnDirChanged(None)
+
+ self._layout(notebook)
+
+
+ def _newObject(self):
+ """!Create corresponding instruction object"""
+ return Image(self.id, self.instruction)
+
+ def _imagePanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = self.imagePanelName)
+ border = wx.BoxSizer(wx.VERTICAL)
+ #
+ # choose image
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Image"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ # choose directory
+ panel.image = {}
+ if self.imageDict['epsfile']:
+ startDir = os.path.dirname(self.imageDict['epsfile'])
+ else:
+ startDir = self._getImageDirectory()
+ dir = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+ labelText = _("Choose a directory:"),
+ dialogTitle = _("Choose a directory with images"),
+ buttonText = _('Browse'),
+ startDirectory = startDir,
+ changeCallback = self.OnDirChanged)
+ panel.image['dir'] = dir
+
+
+ sizer.Add(item = dir, proportion = 0, flag = wx.EXPAND, border = 0)
+
+ # image list
+ hSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ imageList = wx.ListBox(parent = panel, id = wx.ID_ANY)
+ panel.image['list'] = imageList
+ imageList.Bind(wx.EVT_LISTBOX, self.OnImageSelectionChanged)
+
+ hSizer.Add(item = imageList, proportion = 1, flag = wx.EXPAND | wx.RIGHT, border = 10)
+
+ # image preview
+ vSizer = wx.BoxSizer(wx.VERTICAL)
+ self.previewSize = (150, 150)
+ img = wx.EmptyImage(*self.previewSize)
+ panel.image['preview'] = wx.StaticBitmap(parent = panel, id = wx.ID_ANY,
+ bitmap = wx.BitmapFromImage(img))
+ vSizer.Add(item = panel.image['preview'], proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+ panel.image['sizeInfo'] = wx.StaticText(parent = panel, id = wx.ID_ANY)
+ vSizer.Add(item = panel.image['sizeInfo'], proportion = 0, flag = wx.ALIGN_CENTER, border = 0)
+
+ hSizer.Add(item = vSizer, proportion = 0, flag = wx.EXPAND, border = 0)
+ sizer.Add(item = hSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 3)
+
+ epsInfo = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Note: only EPS format supported"))
+ sizer.Add(item = epsInfo, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 3)
+
+
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #
+ # rotation
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Scale And Rotation"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+ scaleLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Scale:"))
+ if fs:
+ panel.image['scale'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+ increment = 0.5, value = 1, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+ panel.image['scale'].SetFormat("%f")
+ panel.image['scale'].SetDigits(1)
+ else:
+ panel.image['scale'] = wx.TextCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+ validator = TCValidator(flag = 'DIGIT_ONLY'))
+
+ if self.imageDict['scale']:
+ if fs:
+ value = float(self.imageDict['scale'])
+ else:
+ value = str(self.imageDict['scale'])
+ else:
+ if fs:
+ value = 0
+ else:
+ value = '0'
+ panel.image['scale'].SetValue(value)
+
+ gridSizer.Add(item = scaleLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = panel.image['scale'], pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+
+ rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+ if fs:
+ panel.image['rotate'] = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 360,
+ increment = 0.5, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+ panel.image['rotate'].SetFormat("%f")
+ panel.image['rotate'].SetDigits(1)
+ else:
+ panel.image['rotate'] = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+ min = 0, max = 359, initial = 0)
+ panel.image['rotate'].SetToolTipString(_("Counterclockwise rotation in degrees"))
+ if self.imageDict['rotate']:
+ panel.image['rotate'].SetValue(int(self.imageDict['rotate']))
+ else:
+ panel.image['rotate'].SetValue(0)
+
+ gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridSizer.Add(item = panel.image['rotate'], pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ self._addConvergence(panel = panel, gridBagSizer = gridSizer)
+ sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ return panel
+
+ def _positionPanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = _("Position"))
+ border = wx.BoxSizer(wx.VERTICAL)
+ #
+ # set position
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridBagSizer.AddGrowableCol(0)
+ gridBagSizer.AddGrowableCol(1)
+
+ self.AddExtendedPosition(panel, gridBagSizer, self.imageDict)
+
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper'])
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ return panel
+
+ def OnDirChanged(self, event):
+ """!Image directory changed"""
+ path = self.imagePanel.image['dir'].GetValue()
+ try:
+ files = os.listdir(path)
+ except OSError: # no such directory
+ files = []
+ imageList = []
+
+ # no setter for startDirectory?
+ try:
+ self.imagePanel.image['dir'].startDirectory = path
+ except AttributeError: # for sure
+ pass
+ for file in files:
+ if os.path.splitext(file)[1].lower() == '.eps':
+ imageList.append(file)
+
+ imageList.sort()
+ self.imagePanel.image['list'].SetItems(imageList)
+ if self.imageDict['epsfile']:
+ file = os.path.basename(self.imageDict['epsfile'])
+ self.imagePanel.image['list'].SetStringSelection(file)
+ elif imageList:
+ self.imagePanel.image['list'].SetSelection(0)
+ self.OnImageSelectionChanged(None)
+
+ def OnPositionType(self, event):
+ if self.positionPanel.position['toPaper'].GetValue():
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Disable()
+ else:
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Disable()
+
+ def _getImageDirectory(self):
+ """!Default image directory"""
+ return os.getcwd()
+
+ def _addConvergence(self, panel, gridBagSizer):
+ pass
+
+ def OnImageSelectionChanged(self, event):
+ """!Image selected, show preview and size"""
+ if not self.imagePanel.image['dir']: # event is emitted when closing dialog an it causes error
+ return
+
+ if not havePILImage:
+ self.DrawWarningText(_("PIL\nmissing"))
+ return
+
+ imageName = self.imagePanel.image['list'].GetStringSelection()
+ if not imageName:
+ self.ClearPreview()
+ return
+ basePath = self.imagePanel.image['dir'].GetValue()
+ file = os.path.join(basePath, imageName)
+ if not os.path.exists(file):
+ return
+
+ if os.path.splitext(file)[1].lower() == '.eps':
+ try:
+ pImg = PILImage.open(file)
+ img = PilImageToWxImage(pImg)
+ except IOError, e:
+ GError(message = _("Unable to read file %s") % file)
+ self.ClearPreview()
+ return
+ self.SetSizeInfoLabel(img)
+ img = self.ScaleToPreview(img)
+ bitmap = img.ConvertToBitmap()
+ self.DrawBitmap(bitmap)
+
+ else:
+ # TODO: read other formats and convert by PIL to eps
+ pass
+
+ def ScaleToPreview(self, img):
+ """!Scale image to preview size"""
+ w = img.GetWidth()
+ h = img.GetHeight()
+ if w <= self.previewSize[0] and h <= self.previewSize[1]:
+ return img
+ if w > h:
+ newW = self.previewSize[0]
+ newH = self.previewSize[0] * h / w
+ else:
+ newH = self.previewSize[0]
+ newW = self.previewSize[0] * w / h
+ return img.Scale(newW, newH, wx.IMAGE_QUALITY_HIGH)
+
+ def DrawWarningText(self, warning):
+ """!Draw text on preview window"""
+ buffer = wx.EmptyBitmap(*self.previewSize)
+ dc = wx.MemoryDC()
+ dc.SelectObject(buffer)
+ dc.SetBrush(wx.Brush(wx.Color(250, 250, 250)))
+ dc.Clear()
+ extent = dc.GetTextExtent(warning)
+ posX = self.previewSize[0] / 2 - extent[0] / 2
+ posY = self.previewSize[1] / 2 - extent[1] / 2
+ dc.DrawText(warning, posX, posY)
+ self.imagePanel.image['preview'].SetBitmap(buffer)
+ dc.SelectObject(wx.NullBitmap)
+
+ def DrawBitmap(self, bitmap):
+ """!Draw bitmap, center it if smaller than preview size"""
+ if bitmap.GetWidth() <= self.previewSize[0] and bitmap.GetHeight() <= self.previewSize[1]:
+ buffer = wx.EmptyBitmap(*self.previewSize)
+ dc = wx.MemoryDC()
+ dc.SelectObject(buffer)
+ dc.SetBrush(dc.GetBrush())
+ dc.Clear()
+ posX = self.previewSize[0] / 2 - bitmap.GetWidth() / 2
+ posY = self.previewSize[1] / 2 - bitmap.GetHeight() / 2
+ dc.DrawBitmap(bitmap, posX, posY)
+ self.imagePanel.image['preview'].SetBitmap(buffer)
+ dc.SelectObject(wx.NullBitmap)
+ else:
+ self.imagePanel.image['preview'].SetBitmap(bitmap)
+
+ def SetSizeInfoLabel(self, image):
+ """!Update image size label"""
+ self.imagePanel.image['sizeInfo'].SetLabel(_("size: %(width)s x %(height)s pts") % \
+ { 'width' : image.GetWidth(),
+ 'height' : image.GetHeight() })
+ self.imagePanel.image['sizeInfo'].GetContainingSizer().Layout()
+
+ def ClearPreview(self):
+ """!Clear preview window"""
+ buffer = wx.EmptyBitmap(*self.previewSize)
+ dc = wx.MemoryDC()
+ dc.SelectObject(buffer)
+ dc.SetBrush(wx.WHITE_BRUSH)
+ dc.Clear()
+ mask = wx.Mask(buffer, wx.WHITE)
+ buffer.SetMask(mask)
+ self.imagePanel.image['preview'].SetBitmap(buffer)
+ dc.SelectObject(wx.NullBitmap)
+
+ def update(self):
+ # epsfile
+ selected = self.imagePanel.image['list'].GetStringSelection()
+ basePath = self.imagePanel.image['dir'].GetValue()
+ if not selected:
+ GMessage(parent = self, message = _("No image selected."))
+ return False
+
+ self.imageDict['epsfile'] = os.path.join(basePath, selected)
+
+ #position
+ if self.positionPanel.position['toPaper'].GetValue():
+ self.imageDict['XY'] = True
+ currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+ self.imageDict['unit'] = currUnit
+ if self.positionPanel.position['xCtrl'].GetValue():
+ x = self.positionPanel.position['xCtrl'].GetValue()
+ else:
+ x = self.imageDict['where'][0]
+
+ if self.positionPanel.position['yCtrl'].GetValue():
+ y = self.positionPanel.position['yCtrl'].GetValue()
+ else:
+ y = self.imageDict['where'][1]
+
+ x = self.unitConv.convert(value = float(x), fromUnit = currUnit, toUnit = 'inch')
+ y = self.unitConv.convert(value = float(y), fromUnit = currUnit, toUnit = 'inch')
+ self.imageDict['where'] = x, y
+
+ else:
+ self.imageDict['XY'] = False
+ if self.positionPanel.position['eCtrl'].GetValue():
+ e = self.positionPanel.position['eCtrl'].GetValue()
+ else:
+ self.imageDict['east'] = self.imageDict['east']
+
+ if self.positionPanel.position['nCtrl'].GetValue():
+ n = self.positionPanel.position['nCtrl'].GetValue()
+ else:
+ self.imageDict['north'] = self.imageDict['north']
+
+ x, y = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.imageDict['east']),
+ y = float(self.imageDict['north']), paperToMap = False)
+
+ #rotation
+ rot = self.imagePanel.image['rotate'].GetValue()
+ if rot == 0:
+ self.imageDict['rotate'] = None
+ else:
+ self.imageDict['rotate'] = rot
+
+ #scale
+ self.imageDict['scale'] = self.imagePanel.image['scale'].GetValue()
+
+ # scale
+ w, h = self.imageObj.GetImageOrigSize(self.imageDict['epsfile'])
+ if self.imageDict['rotate']:
+ self.imageDict['size'] = BBoxAfterRotation(w, h, self.imageDict['rotate'])
+ else:
+ self.imageDict['size'] = w, h
+
+ w = self.unitConv.convert(value = self.imageDict['size'][0],
+ fromUnit = 'point', toUnit = 'inch')
+ h = self.unitConv.convert(value = self.imageDict['size'][1],
+ fromUnit = 'point', toUnit = 'inch')
+
+
+ self.imageDict['rect'] = Rect2D(x = x, y = y,
+ width = w * self.imageDict['scale'],
+ height = h * self.imageDict['scale'])
+
+ if self.id not in self.instruction:
+ image = self._newObject()
+ self.instruction.AddInstruction(image)
+ self.instruction[self.id].SetInstruction(self.imageDict)
+
+ if self.id not in self.parent.objectId:
+ self.parent.objectId.append(self.id)
+
+ return True
+
+ def updateDialog(self):
+ """!Update text coordinates, after moving"""
+ # XY coordinates
+ x, y = self.imageDict['where'][:2]
+ currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+ x = self.unitConv.convert(value = x, fromUnit = 'inch', toUnit = currUnit)
+ y = self.unitConv.convert(value = y, fromUnit = 'inch', toUnit = currUnit)
+ self.positionPanel.position['xCtrl'].SetValue("%5.3f" % x)
+ self.positionPanel.position['yCtrl'].SetValue("%5.3f" % y)
+ # EN coordinates
+ e, n = self.imageDict['east'], self.imageDict['north']
+ self.positionPanel.position['eCtrl'].SetValue(str(self.imageDict['east']))
+ self.positionPanel.position['nCtrl'].SetValue(str(self.imageDict['north']))
+
+
+class NorthArrowDialog(ImageDialog):
+ def __init__(self, parent, id, settings):
+ ImageDialog.__init__(self, parent = parent, id = id, settings = settings,
+ imagePanelName = _("North Arrow"))
+
+ self.objectType = ('northArrow',)
+ self.SetTitle(_("North Arrow settings"))
+
+ def _newObject(self):
+ return NorthArrow(self.id, self.instruction)
+
+ def _getImageDirectory(self):
+ gisbase = os.getenv("GISBASE")
+ return os.path.join(gisbase, 'etc', 'paint', 'decorations')
+
+ def _addConvergence(self, panel, gridBagSizer):
+ convergence = wx.Button(parent = panel, id = wx.ID_ANY,
+ label = _("Compute convergence"))
+ gridBagSizer.Add(item = convergence, pos = (1, 2),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+ convergence.Bind(wx.EVT_BUTTON, self.OnConvergence)
+ panel.image['convergence'] = convergence
+
+ def OnConvergence(self, event):
+ ret = RunCommand('g.region', read = True, flags = 'ng')
+ if ret:
+ convergence = float(ret.strip().split('=')[1])
+ if convergence < 0:
+ self.imagePanel.image['rotate'].SetValue(abs(convergence))
+ else:
+ self.imagePanel.image['rotate'].SetValue(360 - convergence)
+
+
+class PointDialog(PsmapDialog):
+ """!Dialog for setting point properties."""
+ def __init__(self, parent, id, settings, coordinates = None, pointPanelName = _("Point")):
+ PsmapDialog.__init__(self, parent = parent, id = id, title = "Point settings",
+ settings = settings)
+
+ self.objectType = ('point',)
+ if self.id is not None:
+ self.pointObj = self.instruction[self.id]
+ self.pointDict = self.instruction[id].GetInstruction()
+ else:
+ self.id = wx.NewId()
+ self.pointObj = Point(self.id)
+ self.pointDict = self.pointObj.GetInstruction()
+ self.pointDict['where'] = coordinates
+ self.defaultDict = self.pointObj.defaultInstruction
+
+ mapObj = self.instruction.FindInstructionByType('map')
+ if not mapObj:
+ mapObj = self.instruction.FindInstructionByType('initMap')
+ self.mapId = mapObj.id
+
+ self.pointDict['east'], self.pointDict['north'] = PaperMapCoordinates(mapInstr = mapObj, x = self.pointDict['where'][0], y = self.pointDict['where'][1], paperToMap = True)
+
+ notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+ self.pointPanelName = pointPanelName
+ self.pointPanel = self._pointPanel(notebook)
+ self.positionPanel = self._positionPanel(notebook)
+ self.OnPositionType(None)
+
+
+ self._layout(notebook)
+
+ def _pointPanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = self.pointPanelName)
+ border = wx.BoxSizer(wx.VERTICAL)
+ #
+ # choose image
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Symbol"))
+ sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
+
+ gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridSizer.AddGrowableCol(1)
+
+ gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select symbol:")),
+ pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ self.symbolLabel = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = self.pointDict['symbol'])
+ gridSizer.Add(item = self.symbolLabel, pos = (0, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL )
+ bitmap = wx.Bitmap(os.path.join(globalvar.ETCSYMBOLDIR,
+ self.pointDict['symbol']) + '.png')
+ self.symbolButton = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bitmap)
+ self.symbolButton.Bind(wx.EVT_BUTTON, self.OnSymbolSelection)
+
+ gridSizer.Add(self.symbolButton, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+ self.noteLabel = wx.StaticText(parent = panel, id = wx.ID_ANY,
+ label = _("Note: Selected symbol is not displayed\n"
+ "in draft mode (only in preview mode)"))
+ gridSizer.Add(self.noteLabel, pos = (1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ sizer.Add(item = gridSizer, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #
+ # outline/fill color
+ #
+
+ # outline
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Color"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+ outlineLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Outline color:"))
+ self.outlineColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.outlineTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+ if self.pointDict['color'] != 'none':
+ self.outlineTranspCtrl.SetValue(False)
+ self.outlineColorCtrl.SetColour(convertRGB(self.pointDict['color']))
+ else:
+ self.outlineTranspCtrl.SetValue(True)
+ self.outlineColorCtrl.SetColour(convertRGB(self.defaultDict['color']))
+
+ gridSizer.Add(item = outlineLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.outlineColorCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.outlineTranspCtrl, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ fillLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Fill color:"))
+ self.fillColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.fillTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+ if self.pointDict['fcolor'] != 'none':
+ self.fillTranspCtrl.SetValue(False)
+ self.fillColorCtrl.SetColour(convertRGB(self.pointDict['fcolor']))
+ else:
+ self.fillTranspCtrl.SetValue(True)
+ self.fillColorCtrl.SetColour(convertRGB(self.defaultDict['fcolor']))
+
+ gridSizer.Add(item = fillLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.fillColorCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.fillTranspCtrl, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ #
+ # size and rotation
+ #
+
+ # size
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Size and Rotation"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+ sizeLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Size (pt):"))
+ self.sizeCtrl = wx.SpinCtrl(panel, id = wx.ID_ANY, size = self.spinCtrlSize)
+ self.sizeCtrl.SetToolTipString(_("Symbol size in points"))
+ self.sizeCtrl.SetValue(self.pointDict['size'])
+
+ gridSizer.Add(item = sizeLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.sizeCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ # rotation
+ rotLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Rotation angle (deg):"))
+ if fs:
+ self.rotCtrl = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = -360, max_val = 360,
+ increment = 1, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+ self.rotCtrl.SetFormat("%f")
+ self.rotCtrl.SetDigits(1)
+ else:
+ self.rotCtrl = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+ min = -360, max = 360, initial = 0)
+ self.rotCtrl.SetToolTipString(_("Counterclockwise rotation in degrees"))
+ self.rotCtrl.SetValue(float(self.pointDict['rotate']))
+
+ gridSizer.Add(item = rotLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ gridSizer.Add(item = self.rotCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ sizer.Add(item = gridSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ return panel
+
+ def _positionPanel(self, notebook):
+ panel = wx.Panel(parent = notebook, id = wx.ID_ANY, size = (-1, -1), style = wx.TAB_TRAVERSAL)
+ notebook.AddPage(page = panel, text = _("Position"))
+ border = wx.BoxSizer(wx.VERTICAL)
+ #
+ # set position
+ #
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Position"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridBagSizer.AddGrowableCol(0)
+ gridBagSizer.AddGrowableCol(1)
+
+ self.AddExtendedPosition(panel, gridBagSizer, self.pointDict)
+
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toPaper'])
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnPositionType, panel.position['toMap'])
+
+
+ sizer.Add(gridBagSizer, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL| wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+ panel.Fit()
+
+ return panel
+
+ def OnPositionType(self, event):
+ if self.positionPanel.position['toPaper'].GetValue():
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Disable()
+ else:
+ for widget in self.gridBagSizerM.GetChildren():
+ widget.GetWindow().Enable()
+ for widget in self.gridBagSizerP.GetChildren():
+ widget.GetWindow().Disable()
+
+ def OnSymbolSelection(self, event):
+ dlg = SymbolDialog(self, symbolPath = globalvar.ETCSYMBOLDIR,
+ currentSymbol = self.symbolLabel.GetLabel())
+ if dlg.ShowModal() == wx.ID_OK:
+ img = dlg.GetSelectedSymbol(fullPath = True)
+ name = dlg.GetSelectedSymbol(fullPath = False)
+ self.symbolButton.SetBitmapLabel(wx.Bitmap(img + '.png'))
+ self.symbolLabel.SetLabel(name)
+
+ dlg.Destroy()
+
+ def update(self):
+ # symbol
+ self.pointDict['symbol'] = self.symbolLabel.GetLabel()
+
+
+ #position
+ if self.positionPanel.position['toPaper'].GetValue():
+ self.pointDict['XY'] = True
+ currUnit = self.unitConv.findUnit(self.positionPanel.units['unitsCtrl'].GetStringSelection())
+ self.pointDict['unit'] = currUnit
+ if self.positionPanel.position['xCtrl'].GetValue():
+ x = self.positionPanel.position['xCtrl'].GetValue()
+ else:
+ x = self.pointDict['where'][0]
+
+ if self.positionPanel.position['yCtrl'].GetValue():
+ y = self.positionPanel.position['yCtrl'].GetValue()
+ else:
+ y = self.pointDict['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.pointDict['where'] = x, y
+
+ else:
+ self.pointDict['XY'] = False
+ if self.positionPanel.position['eCtrl'].GetValue():
+ e = self.positionPanel.position['eCtrl'].GetValue()
+ else:
+ self.pointDict['east'] = self.pointDict['east']
+
+ if self.positionPanel.position['nCtrl'].GetValue():
+ n = self.positionPanel.position['nCtrl'].GetValue()
+ else:
+ self.pointDict['north'] = self.pointDict['north']
+
+ x, y = PaperMapCoordinates(mapInstr = self.instruction[self.mapId], x = float(self.pointDict['east']),
+ y = float(self.pointDict['north']), paperToMap = False)
+
+ #rotation
+ self.pointDict['rotate'] = self.rotCtrl.GetValue()
+
+ # size
+ self.pointDict['size'] = self.sizeCtrl.GetValue()
+
+ w = h = self.unitConv.convert(value = self.pointDict['size'],
+ fromUnit = 'point', toUnit = 'inch')
+
+ # outline color
+ if self.outlineTranspCtrl.GetValue():
+ self.pointDict['color'] = 'none'
+ else:
+ self.pointDict['color'] = convertRGB(self.outlineColorCtrl.GetColour())
+
+ # fill color
+ if self.fillTranspCtrl.GetValue():
+ self.pointDict['fcolor'] = 'none'
+ else:
+ self.pointDict['fcolor'] = convertRGB(self.fillColorCtrl.GetColour())
+
+ self.pointDict['rect'] = Rect2D(x = x - w / 2, y = y - h / 2, width = w, height = h)
+
+ if self.id not in self.instruction:
+ point = Point(self.id)
+ self.instruction.AddInstruction(point)
+ self.instruction[self.id].SetInstruction(self.pointDict)
+
+ if self.id not in self.parent.objectId:
+ self.parent.objectId.append(self.id)
+
+ return True
+
+ def updateDialog(self):
+ """!Update text coordinates, after moving"""
+ # XY coordinates
+ x, y = self.pointDict['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.pointDict['east'], self.pointDict['north']
+ self.positionPanel.position['eCtrl'].SetValue(str(self.pointDict['east']))
+ self.positionPanel.position['nCtrl'].SetValue(str(self.pointDict['north']))
+
+class RectangleDialog(PsmapDialog):
+ def __init__(self, parent, id, settings, type = 'rectangle', coordinates = None):
+ """!
+
+ @param coordinates begin and end point coordinate (wx.Point, wx.Point)
+ """
+ if type == 'rectangle':
+ title = _("Rectangle settings")
+ else:
+ title = _("Line settings")
+ PsmapDialog.__init__(self, parent = parent, id = id, title = title, settings = settings)
+
+ self.objectType = (type,)
+
+ if self.id is not None:
+ self.rectObj = self.instruction[self.id]
+ self.rectDict = self.rectObj.GetInstruction()
+ else:
+ self.id = wx.NewId()
+ if type == 'rectangle':
+ self.rectObj = Rectangle(self.id)
+ else:
+ self.rectObj = Line(self.id)
+ self.rectDict = self.rectObj.GetInstruction()
+
+ self.rectDict['rect'] = Rect2DPP(coordinates[0], coordinates[1])
+ self.rectDict['where'] = coordinates
+
+ self.defaultDict = self.rectObj.defaultInstruction
+ self.panel = self._rectPanel()
+
+ self._layout(self.panel)
+
+ def _rectPanel(self):
+ panel = wx.Panel(parent = self, id = wx.ID_ANY, style = wx.TAB_TRAVERSAL)
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ # color
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Color"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+ outlineLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Outline color:"))
+ self.outlineColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.outlineTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+ if self.rectDict['color'] != 'none':
+ self.outlineTranspCtrl.SetValue(False)
+ self.outlineColorCtrl.SetColour(convertRGB(self.rectDict['color']))
+ else:
+ self.outlineTranspCtrl.SetValue(True)
+ self.outlineColorCtrl.SetColour(convertRGB(self.defaultDict['color']))
+
+ # transparent outline makes sense only for rectangle
+ if self.objectType == ('line',):
+ self.outlineTranspCtrl.Hide()
+
+ gridSizer.Add(item = outlineLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.outlineColorCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.outlineTranspCtrl, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ # fill color only in rectangle
+ if self.objectType == ('rectangle',):
+ fillLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Fill color:"))
+ self.fillColorCtrl = wx.ColourPickerCtrl(panel, id = wx.ID_ANY)
+ self.fillTranspCtrl = wx.CheckBox(panel, id = wx.ID_ANY, label = _("transparent"))
+
+ if self.rectDict['fcolor'] != 'none':
+ self.fillTranspCtrl.SetValue(False)
+ self.fillColorCtrl.SetColour(convertRGB(self.rectDict['fcolor']))
+ else:
+ self.fillTranspCtrl.SetValue(True)
+ self.fillColorCtrl.SetColour(wx.WHITE)
+
+ gridSizer.Add(item = fillLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.fillColorCtrl, pos = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.fillTranspCtrl, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ sizer.Add(gridSizer, proportion = 1, flag = wx.EXPAND|wx.ALL, border = 5)
+ border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+ gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+
+ # width
+ box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Line style"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ widthLabel = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width:"))
+ if fs:
+ self.widthCtrl = fs.FloatSpin(panel, id = wx.ID_ANY, min_val = 0, max_val = 50,
+ increment = 1, value = 0, style = fs.FS_RIGHT, size = self.spinCtrlSize)
+ self.widthCtrl.SetFormat("%f")
+ self.widthCtrl.SetDigits(1)
+ else:
+ self.widthCtrl = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = self.spinCtrlSize,
+ min = -360, max = 360, initial = 0)
+ self.widthCtrl.SetToolTipString(_("Line width in points"))
+ self.widthCtrl.SetValue(float(self.rectDict['width']))
+
+ gridSizer.Add(item = widthLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item = self.widthCtrl, pos = (0, 1), flag = wx.ALIGN_CENTER_VERTICAL)
+
+ sizer.Add(gridSizer, 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)
+
+ return panel
+
+
+ def update(self):
+ mapInstr = self.instruction.FindInstructionByType('map')
+ if not mapInstr:
+ mapInstr = self.instruction.FindInstructionByType('initMap')
+ self.mapId = mapInstr.id
+ point1 = self.rectDict['where'][0]
+ point2 = self.rectDict['where'][1]
+ self.rectDict['east1'], self.rectDict['north1'] = PaperMapCoordinates(mapInstr = mapInstr,
+ x = point1[0],
+ y = point1[1],
+ paperToMap = True)
+ self.rectDict['east2'], self.rectDict['north2'] = PaperMapCoordinates(mapInstr = mapInstr,
+ x = point2[0],
+ y = point2[1],
+ paperToMap = True)
+ # width
+ self.rectDict['width'] = self.widthCtrl.GetValue()
+
+ # outline color
+ if self.outlineTranspCtrl.GetValue():
+ self.rectDict['color'] = 'none'
+ else:
+ self.rectDict['color'] = convertRGB(self.outlineColorCtrl.GetColour())
+
+ # fill color
+ if self.objectType == ('rectangle',):
+ if self.fillTranspCtrl.GetValue():
+ self.rectDict['fcolor'] = 'none'
+ else:
+ self.rectDict['fcolor'] = convertRGB(self.fillColorCtrl.GetColour())
+
+ if self.id not in self.instruction:
+ if self.objectType == ('rectangle',):
+ rect = Rectangle(self.id)
+ else:
+ rect = Line(self.id)
+ self.instruction.AddInstruction(rect)
+
+ self.instruction[self.id].SetInstruction(self.rectDict)
+
+ 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"""
+ pass
+
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/frame.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/frame.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/frame.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,2176 @@
+"""!
+ at package psmap.frame
+
+ at brief GUI for ps.map
+
+Classes:
+ - frame::PsMapFrame
+ - frame::PsMapBufferedWindow
+
+(C) 2011-2012 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, sqrt
+
+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 core.gcmd import RunCommand, GError, GMessage
+from core.settings import UserSettings
+from gui_core.forms import GUI
+from psmap.menudata import PsMapData
+
+from psmap.dialogs import *
+from psmap.instructions import *
+from psmap.utils 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),
+ 'image': wx.Pen(colour = wx.Color(255, 150, 50), width = 2),
+ 'northArrow': wx.Pen(colour = wx.Color(200, 200, 200), width = 2),
+ 'point': wx.Pen(colour = wx.Color(100, 100, 100), width = 2),
+ 'line': wx.Pen(colour = wx.Color(0, 0, 0), width = 2),
+ 'box': wx.Pen(colour = 'RED', width = 2, style = wx.SHORT_DASH),
+ 'select': wx.Pen(colour = 'BLACK', width = 1, style = wx.SHORT_DASH),
+ 'resize': wx.Pen(colour = 'BLACK', width = 1)
+ }
+ self.brush = {
+ 'paper': wx.WHITE_BRUSH,
+ 'margins': wx.TRANSPARENT_BRUSH,
+ 'map': wx.Brush(wx.Color(151, 214, 90)),
+ 'rasterLegend': wx.Brush(wx.Color(250, 247, 112)),
+ 'vectorLegend': wx.Brush(wx.Color(250, 247, 112)),
+ 'mapinfo': wx.Brush(wx.Color(127, 222, 252)),
+ 'scalebar': wx.Brush(wx.Color(200, 200, 200)),
+ 'image': wx.Brush(wx.Color(255, 200, 50)),
+ 'northArrow': wx.Brush(wx.Color(255, 255, 255)),
+ 'point': wx.Brush(wx.Color(200, 200, 200)),
+ 'line': wx.TRANSPARENT_BRUSH,
+ '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 = grass.tempfile()
+
+ #canvas for preview
+ self.previewCanvas = PsMapBufferedWindow(parent = self, mouse = self.mouse, cursors = self.cursors,
+ pen = self.pen, brush = self.brush, preview = True)
+
+ # set WIND_OVERRIDE
+ grass.use_temp_region()
+
+ # create queues
+ self.requestQ = Queue.Queue()
+ self.resultQ = Queue.Queue()
+ # thread
+ self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
+
+ self._layout()
+ self.SetMinSize(wx.Size(750, 600))
+
+ self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging)
+ self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
+ self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+ self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+
+ if not havePILImage:
+ wx.CallAfter(self._showErrMsg)
+
+ def _showErrMsg(self):
+ """!Show error message (missing preview)
+ """
+ GError(parent = self,
+ message = _("Python Imaging Library is not available.\n"
+ "'Preview' functionality won't work."),
+ showTraceback = False)
+
+ def _layout(self):
+ """!Do layout
+ """
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ if globalvar.hasAgw:
+ self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
+ agwStyle = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
+ fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
+ else:
+ self.book = fnb.FlatNotebook(parent = self, id = wx.ID_ANY,
+ style = fnb.FNB_FANCY_TABS | fnb.FNB_BOTTOM |
+ fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON)
+ #self.book = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM)
+ self.book.AddPage(self.canvas, "Draft mode")
+ self.book.AddPage(self.previewCanvas, "Preview")
+ self.book.SetSelection(0)
+
+ mainSizer.Add(self.book,1, wx.EXPAND)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+
+ def InstructionFile(self):
+ """!Creates mapping instructions"""
+
+ return str(self.instruction)
+
+ def OnPSFile(self, event):
+ """!Generate PostScript"""
+ filename = self.getFile(wildcard = "PostScript (*.ps)|*.ps|Encapsulated PostScript (*.eps)|*.eps")
+ if filename:
+ self.PSFile(filename)
+
+ def OnPsMapDialog(self, event):
+ """!Launch ps.map dialog
+ """
+ GUI(parent = self).ParseCommand(cmd = ['ps.map'])
+
+ def OnPDFFile(self, event):
+ """!Generate PDF from PS with ps2pdf if available"""
+ try:
+ p = grass.Popen(["ps2pdf"], stderr = grass.PIPE)
+ p.stderr.close()
+
+ except OSError:
+ GMessage(parent = self,
+ message = _("Program ps2pdf is not available. Please install it first to create PDF."))
+ return
+
+ filename = self.getFile(wildcard = "PDF (*.pdf)|*.pdf")
+ if filename:
+ self.PSFile(filename, pdf = True)
+
+ def OnPreview(self, event):
+ """!Run ps.map and show result"""
+ self.PSFile()
+
+ def PSFile(self, filename = None, pdf = False):
+ """!Create temporary instructions file and run ps.map with output = filename"""
+ instrFile = grass.tempfile()
+ instrFileFd = open(instrFile, mode = 'w')
+ instrFileFd.write(self.InstructionFile())
+ instrFileFd.flush()
+ instrFileFd.close()
+
+ temp = False
+ regOld = grass.region()
+
+ if pdf:
+ pdfname = filename
+ else:
+ pdfname = None
+ #preview or pdf
+ if not filename or (filename and pdf):
+ temp = True
+ filename = grass.tempfile()
+ if not pdf: # lower resolution for preview
+ if self.instruction.FindInstructionByType('map'):
+ mapId = self.instruction.FindInstructionByType('map').id
+ SetResolution(dpi = 100, width = self.instruction[mapId]['rect'][2],
+ height = self.instruction[mapId]['rect'][3])
+
+ cmd = ['ps.map', '--overwrite']
+ if os.path.splitext(filename)[1] == '.eps':
+ cmd.append('-e')
+ if self.instruction[self.pageId]['Orientation'] == 'Landscape':
+ cmd.append('-r')
+ cmd.append('input=%s' % instrFile)
+ cmd.append('output=%s' % filename)
+ if pdf:
+ self.SetStatusText(_('Generating PDF...'), 0)
+ elif not temp:
+ self.SetStatusText(_('Generating PostScript...'), 0)
+ else:
+ self.SetStatusText(_('Generating preview...'), 0)
+
+ self.cmdThread.RunCmd(cmd, userData = {'instrFile' : instrFile, 'filename' : filename,
+ 'pdfname' : pdfname, 'temp' : temp, 'regionOld' : regOld})
+
+ def OnCmdDone(self, event):
+ """!ps.map process finished"""
+
+ if event.returncode != 0:
+ GMessage(parent = self,
+ message = _("Ps.map exited with return code %s") % event.returncode)
+
+ grass.try_remove(event.userData['instrFile'])
+ if event.userData['temp']:
+ grass.try_remove(event.userData['filename'])
+ return
+
+ if event.userData['pdfname']:
+ try:
+ proc = grass.Popen(['ps2pdf', '-dPDFSETTINGS=/prepress', '-r1200',
+ event.userData['filename'], event.userData['pdfname']])
+
+ ret = proc.wait()
+ if ret > 0:
+ GMessage(parent = self,
+ message = _("ps2pdf exited with return code %s") % ret)
+
+ except OSError, e:
+ GError(parent = self,
+ message = _("Program ps2pdf is not available. Please install it to create PDF.\n\n %s") % e)
+
+ # show preview only when user doesn't want to create ps or pdf
+ if havePILImage and event.userData['temp'] and not event.userData['pdfname']:
+ RunCommand('g.region', cols = event.userData['regionOld']['cols'], rows = event.userData['regionOld']['rows'])
+## wx.BusyInfo does not display the message
+## busy = wx.BusyInfo(message = "Generating preview, wait please", parent = self)
+
+ try:
+ im = PILImage.open(event.userData['filename'])
+ if self.instruction[self.pageId]['Orientation'] == 'Landscape':
+ im = im.rotate(270)
+
+ im.save(self.imgName, format = 'PNG')
+
+ except IOError, e:
+ GError(parent = self,
+ message = _("Unable to generate preview. %s") % e)
+ return
+
+
+ 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 OnAddScalebar(self, event):
+ """!Add scalebar"""
+ if projInfo()['proj'] == 'll':
+ GMessage(message = _("Scalebar is not appropriate for this projection"))
+ return
+ if self.instruction.FindInstructionByType('scalebar'):
+ id = self.instruction.FindInstructionByType('scalebar').id
+ else: id = None
+
+ if 'scalebar' not in self.openDialogs:
+ dlg = ScalebarDialog(self, id = id, settings = self.instruction)
+ self.openDialogs['scalebar'] = dlg
+ self.openDialogs['scalebar'].Show()
+
+ def OnAddLegend(self, event, page = 0):
+ """!Add raster or vector legend"""
+ if self.instruction.FindInstructionByType('rasterLegend'):
+ idR = self.instruction.FindInstructionByType('rasterLegend').id
+ else: idR = None
+ if self.instruction.FindInstructionByType('vectorLegend'):
+ idV = self.instruction.FindInstructionByType('vectorLegend').id
+ else: idV = None
+
+ if 'rasterLegend' not in self.openDialogs:
+ dlg = LegendDialog(self, id = [idR, idV], settings = self.instruction, page = page)
+ self.openDialogs['rasterLegend'] = dlg
+ self.openDialogs['vectorLegend'] = dlg
+ self.openDialogs['rasterLegend'].notebook.ChangeSelection(page)
+ self.openDialogs['rasterLegend'].Show()
+
+ def OnAddMapinfo(self, event):
+ if self.instruction.FindInstructionByType('mapinfo'):
+ id = self.instruction.FindInstructionByType('mapinfo').id
+ else: id = None
+
+ if 'mapinfo' not in self.openDialogs:
+ dlg = MapinfoDialog(self, id = id, settings = self.instruction)
+ self.openDialogs['mapinfo'] = dlg
+ self.openDialogs['mapinfo'].Show()
+
+ def OnAddImage(self, event, id = None):
+ """!Show dialog for image adding and editing"""
+ position = None
+ if 'image' in self.openDialogs:
+ position = self.openDialogs['image'].GetPosition()
+ self.openDialogs['image'].OnApply(event = None)
+ self.openDialogs['image'].Destroy()
+ dlg = ImageDialog(self, id = id, settings = self.instruction)
+ self.openDialogs['image'] = dlg
+ if position:
+ dlg.SetPosition(position)
+ dlg.Show()
+
+ def OnAddNorthArrow(self, event, id = None):
+ """!Show dialog for north arrow adding and editing"""
+ if self.instruction.FindInstructionByType('northArrow'):
+ id = self.instruction.FindInstructionByType('northArrow').id
+ else: id = None
+
+ if 'northArrow' not in self.openDialogs:
+ dlg = NorthArrowDialog(self, id = id, settings = self.instruction)
+ self.openDialogs['northArrow'] = dlg
+ self.openDialogs['northArrow'].Show()
+
+ def OnAddText(self, event, id = None):
+ """!Show dialog for text adding and editing"""
+ position = None
+ if 'text' in self.openDialogs:
+ position = self.openDialogs['text'].GetPosition()
+ self.openDialogs['text'].OnApply(event = None)
+ self.openDialogs['text'].Destroy()
+ dlg = TextDialog(self, id = id, settings = self.instruction)
+ self.openDialogs['text'] = dlg
+ if position:
+ dlg.SetPosition(position)
+ dlg.Show()
+
+ def OnAddPoint(self, event):
+ """!Add point action selected"""
+ self.mouse["use"] = "addPoint"
+ self.canvas.SetCursor(self.cursors["cross"])
+
+ def AddPoint(self, id = None, coordinates = None):
+ """!Add point and open property dialog.
+
+ @param id id point id (None if creating new point)
+ @param coordinates coordinates of new point
+ """
+ position = None
+ if 'point' in self.openDialogs:
+ position = self.openDialogs['point'].GetPosition()
+ self.openDialogs['point'].OnApply(event = None)
+ self.openDialogs['point'].Destroy()
+ dlg = PointDialog(self, id = id, settings = self.instruction,
+ coordinates = coordinates)
+ self.openDialogs['point'] = dlg
+ if position:
+ dlg.SetPosition(position)
+ if coordinates:
+ dlg.OnApply(event = None)
+ dlg.Show()
+
+ def OnAddLine(self, event):
+ """!Add line action selected"""
+ self.mouse["use"] = "addLine"
+ self.canvas.SetCursor(self.cursors["cross"])
+
+ def AddLine(self, id = None, coordinates = None):
+ """!Add line and open property dialog.
+
+ @param id id line id (None if creating new line)
+ @param coordinates coordinates of new line
+ """
+ position = None
+ if 'line' in self.openDialogs:
+ position = self.openDialogs['line'].GetPosition()
+ self.openDialogs['line'].OnApply(event = None)
+ self.openDialogs['line'].Destroy()
+ dlg = RectangleDialog(self, id = id, settings = self.instruction,
+ type = 'line', coordinates = coordinates)
+ self.openDialogs['line'] = dlg
+ if position:
+ dlg.SetPosition(position)
+ if coordinates:
+ dlg.OnApply(event = None)
+ dlg.Show()
+
+ def OnAddRectangle(self, event):
+ """!Add rectangle action selected"""
+ self.mouse["use"] = "addRectangle"
+ self.canvas.SetCursor(self.cursors["cross"])
+
+ def AddRectangle(self, id = None, coordinates = None):
+ """!Add rectangle and open property dialog.
+
+ @param id id rectangle id (None if creating new rectangle)
+ @param coordinates coordinates of new rectangle
+ """
+ position = None
+ if 'rectangle' in self.openDialogs:
+ position = self.openDialogs['rectangle'].GetPosition()
+ self.openDialogs['rectangle'].OnApply(event = None)
+ self.openDialogs['rectangle'].Destroy()
+ dlg = RectangleDialog(self, id = id, settings = self.instruction,
+ type = 'rectangle', coordinates = coordinates)
+ self.openDialogs['rectangle'] = dlg
+ if position:
+ dlg.SetPosition(position)
+ if coordinates:
+ dlg.OnApply(event = None)
+ 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.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
+
+ fn = self.makePSFont(textDict)
+
+ try:
+ dc.SetFont(fn)
+ w,h,lh = dc.GetMultiLineTextExtent(textDict['text'])
+ return (w,h)
+ except:
+ return (0,0)
+
+ def getInitMap(self):
+ """!Create default map frame when no map is selected, needed for coordinates in map units"""
+ instrFile = grass.tempfile()
+ instrFileFd = open(instrFile, mode = 'w')
+ instrFileFd.write(self.InstructionFile())
+ instrFileFd.flush()
+ instrFileFd.close()
+
+ page = self.instruction.FindInstructionByType('page')
+ mapInitRect = GetMapBounds(instrFile, portrait = (page['Orientation'] == 'Portrait'))
+ grass.try_remove(instrFile)
+
+ region = grass.region()
+ units = UnitConversion(self)
+ realWidth = units.convert(value = abs(region['w'] - region['e']), fromUnit = 'meter', toUnit = 'inch')
+ scale = mapInitRect.Get()[2]/realWidth
+
+ initMap = self.instruction.FindInstructionByType('initMap')
+ if initMap:
+ id = initMap.id
+ else:
+ id = None
+
+
+ if not id:
+ id = wx.NewId()
+ initMap = InitMap(id)
+ self.instruction.AddInstruction(initMap)
+ self.instruction[id].SetInstruction(dict(rect = mapInitRect, scale = scale))
+
+ def OnDelete(self, event):
+ if self.canvas.dragId != -1 and self.currentPage == 0:
+ if self.instruction[self.canvas.dragId].type == 'map':
+ self.deleteObject(self.canvas.dragId)
+ self.getInitMap()
+ self.canvas.RecalculateEN()
+ else:
+ self.deleteObject(self.canvas.dragId)
+
+ def deleteObject(self, id):
+ """!Deletes object, his id and redraws"""
+ #delete from canvas
+ self.canvas.pdcObj.RemoveId(id)
+ if id == self.canvas.dragId:
+ self.canvas.pdcTmp.RemoveAll()
+ self.canvas.dragId = -1
+ self.canvas.Refresh()
+
+ # delete from instructions
+ del self.instruction[id]
+
+ def DialogDataChanged(self, id):
+ ids = id
+ if type(id) == int:
+ ids = [id]
+ for id in ids:
+ itype = self.instruction[id].type
+
+ if itype in ('scalebar', 'mapinfo', 'image'):
+ drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+ self.canvas.UpdateLabel(itype = itype, id = id)
+ self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+ pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+ self.canvas.RedrawSelectBox(id)
+ if itype == 'northArrow':
+ self.canvas.UpdateLabel(itype = itype, id = id)
+ drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+ self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+ pdc = self.canvas.pdcObj, drawid = id, pdctype = 'bitmap', bb = drawRectangle)
+ self.canvas.RedrawSelectBox(id)
+
+ if itype in ('point', 'line', 'rectangle'):
+ drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+ # coords only for line
+ coords = None
+ if itype == 'line':
+ point1 = self.instruction[id]['where'][0]
+ point2 = self.instruction[id]['where'][1]
+ point1Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)), canvasToPaper = False)[:2]
+ point2Coords = self.canvas.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)), canvasToPaper = False)[:2]
+ coords = (point1Coords, point2Coords)
+
+ # fill color is not in line
+ fcolor = None
+ if 'fcolor' in self.instruction[id].GetInstruction():
+ fcolor = self.instruction[id]['fcolor']
+ # width is not in point
+ width = None
+ if 'width' in self.instruction[id].GetInstruction():
+ width = self.instruction[id]['width']
+
+ self.canvas.DrawGraphics(drawid = id, color = self.instruction[id]['color'], shape = itype,
+ fcolor = fcolor, width = width, bb = drawRectangle, lineCoords = coords)
+
+ 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 = Rect2DPS(self.instruction[id]['where'], (0, 0))
+ self.instruction[id]['coords'] = list(self.canvas.CanvasPaperCoordinates(rect = rect, canvasToPaper = False)[:2])
+
+ #computes text coordinates according to reference point, not precisely
+ if self.instruction[id]['ref'].split()[0] == 'lower':
+ self.instruction[id]['coords'][1] -= extent[1]
+ elif self.instruction[id]['ref'].split()[0] == 'center':
+ self.instruction[id]['coords'][1] -= extent[1]/2
+ if self.instruction[id]['ref'].split()[1] == 'right':
+ self.instruction[id]['coords'][0] -= extent[0] * cos(rot/180*pi)
+ self.instruction[id]['coords'][1] += extent[0] * sin(rot/180*pi)
+ elif self.instruction[id]['ref'].split()[1] == 'center':
+ self.instruction[id]['coords'][0] -= extent[0]/2 * cos(rot/180*pi)
+ self.instruction[id]['coords'][1] += extent[0]/2 * sin(rot/180*pi)
+
+ self.instruction[id]['coords'][0] += self.instruction[id]['xoffset']
+ self.instruction[id]['coords'][1] -= self.instruction[id]['yoffset']
+ coords = self.instruction[id]['coords']
+ self.instruction[id]['rect'] = bounds = self.getModifiedTextBounds(coords[0], coords[1], extent, rot)
+ self.canvas.DrawRotText(pdc = self.canvas.pdcObj, drawId = id,
+ textDict = self.instruction[id].GetInstruction(),
+ coords = coords, bounds = bounds)
+ self.canvas.RedrawSelectBox(id)
+
+ if itype in ('map', 'vector', 'raster'):
+
+ if itype == 'raster':#set resolution
+ info = grass.raster_info(self.instruction[id]['raster'])
+ RunCommand('g.region', nsres = info['nsres'], ewres = info['ewres'])
+ # change current raster in raster legend
+
+ if 'rasterLegend' in self.openDialogs:
+ self.openDialogs['rasterLegend'].updateDialog()
+ id = self.instruction.FindInstructionByType('map').id
+
+ #check resolution
+ if itype == 'raster':
+ SetResolution(dpi = self.instruction[id]['resolution'],
+ width = self.instruction[id]['rect'].width,
+ height = self.instruction[id]['rect'].height)
+ rectCanvas = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'],
+ canvasToPaper = False)
+ self.canvas.RecalculateEN()
+ self.canvas.UpdateMapLabel()
+
+ self.canvas.Draw(pen = self.pen['map'], brush = self.brush['map'],
+ pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = rectCanvas)
+ # redraw select box
+ self.canvas.RedrawSelectBox(id)
+ self.canvas.pdcTmp.RemoveId(self.canvas.idZoomBoxTmp)
+ # redraw to get map to the bottom layer
+ #self.canvas.Zoom(zoomFactor = 1, view = (0, 0))
+
+ if itype == 'rasterLegend':
+ if self.instruction[id]['rLegend']:
+ self.canvas.UpdateLabel(itype = itype, id = id)
+ drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+ self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+ pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+ self.canvas.RedrawSelectBox(id)
+ else:
+ self.deleteObject(id)
+
+ if itype == 'vectorLegend':
+ if not self.instruction.FindInstructionByType('vector'):
+ self.deleteObject(id)
+ elif self.instruction[id]['vLegend']:
+ self.canvas.UpdateLabel(itype = itype, id = id)
+ drawRectangle = self.canvas.CanvasPaperCoordinates(rect = self.instruction[id]['rect'], canvasToPaper = False)
+ self.canvas.Draw(pen = self.pen[itype], brush = self.brush[itype],
+ pdc = self.canvas.pdcObj, drawid = id, pdctype = 'rectText', bb = drawRectangle)
+ self.canvas.RedrawSelectBox(id)
+
+ else:
+ self.deleteObject(id)
+
+ def OnPageChanged(self, event):
+ """!Flatnotebook page has changed"""
+ self.currentPage = self.book.GetPageIndex(self.book.GetCurrentPage())
+
+
+ def OnPageChanging(self, event):
+ """!Flatnotebook page is changing"""
+ if self.currentPage == 0 and self.mouse['use'] == 'addMap':
+ event.Veto()
+
+ def OnHelp(self, event):
+ """!Show help"""
+ if self.parent and self.parent.GetName() == 'LayerManager':
+ log = self.parent.GetLogWindow()
+ log.RunCmd(['g.manual',
+ 'entry=wxGUI.PsMap'])
+ else:
+ RunCommand('g.manual',
+ quiet = True,
+ entry = 'wxGUI.PsMap')
+
+ def OnAbout(self, event):
+ """!Display About window"""
+ info = wx.AboutDialogInfo()
+
+ info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+ info.SetName(_('wxGUI Cartographic Composer'))
+ info.SetWebSite('http://grass.osgeo.org')
+ info.SetDescription(_('(C) 2011 by the GRASS Development Team\n\n') +
+ '\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
+ '(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
+
+ wx.AboutBox(info)
+
+ def OnCloseWindow(self, event):
+ """!Close window"""
+ try:
+ os.remove(self.imgName)
+ except OSError:
+ pass
+ grass.set_raise_on_error(False)
+ self.Destroy()
+
+
+
+class PsMapBufferedWindow(wx.Window):
+ """!A buffered window class.
+
+ @param parent parent window
+ @param kwargs other wx.Window parameters
+ """
+ def __init__(self, parent, id = wx.ID_ANY,
+ style = wx.NO_FULL_REPAINT_ON_RESIZE,
+ **kwargs):
+ wx.Window.__init__(self, parent, id = id, style = style)
+ self.parent = parent
+
+ self.FitInside()
+
+ # store an off screen empty bitmap for saving to file
+ self._buffer = None
+ # indicates whether or not a resize event has taken place
+ self.resize = False
+
+ self.mouse = kwargs['mouse']
+ self.cursors = kwargs['cursors']
+ self.preview = kwargs['preview']
+ self.pen = kwargs['pen']
+ self.brush = kwargs['brush']
+
+ if kwargs.has_key('instruction'):
+ self.instruction = kwargs['instruction']
+ if kwargs.has_key('openDialogs'):
+ self.openDialogs = kwargs['openDialogs']
+ if kwargs.has_key('pageId'):
+ self.pageId = kwargs['pageId']
+ if kwargs.has_key('objectId'):
+ self.objectId = kwargs['objectId']
+
+
+ #labels
+ self.itemLabelsDict = { 'map': 'MAP FRAME',
+ 'rasterLegend': 'RASTER LEGEND',
+ 'vectorLegend': 'VECTOR LEGEND',
+ 'mapinfo': 'MAP INFO',
+ 'scalebar': 'SCALE BAR',
+ 'image': 'IMAGE',
+ 'northArrow': 'NORTH ARROW'}
+ self.itemLabels = {}
+
+ # define PseudoDC
+ self.pdc = wx.PseudoDC()
+ self.pdcObj = wx.PseudoDC()
+ self.pdcPaper = wx.PseudoDC()
+ self.pdcTmp = wx.PseudoDC()
+ self.pdcImage = wx.PseudoDC()
+ dc = wx.ClientDC(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.idLinePointsTmp = (wx.NewId(), wx.NewId()) # ids of marks for moving line vertices
+
+ self.resizeBoxSize = wx.Size(8, 8)
+
+
+
+ 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)
+ self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
+
+
+ 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.GetWidth(), fromUnit = fromU, toUnit = toU) * scale
+ Height = units.convert(value = rect.GetHeight(), fromUnit = fromU, toUnit = toU) * scale
+ X = units.convert(value = (rect.GetX() - pRectx), fromUnit = fromU, toUnit = toU) * scale
+ Y = units.convert(value = (rect.GetY() - pRecty), fromUnit = fromU, toUnit = toU) * scale
+
+ return 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.ClientDC(self).GetPPI()
+ cW, cH = self.GetClientSize()
+ pW, pH = page['Width']*ppi[0], page['Height']*ppi[1]
+
+ if self.currScale is None:
+ self.currScale = min(cW/pW, cH/pH)
+ pW = pW * self.currScale
+ pH = pH * self.currScale
+
+ x = cW/2 - pW/2
+ y = cH/2 - pH/2
+ self.DrawPaper(wx.Rect(x, y, pW, pH))
+
+
+ def modifyRectangle(self, r):
+ """! Recalculates rectangle not to have negative size"""
+ if r.GetWidth() < 0:
+ r.SetX(r.GetX() + r.GetWidth())
+ if r.GetHeight() < 0:
+ r.SetY(r.GetY() + r.GetHeight())
+ r.SetWidth(abs(r.GetWidth()))
+ r.SetHeight(abs(r.GetHeight()))
+ return r
+
+ def RecalculateEN(self):
+ """!Recalculate east and north for texts (eps, points) after their or map's movement"""
+ try:
+ mapId = self.instruction.FindInstructionByType('map').id
+ except AttributeError:
+ mapId = self.instruction.FindInstructionByType('initMap').id
+
+ for itemType in ('text', 'image', 'northArrow', 'point', 'line', 'rectangle'):
+ items = self.instruction.FindInstructionByType(itemType, list = True)
+ for item in items:
+ instr = self.instruction[item.id]
+ if itemType in ('line', 'rectangle'):
+ if itemType == 'line':
+ e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0][0],
+ y = instr['where'][0][1], paperToMap = True)
+ e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][1][0],
+ y = instr['where'][1][1], paperToMap = True)
+ else:
+ e1, n1 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetLeft(),
+ y = instr['rect'].GetTop(), paperToMap = True)
+ e2, n2 = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['rect'].GetRight(),
+ y = instr['rect'].GetBottom(), paperToMap = True)
+ instr['east1'] = e1
+ instr['north1'] = n1
+ instr['east2'] = e2
+ instr['north2'] = n2
+ else:
+ e, n = PaperMapCoordinates(mapInstr = self.instruction[mapId], x = instr['where'][0],
+ y = instr['where'][1], paperToMap = True)
+ instr['east'], instr['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 MouseActions(self, event):
+ """!Mouse motion and button click notifier
+ """
+ # 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)
+
+ elif event.Moving():
+ self.OnMouseMoving(event)
+
+ def OnMouseWheel(self, event):
+ """!Mouse wheel scrolled.
+
+ Changes zoom."""
+ if not UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'enabled'):
+ event.Skip()
+ return
+
+ zoom = event.GetWheelRotation()
+ oldUse = self.mouse['use']
+ self.mouse['begin'] = event.GetPosition()
+
+ if UserSettings.Get(group = 'display',
+ key = 'mouseWheelZoom',
+ subkey = 'selection'):
+ zoom *= -1
+
+ 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'] = oldUse
+
+ def OnMouseMoving(self, event):
+ """!Mouse cursor moving.
+
+ Change cursor when moving over resize marker.
+ """
+ if self.mouse['use'] in ('pointer', 'resize'):
+ pos = event.GetPosition()
+ foundResize = self.pdcTmp.FindObjects(pos[0], pos[1])
+ if foundResize and foundResize[0] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
+ 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"])
+
+ def OnLeftDown(self, event):
+ """!Left mouse button pressed.
+
+ Select objects, redraw, prepare for moving/resizing.
+ """
+ self.mouse['begin'] = event.GetPosition()
+ self.begin = self.mouse['begin']
+
+ # 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] in (self.idResizeBoxTmp,) + self.idLinePointsTmp:
+ 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)
+
+ if self.instruction[self.dragId].type == 'line':
+ self.currentLinePoint = self.idLinePointsTmp.index(foundResize[0])
+
+ elif found:
+ self.dragId = found[0]
+ self.RedrawSelectBox(self.dragId)
+ if self.instruction[self.dragId].type not in ('map', 'rectangle'):
+ self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+ self.Refresh()
+ if self.instruction[self.dragId].type != 'line':
+ for id in self.idLinePointsTmp:
+ self.pdcTmp.RemoveId(id)
+ self.Refresh()
+
+ else:
+ self.dragId = -1
+ self.pdcTmp.RemoveId(self.idBoxTmp)
+ self.pdcTmp.RemoveId(self.idResizeBoxTmp)
+ for id in self.idLinePointsTmp:
+ self.pdcTmp.RemoveId(id)
+ self.Refresh()
+
+ def OnLeftUp(self, event):
+ """!Left mouse button released.
+
+ Recalculate zooming/resizing/moving and redraw.
+ """
+ # 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
+ return
+
+ # resize resizable objects (map, line, rectangle)
+ if self.mouse['use'] == 'resize':
+ mapObj = self.instruction.FindInstructionByType('map')
+ if not mapObj:
+ mapObj = self.instruction.FindInstructionByType('initMap')
+ mapId = mapObj.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))
+
+ elif self.instruction[self.dragId].type == 'line':
+ points = self.instruction[self.dragId]['where']
+ self.instruction[self.dragId]['rect'] = Rect2DPP(points[0], points[1])
+ self.RecalculatePosition(ids = [self.dragId])
+
+ elif self.instruction[self.dragId].type == 'rectangle':
+ self.RecalculatePosition(ids = [self.dragId])
+
+ 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()
+
+ elif self.mouse['use'] in ('addPoint', 'addLine', 'addRectangle'):
+ endCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(event.GetX(), event.GetY(), 0, 0),
+ canvasToPaper = True)[:2]
+
+ diffX = event.GetX() - self.mouse['begin'][0]
+ diffY = event.GetY() - self.mouse['begin'][1]
+
+ if self.mouse['use'] == 'addPoint':
+ self.parent.AddPoint(coordinates = endCoordinates)
+ elif self.mouse['use'] in ('addLine', 'addRectangle'):
+ # not too small lines/rectangles
+ if sqrt(diffX * diffX + diffY * diffY) < 5:
+ self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+ self.Refresh()
+ return
+
+ beginCoordinates = self.CanvasPaperCoordinates(rect = wx.Rect(self.mouse['begin'][0],
+ self.mouse['begin'][1], 0, 0),
+ canvasToPaper = True)[:2]
+ if self.mouse['use'] == 'addLine':
+ self.parent.AddLine(coordinates = [beginCoordinates, endCoordinates])
+ else:
+ self.parent.AddRectangle(coordinates = [beginCoordinates, endCoordinates])
+ self.pdcTmp.RemoveId(self.idZoomBoxTmp)
+ self.Refresh()
+
+ def OnButtonDClick(self, event):
+ """!Open object dialog for editing."""
+ if self.mouse['use'] == 'pointer' and self.dragId != -1:
+ itemCall = {'text':self.parent.OnAddText,
+ 'mapinfo': self.parent.OnAddMapinfo,
+ 'scalebar': self.parent.OnAddScalebar,
+ 'image': self.parent.OnAddImage,
+ 'northArrow' : self.parent.OnAddNorthArrow,
+ 'point': self.parent.AddPoint,
+ 'line': self.parent.AddLine,
+ 'rectangle': self.parent.AddRectangle,
+ 'rasterLegend': self.parent.OnAddLegend,
+ 'vectorLegend': self.parent.OnAddLegend,
+ 'map': self.parent.OnAddMap}
+
+ itemArg = { 'text': dict(event = None, id = self.dragId),
+ 'mapinfo': dict(event = None),
+ 'scalebar': dict(event = None),
+ 'image': dict(event = None, id = self.dragId),
+ 'northArrow': dict(event = None, id = self.dragId),
+ 'point': dict(id = self.dragId),
+ 'line': dict(id = self.dragId),
+ 'rectangle': dict(id = self.dragId),
+ 'rasterLegend': dict(event = None),
+ 'vectorLegend': dict(event = None, page = 1),
+ 'map': dict(event = None, notebook = True)}
+
+ type = self.instruction[self.dragId].type
+ itemCall[type](**itemArg[type])
+
+ def OnDragging(self, event):
+ """!Process panning/resizing/drawing/moving."""
+ if event.MiddleIsDown():
+ # panning
+ self.mouse['end'] = event.GetPosition()
+ self.Pan(begin = self.mouse['begin'], end = self.mouse['end'])
+ self.mouse['begin'] = event.GetPosition()
+
+ elif event.LeftIsDown():
+ # draw box when zooming, creating map
+ if self.mouse['use'] in ('zoomin', 'zoomout', 'addMap', 'addLine', 'addRectangle'):
+ 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)
+
+ if self.mouse['use'] in ('addLine', 'addRectangle'):
+ if self.mouse['use'] == 'addLine':
+ pdcType = 'line'
+ lineCoords = (self.mouse['begin'], self.mouse['end'])
+ else:
+ pdcType = 'rect'
+ lineCoords = None
+ if r[2] < 2 or r[3] < 2:
+ # to avoid strange behavoiur
+ return
+
+ self.Draw(pen = self.pen['line'], brush = self.brush['line'],
+ pdc = self.pdcTmp, drawid = self.idZoomBoxTmp,
+ pdctype = pdcType, bb = r, lineCoords = lineCoords)
+
+ else:
+ 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()
+ self.Pan(begin = self.mouse['begin'], end = self.mouse['end'])
+ 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)
+ for id in self.idLinePointsTmp:
+ self.pdcTmp.TranslateId(id, 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':
+ pos = event.GetPosition()
+ diffX = pos[0] - self.mouse['begin'][0]
+ diffY = pos[1] - self.mouse['begin'][1]
+ if self.instruction[self.dragId].type == 'map':
+ x, y = self.mapBounds.GetX(), self.mapBounds.GetY()
+ width, height = self.mapBounds.GetWidth(), self.mapBounds.GetHeight()
+ # 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['map'], brush = self.brush['map'], pdc = self.pdcObj, drawid = self.dragId,
+ pdctype = 'rectText', bb = bounds)
+
+ elif self.instruction[self.dragId].type == 'rectangle':
+ instr = self.instruction[self.dragId]
+ rect = self.CanvasPaperCoordinates(rect = instr['rect'], canvasToPaper = False)
+ rect.SetWidth(rect.GetWidth() + diffX)
+ rect.SetHeight(rect.GetHeight() + diffY)
+
+ if rect.GetWidth() < 5 or rect.GetHeight() < 5:
+ return
+
+ self.DrawGraphics(drawid = self.dragId, shape = 'rectangle', color = instr['color'],
+ fcolor = instr['fcolor'], width = instr['width'], bb = rect)
+
+ elif self.instruction[self.dragId].type == 'line':
+ instr = self.instruction[self.dragId]
+ points = instr['where']
+ # moving point
+ if self.currentLinePoint == 0:
+ pPaper = points[1]
+ else:
+ pPaper = points[0]
+ pCanvas = self.CanvasPaperCoordinates(rect = Rect2DPS(pPaper, (0, 0)),
+ canvasToPaper = False)[:2]
+ bounds = wx.RectPP(pCanvas, pos)
+ self.DrawGraphics(drawid = self.dragId, shape = 'line', color = instr['color'],
+ width = instr['width'], bb = bounds, lineCoords = (pos, pCanvas))
+
+ # update paper coordinates
+ points[self.currentLinePoint] = self.CanvasPaperCoordinates(rect = wx.RectPS(pos, (0, 0)),
+ canvasToPaper = True)[:2]
+
+ self.RedrawSelectBox(self.dragId)
+
+ def OnMiddleDown(self, event):
+ """!Middle mouse button pressed."""
+ self.mouse['begin'] = event.GetPosition()
+
+ def Pan(self, begin, end):
+ """!Move canvas while dragging.
+
+ @param begin x,y coordinates of first point
+ @param end x,y coordinates of second point
+ """
+ view = begin[0] - end[0], begin[1] - end[1]
+ zoomFactor = 1
+ self.Zoom(zoomFactor, view)
+
+ def RecalculatePosition(self, ids):
+ for id in ids:
+ itype = self.instruction[id].type
+ if itype in ('map', 'rectangle'):
+ self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+ canvasToPaper = True)
+ self.RecalculateEN()
+
+ elif itype in ('mapinfo' ,'rasterLegend', 'vectorLegend', 'image', 'northArrow'):
+ self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+ canvasToPaper = True)
+ self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+ canvasToPaper = True)[:2]
+ if itype in ('image', 'northArrow'):
+ self.RecalculateEN()
+
+ elif itype == 'point':
+ rect = self.pdcObj.GetIdBounds(id)
+ self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = rect,
+ canvasToPaper = True)
+ rect.OffsetXY(rect.GetWidth()/2, rect.GetHeight()/2)
+ self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = rect,
+ canvasToPaper = True)[:2]
+ self.RecalculateEN()
+
+ elif itype == 'line':
+ rect = self.pdcObj.GetIdBounds(id)
+ oldRect = self.instruction[id]['rect']
+ newRect = self.CanvasPaperCoordinates(rect = rect, canvasToPaper = True)
+ xDiff = newRect[0] - oldRect[0]
+ yDiff = newRect[1] - oldRect[1]
+ self.instruction[id]['rect'] = newRect
+
+ point1 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][0]
+ point2 = wx.Point2D(xDiff, yDiff) + self.instruction[id]['where'][1]
+ self.instruction[id]['where'] = [point1, point2]
+
+ self.RecalculateEN()
+
+ elif itype == 'scalebar':
+ self.instruction[id]['rect'] = self.CanvasPaperCoordinates(rect = self.pdcObj.GetIdBounds(id),
+ canvasToPaper = True)
+
+
+ self.instruction[id]['where'] = self.instruction[id]['rect'].GetCentre()
+
+ elif itype == 'text':
+ x, y = self.instruction[id]['coords'][0] - self.instruction[id]['xoffset'],\
+ self.instruction[id]['coords'][1] + self.instruction[id]['yoffset']
+ extent = self.parent.getTextExtent(textDict = self.instruction[id])
+ if self.instruction[id]['rotate'] is not None:
+ rot = float(self.instruction[id]['rotate'])/180*pi
+ else:
+ rot = 0
+
+ if self.instruction[id]['ref'].split()[0] == 'lower':
+ y += extent[1]
+ elif self.instruction[id]['ref'].split()[0] == 'center':
+ y += extent[1]/2
+ if self.instruction[id]['ref'].split()[1] == 'right':
+ x += extent[0] * cos(rot)
+ y -= extent[0] * sin(rot)
+ elif self.instruction[id]['ref'].split()[1] == 'center':
+ x += extent[0]/2 * cos(rot)
+ y -= extent[0]/2 * sin(rot)
+
+ self.instruction[id]['where'] = self.CanvasPaperCoordinates(rect = 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())
+ try:
+ zoomFactor = 1/max(rW/cW, rH/cH)
+ except ZeroDivisionError:
+ zoomFactor = 1
+ # 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)
+ try:
+ 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
+ except ZeroDivisionError:
+ xView, yView = rect.GetX(), rect.GetY()
+ return zoomFactor, (int(xView), int(yView))
+
+
+ def Zoom(self, zoomFactor, view):
+ """! Zoom to specified region, scroll view, redraw"""
+ if not self.currScale:
+ return
+ self.currScale = self.currScale*zoomFactor
+
+ if self.currScale > 10 or self.currScale < 0.1:
+ self.currScale = self.currScale/zoomFactor
+ return
+ if not self.preview:
+ # redraw paper
+ pRect = self.pdcPaper.GetIdBounds(self.pageId)
+ pRect.OffsetXY(-view[0], -view[1])
+ pRect = self.ScaleRect(rect = pRect, scale = zoomFactor)
+ self.DrawPaper(pRect)
+
+ #redraw objects
+ for id in self.objectId:
+ oRect = self.CanvasPaperCoordinates(
+ rect = self.instruction[id]['rect'], canvasToPaper = False)
+
+ type = self.instruction[id].type
+ if type == 'text':
+ coords = self.instruction[id]['coords']# recalculate coordinates, they are not equal to BB
+ self.instruction[id]['coords'] = coords = [(int(coord) - view[i]) * zoomFactor
+ for i, coord in enumerate(coords)]
+ self.DrawRotText(pdc = self.pdcObj, drawId = id, textDict = self.instruction[id],
+ coords = coords, bounds = oRect )
+ extent = self.parent.getTextExtent(textDict = self.instruction[id])
+ if self.instruction[id]['rotate']:
+ rot = float(self.instruction[id]['rotate'])
+ else:
+ rot = 0
+
+ self.instruction[id]['rect'] = bounds = self.parent.getModifiedTextBounds(coords[0], coords[1], extent, rot)
+ self.pdcObj.SetIdBounds(id, bounds)
+ elif type == 'northArrow':
+ self.Draw(pen = self.pen[type], brush = self.brush[type], pdc = self.pdcObj,
+ drawid = id, pdctype = 'bitmap', bb = oRect)
+
+ elif type in ('point', 'line', 'rectangle'):
+ instr = self.instruction[id]
+ color = self.instruction[id]['color']
+ width = fcolor = coords = None
+
+ if type in ('point', 'rectangle'):
+ fcolor = self.instruction[id]['fcolor']
+ if type in ('line', 'rectangle'):
+ width = self.instruction[id]['width']
+ if type in ('line'):
+ point1, point2 = instr['where'][0], instr['where'][1]
+ point1 = self.CanvasPaperCoordinates(rect = Rect2DPS(point1, (0, 0)),
+ canvasToPaper = False)[:2]
+ point2 = self.CanvasPaperCoordinates(rect = Rect2DPS(point2, (0, 0)),
+ canvasToPaper = False)[:2]
+ coords = (point1, point2)
+
+ self.DrawGraphics(drawid = id, shape = type, bb = oRect, lineCoords = coords,
+ color = color, fcolor = fcolor, width = width)
+
+ 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), lineCoords = None):
+ """! Draw object with given pen and brush.
+
+ @param pdc PseudoDC
+ @param pdctype 'bitmap'/'rectText'/'rect'/'point'/'line'
+ @param bb bounding box
+ @param lineCoords coordinates of line start, end points (wx.Point, wx.Point)
+ """
+ if drawid is None:
+ drawid = wx.NewId()
+ bb = bb.Get()
+ pdc.BeginDrawing()
+ pdc.RemoveId(drawid)
+ pdc.SetId(drawid)
+ pdc.SetPen(pen)
+ pdc.SetBrush(brush)
+
+ if pdctype == 'bitmap':
+ if havePILImage:
+ file = self.instruction[drawid]['epsfile']
+ rotation = self.instruction[drawid]['rotate']
+ self.DrawBitmap(pdc = pdc, filePath = file, rotation = rotation, bbox = bb)
+ else: # draw only rectangle with label
+ pdctype = 'rectText'
+
+ if pdctype in ('rect', 'rectText'):
+ pdc.DrawRectangle(*bb)
+
+ if pdctype == 'rectText':
+ dc = wx.ClientDC(self) # dc created because of method GetTextExtent, which pseudoDC lacks
+ font = self.font
+ size = 10
+ font.SetPointSize(size)
+ font.SetStyle(wx.ITALIC)
+ dc.SetFont(font)
+ pdc.SetFont(font)
+ text = '\n'.join(self.itemLabels[drawid])
+ w,h,lh = dc.GetMultiLineTextExtent(text)
+ textExtent = (w,h)
+ textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
+ r = map(int, bb)
+ while not wx.Rect(*r).ContainsRect(textRect) and size >= 8:
+ size -= 2
+ font.SetPointSize(size)
+ dc.SetFont(font)
+ pdc.SetFont(font)
+ textExtent = dc.GetTextExtent(text)
+ textRect = wx.Rect(0, 0, *textExtent).CenterIn(bb)
+ pdc.SetTextForeground(wx.Color(100,100,100,200))
+ pdc.SetBackgroundMode(wx.TRANSPARENT)
+ pdc.DrawText(text = text, x = textRect.x, y = textRect.y)
+
+ elif pdctype == 'point':
+ pdc.DrawCircle(x = bb[0] + bb[2] / 2,
+ y = bb[1] + bb[3] / 2,
+ radius = bb[2] / 2)
+
+ elif pdctype == 'line':
+ pdc.DrawLinePoint(lineCoords[0], lineCoords[1])
+
+ pdc.SetIdBounds(drawid, bb)
+ pdc.EndDrawing()
+ self.Refresh()
+
+ return drawid
+
+ def DrawGraphics(self, drawid, shape, color, bb, width = None, fcolor = None, lineCoords = None):
+ """!Draw point/line/rectangle with given color and width
+
+ @param drawid id of drawn object
+ @param shape drawn shape: 'point'/'line'/'rectangle'
+ @param color pen outline color ('RRR:GGG:BBB')
+ @param fcolor brush fill color, if meaningful ('RRR:GGG:BBB')
+ @param width pen width
+ @param bb bounding box
+ @param lineCoords line coordinates (for line only)
+ """
+ pdctype = {'point' : 'point',
+ 'line' : 'line',
+ 'rectangle' : 'rect'}
+
+ if color == 'none':
+ pen = wx.TRANSPARENT_PEN
+ else:
+ if width is not None:
+ units = UnitConversion(self)
+ width = int(units.convert(value = width, fromUnit = 'point', toUnit = 'pixel') * self.currScale)
+ else:
+ width = 2
+ pen = wx.Pen(colour = convertRGB(color), width = width)
+ pen.SetCap(wx.CAP_BUTT) # this is how ps.map draws
+
+ brush = wx.TRANSPARENT_BRUSH
+ if fcolor and fcolor != 'none':
+ brush = wx.Brush(colour = convertRGB(fcolor))
+
+ self.Draw(pen = pen, brush = brush, pdc = self.pdcObj, pdctype = pdctype[shape],
+ drawid = drawid, bb = bb, lineCoords = lineCoords)
+
+ def DrawBitmap(self, pdc, filePath, rotation, bbox):
+ """!Draw bitmap using PIL"""
+ pImg = PILImage.open(filePath)
+ if rotation:
+ # get rid of black background
+ pImg = pImg.convert("RGBA")
+ rot = pImg.rotate(rotation, expand = 1)
+ new = PILImage.new('RGBA', rot.size, (255,) * 4)
+ pImg = PILImage.composite(rot, new, rot)
+ pImg = pImg.resize((int(bbox[2]), int(bbox[3])), resample = PILImage.BICUBIC)
+ img = PilImageToWxImage(pImg)
+ bitmap = img.ConvertToBitmap()
+ mask = wx.Mask(bitmap, wx.WHITE)
+ bitmap.SetMask(mask)
+ pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask = True)
+
+ def DrawRotText(self, pdc, drawId, textDict, coords, bounds):
+ if textDict['rotate']:
+ rot = float(textDict['rotate'])
+ else:
+ rot = 0
+
+ fontsize = textDict['fontsize'] * self.currScale
+ if textDict['background'] != 'none':
+ background = textDict['background']
+ else:
+ background = None
+
+ pdc.RemoveId(drawId)
+ pdc.SetId(drawId)
+ pdc.BeginDrawing()
+
+ # border is not redrawn when zoom changes, why?
+## if textDict['border'] != 'none' and not rot:
+## units = UnitConversion(self)
+## borderWidth = units.convert(value = textDict['width'],
+## fromUnit = 'point', toUnit = 'pixel' ) * self.currScale
+## pdc.SetPen(wx.Pen(colour = convertRGB(textDict['border']), width = borderWidth))
+## pdc.DrawRectangle(*bounds)
+
+ if background:
+ pdc.SetTextBackground(convertRGB(background))
+ pdc.SetBackgroundMode(wx.SOLID)
+ else:
+ pdc.SetBackgroundMode(wx.TRANSPARENT)
+
+ fn = self.parent.makePSFont(textDict)
+
+ pdc.SetFont(fn)
+ pdc.SetTextForeground(convertRGB(textDict['color']))
+ pdc.DrawRotatedText(textDict['text'], coords[0], coords[1], rot)
+
+ pdc.SetIdBounds(drawId, wx.Rect(*bounds))
+ self.Refresh()
+ pdc.EndDrawing()
+
+ def DrawImage(self, rect):
+ """!Draw preview image to pseudoDC"""
+ self.pdcImage.ClearId(self.imageId)
+ self.pdcImage.SetId(self.imageId)
+ img = self.image
+
+
+ if img.GetWidth() != rect.width or img.GetHeight() != rect.height:
+ img = img.Scale(rect.width, rect.height)
+ bitmap = img.ConvertToBitmap()
+
+ self.pdcImage.BeginDrawing()
+ self.pdcImage.DrawBitmap(bitmap, rect.x, rect.y)
+ self.pdcImage.SetIdBounds(self.imageId, rect)
+ self.pdcImage.EndDrawing()
+ self.Refresh()
+
+ def DrawPaper(self, rect):
+ """!Draw paper and margins"""
+ page = self.instruction[self.pageId]
+ scale = page['Width'] / rect.GetWidth()
+ w = (page['Width'] - page['Right'] - page['Left']) / scale
+ h = (page['Height'] - page['Top'] - page['Bottom']) / scale
+ x = page['Left'] / scale + rect.GetX()
+ y = page['Top'] / scale + rect.GetY()
+
+ self.pdcPaper.BeginDrawing()
+ self.pdcPaper.RemoveId(self.pageId)
+ self.pdcPaper.SetId(self.pageId)
+ self.pdcPaper.SetPen(self.pen['paper'])
+ self.pdcPaper.SetBrush(self.brush['paper'])
+ self.pdcPaper.DrawRectangleRect(rect)
+
+ self.pdcPaper.SetPen(self.pen['margins'])
+ self.pdcPaper.SetBrush(self.brush['margins'])
+ self.pdcPaper.DrawRectangle(x, y, w, h)
+
+ self.pdcPaper.SetIdBounds(self.pageId, rect)
+ self.pdcPaper.EndDrawing()
+ self.Refresh()
+
+
+ def ImageRect(self):
+ """!Returns image centered in canvas, computes scale"""
+ img = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG)
+ cW, cH = self.GetClientSize()
+ iW, iH = img.GetWidth(), img.GetHeight()
+
+ self.currScale = min(float(cW)/iW, float(cH)/iH)
+ iW = iW * self.currScale
+ iH = iH * self.currScale
+ x = cW/2 - iW/2
+ y = cH/2 - iH/2
+ imageRect = wx.Rect(x, y, iW, iH)
+
+ return imageRect
+
+ def RedrawSelectBox(self, id):
+ """!Redraws select box when selected object changes its size"""
+ if self.dragId == id:
+ rect = self.pdcObj.GetIdBounds(id)
+ if self.instruction[id].type != 'line':
+ rect = rect.Inflate(3,3)
+ # draw select box around object
+ self.Draw(pen = self.pen['select'], brush = self.brush['select'], pdc = self.pdcTmp,
+ drawid = self.idBoxTmp, pdctype = 'rect', bb = rect)
+
+ # draw small marks signalizing resizing
+ if self.instruction[id].type in ('map', 'rectangle'):
+ controlP = self.pdcObj.GetIdBounds(id).GetBottomRight()
+ rect = wx.RectPS(controlP, self.resizeBoxSize)
+ self.Draw(pen = self.pen['resize'], brush = self.brush['resize'], pdc = self.pdcTmp,
+ drawid = self.idResizeBoxTmp, pdctype = 'rect', bb = rect)
+
+ elif self.instruction[id].type == 'line':
+ p1Paper = self.instruction[id]['where'][0]
+ p2Paper = self.instruction[id]['where'][1]
+ p1Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p1Paper, (0, 0)), canvasToPaper = False)[:2]
+ p2Canvas = self.CanvasPaperCoordinates(rect = Rect2DPS(p2Paper, (0, 0)), canvasToPaper = False)[:2]
+ rect = []
+ box = wx.RectS(self.resizeBoxSize)
+ rect.append(box.CenterIn(wx.RectPS(p1Canvas, wx.Size())))
+ rect.append(box.CenterIn(wx.RectPS(p2Canvas, wx.Size())))
+ for i, point in enumerate((p1Canvas, p2Canvas)):
+ self.Draw(pen = self.pen['resize'], brush = self.brush['resize'], pdc = self.pdcTmp,
+ drawid = self.idLinePointsTmp[i], pdctype = 'rect', bb = rect[i])
+
+ def UpdateMapLabel(self):
+ """!Updates map frame label"""
+
+ vector = self.instruction.FindInstructionByType('vector')
+ if vector:
+ vectorId = vector.id
+ else:
+ vectorId = None
+
+ raster = self.instruction.FindInstructionByType('raster')
+ if raster:
+ rasterId = raster.id
+ else:
+ rasterId = None
+
+ rasterName = 'None'
+ if rasterId:
+ rasterName = self.instruction[rasterId]['raster'].split('@')[0]
+
+ mapId = self.instruction.FindInstructionByType('map').id
+ self.itemLabels[mapId] = []
+ self.itemLabels[mapId].append(self.itemLabelsDict['map'])
+ self.itemLabels[mapId].append("raster: " + rasterName)
+ if vectorId:
+ for map in self.instruction[vectorId]['list']:
+ self.itemLabels[mapId].append('vector: ' + map[0].split('@')[0])
+
+ def UpdateLabel(self, itype, id):
+ self.itemLabels[id] = []
+ self.itemLabels[id].append(self.itemLabelsDict[itype])
+ if itype == 'image':
+ file = os.path.basename(self.instruction[id]['epsfile'])
+ self.itemLabels[id].append(file)
+
+ def OnSize(self, event):
+ """!Init image size to match window size
+ """
+ # not zoom all when notebook page is changed
+ if self.preview and self.parent.currentPage == 1 or not self.preview and self.parent.currentPage == 0:
+ self.ZoomAll()
+ self.OnIdle(None)
+ event.Skip()
+
+ def OnIdle(self, event):
+ """!Only re-render a image during idle time instead of
+ multiple times during resizing.
+ """
+
+ width, height = self.GetClientSize()
+ # Make new off screen bitmap: this bitmap will always have the
+ # current drawing in it, so it can be used to save the image
+ # to a file, or whatever.
+ self._buffer = wx.EmptyBitmap(width, height)
+ # re-render image on idle
+ self.resize = True
+
+ def ScaleRect(self, rect, scale):
+ """! Scale rectangle"""
+ return wx.Rect(rect.GetLeft()*scale, rect.GetTop()*scale,
+ rect.GetSize()[0]*scale, rect.GetSize()[1]*scale)
+
+def main():
+ import gettext
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+
+ app = wx.PySimpleApp()
+ wx.InitAllImageHandlers()
+ frame = PsMapFrame()
+ frame.Show()
+
+ app.MainLoop()
+
+if __name__ == "__main__":
+ main()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/frame.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/instructions.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/instructions.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/instructions.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1811 @@
+"""!
+ at package psmap.instructions
+
+ at brief Map feature objects
+
+Classes:
+ - dialogs::Instruction
+ - dialogs::InstructionObject
+ - dialogs::InitMap
+ - dialogs::MapFrame
+ - dialogs::PageSetup
+ - dialogs::Mapinfo
+ - dialogs::Text
+ - dialogs::Image
+ - dialogs::NorthArrow
+ - dialogs::Point
+ - dialogs::Line
+ - dialogs::Rectangle
+ - dialogs::Scalebar
+ - dialogs::RasterLegend
+ - dialogs::VectorLegend
+ - dialogs::Raster
+ - dialogs::Vector
+ - dialogs::VProperties
+
+(C) 2011-2012 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 string
+from math import ceil
+from time import strftime, localtime
+
+import wx
+import grass.script as grass
+
+from core.gcmd import RunCommand, GError, GMessage, GWarning
+from core.utils import CmdToTuple, GetCmdString
+from dbmgr.vinfo import VectorDBInfo
+from psmap.utils import *
+
+class Instruction:
+ """!Class which represents instruction file"""
+ def __init__(self, parent, objectsToDraw):
+
+ self.parent = parent
+ self.objectsToDraw = objectsToDraw
+ #here are kept objects like mapinfo, rasterlegend, etc.
+ self.instruction = list()
+
+ def __str__(self):
+ """!Returns text for instruction file"""
+ comment = "# timestamp: " + strftime("%Y-%m-%d %H:%M", localtime()) + '\n'
+ env = grass.gisenv()
+ comment += "# location: %s\n" % env['LOCATION_NAME']
+ comment += "# mapset: %s\n" % env['MAPSET']
+ comment += "# page orientation: %s\n" % self.FindInstructionByType('page')['Orientation']
+ border = ''
+ if not self.FindInstructionByType('map'):
+ border = 'border n\n'
+ text = [str(each) for each in self.instruction]
+ return comment + border + '\n'.join(text) + '\nend'
+
+ def __getitem__(self, id):
+ for each in self.instruction:
+ if each.id == id:
+ return each
+ return None
+
+ def __contains__(self, id):
+ """!Test if instruction is included"""
+ for each in self.instruction:
+ if each.id == id:
+ return True
+ return False
+
+ def __delitem__(self, id):
+ """!Delete instruction"""
+ for each in self.instruction:
+ if each.id == id:
+ if each.type == 'map':
+ #must remove raster, vector layers too
+ vektor = self.FindInstructionByType('vector', list = True)
+ vProperties = self.FindInstructionByType('vProperties', list = True)
+ raster = self.FindInstructionByType('raster', list = True)
+ for item in vektor + vProperties + raster:
+ if item in self.instruction:
+ self.instruction.remove(item)
+
+ self.instruction.remove(each)
+ if id in self.objectsToDraw:
+ self.objectsToDraw.remove(id)
+ return
+
+ def AddInstruction(self, instruction):
+ """!Add instruction"""
+ # add to instructions
+ if instruction.type == 'map':
+ self.instruction.insert(0, instruction)
+ else:
+ self.instruction.append(instruction)
+ # add to drawable objects
+ if instruction.type not in ('page', 'raster', 'vector', 'vProperties', 'initMap'):
+ if instruction.type == 'map':
+ self.objectsToDraw.insert(0, instruction.id)
+ else:
+ self.objectsToDraw.append(instruction.id)
+
+
+ def FindInstructionByType(self, type, list = False):
+ """!Find instruction(s) with the given type"""
+ inst = []
+ for each in self.instruction:
+ if each.type == type:
+ inst.append(each)
+ if len(inst) == 1 and not list:
+ return inst[0]
+ return inst
+
+ def Read(self, filename):
+ """!Reads instruction file and creates instruction objects"""
+ self.filename = filename
+ # open file
+ try:
+ file = open(filename, 'r')
+ except IOError:
+ GError(message = _("Unable to open file\n%s") % filename)
+ return
+ # first read file to get information about region and scaletype
+ isRegionComment = False
+ orientation = 'Portrait'
+ for line in file:
+ if '# g.region' in line:
+ self.SetRegion(regionInstruction = line)
+ isRegionComment = True
+ break
+ if '# page orientation' in line:
+ orientation = line.split(':')[-1].strip()
+
+ if not isRegionComment:
+ self.SetRegion(regionInstruction = None)
+ # then run ps.map -b to get information for maploc
+ # compute scale and center
+ map = self.FindInstructionByType('map')
+ region = grass.region()
+ map['center'] = (region['n'] + region['s']) / 2, (region['w'] + region['e']) / 2
+ mapRect = GetMapBounds(self.filename, portrait = (orientation == 'Portrait'))
+ map['rect'] = mapRect
+ proj = projInfo()
+ toM = 1.0
+ if proj['units']:
+ toM = float(proj['meters'])
+ units = UnitConversion(self.parent)
+ w = units.convert(value = mapRect.Get()[2], fromUnit = 'inch', toUnit = 'meter') / toM
+ map['scale'] = w / abs((region['w'] - region['e']))
+
+ SetResolution(dpi = 300, width = map['rect'].width, height = map['rect'].height)
+
+ # read file again, now with information about map bounds
+ isBuffer = False
+ buffer = []
+ instruction = None
+ vectorMapNumber = 1
+ file.seek(0)
+ for line in file:
+ if not line.strip():
+ continue
+ line = line.strip()
+ if isBuffer:
+ buffer.append(line)
+ if 'end' in line:
+ isBuffer = False
+ kwargs = {}
+ if instruction == 'scalebar':
+ kwargs['scale'] = map['scale']
+ elif instruction in ('text', 'eps', 'point', 'line', 'rectangle'):
+ kwargs['mapInstruction'] = map
+ elif instruction in ('vpoints', 'vlines', 'vareas'):
+ kwargs['id'] = wx.NewId()
+ kwargs['vectorMapNumber'] = vectorMapNumber
+ vectorMapNumber += 1
+ elif instruction == 'paper':
+ kwargs['Orientation'] = orientation
+
+ ok = self.SendToRead(instruction, buffer, **kwargs)
+ if not ok: return False
+ buffer = []
+ continue
+
+ elif line.startswith('paper'):
+ instruction = 'paper'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('border'):
+ if line.split()[1].lower() in ('n', 'no', 'none'):
+ ok = self.SendToRead('border', [line])
+ if not ok: return False
+ elif line.split()[1].lower() in ('y', 'yes'):
+ instruction = 'border'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('scale '):
+ if isBuffer:
+ continue
+ ok = self.SendToRead('scale', line, isRegionComment = isRegionComment)
+ if not ok: return False
+
+ elif line.startswith('maploc'):
+ ok = self.SendToRead(instruction = 'maploc', text = line)
+ if not ok: return False
+
+ elif line.startswith('raster'):
+ ok = self.SendToRead(instruction = 'raster', text = line)
+ if not ok: return False
+
+ elif line.startswith('mapinfo'):
+ instruction = 'mapinfo'
+ isBuffer = True
+ buffer.append(line)
+
+
+ elif line.startswith('scalebar'):
+ instruction = 'scalebar'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('text'):
+ instruction = 'text'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('eps'):
+ instruction = 'eps'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('point'):
+ instruction = 'point'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('line'):
+ instruction = 'line'
+ isBuffer = True
+ buffer.append(line)
+
+ elif line.startswith('rectangle'):
+ instruction = 'rectangle'
+ 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'] = Rect2D(x = float(rasterLegend['where'][0]), y = float(rasterLegend['where'][1]),
+ width = width, height = 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'] = Rect2D(x = float(vectorLegend['where'][0]), y = float(vectorLegend['where'][1]),
+ width = size[0], height = size[1])
+
+
+ page = self.FindInstructionByType('page')
+ if not page:
+ page = PageSetup(wx.NewId())
+ self.AddInstruction(page)
+ else:
+ page['Orientation'] = orientation
+
+
+ #
+ return True
+
+ def SendToRead(self, instruction, text, **kwargs):
+ psmapInstrDict = dict(paper = ['page'],
+ maploc = ['map'],
+ scale = ['map'],
+ border = ['map'],
+ raster = ['raster'],
+ mapinfo = ['mapinfo'],
+ scalebar = ['scalebar'],
+ text = ['text'],
+ eps = ['image', 'northArrow'],
+ point = ['point'],
+ line = ['line'],
+ rectangle = ['rectangle'],
+ vpoints = ['vector', 'vProperties'],
+ vlines = ['vector', 'vProperties'],
+ vareas = ['vector', 'vProperties'],
+ colortable = ['rasterLegend'],
+ vlegend = ['vectorLegend']
+ )
+
+ myInstrDict = dict(page = PageSetup,
+ map = MapFrame,
+ raster = Raster,
+ mapinfo = Mapinfo,
+ scalebar = Scalebar,
+ text = Text,
+ image = Image,
+ northArrow = NorthArrow,
+ point = Point,
+ line = Line,
+ rectangle = Rectangle,
+ rasterLegend = RasterLegend,
+ vectorLegend = VectorLegend,
+ vector = Vector,
+ vProperties = VProperties
+ )
+
+ myInstruction = psmapInstrDict[instruction]
+
+ for i in myInstruction:
+ instr = self.FindInstructionByType(i)
+ if i in ('text', 'vProperties', 'image', 'northArrow', 'point', 'line', 'rectangle') or not instr:
+
+ id = wx.NewId() #!vProperties expect subtype
+ if i == 'vProperties':
+ id = kwargs['id']
+ newInstr = myInstrDict[i](id, subType = instruction[1:])
+ elif i in ('image', 'northArrow'):
+ commentFound = False
+ for line in text:
+ if line.find("# north arrow") >= 0:
+ commentFound = True
+ if i == 'image' and commentFound or \
+ i == 'northArrow' and not commentFound:
+ continue
+ newInstr = myInstrDict[i](id, settings = self)
+ else:
+ newInstr = myInstrDict[i](id)
+ ok = newInstr.Read(instruction, text, **kwargs)
+ if ok:
+ self.AddInstruction(newInstr)
+ else:
+ return False
+
+ else:
+ ok = instr.Read(instruction, text, **kwargs)
+
+ if not ok:
+ return False
+ return True
+
+ def SetRegion(self, regionInstruction):
+ """!Sets region from file comment or sets current region in case of no comment"""
+ map = MapFrame(wx.NewId())
+ self.AddInstruction(map)
+ if regionInstruction:
+ cmd = CmdToTuple(regionInstruction.strip('# ').split())
+
+ # define scaleType
+ if len(cmd[1]) <= 3:
+ if 'rast' in cmd[1]:
+ map['scaleType'] = 0
+ map['mapType'] = 'raster'
+ map['map'] = cmd[1]['rast']
+ elif 'vect' in cmd[1]:
+ map['scaleType'] = 0
+ map['mapType'] = 'vector'
+ map['map'] = cmd[1]['vect']
+ elif 'region' in cmd[1]:
+ map['scaleType'] = 1
+ map['region'] = cmd[1]['region']
+
+ else:
+ map['scaleType'] = 2
+ else:
+ map['scaleType'] = 2
+ grass.del_temp_region()
+ region = grass.region()
+ grass.use_temp_region()
+ cmd = ['g.region', region]
+ cmdString = GetCmdString(cmd).replace('g.region', '')
+ GMessage(_("Instruction file will be loaded with following region: %s\n") % cmdString)
+ try:
+ RunCommand(cmd[0], **cmd[1])
+
+ except grass.ScriptError, e:
+ GError(_("Region cannot be set\n%s") % e)
+ return False
+
+
+class InstructionObject:
+ """!Abtract class representing single instruction"""
+ def __init__(self, id):
+ self.id = id
+
+ # default values
+ self.defaultInstruction = dict()
+ # current values
+ self.instruction = self.defaultInstruction
+ # converting units
+ self.unitConv = UnitConversion()
+
+ def __str__(self):
+ """!Returns particular part of text instruction"""
+ return ''
+
+ def __getitem__(self, key):
+ for each in self.instruction.keys():
+ if each == key:
+ return self.instruction[key]
+ return None
+
+ def __setitem__(self, key, value):
+ self.instruction[key] = value
+
+ def GetInstruction(self):
+ """!Get current values"""
+ return self.instruction
+
+ def SetInstruction(self, instruction):
+ """!Set default values"""
+ self.instruction = instruction
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save them"""
+ pass
+
+ 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 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 = 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 Rect2D(x = float(mapinfoDict['where'][0]), y = float(mapinfoDict['where'][1]),
+ width = width, height = 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 = u"text %s %s" % (self.instruction['east'], self.instruction['north'])
+ instr += " %s\n" % text
+ instr += (string.Template(" font $font\n fontsize $fontsize\n color $color\n").
+ substitute(self.instruction))
+ instr += string.Template(" hcolor $hcolor\n").substitute(self.instruction)
+ if self.instruction['hcolor'] != 'none':
+ instr += string.Template(" hwidth $hwidth\n").substitute(self.instruction)
+ instr += string.Template(" border $border\n").substitute(self.instruction)
+ if self.instruction['border'] != 'none':
+ instr += string.Template(" width $width\n").substitute(self.instruction)
+ instr += string.Template(" background $background\n").substitute(self.instruction)
+ if self.instruction["ref"] != '0':
+ instr += string.Template(" ref $ref\n").substitute(self.instruction)
+ if self.instruction["rotate"]:
+ instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
+ if float(self.instruction["xoffset"]) or float(self.instruction["yoffset"]):
+ instr += (string.Template(" xoffset $xoffset\n yoffset $yoffset\n").
+ substitute(self.instruction))
+ instr += " end"
+ try:
+ instr = instr.encode('latin1')
+ 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 ''
+
+ 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].decode('latin_1')
+
+ 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(mapInstr = map, x = instr['east'], y = instr['north'], paperToMap = False)
+ self.instruction.update(instr)
+
+ return True
+
+class Image(InstructionObject):
+ """!Class representing eps instruction - image"""
+ def __init__(self, id, settings):
+ InstructionObject.__init__(self, id = id)
+ self.settings = settings
+ self.type = 'image'
+ # default values
+ self.defaultInstruction = dict(epsfile = "", XY = True, where = (0,0), unit = 'inch',
+ east = None, north = None,
+ rotate = None, scale = 1)
+ # current values
+ self.instruction = dict(self.defaultInstruction)
+
+ def __str__(self):
+ self.ChangeRefPoint(toCenter = True)
+
+ instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+ instr += string.Template(" epsfile $epsfile\n").substitute(self.instruction)
+ if self.instruction["rotate"]:
+ instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
+ if self.instruction["scale"]:
+ instr += string.Template(" scale $scale\n").substitute(self.instruction)
+ instr += " end"
+ return instr
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save information"""
+ mapInstr = kwargs['mapInstruction']
+ instr = {}
+ for line in text:
+ try:
+ sub = line.split(None, 1)[0]
+ if sub == 'eps':
+ e, n = line.split(None, 3)[1:3]
+ if '%' in e and '%' in n:
+ instr['XY'] = True
+ instr['east'], instr['north'] = self.PercentToReal(e, n)
+ else:
+ instr['XY'] = False
+ instr['east'], instr['north'] = float(e), float(n)
+
+ elif sub == 'epsfile':
+ instr['epsfile'] = line.split(None, 1)[1]
+ elif sub == 'rotate':
+ instr['rotate'] = float(line.split(None, 1)[1])
+ elif sub == 'scale':
+ instr['scale'] = float(line.split(None, 1)[1])
+
+ except(IndexError, ValueError):
+ GError(_("Failed to read instruction %s") % instruction)
+ return False
+ if not os.path.exists(instr['epsfile']):
+ GError(_("Failed to read instruction %(inst)s: "
+ "file %(file)s not found.") % { 'inst' : instruction,
+ 'file' : instr['epsfile'] })
+ return False
+
+ instr['epsfile'] = os.path.abspath(instr['epsfile'])
+ instr['size'] = self.GetImageOrigSize(instr['epsfile'])
+ if 'rotate' in instr:
+ instr['size'] = BBoxAfterRotation(instr['size'][0], instr['size'][1], instr['rotate'])
+ self.instruction.update(instr)
+ self.ChangeRefPoint(toCenter = False)
+ instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
+ y = self.instruction['north'], paperToMap = False)
+ w = self.unitConv.convert(value = instr['size'][0], fromUnit = 'point', toUnit = 'inch')
+ h = self.unitConv.convert(value = instr['size'][1], fromUnit = 'point', toUnit = 'inch')
+ instr['rect'] = Rect2D(x = float(instr['where'][0]), y = float(instr['where'][1]),
+ width = w * self.instruction['scale'], height = h * self.instruction['scale'])
+ self.instruction.update(instr)
+
+ return True
+
+ def ChangeRefPoint(self, toCenter):
+ """!Change reference point (left top x center)"""
+ mapInstr = self.settings.FindInstructionByType('map')
+ if not mapInstr:
+ mapInstr = self.settings.FindInstructionByType('initMap')
+ mapId = mapInstr.id
+ if toCenter:
+ center = self.instruction['rect'].GetCentre()
+ ENCenter = PaperMapCoordinates(mapInstr = self.settings[mapId],
+ x = center[0], y = center[1], paperToMap = True)
+
+ self.instruction['east'], self.instruction['north'] = ENCenter
+ else:
+ x, y = PaperMapCoordinates(mapInstr = self.settings[mapId], x = self.instruction['east'],
+ y = self.instruction['north'], paperToMap = False)
+ w = self.unitConv.convert(value = self.instruction['size'][0], fromUnit = 'point', toUnit = 'inch')
+ h = self.unitConv.convert(value = self.instruction['size'][1], fromUnit = 'point', toUnit = 'inch')
+ x -= w * self.instruction['scale'] / 2
+ y -= h * self.instruction['scale'] / 2
+ e, n = PaperMapCoordinates(mapInstr = self.settings[mapId], x = x, y = y, paperToMap = True)
+ self.instruction['east'], self.instruction['north'] = e, n
+
+ def GetImageOrigSize(self, imagePath):
+ """!Get image size.
+
+ If eps, size is read from image header.
+ """
+ fileName = os.path.split(imagePath)[1]
+ # if eps, read info from header
+ if os.path.splitext(fileName)[1].lower() == '.eps':
+ bbInfo = "%%BoundingBox"
+ file = open(imagePath,"r")
+ w = h = 0
+ while file:
+ line = file.readline()
+ if line.find(bbInfo) == 0:
+ w, h = line.split()[3:5]
+ break
+ file.close()
+ return float(w), float(h)
+ else: # we can use wx.Image
+ img = wx.Image(fileName, type=wx.BITMAP_TYPE_ANY)
+ return img.GetWidth(), img.GetHeight()
+
+class NorthArrow(Image):
+ """!Class representing eps instruction -- North Arrow"""
+ def __init__(self, id, settings):
+ Image.__init__(self, id = id, settings = settings)
+ self.type = 'northArrow'
+
+ def __str__(self):
+ self.ChangeRefPoint(toCenter = True)
+
+ instr = "eps %s %s\n" % (self.instruction['east'], self.instruction['north'])
+ instr += "# north arrow\n"
+ instr += string.Template(" epsfile $epsfile\n").substitute(self.instruction)
+ if self.instruction["rotate"]:
+ instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
+ if self.instruction["scale"]:
+ instr += string.Template(" scale $scale\n").substitute(self.instruction)
+ instr += " end"
+ return instr
+
+class Point(InstructionObject):
+ """!Class representing point instruction"""
+ def __init__(self, id):
+ InstructionObject.__init__(self, id = id)
+ self.type = 'point'
+ # default values
+ self.defaultInstruction = dict(symbol = os.path.join('basic', 'x'),
+ color = '0:0:0', fcolor = '200:200:200',
+ rotate = 0, size = 10,
+ XY = True, where = (0,0), unit = 'inch',
+ east = None, north = None)
+ # current values
+ self.instruction = dict(self.defaultInstruction)
+
+ def __str__(self):
+ instr = string.Template("point $east $north\n").substitute(self.instruction)
+ instr += string.Template(" symbol $symbol\n").substitute(self.instruction)
+ instr += string.Template(" color $color\n").substitute(self.instruction)
+ instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction)
+ instr += string.Template(" rotate $rotate\n").substitute(self.instruction)
+ instr += string.Template(" size $size\n").substitute(self.instruction)
+ instr += " end"
+ return instr
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save information"""
+ mapInstr = kwargs['mapInstruction']
+ instr = {}
+ for line in text:
+ try:
+ sub = line.split(None, 1)[0]
+ if sub == 'point':
+ e, n = line.split(None, 3)[1:3]
+ if '%' in e and '%' in n:
+ instr['XY'] = True
+ instr['east'], instr['north'] = self.PercentToReal(e, n)
+ else:
+ instr['XY'] = False
+ instr['east'], instr['north'] = float(e), float(n)
+
+ elif sub == 'symbol':
+ instr['symbol'] = line.split(None, 1)[1]
+ elif sub == 'rotate':
+ instr['rotate'] = float(line.split(None, 1)[1])
+ elif sub == 'size':
+ instr['size'] = float(line.split(None, 1)[1])
+ elif sub == 'color':
+ instr['color'] = line.split(None, 1)[1]
+ elif sub == 'fcolor':
+ instr['fcolor'] = line.split(None, 1)[1]
+
+
+ except(IndexError, ValueError):
+ GError(_("Failed to read instruction %s") % instruction)
+ return False
+
+ self.instruction.update(instr)
+ instr['where'] = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east'],
+ y = self.instruction['north'], paperToMap = False)
+ w = h = self.unitConv.convert(value = instr['size'], fromUnit = 'point', toUnit = 'inch')
+ instr['rect'] = Rect2D(x = float(instr['where'][0]) - w / 2, y = float(instr['where'][1] - h / 2),
+ width = w, height = h)
+ self.instruction.update(instr)
+
+ return True
+
+class Line(InstructionObject):
+ """!Class representing line instruction"""
+ def __init__(self, id):
+ InstructionObject.__init__(self, id = id)
+ self.type = 'line'
+ # default values
+ self.defaultInstruction = dict(color = '0:0:0', width = 2,
+ where = [wx.Point2D(), wx.Point2D()],
+ east1 = None, north1 = None,
+ east2 = None, north2 = None)
+ # current values
+ self.instruction = dict(self.defaultInstruction)
+
+ def __str__(self):
+ instr = string.Template("line $east1 $north1 $east2 $north2\n").substitute(self.instruction)
+ instr += string.Template(" color $color\n").substitute(self.instruction)
+ instr += string.Template(" width $width\n").substitute(self.instruction)
+ instr += " end\n"
+ return instr
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save information"""
+ mapInstr = kwargs['mapInstruction']
+ instr = {}
+ for line in text:
+ try:
+ sub = line.split(None, 1)[0]
+ if sub == 'line':
+ e1, n1, e2, n2 = line.split(None, 5)[1:5]
+ if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
+ instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
+ instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
+ else:
+ instr['east1'], instr['north1'] = float(e1), float(n1)
+ instr['east2'], instr['north2'] = float(e2), float(n2)
+
+ elif sub == 'width':
+ instr['width'] = float(line.split(None, 1)[1])
+ elif sub == 'color':
+ instr['color'] = line.split(None, 1)[1]
+
+ except(IndexError, ValueError):
+ GError(_("Failed to read instruction %s") % instruction)
+ return False
+
+ self.instruction.update(instr)
+ e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
+ y = self.instruction['north1'], paperToMap = False)
+ e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
+ y = self.instruction['north2'], paperToMap = False)
+ instr['where'] = [wx.Point2D(e1, n1), wx.Point2D(e2, n2)]
+ instr['rect'] = Rect2DPP(instr['where'][0], instr['where'][1])
+ self.instruction.update(instr)
+
+ return True
+
+class Rectangle(InstructionObject):
+ """!Class representing rectangle instruction"""
+ def __init__(self, id):
+ InstructionObject.__init__(self, id = id)
+ self.type = 'rectangle'
+ # default values
+ self.defaultInstruction = dict(color = '0:0:0', fcolor = 'none', width = 2,
+ east1 = None, north1 = None,
+ east2 = None, north2 = None)
+ # current values
+ self.instruction = dict(self.defaultInstruction)
+
+ def __str__(self):
+ instr = string.Template("rectangle $east1 $north1 $east2 $north2\n").substitute(self.instruction)
+ instr += string.Template(" color $color\n").substitute(self.instruction)
+ instr += string.Template(" fcolor $fcolor\n").substitute(self.instruction)
+ instr += string.Template(" width $width\n").substitute(self.instruction)
+ instr += " end\n"
+ return instr
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save information"""
+ mapInstr = kwargs['mapInstruction']
+ instr = {}
+ for line in text:
+ try:
+ sub = line.split(None, 1)[0]
+ if sub == 'rectangle':
+ e1, n1, e2, n2 = line.split(None, 5)[1:5]
+ if '%' in e1 and '%' in n1 and '%' in e2 and '%' in n2:
+ instr['east1'], instr['north1'] = self.PercentToReal(e1, n1)
+ instr['east2'], instr['north2'] = self.PercentToReal(e2, n2)
+ else:
+ instr['east1'], instr['north1'] = float(e1), float(n1)
+ instr['east2'], instr['north2'] = float(e2), float(n2)
+
+ elif sub == 'width':
+ instr['width'] = float(line.split(None, 1)[1])
+ elif sub == 'color':
+ instr['color'] = line.split(None, 1)[1]
+ elif sub == 'fcolor':
+ instr['fcolor'] = line.split(None, 1)[1]
+
+
+ except(IndexError, ValueError):
+ GError(_("Failed to read instruction %s") % instruction)
+ return False
+
+ self.instruction.update(instr)
+ e1, n1 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east1'],
+ y = self.instruction['north1'], paperToMap = False)
+ e2, n2 = PaperMapCoordinates(mapInstr = mapInstr, x = self.instruction['east2'],
+ y = self.instruction['north2'], paperToMap = False)
+ instr['rect'] = Rect2DPP(wx.Point2D(e1, n1), wx.Point2D(e2, n2))
+ self.instruction.update(instr)
+
+ return True
+
+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'] = 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 not dic['eps']:
+ 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"
+ try:
+ vInstruction = vInstruction.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 ''
+ return vInstruction
+
+ def Read(self, instruction, text, **kwargs):
+ """!Read instruction and save information"""
+ instr = {}
+ try:
+ info = grass.find_file(name = text[0].split()[1], element = 'vector')
+ except grass.ScriptError, e:
+ GError(message = e.value)
+ return False
+ instr['name'] = info['fullname']
+ #connection
+ instr['connection'] = True
+ self.mapDBInfo = VectorDBInfo(instr['name'])
+ self.layers = self.mapDBInfo.layers.keys()
+ if not self.layers:
+ instr['connection'] = False
+
+ # points
+ if text[0].startswith('vpoints'):
+ for line in text[1:]:
+ if line.startswith('type'):
+ tp = []
+ if line.find('point') != -1:
+ tp.append('point')
+ if line.find('centroid') != -1:
+ tp.append('centroid')
+ instr['type'] = ' or '.join(tp)
+ elif line.startswith('fcolor'):
+ instr['fcolor'] = line.split()[1]
+ elif line.startswith('rgbcolumn'):
+ instr['rgbcolumn'] = line.split()[1]
+ elif line.startswith('symbol'):
+ instr['symbol'] = line.split()[1]
+ elif line.startswith('eps'):
+ instr['eps'] = line.split()[1]
+ elif line.startswith('size '):
+ instr['size'] = line.split()[1]
+ elif line.startswith('sizecolumn'):
+ instr['size'] = None
+ instr['sizecolumn'] = line.split()[1]
+ elif line.startswith('scale '):
+ instr['scale'] = float(line.split()[1])
+ elif line.startswith('rotate '):
+ instr['rotation'] = True
+ instr['rotate'] = line.split()[1]
+ elif line.startswith('rotatecolumn'):
+ instr['rotatecolumn'] = line.split()[1]
+ instr['rotation'] = True
+ instr['rotate'] = None
+
+ # lines
+ elif text[0].startswith('vlines'):
+ for line in text[1:]:
+ if line.startswith('type'):
+ tp = []
+ if line.find('line') != -1:
+ tp.append('line')
+ if line.find('boundary') != -1:
+ tp.append('boundary')
+ instr['type'] = ' or '.join(tp)
+ elif line.startswith('hwidth'):
+ instr['hwidth'] = float(line.split()[1])
+ elif line.startswith('hcolor'):
+ instr['hcolor'] = line.split()[1]
+ elif line.startswith('rgbcolumn'):
+ instr['rgbcolumn'] = line.split()[1]
+ elif line.startswith('cwidth'):
+ instr['cwidth'] = float(line.split()[1])
+ instr['width'] = None
+ elif line.startswith('style'):
+ instr['style'] = line.split()[1]
+ elif line.startswith('linecap'):
+ instr['linecap'] = line.split()[1]
+
+ elif text[0].startswith('vareas'):
+ for line in text[1:]:
+ if line.startswith('fcolor'):
+ instr['fcolor'] = line.split()[1]
+ elif line.startswith('pat'):
+ instr['pat'] = line.split()[1]
+ elif line.startswith('pwidth'):
+ instr['pwidth'] = float(line.split()[1])
+ elif line.startswith('scale'):
+ instr['scale'] = float(line.split()[1])
+
+
+ # same properties for all
+ for line in text[1:]:
+ if line.startswith('lpos'):
+ instr['lpos'] = int(line.split()[1])
+ elif line.startswith('label'):
+ instr['label'] = line.split(None, 1)[1].decode('latin_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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/instructions.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/menudata.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/menudata.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/menudata.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/menudata.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,162 @@
+"""!
+ 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, BaseIcons
+from icons.icon import MetaIcon
+
+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.frame import havePILImage
+ if not havePILImage:
+ self.EnableTool(self.preview, False)
+
+ def _toolbarData(self):
+ """!Toolbar data
+ """
+ icons = {
+ 'scriptSave' : MetaIcon(img = 'script-save',
+ label = _('Generate text file with mapping instructions')),
+ 'scriptLoad' : MetaIcon(img = 'script-load',
+ label = _('Load text file with mapping instructions')),
+ 'psExport' : MetaIcon(img = 'ps-export',
+ label = _('Generate PostScript output')),
+ 'pdfExport' : MetaIcon(img = 'pdf-export',
+ label = _('Generate PDF output')),
+ 'pageSetup' : MetaIcon(img = 'page-settings',
+ label = _('Page setup'),
+ desc = _('Specify paper size, margins and orientation')),
+ 'fullExtent' : MetaIcon(img = 'zoom-extent',
+ label = _("Full extent"),
+ desc = _("Zoom to full extent")),
+ 'addMap' : MetaIcon(img = 'layer-add',
+ label = _("Map frame"),
+ desc = _("Click and drag to place map frame")),
+ 'deleteObj' : MetaIcon(img = 'layer-remove',
+ label = _("Delete selected object")),
+ 'preview' : MetaIcon(img = 'execute',
+ label = _("Show preview")),
+ 'quit' : MetaIcon(img = 'quit',
+ label = _('Quit Cartographic Composer')),
+ 'addText' : MetaIcon(img = 'text-add',
+ label = _('Text')),
+ 'addMapinfo' : MetaIcon(img = 'map-info',
+ label = _('Map info')),
+ 'addLegend' : MetaIcon(img = 'legend-add',
+ label = _('Legend')),
+ 'addScalebar' : MetaIcon(img = 'scalebar-add',
+ label = _('Scale bar')),
+ 'addImage' : MetaIcon(img = 'image-add',
+ label = _('Image')),
+ 'addNorthArrow': MetaIcon(img = 'north-arrow-add',
+ label = _('North Arrow')),
+ 'drawGraphics': MetaIcon(img = 'edit',
+ label = _('Add simple graphics')),
+ 'pointAdd' : MetaIcon(img = '',
+ label = _('Point')),
+ 'lineAdd' : MetaIcon(img = '',
+ label = _('Line')),
+ 'rectangleAdd': MetaIcon(img = '',
+ label = _('Rectangle')),
+ }
+ self.icons = icons
+
+ return self._getToolbarData((('loadFile', icons['scriptLoad'],
+ self.parent.OnLoadFile),
+ ('instructionFile', icons['scriptSave'],
+ self.parent.OnInstructionFile),
+ (None, ),
+ ('pagesetup', icons['pageSetup'],
+ self.parent.OnPageSetup),
+ (None, ),
+ ("pointer", BaseIcons["pointer"],
+ self.parent.OnPointer, wx.ITEM_CHECK),
+ ('pan', BaseIcons['pan'],
+ self.parent.OnPan, wx.ITEM_CHECK),
+ ("zoomin", BaseIcons["zoomIn"],
+ self.parent.OnZoomIn, wx.ITEM_CHECK),
+ ("zoomout", BaseIcons["zoomOut"],
+ self.parent.OnZoomOut, wx.ITEM_CHECK),
+ ('zoomAll', icons['fullExtent'],
+ self.parent.OnZoomAll),
+ (None, ),
+ ('addMap', icons['addMap'],
+ self.parent.OnAddMap, wx.ITEM_CHECK),
+ ('addRaster', BaseIcons['addRast'],
+ self.parent.OnAddRaster),
+ ('addVector', BaseIcons['addVect'],
+ self.parent.OnAddVect),
+ ("dec", BaseIcons["overlay"],
+ self.OnDecoration),
+ ("drawGraphics", icons["drawGraphics"],
+ self.OnDrawGraphics, wx.ITEM_CHECK),
+ ("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", BaseIcons['help'],
+ self.parent.OnHelp),
+ ('quit', icons['quit'],
+ self.parent.OnCloseWindow))
+ )
+
+ def OnDecoration(self, event):
+ """!Decorations overlay menu
+ """
+ self._onMenu(((self.icons["addLegend"], self.parent.OnAddLegend),
+ (self.icons["addMapinfo"], self.parent.OnAddMapinfo),
+ (self.icons["addScalebar"], self.parent.OnAddScalebar),
+ (self.icons["addText"], self.parent.OnAddText),
+ (self.icons["addImage"], self.parent.OnAddImage),
+ (self.icons["addNorthArrow"], self.parent.OnAddNorthArrow)))
+
+ def OnDrawGraphics(self, event):
+ """!Simple geometry features (point, line, rectangle) overlay menu
+ """
+ # we need the previous id
+ self.actionOld = self.action['id']
+ self.OnTool(event)
+ self.action['id'] = self.actionOld
+ self._onMenu(((self.icons["pointAdd"], self.parent.OnAddPoint),
+ (self.icons["lineAdd"], self.parent.OnAddLine),
+ (self.icons["rectangleAdd"], self.parent.OnAddRectangle),
+ ))
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/psmap/utils.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/psmap/utils.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/psmap/utils.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,422 @@
+"""!
+ at package psmap.utils
+
+ at brief utilities for wxpsmap (classes, functions)
+
+Classes:
+ - utils::Rect2D
+ - utils::Rect2DPP
+ - utils::Rect2DPS
+ - utils::UnitConversion
+
+(C) 2012 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>
+"""
+
+import wx
+from math import ceil, floor, sin, cos, pi
+
+try:
+ import Image as PILImage
+ havePILImage = True
+except ImportError:
+ havePILImage = False
+
+import grass.script as grass
+from core.gcmd import RunCommand
+
+class Rect2D(wx.Rect2D):
+ """!Class representing rectangle with floating point values.
+
+ Overrides wx.Rect2D to unify Rect access methods, which are
+ different (e.g. wx.Rect.GetTopLeft() x wx.Rect2D.GetLeftTop()).
+ More methods can be added depending on needs.
+ """
+ def __init__(self, x = 0, y = 0, width = 0, height = 0):
+ wx.Rect2D.__init__(self, x = x, y = y, w = width, h = height)
+
+ def GetX(self):
+ return self.x
+
+ def GetY(self):
+ return self.y
+
+ def GetWidth(self):
+ return self.width
+
+ def SetWidth(self, width):
+ self.width = width
+
+ def GetHeight(self):
+ return self.height
+
+ def SetHeight(self, height):
+ self.height = height
+
+class Rect2DPP(Rect2D):
+ """!Rectangle specified by 2 points (with floating point values).
+
+ @see Rect2D, Rect2DPS
+ """
+ def __init__(self, topLeft = wx.Point2D(), bottomRight = wx.Point2D()):
+ Rect2D.__init__(self, x = 0, y = 0, width = 0, height = 0)
+
+ x1, y1 = topLeft[0], topLeft[1]
+ x2, y2 = bottomRight[0], bottomRight[1]
+
+ self.SetLeft(min(x1, x2))
+ self.SetTop(min(y1, y2))
+ self.SetRight(max(x1, x2))
+ self.SetBottom(max(y1, y2))
+
+class Rect2DPS(Rect2D):
+ """!Rectangle specified by point and size (with floating point values).
+
+ @see Rect2D, Rect2DPP
+ """
+ def __init__(self, pos = wx.Point2D(), size = (0, 0)):
+ Rect2D.__init__(self, x = pos[0], y = pos[1], width = size[0], height = size[1])
+
+class UnitConversion:
+ """! Class for converting units"""
+ def __init__(self, parent = None):
+ self.parent = parent
+ if self.parent:
+ ppi = wx.ClientDC(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']
+
+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(mapInstr, x, y, paperToMap = True):
+ """!Converts paper (inch) coordinates <-> map coordinates.
+
+ @param mapInstr map frame instruction
+ @param x,y paper coords in inches or mapcoords in map units
+ @param paperToMap specify conversion direction
+ """
+ region = grass.region()
+ mapWidthPaper = mapInstr['rect'].GetWidth()
+ mapHeightPaper = mapInstr['rect'].GetHeight()
+ mapWidthEN = region['e'] - region['w']
+ mapHeightEN = region['n'] - region['s']
+
+ if paperToMap:
+ diffX = x - mapInstr['rect'].GetX()
+ diffY = y - mapInstr['rect'].GetY()
+ diffEW = diffX * mapWidthEN / mapWidthPaper
+ diffNS = diffY * mapHeightEN / mapHeightPaper
+ e = region['w'] + diffEW
+ n = region['n'] - diffNS
+
+ if projInfo()['proj'] == 'll':
+ return e, n
+ else:
+ return int(e), int(n)
+
+ else:
+ diffEW = x - region['w']
+ diffNS = region['n'] - y
+ diffX = mapWidthPaper * diffEW / mapWidthEN
+ diffY = mapHeightPaper * diffNS / mapHeightEN
+ xPaper = mapInstr['rect'].GetX() + diffX
+ yPaper = mapInstr['rect'].GetY() + diffY
+
+ return xPaper, yPaper
+
+
+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), 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 Rect2D(bb[0], bb[3], bb[2] - bb[0], bb[1] - bb[3])
+
+def getRasterType(map):
+ """!Returns type of raster map (CELL, FCELL, DCELL)"""
+ if map is None:
+ map = ''
+ file = grass.find_file(name = map, element = 'cell')
+ if file['file']:
+ rasterType = grass.raster_info(map)['datatype']
+ return rasterType
+ else:
+ return None
+
+def PilImageToWxImage(pilImage, copyAlpha = True):
+ """!Convert PIL image to wx.Image
+
+ Based on http://wiki.wxpython.org/WorkingWithImages
+ """
+ hasAlpha = pilImage.mode[-1] == 'A'
+ if copyAlpha and hasAlpha : # Make sure there is an alpha layer copy.
+ wxImage = wx.EmptyImage( *pilImage.size )
+ pilImageCopyRGBA = pilImage.copy()
+ pilImageCopyRGB = pilImageCopyRGBA.convert('RGB') # RGBA --> RGB
+ pilImageRgbData = pilImageCopyRGB.tostring()
+ wxImage.SetData(pilImageRgbData)
+ wxImage.SetAlphaData(pilImageCopyRGBA.tostring()[3::4]) # Create layer and insert alpha values.
+
+ else : # The resulting image will not have alpha.
+ wxImage = wx.EmptyImage(*pilImage.size)
+ pilImageCopy = pilImage.copy()
+ pilImageCopyRGB = pilImageCopy.convert('RGB') # Discard any alpha from the PIL image.
+ pilImageRgbData = pilImageCopyRGB.tostring()
+ wxImage.SetData(pilImageRgbData)
+
+ return wxImage
+
+def BBoxAfterRotation(w, h, angle):
+ """!Compute bounding box or rotated rectangle
+
+ @param w rectangle width
+ @param h rectangle height
+ @param angle angle (0, 360) in degrees
+ """
+ angleRad = angle / 180. * pi
+ ct = cos(angleRad)
+ st = sin(angleRad)
+
+ hct = h * ct
+ wct = w * ct
+ hst = h * st
+ wst = w * st
+ y = x = 0
+
+ if 0 < angle <= 90:
+ y_min = y
+ y_max = y + hct + wst
+ x_min = x - hst
+ x_max = x + wct
+ elif 90 < angle <= 180:
+ y_min = y + hct
+ y_max = y + wst
+ x_min = x - hst + wct
+ x_max = x
+ elif 180 < angle <= 270:
+ y_min = y + wst + hct
+ y_max = y
+ x_min = x + wct
+ x_max = x - hst
+ elif 270 < angle <= 360:
+ y_min = y + wst
+ y_max = y + hct
+ x_min = x
+ x_max = x + wct - hst
+
+ width = int(ceil(abs(x_max) + abs(x_min)))
+ height = int(ceil(abs(y_max) + abs(y_min)))
+ return width, height
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/psmap/utils.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/states.txt
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/states.txt (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/states.txt 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/states.txt
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Author Date Id
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/tools/update_menudata.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/tools/update_menudata.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/tools/update_menudata.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -30,23 +30,24 @@
from grass.script import core as grass
from grass.script import task as gtask
-sys.path.append('gui_modules')
-import menudata
+if __name__ == "__main__":
+ sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython'))
+from lmgr.menudata import ManagerData
+from core.globalvar import grassCmd
def parseModules():
"""!Parse modules' interface"""
modules = dict()
# list of modules to be ignored
- ignore = [ 'mkftcap',
+ ignore = [ 'g.mapsets_picker.py',
+ 'v.type_wrapper.py',
'g.parser',
- 'r.mapcalc',
- 'r3.mapcalc',
'vcolors' ]
- count = len(globalvar.grassCmd['all'])
+ count = len(grassCmd)
i = 0
- for module in globalvar.grassCmd['all']:
+ for module in grassCmd:
i += 1
if i % 10 == 0:
grass.info('* %d/%d' % (i, count))
@@ -54,8 +55,8 @@
continue
try:
interface = gtask.parse_interface(module)
- except:
- grass.error(module)
+ except (StandardError, grass.ScriptError), e:
+ grass.error(module + ': ' + str(e))
continue
modules[interface.name] = { 'label' : interface.label,
'desc' : interface.description,
@@ -69,7 +70,7 @@
ignore = ['v.type_wrapper.py',
'vcolors']
- menu_modules = list()
+ menu_modules = list()
for node in data.tree.getiterator():
if node.tag != 'menuitem':
continue
@@ -105,7 +106,7 @@
node.find('keywords').text = ','.join(modules[module]['keywords'])
menu_modules.append(item['command'])
-
+
for module in modules.keys():
if module not in menu_modules:
grass.warning("'%s' not available from the menu" % module)
@@ -150,7 +151,7 @@
modules = dict()
modules = parseModules()
grass.info("Step 3: reading menu data...")
- data = menudata.ManagerData()
+ data = ManagerData()
grass.info("Step 4: updating menu data...")
updateData(data, modules)
@@ -172,9 +173,4 @@
if os.getenv("GISBASE") is None:
sys.exit("You must be in GRASS GIS to run this program.")
- sys.path.append(os.path.join(os.getenv("GISBASE"), 'etc', 'wxpython', 'gui_modules'))
- import menudata
- import menuform
- import globalvar
-
sys.exit(main())
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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 than 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 than zero.") %
+ {'layer' : str(self.layerNew.GetValue()),
+ 'category' : str(self.catNew.GetValue())})
+ return False
+
+ if layer not in self.cats[self.fid].keys():
+ self.cats[self.fid][layer] = []
+
+ self.cats[self.fid][layer].append(cat)
+
+ # reload list
+ self.itemDataMap = self.list.Populate(self.cats[self.fid],
+ update = True)
+
+ # update category number for add
+ self.catNew.SetValue(cat + 1)
+
+ event.Skip()
+
+ return True
+
+ def GetLine(self):
+ """!Get id of selected line of 'None' if no line is selected
+ """
+ return self.cats.keys()
+
+ def UpdateDialog(self, query = None, cats = None):
+ """!Update dialog
+
+ @param query {coordinates, distance} - v.what
+ @param cats directory layer/cats - vdigit
+ Return True if updated otherwise False
+ """
+ # line: {layer: [categories]}
+ self.cats = {}
+ # do not display dialog if no line is found (-> self.cats)
+ if cats is None:
+ ret = self._getCategories(query[0], query[1])
+ else:
+ self.cats = cats
+ for line in cats.keys():
+ for layer in cats[line].keys():
+ self.cats[line][layer] = list(cats[line][layer])
+ ret = 1
+ if ret == 0 or len(self.cats.keys()) < 1:
+ Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
+ return False
+
+ # make copy of cats (used for 'reload')
+ self.cats_orig = copy.deepcopy(self.cats)
+
+ # polulate list
+ self.fid = self.cats.keys()[0]
+ self.itemDataMap = self.list.Populate(self.cats[self.fid],
+ update = True)
+
+ try:
+ newCat = max(self.cats[self.fid][1]) + 1
+ except KeyError:
+ newCat = 1
+ self.catNew.SetValue(newCat)
+
+ if len(self.cats.keys()) == 1:
+ self.fidText.Show(True)
+ self.fidMulti.Show(False)
+ self.fidText.SetLabel("%d" % self.fid)
+ else:
+ self.fidText.Show(False)
+ self.fidMulti.Show(True)
+ choices = []
+ for fid in self.cats.keys():
+ choices.append(str(fid))
+ self.fidMulti.SetItems(choices)
+ self.fidMulti.SetSelection(0)
+
+ self.Layout()
+
+ return True
+
+class CategoryListCtrl(wx.ListCtrl,
+ listmix.ListCtrlAutoWidthMixin,
+ listmix.TextEditMixin):
+ def __init__(self, parent, id, pos = wx.DefaultPosition,
+ size = wx.DefaultSize, style = 0):
+ """!List of layers/categories"""
+ self.parent = parent
+
+ wx.ListCtrl.__init__(self, parent, id, pos, size, style)
+
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+ listmix.TextEditMixin.__init__(self)
+
+ def Populate(self, cats, update = False):
+ """!Populate the list
+ """
+ itemData = {} # requested by sorter
+
+ if not update:
+ self.InsertColumn(0, _("Layer"))
+ self.InsertColumn(1, _("Category"))
+ else:
+ self.DeleteAllItems()
+
+ i = 1
+ for layer in cats.keys():
+ catsList = cats[layer]
+ for cat in catsList:
+ index = self.InsertStringItem(sys.maxint, str(catsList[0]))
+ self.SetStringItem(index, 0, str(layer))
+ self.SetStringItem(index, 1, str(cat))
+ self.SetItemData(index, i)
+ itemData[i] = (str(layer), str(cat))
+ i = i + 1
+
+ if not update:
+ self.SetColumnWidth(0, 100)
+ self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
+
+ self.currentItem = 0
+
+ return itemData
+
+class VDigitZBulkDialog(wx.Dialog):
+ def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
+ """!Dialog used for Z bulk-labeling tool
+ """
+ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
+
+ self.parent = parent # mapdisplay.BufferedWindow class instance
+
+ # panel = wx.Panel(parent=self, id=wx.ID_ANY)
+
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ txt = wx.StaticText(parent = self,
+ label = _("%d lines selected for z bulk-labeling") % nselected);
+ border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
+
+ box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
+ flexSizer.AddGrowableCol(0)
+
+ # starting value
+ txt = wx.StaticText(parent = self,
+ label = _("Starting value"));
+ self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
+ initial = 0,
+ min = -1e6, max = 1e6)
+ flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+
+ # step
+ txt = wx.StaticText(parent = self,
+ label = _("Step"))
+ self.step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
+ initial = 0,
+ min = 0, max = 1e6)
+ flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
+
+ sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
+ border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
+
+ # buttons
+ btnCancel = wx.Button(self, wx.ID_CANCEL)
+ btnOk = wx.Button(self, wx.ID_OK)
+ btnOk.SetDefault()
+
+ # sizers
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(btnCancel)
+ btnSizer.AddButton(btnOk)
+ btnSizer.Realize()
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ mainSizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+class VDigitDuplicatesDialog(wx.Dialog):
+ def __init__(self, parent, data, title = _("List of duplicates"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+ pos = wx.DefaultPosition):
+ """!Show duplicated feature ids
+ """
+ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
+ pos = pos)
+
+ self.parent = parent # BufferedWindow
+ self.data = data
+ self.winList = []
+
+ # panel = wx.Panel(parent=self, id=wx.ID_ANY)
+
+ # notebook
+ self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
+
+ id = 1
+ for key in self.data.keys():
+ panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY)
+ self.notebook.AddPage(page = panel, text = " %d " % (id))
+
+ # notebook body
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ win = CheckListFeature(parent = panel, data = list(self.data[key]))
+ self.winList.append(win.GetId())
+
+ border.Add(item = win, proportion = 1,
+ flag = wx.ALL | wx.EXPAND, border = 5)
+
+ panel.SetSizer(border)
+
+ id += 1
+
+ # buttons
+ btnCancel = wx.Button(self, wx.ID_CANCEL)
+ btnOk = wx.Button(self, wx.ID_OK)
+ btnOk.SetDefault()
+
+ # sizers
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(btnCancel)
+ btnSizer.AddButton(btnOk)
+ btnSizer.Realize()
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ mainSizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+ self.SetAutoLayout(True)
+
+ # set min size for dialog
+ self.SetMinSize((250, 180))
+
+ def GetUnSelected(self):
+ """!Get unselected items (feature id)
+
+ @return list of ids
+ """
+ ids = []
+ for id in self.winList:
+ wlist = self.FindWindowById(id)
+
+ for item in range(wlist.GetItemCount()):
+ if not wlist.IsChecked(item):
+ ids.append(int(wlist.GetItem(item, 0).GetText()))
+
+ return ids
+
+class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
+ def __init__(self, parent, data,
+ pos = wx.DefaultPosition, log = None):
+ """!List of mapset/owner/group
+ """
+ self.parent = parent
+ self.data = data
+
+ wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
+ style = wx.LC_REPORT)
+
+ listmix.CheckListCtrlMixin.__init__(self)
+
+ self.log = log
+
+ # setup mixins
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+
+ self.LoadData(self.data)
+
+ def LoadData(self, data):
+ """!Load data into list
+ """
+ self.InsertColumn(0, _('Feature id'))
+ self.InsertColumn(1, _('Layer (Categories)'))
+
+ for item in data:
+ index = self.InsertStringItem(sys.maxint, str(item[0]))
+ self.SetStringItem(index, 1, str(item[1]))
+
+ # enable all items by default
+ for item in range(self.GetItemCount()):
+ self.CheckItem(item, True)
+
+ self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
+ self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
+
+ def OnCheckItem(self, index, flag):
+ """!Mapset checked/unchecked
+ """
+ pass
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/main.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/main.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/main.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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, NameError), err:
+ haveVDigit = False
+ errorMsg = err
+ GV_LINES = -1
+ class IVDigit:
+ def __init__(self):
+ pass
+
+class VDigit(IVDigit):
+ def __init__(self, mapwindow):
+ """!Base class of vector digitizer
+
+ @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance
+ """
+ IVDigit.__init__(self, mapwindow)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/main.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/mapwindow.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/mapwindow.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/mapwindow.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1074 @@
+"""!
+ 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 GetDisplay(self):
+ if self.digit:
+ return self.digit.GetDisplay()
+ return None
+
+ 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:
+ GMessage(parent = self,
+ message = _("Nothing to do. "
+ "Choose appropriate tool from digitizer toolbar."))
+ event.Skip()
+ 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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/mapwindow.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/preferences.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/preferences.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/preferences.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/preferences.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/toolbars.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/toolbars.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/toolbars.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,806 @@
+"""!
+ 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, BaseIcons
+from gui_core.dialogs import CreateNewVector
+from vdigit.preferences import VDigitSettingsDialog
+from vdigit.main import VDigit
+from core.debug import Debug
+from core.settings import UserSettings
+from core.gcmd import GError
+from icons.icon import MetaIcon
+
+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 = {
+ 'addPoint' : MetaIcon(img = 'point-create',
+ label = _('Digitize new point'),
+ desc = _('Left: new point')),
+ 'addLine' : MetaIcon(img = 'line-create',
+ label = _('Digitize new line'),
+ desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
+ 'addBoundary' : MetaIcon(img = 'boundary-create',
+ label = _('Digitize new boundary'),
+ desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
+ 'addCentroid' : MetaIcon(img = 'centroid-create',
+ label = _('Digitize new centroid'),
+ desc = _('Left: new point')),
+ 'addArea' : MetaIcon(img = 'polygon-create',
+ label = _('Digitize new area (composition of boundaries without category and one centroid with category)'),
+ desc = _('Left: new point')),
+ 'addVertex' : MetaIcon(img = 'vertex-create',
+ label = _('Add new vertex'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'deleteLine' : MetaIcon(img = 'line-delete',
+ label = _('Delete feature(s)'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'displayAttr' : MetaIcon(img = 'attributes-display',
+ label = _('Display/update attributes'),
+ desc = _('Left: Select')),
+ 'displayCats' : MetaIcon(img = 'cats-display',
+ label = _('Display/update categories'),
+ desc = _('Left: Select')),
+ 'editLine' : MetaIcon(img = 'line-edit',
+ label = _('Edit line/boundary'),
+ desc = _('Left: new point; Ctrl+Left: undo last point; Right: close line')),
+ 'moveLine' : MetaIcon(img = 'line-move',
+ label = _('Move feature(s)'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'moveVertex' : MetaIcon(img = 'vertex-move',
+ label = _('Move vertex'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'removeVertex' : MetaIcon(img = 'vertex-delete',
+ label = _('Remove vertex'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'settings' : BaseIcons['settings'].SetLabel(_('Digitization settings')),
+ 'quit' : BaseIcons['quit'].SetLabel(label = _('Quit digitizer'),
+ desc = _('Quit digitizer and save changes')),
+ 'additionalTools' : MetaIcon(img = 'tools',
+ label = _('Additional tools '
+ '(copy, flip, connect, etc.)'),
+ desc = _('Left: Select; Ctrl+Left: Unselect; Right: Confirm')),
+ 'undo' : MetaIcon(img = 'undo',
+ label = _('Undo'),
+ desc = _('Undo previous changes')),
+ }
+
+ 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/toolbars.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdigit.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdigit.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdigit.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1747 @@
+"""!
+ 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 canceled.'),
+ 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 canceled.') % line,
+ parent = self.parent,
+ caption = self.caption)
+
+ def DbLink(self, dblink):
+ """!No dblink available
+ """
+ GError(message = _('Database link %d not available. '
+ 'Operation canceled.') % dblink,
+ parent = self.parent,
+ caption = self.caption)
+
+ def Driver(self, driver):
+ """!Staring driver failed
+ """
+ GError(message = _('Unable to start database driver <%s>. '
+ 'Operation canceled.') % 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 canceled.') % { '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 canceled.") % sql,
+ parent = self.parent,
+ caption = self.caption)
+
+ def DeadLine(self, line):
+ """!Dead line
+ """
+ GError(message = _("Feature id %d is marked as dead. "
+ "Operation canceled.") % line,
+ parent = self.parent,
+ caption = self.caption)
+
+ def FeatureType(self, ftype):
+ """!Unknown feature type
+ """
+ GError(message = _("Unsupported feature type %d. "
+ "Operation canceled.") % 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:
+ poCatsDel = Vect_new_cats_struct()
+ for i in self._display.selected['ids']:
+ if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
+ Vect_destroy_cats_struct(poCatsDel)
+ self._error.ReadLine(i)
+ return -1
+
+ cats = self.poCats.contents
+ for j in range(cats.n_cats):
+ Vect_cat_set(poCatsDel, cats.field[j], cats.cat[j])
+
+ # 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
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdigit.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdisplay.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdisplay.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdisplay.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,1035 @@
+"""!
+ 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(): line=%d type=%d npoints=%d", robj.fid, robj.type, robj.npoints)
+ brush = None
+ if self._isSelected(robj.fid):
+ pdc = self.dcTmp
+ if robj.type == TYPE_AREA:
+ return 1
+ else:
+ 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 line in self.selected['ids']:
+ 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
+
+ self.selected['field'] = layer
+ if layer > 0:
+ self.selected['cats'] = ids
+ self.selected['ids'] = list()
+ ### cidx is not up-to-date
+ # Vect_cidx_find_all(self.poMapInfo, layer, GV_POINTS | GV_LINES, lid, ilist)
+ nlines = Vect_get_num_lines(self.poMapInfo)
+ for line in range(1, nlines + 1):
+ if not Vect_line_alive(self.poMapInfo, line):
+ continue
+
+ ltype = Vect_read_line (self.poMapInfo, None, self.poCats, line)
+ if not (ltype & (GV_POINTS | GV_LINES)):
+ continue
+
+ found = False
+ cats = self.poCats.contents
+ for i in range(0, cats.n_cats):
+ for cat in self.selected['cats']:
+ if cats.cat[i] == cat:
+ found = True
+ break
+ if found:
+ self.selected['ids'].append(line)
+ else:
+ self.selected['ids'] = ids
+ self.selected['cats'] = []
+
+ 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 GetRegionSelected(self):
+ """!Get minimal region extent of selected features
+
+ @return n,s,w,e
+ """
+ regionBox = bound_box()
+ lineBox = bound_box()
+ setRegion = True
+
+ nareas = Vect_get_num_areas(self.poMapInfo)
+ for line in self.selected['ids']:
+ area = Vect_get_centroid_area(self.poMapInfo, line)
+
+ if area > 0 and area <= nareas:
+ if not Vect_get_area_box(self.poMapInfo, area, byref(lineBox)):
+ continue
+ else:
+ if not Vect_get_line_box(self.poMapInfo, line, byref(lineBox)):
+ continue
+
+ if setRegion:
+ Vect_box_copy(byref(regionBox), byref(lineBox))
+ setRegion = False
+ else:
+ Vect_box_extend(byref(regionBox), byref(lineBox))
+
+ return regionBox.N, regionBox.S, regionBox.W, regionBox.E
+
+ 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'])
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/vdigit/wxdisplay.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -1,1598 +1,38 @@
"""!
- 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
Classes:
- - GMFrame
- - GMApp
+ - 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)
@author Martin Landa <landa.martin gmail.com>
@author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
"""
-import sys
import os
-import time
-import string
+import sys
import getopt
-import platform
-import signal
-import tempfile
-### XML
-try:
- import xml.etree.ElementTree as etree
-except ImportError:
- import elementtree.ElementTree as etree # Python <= 2.4
-
-### i18N
-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', 'wxpython'))
+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 lmgr.frame import GMFrame
-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, UninstallExtensionWindow
-from gui_modules.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar, LMMiscToolbar, LMVectorToolbar
-from gui_modules.gpyshell import PyShellWindow
-from icons.icon import Icons
-
-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)
- commands, tree widget page for managing map layers.
- """
- def __init__(self, parent, id = wx.ID_ANY, title = _("GRASS GIS Layer Manager"),
- workspace = None,
- size = globalvar.GM_WINDOW_SIZE, style = wx.DEFAULT_FRAME_STYLE, **kwargs):
- self.parent = parent
- self.baseTitle = title
- self.iconsize = (16, 16)
-
- wx.Frame.__init__(self, parent = parent, id = id, size = size,
- style = style, **kwargs)
-
- self.SetTitle(self.baseTitle)
- self.SetName("LayerManager")
-
- self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
-
- self._auimgr = wx.aui.AuiManager(self)
-
- # initialize variables
- self.disp_idx = 0 # index value for map displays and layer trees
- self.curr_page = None # currently selected page for layer tree notebook
- self.curr_pagenum = None # currently selected page number for layer tree notebook
- self.workspaceFile = workspace # workspace file
- self.workspaceChanged = False # track changes in workspace
- self.georectifying = None # reference to GCP class or None
- self.gcpmanagement = None # reference to GCP class or None
- # list of open dialogs
- self.dialogs = dict()
- self.dialogs['preferences'] = None
- self.dialogs['atm'] = list()
-
- # creating widgets
- self._createMenuBar()
- self.statusbar = self.CreateStatusBar(number = 1)
- self.notebook = self._createNoteBook()
- self.toolbars = { 'workspace' : LMWorkspaceToolbar(parent = self),
- 'data' : LMDataToolbar(parent = self),
- 'tools' : LMToolsToolbar(parent = self),
- 'misc' : LMMiscToolbar(parent = self),
- 'vector' : LMVectorToolbar(parent = self) }
-
- self._toolbarsData = { 'workspace' : ("toolbarWorkspace", # name
- _("Workspace Toolbar"), # caption
- 1), # row
- 'data' : ("toolbarData",
- _("Data Toolbar"),
- 1),
- 'misc' : ("toolbarMisc",
- _("Misc Toolbar"),
- 2),
- 'tools' : ("toolbarTools",
- _("Tools Toolbar"),
- 2),
- 'vector' : ("toolbarVector",
- _("Vector Toolbar"),
- 2),
- }
- if sys.platform == 'win32':
- self._toolbarsList = ('workspace', 'data',
- 'vector', 'tools', 'misc')
- else:
- self._toolbarsList = ('data', 'workspace',
- 'misc', 'tools', 'vector')
- for toolbar in self._toolbarsList:
- name, caption, row = self._toolbarsData[toolbar]
- self._auimgr.AddPane(self.toolbars[toolbar],
- wx.aui.AuiPaneInfo().
- Name(name).Caption(caption).
- ToolbarPane().Top().Row(row).
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2).
- BestSize((self.toolbars[toolbar].GetBestSize())))
-
- # bindings
- self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
- self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-
- # minimal frame size
- self.SetMinSize((500, 400))
-
- # AUI stuff
- self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
- Left().CentrePane().BestSize((-1,-1)).Dockable(False).
- CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
-
- self._auimgr.Update()
-
- wx.CallAfter(self.notebook.SetSelectionByName, 'layers')
-
- # use default window layout ?
- if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
- dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
- try:
- x, y = map(int, dim.split(',')[0:2])
- w, h = map(int, dim.split(',')[2:4])
- self.SetPosition((x, y))
- self.SetSize((w, h))
- except:
- pass
- else:
- self.Centre()
-
- self.Layout()
- self.Show()
-
- # load workspace file if requested
- if self.workspaceFile:
- # load given workspace file
- if self.LoadWorkspaceFile(self.workspaceFile):
- self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
- else:
- self.workspaceFile = None
- else:
- # start default initial display
- self.NewDisplay(show = False)
-
- # show map display widnow
- # -> OnSize() -> UpdateMap()
- if self.curr_page and not self.curr_page.maptree.mapdisplay.IsShown():
- self.curr_page.maptree.mapdisplay.Show()
-
- # redirect stderr to log area
- self.goutput.Redirect()
- # fix goutput's pane size
- self.goutput.SetSashPosition(int(self.GetSize()[1] * .60))
-
- self.workspaceChanged = False
-
- # start with layer manager on top
- if self.curr_page:
- self.curr_page.maptree.mapdisplay.Raise()
- wx.CallAfter(self.Raise)
-
- def _createMenuBar(self):
- """!Creates menu bar"""
- self.menubar = menu.Menu(parent = self, data = menudata.ManagerData())
- self.SetMenuBar(self.menubar)
- self.menucmd = self.menubar.GetCmd()
-
- def _setCopyingOfSelectedText(self):
- copy = UserSettings.Get(group = 'manager', key = 'copySelectedTextToClipboard', subkey = 'enabled')
- self.goutput.SetCopyingOfSelectedText(copy)
-
- def _createNoteBook(self):
- """!Creates notebook widgets"""
- self.notebook = menuform.GNotebook(parent = self, style = globalvar.FNPageDStyle)
- # create displays notebook widget and add it to main notebook page
- cbStyle = globalvar.FNPageStyle
- if globalvar.hasAgw:
- self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, agwStyle = cbStyle)
- else:
- self.gm_cb = FN.FlatNotebook(self, id = wx.ID_ANY, style = cbStyle)
- self.gm_cb.SetTabAreaColour(globalvar.FNPageColor)
- self.notebook.AddPage(page = self.gm_cb, text = _("Map layers"), name = 'layers')
-
- # create 'command output' text area
- self.goutput = goutput.GMConsole(self)
- self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
- self._setCopyingOfSelectedText()
-
- # create 'search module' notebook page
- if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'search'):
- self.search = MenuTreeWindow(parent = self)
- self.notebook.AddPage(page = self.search, text = _("Search module"), name = 'search')
- else:
- self.search = None
-
- # create 'python shell' notebook page
- if not UserSettings.Get(group = 'manager', key = 'hideTabs', subkey = 'pyshell'):
- self.pyshell = PyShellWindow(parent = self)
- self.notebook.AddPage(page = self.pyshell, text = _("Python shell"), name = 'pyshell')
- else:
- self.pyshell = None
-
- # bindings
- self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnCBPageChanged)
- self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
- self.gm_cb.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.OnCBPageClosed)
-
- return self.notebook
-
- def AddNviz(self):
- """!Add nviz notebook page"""
- self.nviz = nviz_tools.NvizToolWindow(parent = self,
- display = self.curr_page.maptree.GetMapDisplay())
- self.notebook.AddPage(page = self.nviz, text = _("3D view"), name = 'nviz')
- self.notebook.SetSelectionByName('nviz')
-
- def RemoveNviz(self):
- """!Remove nviz notebook page"""
- # print self.notebook.GetPage(1)
- self.notebook.RemovePage(self.notebook.GetPageIndexByName('nviz'))
- del self.nviz
- self.notebook.SetSelectionByName('layers')
-
- def WorkspaceChanged(self):
- """!Update window title"""
- if not self.workspaceChanged:
- self.workspaceChanged = True
-
- if self.workspaceFile:
- self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile) + '*')
-
- def OnSettingsChanged(self, event):
- """!Here can be functions which have to be called after EVT_SETTINGS_CHANGED.
- Now only set copying of selected text to clipboard (in goutput).
- """
- ### self._createMenuBar() # bug when menu is re-created on the fly
- self._setCopyingOfSelectedText()
-
- def OnGCPManager(self, event):
- """!Launch georectifier module
- """
- from gui_modules import gcpmanager
- gcpmanager.GCPWizard(self)
-
- def OnGModeler(self, event):
- """!Launch Graphical Modeler"""
- win = gmodeler.ModelFrame(parent = self)
- win.CentreOnScreen()
-
- win.Show()
-
- def OnPsMap(self, event):
- """!Launch Cartographic Composer
- """
- 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')
- return
-
- win = psmap.PsMapFrame(parent = self)
- win.CentreOnScreen()
-
- win.Show()
-
- def OnDone(self, cmd, returncode):
- """Command execution finised"""
- if hasattr(self, "model"):
- self.model.DeleteIntermediateData(log = self.goutput)
- del self.model
- self.SetStatusText('')
-
- def OnRunModel(self, event):
- """!Run model"""
- filename = ''
- dlg = wx.FileDialog(parent = self, message =_("Choose model to run"),
- defaultDir = os.getcwd(),
- wildcard = _("GRASS Model File (*.gxm)|*.gxm"))
- if dlg.ShowModal() == wx.ID_OK:
- filename = dlg.GetPath()
-
- if not filename:
- dlg.Destroy()
- return
-
- self.model = gmodeler.Model()
- self.model.LoadModel(filename)
- self.model.Run(log = self.goutput, onDone = self.OnDone, parent = self)
-
- dlg.Destroy()
-
- def OnMapsets(self, event):
- """!Launch mapset access dialog
- """
- dlg = preferences.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))
-
- def OnCBPageChanged(self, event):
- """!Page in notebook (display) changed"""
- old_pgnum = event.GetOldSelection()
- new_pgnum = event.GetSelection()
-
- self.curr_page = self.gm_cb.GetCurrentPage()
- self.curr_pagenum = self.gm_cb.GetSelection()
- try:
- self.curr_page.maptree.mapdisplay.SetFocus()
- self.curr_page.maptree.mapdisplay.Raise()
- except:
- pass
-
- event.Skip()
-
- def OnPageChanged(self, event):
- """!Page in notebook changed"""
- page = event.GetSelection()
- if page == self.notebook.GetPageIndexByName('output'):
- # remove '(...)'
- self.notebook.SetPageText(page, _("Command console"))
- wx.CallAfter(self.goutput.cmd_prompt.SetFocus)
- self.SetStatusText('', 0)
-
- event.Skip()
-
- def OnCBPageClosed(self, event):
- """!Page of notebook closed
- Also close associated map display
- """
- if UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
- maptree = self.curr_page.maptree
-
- if self.workspaceFile:
- message = _("Do you want to save changes in the workspace?")
- else:
- message = _("Do you want to store current settings "
- "to workspace file?")
-
- # ask user to save current settings
- if maptree.GetCount() > 0:
- dlg = wx.MessageDialog(self,
- message = message,
- caption = _("Close Map Display %d") % (self.curr_pagenum + 1),
- 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.workspaceFile:
- self.OnWorkspaceSaveAs()
- else:
- self.SaveToWorkspaceFile(self.workspaceFile)
- elif ret == wx.ID_CANCEL:
- event.Veto()
- dlg.Destroy()
- return
- dlg.Destroy()
-
- self.gm_cb.GetPage(event.GetSelection()).maptree.Map.Clean()
- self.gm_cb.GetPage(event.GetSelection()).maptree.Close(True)
-
- self.curr_page = None
-
- event.Skip()
-
- def GetLayerTree(self):
- """!Get current layer tree"""
- return self.curr_page.maptree
-
- def GetLogWindow(self):
- """!Get widget for command output"""
- return self.goutput
-
- def GetMenuCmd(self, event):
- """!Get GRASS command from menu item
-
- Return command as a list"""
- layer = None
-
- if event:
- cmd = self.menucmd[event.GetId()]
-
- try:
- cmdlist = cmd.split(' ')
- except: # already list?
- cmdlist = cmd
-
- # check list of dummy commands for GUI modules that do not have GRASS
- # bin modules or scripts.
- if cmd in ['vcolors', 'r.mapcalc', 'r3.mapcalc']:
- return cmdlist
-
- try:
- layer = self.curr_page.maptree.layer_selected
- name = self.curr_page.maptree.GetPyData(layer)[0]['maplayer'].name
- type = self.curr_page.maptree.GetPyData(layer)[0]['type']
- except:
- layer = None
-
- 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])
- if input:
- cmdlist.append("%s=%s" % (input, name))
-
- return cmdlist
-
- def RunMenuCmd(self, event = None, cmd = []):
- """!Run command selected from menu"""
- if event:
- cmd = self.GetMenuCmd(event)
- self.goutput.RunCmd(cmd, switchPage = False)
-
- def OnMenuCmd(self, event = None, cmd = []):
- """!Parse command selected from menu"""
- if event:
- cmd = self.GetMenuCmd(event)
- menuform.GUI(parent = self).ParseCommand(cmd)
-
- def OnVDigit(self, event):
- """!Start vector digitizer
- """
- if not self.curr_page:
- self.MsgNoLayerSelected()
- return
-
- tree = self.GetLayerTree()
- layer = tree.layer_selected
- # no map layer selected
- if not layer:
- self.MsgNoLayerSelected()
- return
-
- # available only for vector map layers
- try:
- mapLayer = tree.GetPyData(layer)[0]['maplayer']
- except:
- mapLayer = None
-
- if not mapLayer or mapLayer.GetType() != 'vector':
- gcmd.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."))
- return
-
- if not tree.GetPyData(layer)[0]:
- return
- dcmd = tree.GetPyData(layer)[0]['cmd']
- if not dcmd:
- return
-
- tree.OnStartEditing(None)
-
- def OnRunScript(self, event):
- """!Run script"""
- # open dialog and choose script file
- dlg = wx.FileDialog(parent = self, message = _("Choose script file to run"),
- defaultDir = os.getcwd(),
- wildcard = _("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"))
-
- filename = None
- if dlg.ShowModal() == wx.ID_OK:
- filename = dlg.GetPath()
-
- if not filename:
- return False
-
- if not os.path.exists(filename):
- gcmd.GError(parent = self,
- message = _("Script file '%s' doesn't exist. "
- "Operation cancelled.") % filename)
- return
-
- self.goutput.WriteCmdLog(_("Launching script '%s'...") % filename)
- self.goutput.RunCmd([filename], switchPage = True)
-
- def OnChangeLocation(self, event):
- """Change current location"""
- dlg = gdialogs.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)
- if ret > 0:
- wx.MessageBox(parent = self,
- message = _("Unable to switch to location <%(loc)s> mapset <%(mapset)s>.") % \
- { 'loc' : location, 'mapset' : mapset },
- caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
- else:
- # close workspace
- self.OnWorkspaceClose()
- self.OnWorkspaceNew()
- wx.MessageBox(parent = self,
- message = _("Current location is <%(loc)s>.\n"
- "Current mapset is <%(mapset)s>.") % \
- { 'loc' : location, 'mapset' : mapset },
- caption = _("Info"), style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-
- def OnChangeMapset(self, event):
- """Change current mapset"""
- dlg = gdialogs.MapsetDialog(parent = self)
- if dlg.ShowModal() == wx.ID_OK:
- mapset = dlg.GetMapset()
- if mapset:
- if gcmd.RunCommand("g.gisenv",
- set = "MAPSET=%s" % mapset) != 0:
- wx.MessageBox(parent = self,
- message = _("Unable to switch to mapset <%s>.") % mapset,
- caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
- else:
- wx.MessageBox(parent = self,
- message = _("Current mapset is <%s>.") % mapset,
- caption = _("Info"), style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-
- def OnNewVector(self, event):
- """!Create new vector map layer"""
- dlg = gdialogs.CreateNewVector(self, log = self.goutput,
- cmd = (('v.edit',
- { 'tool' : 'create' },
- 'map')))
-
- if not dlg:
- return
-
- name = dlg.GetName(full = True)
- if name and dlg.IsChecked('add'):
- # add layer to map layer tree
- self.curr_page.maptree.AddLayer(ltype = 'vector',
- lname = name,
- lcmd = ['d.vect', 'map=%s' % name])
-
- # create table ?
- if dlg.IsChecked('table'):
- self.OnShowAttributeTable(None, selection = 1)
-
- dlg.Destroy()
-
- def OnAboutGRASS(self, event):
- """!Display 'About GRASS' dialog"""
- win = AboutWindow(self)
- win.CentreOnScreen()
- win.Show(True)
-
- def _popupMenu(self, data):
- """!Create popup menu
- """
- point = wx.GetMousePosition()
- menu = wx.Menu()
-
- for key, handler in data:
- if key is None:
- menu.AppendSeparator()
- continue
- item = wx.MenuItem(menu, wx.ID_ANY, Icons['layerManager'][key].GetLabel())
- item.SetBitmap(Icons['layerManager'][key].GetBitmap(self.iconsize))
- menu.AppendItem(item)
- self.Bind(wx.EVT_MENU, handler, item)
-
- # create menu
- self.PopupMenu(menu)
- menu.Destroy()
-
- def OnImportMenu(self, event):
- """!Import maps menu (import, link)
- """
- self._popupMenu((('rastImport', self.OnImportGdalLayers),
- ('vectImport', self.OnImportOgrLayers)))
-
- def OnWorkspaceNew(self, event = None):
- """!Create new workspace file
-
- Erase current workspace settings first
- """
- Debug.msg(4, "GMFrame.OnWorkspaceNew():")
-
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay()
-
- maptree = self.curr_page.maptree
-
- # ask user to save current settings
- if self.workspaceFile and self.workspaceChanged:
- self.OnWorkspaceSave()
- elif self.workspaceFile is None and maptree.GetCount() > 0:
- dlg = wx.MessageDialog(self, message = _("Current workspace is not empty. "
- "Do you want to store current settings "
- "to workspace file?"),
- caption = _("Create new workspace?"),
- style = wx.YES_NO | wx.YES_DEFAULT | \
- wx.CANCEL | wx.ICON_QUESTION)
- ret = dlg.ShowModal()
- if ret == wx.ID_YES:
- self.OnWorkspaceSaveAs()
- elif ret == wx.ID_CANCEL:
- dlg.Destroy()
- return
-
- dlg.Destroy()
-
- # delete all items
- maptree.DeleteAllItems()
-
- # add new root element
- maptree.root = maptree.AddRoot("Map Layers")
- self.curr_page.maptree.SetPyData(maptree.root, (None,None))
-
- # no workspace file loaded
- self.workspaceFile = None
- self.workspaceChanged = False
- self.SetTitle(self.baseTitle)
-
- def OnWorkspaceOpen(self, event = None):
- """!Open file with workspace definition"""
- dlg = wx.FileDialog(parent = self, message = _("Choose workspace file"),
- defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"))
-
- filename = ''
- if dlg.ShowModal() == wx.ID_OK:
- filename = dlg.GetPath()
-
- if filename == '':
- return
-
- Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename)
-
- # delete current layer tree content
- self.OnWorkspaceClose()
-
- self.LoadWorkspaceFile(filename)
-
- self.workspaceFile = filename
- self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
-
- def LoadWorkspaceFile(self, filename):
- """!Load layer tree definition stored in GRASS Workspace XML file (gxw)
-
- @todo Validate against DTD
-
- @return True on success
- @return False on error
- """
- # dtd
- dtdFilename = os.path.join(globalvar.ETCWXDIR, "xml", "grass-gxw.dtd")
-
- # parse workspace file
- try:
- gxwXml = workspace.ProcessWorkspaceFile(etree.parse(filename))
- except Exception, e:
- gcmd.GError(parent = self,
- message = _("Reading workspace file <%s> failed.\n"
- "Invalid file, unable to parse XML document.") % filename)
- return
-
- busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
- parent = self)
- wx.Yield()
-
- #
- # load layer manager window properties
- #
- if UserSettings.Get(group = 'workspace', key = 'posManager', subkey = 'enabled') is False:
- if gxwXml.layerManager['pos']:
- self.SetPosition(gxwXml.layerManager['pos'])
- if gxwXml.layerManager['size']:
- self.SetSize(gxwXml.layerManager['size'])
-
- #
- # start map displays first (list of layers can be empty)
- #
- displayId = 0
- mapdisplay = list()
- for display in gxwXml.displays:
- mapdisp = self.NewDisplay(show = False)
- mapdisplay.append(mapdisp)
- maptree = self.gm_cb.GetPage(displayId).maptree
-
- # set windows properties
- mapdisp.SetProperties(render = display['render'],
- mode = display['mode'],
- showCompExtent = display['showCompExtent'],
- constrainRes = display['constrainRes'],
- projection = display['projection']['enabled'])
-
- if display['projection']['enabled']:
- if display['projection']['epsg']:
- UserSettings.Set(group = 'display', key = 'projection', subkey = 'epsg',
- value = display['projection']['epsg'])
- if display['projection']['proj']:
- UserSettings.Set(group = 'display', key = 'projection', subkey = 'proj4',
- value = display['projection']['proj'])
-
- # set position and size of map display
- if UserSettings.Get(group = 'workspace', key = 'posDisplay', subkey = 'enabled') is False:
- if display['pos']:
- mapdisp.SetPosition(display['pos'])
- if display['size']:
- mapdisp.SetSize(display['size'])
-
- # set extent if defined
- if display['extent']:
- w, s, e, n = display['extent']
- region = maptree.Map.region = maptree.Map.GetRegion(w = w, s = s, e = e, n = n)
- mapdisp.GetWindow().ResetZoomHistory()
- mapdisp.GetWindow().ZoomHistory(region['n'],
- region['s'],
- region['e'],
- region['w'])
-
- mapdisp.Show()
-
- displayId += 1
-
- maptree = None
- selected = [] # list of selected layers
- #
- # load list of map layers
- #
- for layer in gxwXml.layers:
- display = layer['display']
- maptree = self.gm_cb.GetPage(display).maptree
-
- newItem = maptree.AddLayer(ltype = layer['type'],
- lname = layer['name'],
- lchecked = layer['checked'],
- lopacity = layer['opacity'],
- lcmd = layer['cmd'],
- lgroup = layer['group'],
- lnviz = layer['nviz'],
- lvdigit = layer['vdigit'])
-
- if layer.has_key('selected'):
- if layer['selected']:
- selected.append((maptree, newItem))
- else:
- maptree.SelectItem(newItem, select = False)
-
- for maptree, layer in selected:
- if not maptree.IsSelected(layer):
- maptree.SelectItem(layer, select = True)
- maptree.layer_selected = layer
-
- busy.Destroy()
-
- for mdisp in mapdisplay:
- mdisp.MapWindow2D.UpdateMap()
-
- return True
-
- def OnWorkspaceLoadGrcFile(self, event):
- """!Load map layers from GRC file (Tcl/Tk GUI) into map layer tree"""
- dlg = wx.FileDialog(parent = self, message = _("Choose GRC file to load"),
- defaultDir = os.getcwd(), wildcard = _("Old GRASS Workspace File (*.grc)|*.grc"))
-
- filename = ''
- if dlg.ShowModal() == wx.ID_OK:
- filename = dlg.GetPath()
-
- if filename == '':
- return
-
- Debug.msg(4, "GMFrame.OnWorkspaceLoadGrcFile(): filename=%s" % filename)
-
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay()
-
- busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
- parent = self)
- wx.Yield()
-
- maptree = None
- for layer in workspace.ProcessGrcFile(filename).read(self):
- maptree = self.gm_cb.GetPage(layer['display']).maptree
- newItem = maptree.AddLayer(ltype = layer['type'],
- lname = layer['name'],
- lchecked = layer['checked'],
- lopacity = layer['opacity'],
- lcmd = layer['cmd'],
- lgroup = layer['group'])
-
- busy.Destroy()
-
- if maptree:
- # reverse list of map layers
- maptree.Map.ReverseListOfLayers()
-
- def OnWorkspaceSaveAs(self, event = None):
- """!Save workspace definition to selected file"""
- dlg = wx.FileDialog(parent = self, message = _("Choose file to save current workspace"),
- defaultDir = os.getcwd(), wildcard = _("GRASS Workspace File (*.gxw)|*.gxw"), style = wx.FD_SAVE)
-
- filename = ''
- if dlg.ShowModal() == wx.ID_OK:
- filename = dlg.GetPath()
-
- if filename == '':
- return False
-
- # check for extension
- if filename[-4:] != ".gxw":
- filename += ".gxw"
-
- if os.path.exists(filename):
- dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
- "Do you want to overwrite this file?") % filename,
- caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
- if dlg.ShowModal() != wx.ID_YES:
- dlg.Destroy()
- return False
-
- Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename)
-
- self.SaveToWorkspaceFile(filename)
- self.workspaceFile = filename
- self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
-
- def OnWorkspaceSave(self, event = None):
- """!Save file with workspace definition"""
- if self.workspaceFile:
- dlg = wx.MessageDialog(self, message = _("Workspace file <%s> already exists. "
- "Do you want to overwrite this file?") % \
- self.workspaceFile,
- caption = _("Save workspace"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
- if dlg.ShowModal() == wx.ID_NO:
- dlg.Destroy()
- else:
- Debug.msg(4, "GMFrame.OnWorkspaceSave(): filename=%s" % self.workspaceFile)
- self.SaveToWorkspaceFile(self.workspaceFile)
- self.SetTitle(self.baseTitle + " - " + os.path.basename(self.workspaceFile))
- self.workspaceChanged = False
- else:
- self.OnWorkspaceSaveAs()
-
- def SaveToWorkspaceFile(self, filename):
- """!Save layer tree layout to workspace file
-
- Return True on success, False on error
- """
- tmpfile = tempfile.TemporaryFile(mode = 'w+b')
- try:
- workspace.WriteWorkspaceFile(lmgr = self, file = tmpfile)
- except StandardError, e:
- gcmd.GError(parent = self,
- message = _("Writing current settings to workspace file "
- "failed."))
- return False
-
- try:
- mfile = open(filename, "w")
- tmpfile.seek(0)
- for line in tmpfile.readlines():
- mfile.write(line)
- except IOError:
- gcmd.GError(parent = self,
- message = _("Unable to open file <%s> for writing.") % filename)
- return False
-
- mfile.close()
-
- return True
-
- def OnWorkspaceClose(self, event = None):
- """!Close file with workspace definition
-
- If workspace has been modified ask user to save the changes.
- """
- Debug.msg(4, "GMFrame.OnWorkspaceClose(): file=%s" % self.workspaceFile)
-
- self.OnDisplayCloseAll()
- self.workspaceFile = None
- self.workspaceChanged = False
- self.SetTitle(self.baseTitle)
- self.disp_idx = 0
- self.curr_page = None
-
- def OnDisplayClose(self, event = None):
- """!Close current map display window
- """
- if self.curr_page and self.curr_page.maptree.mapdisplay:
- self.curr_page.maptree.mapdisplay.OnCloseWindow(event)
-
- def OnDisplayCloseAll(self, event = None):
- """!Close all open map display windows
- """
- displays = list()
- for page in range(0, self.gm_cb.GetPageCount()):
- displays.append(self.gm_cb.GetPage(page).maptree.mapdisplay)
-
- for display in displays:
- display.OnCloseWindow(event)
-
- def RulesCmd(self, event):
- """!Launches dialog for commands that need rules input and
- processes rules
- """
- cmd = self.GetMenuCmd(event)
-
- if cmd[0] == 'r.colors':
- ctable = colorrules.ColorTable(self, raster = True)
- else:
- ctable = colorrules.ColorTable(self, raster = False)
- ctable.CentreOnScreen()
- ctable.Show()
-
- def OnXTermNoXMon(self, event):
- """!
- Run commands that need xterm
- """
- self.OnXTerm(event, need_xmon = False)
-
- def OnXTerm(self, event, need_xmon = True):
- """!
- Run commands that need interactive xmon
-
- @param need_xmon True to start X monitor
- """
- # unset display mode
- del os.environ['GRASS_RENDER_IMMEDIATE']
-
- if need_xmon:
- # open next available xmon
- xmonlist = []
-
- # make list of xmons that are not running
- ret = gcmd.RunCommand('d.mon',
- flags = 'L',
- read = True)
-
- for line in ret.split('\n'):
- line = line.strip()
- if line.startswith('x') and 'not running' in line:
- xmonlist.append(line[0:2])
-
- # find available xmon
- xmon = xmonlist[0]
-
- # bring up the xmon
- cmdlist = ['d.mon', xmon]
- p = gcmd.Command(cmdlist, wait=False)
-
- # run the command
- command = self.GetMenuCmd(event)
- command = ' '.join(command)
-
- gisbase = os.environ['GISBASE']
-
- if sys.platform == "win32":
- runbat = os.path.join(gisbase,'etc','grass-run.bat')
- cmdlist = ["start", runbat, runbat, command]
- else:
- if sys.platform == "darwin":
- xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-mac')
- else:
- xtermwrapper = os.path.join(gisbase,'etc','grass-xterm-wrapper')
-
- grassrun = os.path.join(gisbase,'etc','grass-run.sh')
- cmdlist = [xtermwrapper, '-e', grassrun, command]
-
- p = gcmd.Command(cmdlist, wait=False)
-
- # reset display mode
- os.environ['GRASS_RENDER_IMMEDIATE'] = 'TRUE'
-
- def OnInstallExtension(self, event):
- """!Install extension from GRASS Addons SVN repository"""
- win = InstallExtensionWindow(self, size = (650, 550))
- win.CentreOnScreen()
- win.Show()
-
- def OnUninstallExtension(self, event):
- """!Uninstall extension"""
- win = UninstallExtensionWindow(self, size = (650, 300))
- win.CentreOnScreen()
- win.Show()
-
- def OnPreferences(self, event):
- """!General GUI preferences/settings
- """
- if not self.dialogs['preferences']:
- dlg = preferences.PreferencesDialog(parent = self)
- self.dialogs['preferences'] = dlg
- self.dialogs['preferences'].CenterOnScreen()
-
- dlg.Bind(preferences.EVT_SETTINGS_CHANGED, self.OnSettingsChanged)
-
- self.dialogs['preferences'].ShowModal()
-
- def OnHelp(self, event):
- """!Show help
- """
- self.goutput.RunCmd(['g.manual','-i'])
-
- def DispHistogram(self, event):
- """
- 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)
-
- #show new display
- self.histogram.Show()
- self.histogram.Refresh()
- self.histogram.Update()
-
- def DispProfile(self, event):
- """
- Init profile canvas and tools
- """
- self.profile = profile.ProfileFrame(self,
- id = wx.ID_ANY, pos = wx.DefaultPosition, size = (400,300),
- style = wx.DEFAULT_FRAME_STYLE)
- self.profile.Show()
- self.profile.Refresh()
- self.profile.Update()
-
- def OnMapCalculator(self, event, cmd = ''):
- """!Init map calculator for interactive creation of mapcalc statements
- """
- if event:
- try:
- cmd = self.GetMenuCmd(event)
- except KeyError:
- cmd = ['r.mapcalc']
-
- win = mapcalculator.MapCalcFrame(parent = self,
- cmd = cmd[0])
- win.CentreOnScreen()
- win.Show()
-
- def OnVectorCleaning(self, event, cmd = ''):
- """!Init interactive vector cleaning
- """
-
- if event:
- cmd = self.GetMenuCmd(event)
-
- win = vclean.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.CentreOnScreen()
- dlg.Show()
-
- def OnImportGdalLayers(self, event, cmd = None):
- """!Convert multiple GDAL layers to GRASS raster map layers"""
- dlg = gdialogs.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.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.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.CentreOnScreen()
- dlg.Show()
-
- def OnImportWMS(self, event):
- """!Import data from OGC WMS server"""
- dlg = ogc_services.WMSDialog(parent = self, service = 'wms')
- dlg.CenterOnScreen()
-
- if dlg.ShowModal() == wx.ID_OK: # -> import layers
- layers = dlg.GetLayers()
-
- if len(layers.keys()) > 0:
- for layer in layers.keys():
- cmd = ['r.in.wms',
- 'mapserver=%s' % dlg.GetSettings()['server'],
- 'layers=%s' % layer,
- 'output=%s' % layer,
- 'format=png',
- '--overwrite']
- styles = ','.join(layers[layer])
- if styles:
- cmd.append('styles=%s' % styles)
- self.goutput.RunCmd(cmd, switchPage = True)
-
- self.curr_page.maptree.AddLayer(ltype = 'raster',
- lname = layer,
- lcmd = ['d.rast', 'map=%s' % layer],
- multiple = False)
- else:
- self.goutput.WriteWarning(_("Nothing to import. No WMS layer selected."))
-
-
- dlg.Destroy()
-
- def OnShowAttributeTable(self, event, selection = 0):
- """!Show attribute table of the given vector map layer
- """
- if not self.curr_page:
- self.MsgNoLayerSelected()
- return
-
- tree = self.GetLayerTree()
- layer = tree.layer_selected
- # no map layer selected
- if not layer:
- self.MsgNoLayerSelected()
- return
-
- # available only for vector map layers
- try:
- maptype = tree.GetPyData(layer)[0]['maplayer'].type
- except:
- maptype = None
-
- if not maptype or maptype != 'vector':
- gcmd.GMessage(parent = self,
- message = _("Selected map layer is not vector."))
- return
-
- if not tree.GetPyData(layer)[0]:
- return
- dcmd = tree.GetPyData(layer)[0]['cmd']
- if not dcmd:
- return
-
- busy = wx.BusyInfo(message = _("Please wait, loading attribute data..."),
- 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)
-
- busy.Destroy()
-
- # register ATM dialog
- self.dialogs['atm'].append(dbmanager)
-
- # show ATM window
- dbmanager.Show()
-
- def OnNewDisplay(self, event = None):
- """!Create new layer tree and map display instance"""
- self.NewDisplay()
-
- def NewDisplay(self, show = True):
- """!Create new layer tree, which will
- create an associated map display frame
-
- @param show show map display window if True
-
- @return reference to mapdisplay intance
- """
- Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.disp_idx)
-
- # make a new page in the bookcontrol for the layer tree (on page 0 of the notebook)
- self.pg_panel = wx.Panel(self.gm_cb, id = wx.ID_ANY, style = wx.EXPAND)
- self.gm_cb.AddPage(self.pg_panel, text = "Display "+ str(self.disp_idx + 1), select = True)
- 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)
-
- # layout for controls
- cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
- cb_boxsizer.Add(self.curr_page.maptree, proportion = 1, flag = wx.EXPAND, border = 1)
- self.curr_page.SetSizer(cb_boxsizer)
- cb_boxsizer.Fit(self.curr_page.maptree)
- self.curr_page.Layout()
- self.curr_page.maptree.Layout()
-
- # use default window layout
- if UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'enabled'):
- dim = UserSettings.Get(group = 'general', key = 'defWindowPos', subkey = 'dim')
- idx = 4 + self.disp_idx * 4
- try:
- x, y = map(int, dim.split(',')[idx:idx + 2])
- w, h = map(int, dim.split(',')[idx + 2:idx + 4])
- self.curr_page.maptree.mapdisplay.SetPosition((x, y))
- self.curr_page.maptree.mapdisplay.SetSize((w, h))
- except:
- pass
-
- self.disp_idx += 1
-
- return self.curr_page.maptree.mapdisplay
-
- def OnAddMaps(self, event = None):
- """!Add selected map layers into layer tree"""
- dialog = gdialogs.AddMapLayersDialog(parent = self, title = _("Add selected map layers into layer tree"))
-
- if dialog.ShowModal() == wx.ID_OK:
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay()
-
- maptree = self.curr_page.maptree
- busy = wx.BusyInfo(message = _("Please wait, loading workspace..."),
- parent = self)
- wx.Yield()
-
- for layerName in dialog.GetMapLayers():
- if dialog.GetLayerType() == 'raster':
- cmd = ['d.rast', 'map=%s' % layerName]
- elif dialog.GetLayerType() == 'vector':
- cmd = ['d.vect', 'map=%s' % layerName]
- newItem = maptree.AddLayer(ltype = dialog.GetLayerType(),
- lname = layerName,
- lchecked = False,
- lopacity = 1.0,
- lcmd = cmd,
- lgroup = None)
-
- busy.Destroy()
-
- def OnAddRaster(self, event):
- """!Add raster map layer"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('raster')
-
- def OnAddRaster3D(self, event):
- """!Add 3D raster map layer"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.AddRaster3D(event)
-
- def OnAddRasterMisc(self, event):
- """!Create misc raster popup-menu"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self._popupMenu((('addRast3d', self.OnAddRaster3D),
- (None, None),
- ('addRgb', self.OnAddRasterRGB),
- ('addHis', self.OnAddRasterHIS),
- (None, None),
- ('addShaded', self.OnAddRasterShaded),
- (None, None),
- ('addRArrow', self.OnAddRasterArrow),
- ('addRNum', self.OnAddRasterNum)))
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnAddVector(self, event):
- """!Add vector map to the current layer tree"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('vector')
-
- def OnAddVectorMisc(self, event):
- """!Create misc vector popup-menu"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self._popupMenu((('addThematic', self.OnAddVectorTheme),
- ('addChart', self.OnAddVectorChart)))
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnAddVectorTheme(self, event):
- """!Add thematic vector map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('thememap')
-
- def OnAddVectorChart(self, event):
- """!Add chart vector map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('themechart')
-
- def OnAddOverlay(self, event):
- """!Create decoration overlay menu"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self._popupMenu((('addGrid', self.OnAddGrid),
- ('addLabels', self.OnAddLabels),
- ('addGeodesic', self.OnAddGeodesic),
- ('addRhumb', self.OnAddRhumb),
- (None, None),
- ('addCmd', self.OnAddCommand)))
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnAddRaster3D(self, event):
- """!Add 3D raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('3d-raster')
-
- def OnAddRasterRGB(self, event):
- """!Add RGB raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('rgb')
-
- def OnAddRasterHIS(self, event):
- """!Add HIS raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('his')
-
- def OnAddRasterShaded(self, event):
- """!Add shaded relief raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('shaded')
-
- def OnAddRasterArrow(self, event):
- """!Add flow arrows raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('rastarrow')
-
- def OnAddRasterNum(self, event):
- """!Add cell number raster map to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('rastnum')
-
- def OnAddCommand(self, event):
- """!Add command line map layer to the current layer tree"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('command')
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnAddGroup(self, event):
- """!Add layer group"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('group')
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnAddGrid(self, event):
- """!Add grid map layer to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('grid')
-
- def OnAddGeodesic(self, event):
- """!Add geodesic line map layer to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('geodesic')
-
- def OnAddRhumb(self, event):
- """!Add rhumb map layer to the current layer tree"""
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('rhumb')
-
- def OnAddLabels(self, event):
- """!Add vector labels map layer to the current layer tree"""
- # start new map display if no display is available
- if not self.curr_page:
- self.NewDisplay(show = True)
-
- self.notebook.SetSelectionByName('layers')
- self.curr_page.maptree.AddLayer('labels')
-
- # show map display
- self.curr_page.maptree.mapdisplay.Show()
-
- def OnDeleteLayer(self, event):
- """!Remove selected map layer from the current layer Tree
- """
- if not self.curr_page or not self.curr_page.maptree.layer_selected:
- self.MsgNoLayerSelected()
- return
-
- if UserSettings.Get(group = 'manager', key = 'askOnRemoveLayer', subkey = 'enabled'):
- layerName = ''
- for item in self.curr_page.maptree.GetSelections():
- name = str(self.curr_page.maptree.GetItemText(item))
- idx = name.find('(opacity')
- if idx > -1:
- layerName += '<' + name[:idx].strip(' ') + '>,\n'
- else:
- layerName += '<' + name + '>,\n'
- layerName = layerName.rstrip(',\n')
-
- if len(layerName) > 2: # <>
- message = _("Do you want to remove map layer(s)\n%s\n"
- "from layer tree?") % layerName
- else:
- message = _("Do you want to remove selected map layer(s) "
- "from layer tree?")
-
- dlg = wx.MessageDialog (parent = self, message = message,
- caption = _("Remove map layer"),
- style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
-
- if dlg.ShowModal() != wx.ID_YES:
- dlg.Destroy()
- return
-
- dlg.Destroy()
-
- for layer in self.curr_page.maptree.GetSelections():
- if self.curr_page.maptree.GetPyData(layer)[0]['type'] == 'group':
- self.curr_page.maptree.DeleteChildren(layer)
- self.curr_page.maptree.Delete(layer)
-
- def OnKeyDown(self, event):
- """!Key pressed"""
- kc = event.GetKeyCode()
-
- if event.ControlDown():
- if kc == wx.WXK_TAB:
- # switch layer list / command output
- if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('layers'):
- self.notebook.SetSelectionByName('output')
- else:
- self.notebook.SetSelectionByName('layers')
-
- try:
- ckc = chr(kc)
- except ValueError:
- event.Skip()
- return
-
- if event.CtrlDown():
- if kc == 'R':
- self.OnAddRaster(None)
- elif kc == 'V':
- self.OnAddVector(None)
-
- event.Skip()
-
- def OnCloseWindow(self, event):
- """!Cleanup when wxGUI is quitted"""
- if not self.curr_page:
- self._auimgr.UnInit()
- self.Destroy()
- return
-
- maptree = self.curr_page.maptree
- if self.workspaceChanged and \
- UserSettings.Get(group = 'manager', key = 'askOnQuit', subkey = 'enabled'):
- if self.workspaceFile:
- message = _("Do you want to save changes in the workspace?")
- else:
- message = _("Do you want to store current settings "
- "to workspace file?")
-
- # ask user to save current settings
- if maptree.GetCount() > 0:
- dlg = wx.MessageDialog(self,
- message = message,
- caption = _("Quit GRASS GUI"),
- 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.workspaceFile:
- self.OnWorkspaceSaveAs()
- else:
- self.SaveToWorkspaceFile(self.workspaceFile)
- elif ret == wx.ID_CANCEL:
- event.Veto()
- dlg.Destroy()
- return
- dlg.Destroy()
-
- # don't ask any more...
- UserSettings.Set(group = 'manager', key = 'askOnQuit', subkey = 'enabled',
- value = False)
-
- self.OnDisplayCloseAll()
-
- self.gm_cb.DeleteAllPages()
-
- self._auimgr.UnInit()
- self.Destroy()
-
- def MsgNoLayerSelected(self):
- """!Show dialog message 'No layer selected'"""
- wx.MessageBox(parent = self,
- message = _("No map layer selected. Operation cancelled."),
- caption = _("Message"),
- style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
-
class GMApp(wx.App):
def __init__(self, workspace = None):
"""!Main GUI class.
@@ -1631,27 +71,6 @@
wx.Yield()
- ### TODO: adjust initial window layout if necessary
- w, h = wx.GetDisplaySize()
- # only neccessary if one of the windows is falling out of
- # the current display size
-
- # check if settings file exists
- # if settings file exists, check if we should use the stored settings
- # if we should use stored settings, use stored settings
- # else use default settings
- # else if settings file does not exist, use default settings
- # check if any of the windows is falling out of the current display
- # if yes, pull it in
- # falling out to the right
- # x pos = display width - window width
- # falling out to the bottom
- # y pos = 0
- # update settings
- # if settings file exists, update settings but keep settings for
- # additional map display windows, or update them too
- # do not erase settings for additional map display windows !
-
# create and show main frame
mainframe = GMFrame(parent = None, id = wx.ID_ANY,
workspace = self.workspaceFile)
@@ -1689,9 +108,9 @@
return (workspaceFile,)
def main(argv = None):
- #
- # process command-line arguments
- #
+ import gettext
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
+
if argv is None:
argv = sys.argv
try:
@@ -1700,22 +119,19 @@
["help", "workspace"])
except getopt.error, msg:
raise Usage(msg)
-
+
except Usage, err:
print >> sys.stderr, err.msg
print >> sys.stderr, "for help use --help"
printHelp()
-
+
workspaceFile = process_opt(opts, args)[0]
-
- #
- # run application
- #
+
app = GMApp(workspaceFile)
# suppress wxPython logs
q = wx.LogNull()
-
+
app.MainLoop()
-
+
if __name__ == "__main__":
sys.exit(main())
Added: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/base.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxplot/base.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxplot/base.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,543 @@
+"""!
+ at package wxplot.base
+
+ at brief Base classes for iinteractive plotting using PyPlot
+
+Classes:
+ - base::PlotIcons
+ - 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
+from icons.icon import MetaIcon
+from gui_core.toolbars import BaseIcons
+
+import grass.script as grass
+
+PlotIcons = {
+ 'draw' : MetaIcon(img = 'show',
+ label = _('Draw/re-draw plot')),
+ 'transect' : MetaIcon(img = 'layer-raster-profile',
+ label = _('Draw transect in map display window to profile')),
+ 'options' : MetaIcon(img = 'settings',
+ label = _('Plot options')),
+ 'statistics' : MetaIcon(img = 'check',
+ label = _('Plot statistics')),
+ 'save' : MetaIcon(img = 'save',
+ label = _('Save profile data to CSV file')),
+ 'quit' : BaseIcons['quit'].SetLabel(_('Quit plot tool')),
+ }
+
+class BasePlotFrame(wx.Frame):
+ """!Abstract PyPlot display frame class"""
+ def __init__(self, parent = None, id = wx.ID_ANY, size = wx.Size(700, 400),
+ 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()
+
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/base.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxplot/dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxplot/dialogs.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,796 @@
+"""!
+ at package wxplot.dialogs
+
+ at brief Dialogs for different plotting routines
+
+Classes:
+ - dialogs::ProfileRasterDialog
+ - dialogs::PlotStatsFrame
+ - dialogs::TextDialog
+ - dialogs::OptDialog
+
+(C) 2011 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton, Arizona State University
+"""
+
+import wx
+import wx.lib.colourselect as csel
+import wx.lib.scrolledpanel as scrolled
+
+from core import globalvar
+from core.settings import UserSettings
+from 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)
+
+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()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/profile.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxplot/profile.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxplot/profile.py 2012-02-19 20:31:20 UTC (rev 50882)
@@ -0,0 +1,428 @@
+"""!
+ 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, PlotIcons
+from gui_core.toolbars import BaseToolbar, BaseIcons
+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,
+ size = wx.Size(700, 400),
+ rasterList = [], **kwargs):
+ BasePlotFrame.__init__(self, parent, size = size, **kwargs)
+
+ self.toolbar = ProfileToolbar(parent = self)
+ self.SetToolBar(self.toolbar)
+ self.SetTitle(_("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"""
+ return self._getToolbarData((('addraster', BaseIcons["addRast"],
+ self.parent.OnSelectRaster),
+ ('transect', PlotIcons["transect"],
+ self.parent.OnDrawTransect),
+ (None, ),
+ ('draw', PlotIcons["draw"],
+ self.parent.OnCreateProfile),
+ ('erase', BaseIcons["erase"],
+ self.parent.OnErase),
+ ('drag', BaseIcons['pan'],
+ self.parent.OnDrag),
+ ('zoom', BaseIcons['zoomIn'],
+ self.parent.OnZoom),
+ ('unzoom', BaseIcons['zoomBack'],
+ self.parent.OnRedraw),
+ (None, ),
+ ('statistics', PlotIcons['statistics'],
+ self.parent.OnStats),
+ ('datasave', PlotIcons["save"],
+ self.parent.SaveProfileToFile),
+ ('image', BaseIcons["saveFile"],
+ self.parent.SaveToFile),
+ ('print', BaseIcons["print"],
+ self.parent.PrintMenu),
+ (None, ),
+ ('settings', PlotIcons["options"],
+ self.parent.PlotOptionsMenu),
+ ('quit', PlotIcons["quit"],
+ self.parent.OnQuit),
+ ))
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/wxplot/profile.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/wxpythonlib.dox 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/wxpythonlib.dox 2012-02-19 20:31:20 UTC (rev 50882)
@@ -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,425 @@
\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::BaseValidator
+ - widgets::IntegerValidator
+ - widgets::FloatValidator
+ - widgets::NTCValidator
+ - 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::ModelItemDialog
+ - dialogs::ModelLoopDialog
+ - dialogs::ModelConditionDialog
+ - dialogs::ModelListCtrl
+ - dialogs::ValiableListCtrl
+ - dialogs::ItemListCtrl
+ - dialogs::ItemCheckListCtrl
+- gmodeler::frame
+ - frame::ModelToolbar
+ - frame::ModelFrame
+ - frame::ModelCanvas
+ - frame::ModelEvtHandler
+ - frame::VariablePanel
+ - frame::ItemPanel
+- 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
+ - model::ModelParamDialog
+- 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::TCValidator
+ - dialogs::PenStyleComboBox
+ - dialogs::CheckListCtrl
+ - 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::instructions
+ - dialogs::Instruction
+ - dialogs::InstructionObject
+ - dialogs::InitMap
+ - dialogs::MapFrame
+ - dialogs::PageSetup
+ - dialogs::Mapinfo
+ - dialogs::Text
+ - dialogs::Image
+ - dialogs::NorthArrow
+ - dialogs::Point
+ - dialogs::Line
+ - dialogs::Rectangle
+ - dialogs::Scalebar
+ - dialogs::RasterLegend
+ - dialogs::VectorLegend
+ - dialogs::Raster
+ - dialogs::Vector
+ - dialogs::VProperties
+- psmap::utils
+ - utils::Rect2D
+ - utils::Rect2DPP
+ - utils::Rect2DPS
+ - utils::UnitConversion
+- 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
+ - extensions::UninstallExtensionWindow
+ - extensions::CheckListExtension
+- 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
Modified: grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml 2012-02-19 20:31:20 UTC (rev 50882)
@@ -11,28 +11,33 @@
<help>Create new workspace</help>
<handler>OnWorkspaceNew</handler>
<shortcut>Ctrl+N</shortcut>
+ <id>ID_NEW</id>
</menuitem>
<menuitem>
<label>Open</label>
<help>Load workspace from file</help>
<handler>OnWorkspaceOpen</handler>
<shortcut>Ctrl+O</shortcut>
+ <id>ID_OPEN</id>
</menuitem>
<menuitem>
<label>Save</label>
<help>Save workspace</help>
<handler>OnWorkspaceSave</handler>
<shortcut>Ctrl+S</shortcut>
+ <id>ID_SAVE</id>
</menuitem>
<menuitem>
<label>Save as</label>
<help>Save workspace to file</help>
<handler>OnWorkspaceSaveAs</handler>
+ <id>ID_SAVEAS</id>
</menuitem>
<menuitem>
<label>Close</label>
<help>Close workspace file</help>
<handler>OnWorkspaceClose</handler>
+ <id>ID_CLOSE</id>
</menuitem>
<separator />
<menuitem>
@@ -87,7 +92,7 @@
<label>Import raster data</label>
<items>
<menuitem>
- <label>Common import formats</label>
+ <label>Common formats import</label>
<help>Import raster data into a GRASS map layer using GDAL.</help>
<keywords>raster,import</keywords>
<handler>OnImportGdalLayers</handler>
@@ -364,7 +369,7 @@
<menuitem>
<label>MPEG-1 export</label>
<help>Raster File Series to MPEG Conversion.</help>
- <keywords>raster,export</keywords>
+ <keywords>raster,export,animation</keywords>
<handler>OnMenuCmd</handler>
<command>r.out.mpeg</command>
</menuitem>
@@ -424,7 +429,7 @@
<items>
<menuitem>
<label>Common export formats</label>
- <help>Converts GRASS vector map to one of the supported OGR vector formats.</help>
+ <help>Converts to one of the supported OGR vector formats.</help>
<keywords>vector,export</keywords>
<handler>OnMenuCmd</handler>
<command>v.out.ogr</command>
@@ -588,7 +593,7 @@
<items>
<menuitem>
<label>Raster to vector</label>
- <help>Converts a raster map into a vector map layer.</help>
+ <help>Converts a raster map into a vector map.</help>
<keywords>raster,conversion,vectorization</keywords>
<handler>OnMenuCmd</handler>
<command>r.to.vect</command>
@@ -706,6 +711,7 @@
<help>Quit wxGUI session</help>
<handler>OnCloseWindow</handler>
<shortcut>Ctrl+Q</shortcut>
+ <id>ID_EXIT</id>
</menuitem>
</items>
</menu>
@@ -759,11 +765,13 @@
<menuitem>
<label>Change location and mapset</label>
<help>Change current location and mapset.</help>
+ <keywords>general,location,current</keywords>
<handler>OnChangeLocation</handler>
</menuitem>
<menuitem>
<label>Change mapset</label>
<help>Change current mapset.</help>
+ <keywords>general,mapset,current</keywords>
<handler>OnChangeMapset</handler>
</menuitem>
<separator />
@@ -790,6 +798,19 @@
</menuitem>
<separator />
<menuitem>
+ <label>Create new location</label>
+ <help>Launches location wizard to create new GRASS location.</help>
+ <keywords>general,location,wizard</keywords>
+ <handler>OnLocationWizard</handler>
+ </menuitem>
+ <menuitem>
+ <label>Create new mapset</label>
+ <help>Creates new mapset in the current location, changes current mapset.</help>
+ <keywords>general,mapset,create</keywords>
+ <handler>OnCreateMapset</handler>
+ </menuitem>
+ <separator />
+ <menuitem>
<label>Version</label>
<help>Displays version and copyright information.</help>
<keywords>general,version</keywords>
@@ -859,6 +880,7 @@
<label>Preferences</label>
<help>User GUI preferences (display font, commands, digitizer, etc.)</help>
<handler>OnPreferences</handler>
+ <id>ID_PREFERENCES</id>
</menuitem>
</items>
</menu>
@@ -1052,7 +1074,7 @@
<items>
<menuitem>
<label>Raster to vector</label>
- <help>Converts a raster map into a vector map layer.</help>
+ <help>Converts a raster map into a vector map.</help>
<keywords>raster,conversion,vectorization</keywords>
<handler>OnMenuCmd</handler>
<command>r.to.vect</command>
@@ -1252,7 +1274,7 @@
</menuitem>
<menuitem>
<label>Distance to features</label>
- <help>Generates a raster map layer of distance to features in input layer.</help>
+ <help>Generates a raster map of distance to features in input raster map.</help>
<keywords>raster,geometry</keywords>
<handler>OnMenuCmd</handler>
<command>r.grow.distance</command>
@@ -1299,7 +1321,7 @@
<items>
<menuitem>
<label>Carve stream channels</label>
- <help>Takes vector stream data, transforms it to raster and subtracts depth from the output DEM.</help>
+ <help>Generates stream channels.</help>
<keywords>raster,hydrology</keywords>
<handler>OnMenuCmd</handler>
<command>r.carve</command>
@@ -1328,14 +1350,14 @@
</menuitem>
<menuitem>
<label>Flow lines</label>
- <help>Construction of slope curves (flowlines), flowpath lengths, and flowline densities (upslope areas) from a raster digital elevation model (DEM).</help>
+ <help>Constructs flow lines.</help>
<keywords>raster,hydrology</keywords>
<handler>OnMenuCmd</handler>
<command>r.flow</command>
</menuitem>
<menuitem>
<label>Watershed analysis</label>
- <help>Watershed basin analysis program.</help>
+ <help>Watershed basin analysis program</help>
<keywords>raster,hydrology</keywords>
<handler>OnMenuCmd</handler>
<command>r.watershed</command>
@@ -1349,7 +1371,7 @@
</menuitem>
<menuitem>
<label>Watershed basin creation</label>
- <help>Watershed basin creation program.</help>
+ <help>Creates watershed basins.</help>
<keywords>raster,hydrology</keywords>
<handler>OnMenuCmd</handler>
<command>r.water.outlet</command>
@@ -1358,7 +1380,7 @@
<menuitem>
<label>Groundwater modeling</label>
<help>Numerical calculation program for transient, confined and unconfined groundwater flow in two dimensions.</help>
- <keywords>raster,hydrology</keywords>
+ <keywords>raster</keywords>
<handler>OnMenuCmd</handler>
<command>r.gwflow</command>
</menuitem>
@@ -1582,8 +1604,8 @@
</menuitem>
<menuitem>
<label>Reclassify</label>
- <help>Creates a new map layer whose category values are based upon a reclassification of the categories in an existing raster map layer.</help>
- <keywords>raster,statistics,reclass</keywords>
+ <help>Reclassify raster map based on category values.</help>
+ <keywords>raster,reclassification</keywords>
<handler>OnMenuCmd</handler>
<command>r.reclass</command>
</menuitem>
@@ -1747,7 +1769,7 @@
<separator />
<menuitem>
<label>Fill NULL cells</label>
- <help>Fills no-data areas in raster maps using v.surf.rst splines interpolation</help>
+ <help>Fills no-data areas in raster maps using spline interpolation.</help>
<keywords>raster,elevation,interpolation</keywords>
<handler>OnMenuCmd</handler>
<command>r.fillnulls</command>
@@ -1803,7 +1825,7 @@
</menuitem>
<menuitem>
<label>Sum area by raster map and category</label>
- <help>Reports statistics for raster map layers.</help>
+ <help>Reports statistics for raster maps.</help>
<keywords>raster,statistics</keywords>
<handler>OnMenuCmd</handler>
<command>r.report</command>
@@ -1906,7 +1928,7 @@
<separator />
<menuitem>
<label>Parallel lines</label>
- <help>Creates parallel line to input vector lines.</help>
+ <help>Create parallel line to input lines</help>
<keywords>vector,geometry</keywords>
<handler>OnMenuCmd</handler>
<command>v.parallel</command>
@@ -2074,19 +2096,19 @@
<command>v.db.select</command>
</menuitem>
</items>
- </menu>
+ </menu>
<menu>
<label>Feature selection</label>
<items>
<menuitem>
- <label>Query with attributes</label>
+ <label>Attribute query</label>
<help>Selects vector objects from an existing vector map and creates a new map containing only the selected objects.</help>
<keywords>vector,extract</keywords>
<handler>OnMenuCmd</handler>
<command>v.extract</command>
</menuitem>
<menuitem>
- <label>Query with another vector map</label>
+ <label>Spatial query</label>
<help>Selects features from vector map (A) by features from other vector map (B).</help>
<keywords>vector,spatial query</keywords>
<handler>OnMenuCmd</handler>
@@ -2559,9 +2581,9 @@
<items>
<menuitem>
<label>Create/edit group</label>
- <help>Creates, edits, and lists groups and subgroups of imagery files.</help>
+ <help>Creates, edits, and lists groups of imagery files.</help>
<keywords>imagery,map management</keywords>
- <handler>OnMenuCmd</handler>
+ <handler>OnEditImageryGroups</handler>
<command>i.group</command>
</menuitem>
<menuitem>
@@ -2574,7 +2596,7 @@
<separator />
<menuitem>
<label>Mosaic images</label>
- <help>Mosaics up to 4 images and extends colormap; creates map *.mosaic</help>
+ <help>Mosaics up to four images, extending the color table.</help>
<keywords>raster,imagery,mosaicking</keywords>
<handler>OnMenuCmd</handler>
<command>i.image.mosaic</command>
@@ -2609,14 +2631,6 @@
</menu>
<separator />
<menuitem>
- <label>Ortho photo rectification (requires Xterm)</label>
- <help>Menu driver for the photo imagery programs.</help>
- <keywords>imagery,orthorectify</keywords>
- <handler>OnXTerm</handler>
- <command>i.ortho.photo</command>
- </menuitem>
- <separator />
- <menuitem>
<label>Rectify image or raster</label>
<help>Rectifies an image by computing a coordinate transformation for each pixel in the image based on the control points.</help>
<keywords>imagery,rectify</keywords>
@@ -2626,7 +2640,7 @@
<menuitem>
<label>Histogram</label>
<help>Generate histogram of image</help>
- <handler>DispHistogram</handler>
+ <handler>OnHistogram</handler>
</menuitem>
<menuitem>
<label>Spectral response</label>
@@ -2750,6 +2764,29 @@
<label>Satellite images tools</label>
<items>
<menuitem>
+ <label>Landsat DN to radiance/reflectance</label>
+ <help>Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+.</help>
+ <keywords>imagery,landsat,top-of-atmosphere reflectance,dos-type simple atmospheric correction</keywords>
+ <handler>OnMenuCmd</handler>
+ <command>i.landsat.toar</command>
+ </menuitem>
+ <menuitem>
+ <label>Landsat cloud cover assessment</label>
+ <help>Performs Landsat TM/ETM+ Automatic Cloud Cover Assessment (ACCA).</help>
+ <keywords>imagery,landsat,acca</keywords>
+ <handler>OnMenuCmd</handler>
+ <command>i.landsat.acca</command>
+ </menuitem>
+ <separator />
+ <menuitem>
+ <label>Modis quality control</label>
+ <help>Extract quality control parameters from Modis QC layers</help>
+ <keywords>QC,Quality Control,surface reflectance,Modis</keywords>
+ <handler>OnMenuCmd</handler>
+ <command>i.modis.qc</command>
+ </menuitem>
+ <separator />
+ <menuitem>
<label>Atmospheric correction</label>
<help>Performs atmospheric correction using the 6S algorithm.</help>
<keywords>imagery,atmospheric correction</keywords>
@@ -3101,6 +3138,7 @@
<keywords>general,manual,help</keywords>
<handler>RunMenuCmd</handler>
<command>g.manual -i</command>
+ <id>ID_HELP</id>
</menuitem>
<menuitem>
<label>GUI help</label>
@@ -3108,12 +3146,14 @@
<keywords>general,manual,help</keywords>
<handler>RunMenuCmd</handler>
<command>g.manual entry=wxGUI</command>
+ <id>ID_HELP</id>
</menuitem>
<separator />
<menuitem>
<label>About GRASS GIS</label>
<help>About GRASS GIS</help>
<handler>OnAboutGRASS</handler>
+ <id>ID_ABOUT</id>
</menuitem>
</items>
</menu>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_modeler.xml
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_modeler.xml 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_modeler.xml 2012-02-19 20:31:20 UTC (rev 50882)
@@ -66,8 +66,8 @@
<label>&Model</label>
<items>
<menuitem>
- <label>Add action</label>
- <help>Add action (GRASS module) to model</help>
+ <label>Add command</label>
+ <help>Add action (GRASS command) to model</help>
<handler>OnAddAction</handler>
<shortcut>Ctrl+A</shortcut>
</menuitem>
@@ -83,8 +83,8 @@
<handler>OnDefineRelation</handler>
</menuitem>
<menuitem>
- <label>Add loop</label>
- <help>Adds loop (for) to model</help>
+ <label>Add loop / series</label>
+ <help>Adds loop (series) to model</help>
<handler>OnDefineLoop</handler>
<shortcut>Ctrl+L</shortcut>
</menuitem>
@@ -122,7 +122,6 @@
<label>Validate model</label>
<help>Validate entire model</help>
<handler>OnValidateModel</handler>
- <shortcut>Ctrl+V</shortcut>
</menuitem>
</items>
</menu>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_psmap.xml
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_psmap.xml 2012-02-19 18:44:49 UTC (rev 50881)
+++ grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_psmap.xml 2012-02-19 20:31:20 UTC (rev 50882)
@@ -94,6 +94,18 @@
<handler>OnAddText</handler>
<shortcut>Ctrl+T</shortcut>
</menuitem>
+ <menuitem>
+ <label>Image</label>
+ <help>Add image</help>
+ <handler>OnAddImage</handler>
+ <shortcut></shortcut>
+ </menuitem>
+ <menuitem>
+ <label>North Arrow</label>
+ <help>Add north arrow</help>
+ <handler>OnAddNorthArrow</handler>
+ <shortcut></shortcut>
+ </menuitem>
<separator/>
<menuitem>
<label>Delete</label>
More information about the grass-commit
mailing list