[GRASS-SVN] r43911 - in grass/branches/releasebranch_6_4/gui:
icons/grass2 wxpython wxpython/compat wxpython/docs
wxpython/gui_modules wxpython/icons wxpython/scripts
wxpython/support wxpython/vdigit wxpython/xml
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Oct 14 11:39:14 EDT 2010
Author: martinl
Date: 2010-10-14 08:39:14 -0700 (Thu, 14 Oct 2010)
New Revision: 43911
Added:
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-fringe.png
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-light.png
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-raster.png
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-vector.png
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-view.png
grass/branches/releasebranch_6_4/gui/icons/grass2/3d-volume.png
grass/branches/releasebranch_6_4/gui/icons/grass2/check.png
grass/branches/releasebranch_6_4/gui/icons/grass2/data-add.png
grass/branches/releasebranch_6_4/gui/icons/grass2/execute.png
grass/branches/releasebranch_6_4/gui/icons/grass2/help.png
grass/branches/releasebranch_6_4/gui/icons/grass2/image-export.png
grass/branches/releasebranch_6_4/gui/icons/grass2/layer-add.png
grass/branches/releasebranch_6_4/gui/icons/grass2/map-add.png
grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-main.png
grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-variables.png
grass/branches/releasebranch_6_4/gui/icons/grass2/module-add.png
grass/branches/releasebranch_6_4/gui/icons/grass2/move.png
grass/branches/releasebranch_6_4/gui/icons/grass2/python-export.png
grass/branches/releasebranch_6_4/gui/icons/grass2/redo.png
grass/branches/releasebranch_6_4/gui/icons/grass2/relation-create.png
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_toolbar.jpg
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_base.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_dialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gmodeler.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/layertree.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp_command.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp_window.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/menu.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/nviz_preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ogc_services.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/prompt.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/units.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/vclean.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/wxnviz.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/d.rast3d.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/p.cmd.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/p.db.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/p.mon.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/p.rast.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/p.vect.py
grass/branches/releasebranch_6_4/gui/wxpython/scripts/vkrige.py
grass/branches/releasebranch_6_4/gui/wxpython/xml/grass-gxm.dtd
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata_modeler.xml
Modified:
grass/branches/releasebranch_6_4/gui/icons/grass2/options.png
grass/branches/releasebranch_6_4/gui/icons/grass2/overlay-add.png
grass/branches/releasebranch_6_4/gui/wxpython/Makefile
grass/branches/releasebranch_6_4/gui/wxpython/README
grass/branches/releasebranch_6_4/gui/wxpython/build_ext.py
grass/branches/releasebranch_6_4/gui/wxpython/compat/subprocess.py
grass/branches/releasebranch_6_4/gui/wxpython/docs/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.Nviz.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizing_Tool.html
grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html
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/gis_set.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/__init__.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/colorrules.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/debug.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmanager.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmapdisp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gdialogs.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/georect.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/globalvar.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gselect.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/histogram.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/location_wizard.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mcalc_builder.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/menuform.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/nviz.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/nviz_mapdisp.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/nviz_tools.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/preferences.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/profile.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/render.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/rules.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/sqlbuilder.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/toolbars.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/utils.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/vdigit.py
grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/workspace.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/scripts/Makefile
grass/branches/releasebranch_6_4/gui/wxpython/support/update_menudata.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/Makefile
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/digit.cpp
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/digit.h
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/driver.cpp
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/driver.h
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/line.cpp
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/pseudodc.i
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/setup.py
grass/branches/releasebranch_6_4/gui/wxpython/vdigit/vertex.cpp
grass/branches/releasebranch_6_4/gui/wxpython/wxgui.py
grass/branches/releasebranch_6_4/gui/wxpython/xml/grass-gxw.dtd
grass/branches/releasebranch_6_4/gui/wxpython/xml/menudata.xml
Log:
wxGUI backported from devbr6 (some testing required)
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-fringe.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-fringe.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-light.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-light.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-raster.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-raster.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-vector.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-vector.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-view.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-view.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-volume.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/3d-volume.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/check.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/check.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/data-add.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/data-add.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/execute.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/execute.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/help.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/help.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/image-export.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/image-export.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/layer-add.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/layer-add.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/map-add.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/map-add.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-main.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-main.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-variables.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/modeler-variables.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/module-add.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/module-add.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/move.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/move.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/options.png
___________________________________________________________________
Modified: svn:mime-type
- application/octet-stream
+ image/png
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/overlay-add.png
___________________________________________________________________
Modified: svn:mime-type
- application/octet-stream
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/python-export.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/python-export.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/redo.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/redo.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Added: grass/branches/releasebranch_6_4/gui/icons/grass2/relation-create.png
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/icons/grass2/relation-create.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Modified: grass/branches/releasebranch_6_4/gui/wxpython/Makefile
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/Makefile 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/Makefile 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,15 +1,17 @@
MODULE_TOPDIR = ../..
-SUBDIRS = docs scripts
-EXTRA_CLEAN_FILES = menustrings.py
+SUBDIRS = docs vdigit scripts
+EXTRA_CLEAN_FILES = menustrings.py build_ext.pyc
+CLEAN_SUBDIRS = vdigit scripts
include $(MODULE_TOPDIR)/include/Make/Dir.make
include $(MODULE_TOPDIR)/include/Make/Doxygen.make
+include $(MODULE_TOPDIR)/include/Make/Python.make
ETCDIR = $(ETC)/wxpython
-SRCFILES := $(wildcard scripts/p.* compat/* gui_modules/* icons/*.* icons/silk/* images/* xml/*) gis_set.py wxgui.py README scripts/wxgui
-DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES))
+SRCFILES := $(wildcard compat/* gui_modules/* icons/*.* icons/silk/* images/* xml/*) gis_set.py wxgui.py README
+DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) $(patsubst %.py,$(ETCDIR)/%.pyc,$(filter %.py,$(SRCFILES)))
default: install_scripts
$(MAKE) parsubdirs
@@ -17,23 +19,20 @@
clean: cleansubdirs
install_scripts:
- -for dir in '' compat gui_modules icons icons/silk images scripts xml; do \
+ -for dir in '' compat gui_modules icons icons/silk images vdigit xml; do \
if [ ! -d $(ETCDIR)/$$dir ] ; then $(MKDIR) $(ETCDIR)/$$dir ; fi ; \
done
$(MAKE) $(DSTFILES)
$(MAKE) menustrings.py
-$(ETCDIR)/scripts/wxgui: wxgui
- $(INSTALL) $< $@
-
-$(ETCDIR)/scripts/%: scripts/%
- $(INSTALL) $< $@
-
$(ETCDIR)/%: %
$(INSTALL_DATA) $< $@
-menustrings.py: gui_modules/menudata.py xml/menudata.xml
- python $< $(GISBASE) > $@
+menustrings.py: gui_modules/menudata.py $(ETCDIR)/xml/menudata.xml $(ETCDIR)/xml/menudata_modeler.xml
+ GISBASE="$(GISBASE)" \
+ $(PYTHON) $< > $@
+ GISBASE="$(GISBASE)" \
+ $(PYTHON) $< "modeler" >> $@
#doxygen:
DOXNAME=wxpython
Modified: grass/branches/releasebranch_6_4/gui/wxpython/README
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/README 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/README 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,5 +1,5 @@
-wxPython GRASS Graphical User Interface
-=======================================
+wxPython GRASS Graphical User Interface (wxGUI)
+===============================================
$Date$
@@ -66,7 +66,7 @@
or easier start new GRASS session with -wxpython switch.
-$ grass64 -wxpython
+$ grass65 -wxpython
3 - STARTUP FROM GRASS TERMINAL
@@ -98,7 +98,7 @@
Start GRASS:
-$~ grass64 ~/grassdata/spearfish60/user1
+$~ grass65 ~/grassdata/spearfish60/user1
Use command p.mon (shell script in gui/scripts directory) to start map
display:
@@ -138,9 +138,12 @@
$ export GRASS_WX_DEBUG=3
-6 - EXTENSIONS - VECTOR DIGITIZER AND 3D VIEWER
+6 - VECTOR DIGITIZER
-To enable digitizer you need to compile 'vdigit' or 'nviz'
-component. Note that you must configure GRASS with C++ (--with-cxx),
-Python (--with-python) and wxWidgets (--with-wxwidgets) support.
+To enable digitizer you need to compile 'vdigit' component. Note that
+you must configure GRASS with C++ (--with-cxx), Python (--with-python)
+and wxWidgets (--with-wxwidgets) support.
+$ cd gui/wxpython/vdigit
+$ make
+$ make install
Modified: grass/branches/releasebranch_6_4/gui/wxpython/build_ext.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/build_ext.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/build_ext.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -4,7 +4,7 @@
import sys
def __read_variables(file, dict={}):
- """Read variables from file (e.g. Platform.make)
+ """!Read variables from file (e.g. Platform.make)
@param file file descriptor
@param dict dictionary to store (variable, value)
@@ -22,7 +22,7 @@
dict[var.strip()] = val.strip()
def update_opts(flag, macros, inc_dirs, lib_dirs, libs, extras):
- """Update Extension options"""
+ """!Update Extension options"""
global variables
line = variables[flag]
fw_next = False
Modified: grass/branches/releasebranch_6_4/gui/wxpython/compat/subprocess.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/compat/subprocess.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/compat/subprocess.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -9,7 +9,7 @@
# Licensed to PSF under a Contributor Agreement.
# See http://www.python.org/2.4/license for licensing details.
-r"""subprocess - Subprocesses with accessible I/O streams
+r"""!subprocess - Subprocesses with accessible I/O streams
This module allows you to spawn processes, connect to their
input/output/error pipes, and obtain their return codes. This module
@@ -402,7 +402,7 @@
def call(*args, **kwargs):
- """Run command with arguments. Wait for command to complete, then
+ """!Run command with arguments. Wait for command to complete, then
return the returncode attribute.
The arguments are the same as for the Popen constructor. Example:
@@ -486,7 +486,7 @@
preexec_fn=None, close_fds=False, shell=False,
cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0):
- """Create new Popen instance."""
+ """!Create new Popen instance."""
_cleanup()
if not isinstance(bufsize, (int, long)):
@@ -568,7 +568,7 @@
# Windows methods
#
def _get_handles(self, stdin, stdout, stderr):
- """Construct and return tupel with IO objects:
+ """!Construct and return tupel with IO objects:
p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
"""
if stdin == None and stdout == None and stderr == None:
@@ -628,14 +628,14 @@
def _make_inheritable(self, handle):
- """Return a duplicate of handle, which is inheritable"""
+ """!Return a duplicate of handle, which is inheritable"""
return DuplicateHandle(GetCurrentProcess(), handle,
GetCurrentProcess(), 0, 1,
DUPLICATE_SAME_ACCESS)
def _find_w9xpopen(self):
- """Find and return absolut path to w9xpopen.exe"""
+ """!Find and return absolut path to w9xpopen.exe"""
w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
"w9xpopen.exe")
if not os.path.exists(w9xpopen):
@@ -656,7 +656,7 @@
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
- """Execute program (MS Windows version)"""
+ """!Execute program (MS Windows version)"""
if not isinstance(args, types.StringTypes):
args = list2cmdline(args)
@@ -731,7 +731,7 @@
def poll(self):
- """Check if child process has terminated. Returns returncode
+ """!Check if child process has terminated. Returns returncode
attribute."""
if self.returncode == None:
if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
@@ -741,7 +741,7 @@
def wait(self):
- """Wait for child process to terminate. Returns returncode
+ """!Wait for child process to terminate. Returns returncode
attribute."""
if self.returncode == None:
obj = WaitForSingleObject(self._handle, INFINITE)
@@ -755,7 +755,7 @@
def communicate(self, input=None):
- """Interact with process: Send data to stdin. Read data from
+ """!Interact with process: Send data to stdin. Read data from
stdout and stderr, until end-of-file is reached. Wait for
process to terminate. The optional input argument should be a
string to be sent to the child process, or None, if no data
@@ -812,7 +812,7 @@
# POSIX methods
#
def _get_handles(self, stdin, stdout, stderr):
- """Construct and return tupel with IO objects:
+ """!Construct and return tupel with IO objects:
p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
"""
p2cread, p2cwrite = None, None
@@ -882,7 +882,7 @@
p2cread, p2cwrite,
c2pread, c2pwrite,
errread, errwrite):
- """Execute program (POSIX version)"""
+ """!Execute program (POSIX version)"""
if isinstance(args, types.StringTypes):
args = [args]
@@ -988,7 +988,7 @@
def poll(self):
- """Check if child process has terminated. Returns returncode
+ """!Check if child process has terminated. Returns returncode
attribute."""
if self.returncode == None:
try:
@@ -1001,7 +1001,7 @@
def wait(self):
- """Wait for child process to terminate. Returns returncode
+ """!Wait for child process to terminate. Returns returncode
attribute."""
if self.returncode == None:
pid, sts = os.waitpid(self.pid, 0)
@@ -1010,7 +1010,7 @@
def communicate(self, input=None):
- """Interact with process: Send data to stdin. Read data from
+ """!Interact with process: Send data to stdin. Read data from
stdout and stderr, until end-of-file is reached. Wait for
process to terminate. The optional input argument should be a
string to be sent to the child process, or None, if no data
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/Makefile
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/Makefile 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/Makefile 2010-10-14 15:39:14 UTC (rev 43911)
@@ -5,6 +5,7 @@
wxGUI.Attribute_Table_Manager \
wxGUI.Nviz \
wxGUI.Icons \
+ wxGUI.Modeler \
wxGUI.GCP_Manager
include $(MODULE_TOPDIR)/include/Make/Platform.make
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 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Attribute_Table_Manager.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -36,7 +36,7 @@
</em>
<p>
-See also <a href="http://grass.osgeo.org/wiki/WxPython-based_GUI_for_GRASS#Attribute_table_manager">Wiki</a> page.
+See also <a href="http://grass.osgeo.org/wiki/WxPython-based_GUI_for_GRASS#Attribute_table_manager">wiki</a> page.
<h2>AUTHORS</h2>
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 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.GCP_Manager.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -154,7 +154,7 @@
the mouse over the map canvas to be used as active canvas.</dd>
<dt><img src="icons/grass2/zoom-last.png">
- <em>Return to previous zoom</em></dt>
+ <em>Return to pervious zoom</em></dt>
<dd>Returns to the previous zoom extent. Up to 10 levels of zoom back are
maintained.</dd>
Added: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,39 @@
+<h2>DESCRIPTION</h2>
+
+<b>Note:</b> <em>wxGUI Modeler is currently under development.</em>
+
+<p>
+<b>Graphical modeler</b> is a <em><a href="wxGUI.html">wxGUI</a></em>
+extension which allows the user to create, edit, and manage
+models. It's available from the menu "File | Graphical modeler".
+
+<p>
+The modeler currently allows to:
+
+<ul>
+ <li>define actions (GRASS modules)
+ <li>define data items (raster, vector, 3D raster)
+ <li>define relations between data and action items
+ <li>validate model
+ <li>run model
+ <li>store model settings to the file (GRASS Model File|*.gxm)
+ <li>export model settings to Python script
+ <li>export model to image file
+</ul>
+
+<h2>SEE ALSO</h2>
+
+<em>
+ <a href="wxGUI.html">wxGUI</a>,
+ <a href="wxGUI.Icons.html">Icon themes</a>
+</em>
+
+<p>
+See also <a href="http://grass.osgeo.org/wiki/WxGUI_Modeler">wiki</a> page.
+
+<h2>AUTHORS</h2>
+
+Martin Landa, CTU in Prague, Czech Republic
+
+<p>
+<i>$Date$</i>
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Modeler.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.Nviz.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Nviz.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,18 +1,21 @@
<h2>DESCRIPTION</h2>
-<b>Note:</b> <em>wxGUI Nviz extension is currently under development. Not
-all functionality is implemented.</em>
+Note: <b>wxNviz is currently under development. Not
+all functionality is implemented.</b>
<p>
-<b>wxGUI Nviz extension</b> allows users to realistically render multiple
+<b>wxNviz</b> is a <em><a href="wxGUI.html">wxGUI</a></em> <b>3D view
+mode</b> which allows users to realistically render multiple
<em>surfaces</em> (raster data) in a 3D space, optionally using
thematic coloring, draping 2D <em>vector</em> data over the surfaces,
displaying 3D vector data in the space, and visualization
of <em>volume</em> data (3D raster data).
+
<p>
-To start the wxGUI Nviz extension, choose '3D view' from the map toolbar.
+To start the wxGUI 3D view mode, choose '3D view' from the map
+toolbar.
<p>
-Nviz is emphasized on the ease and speed of viewer positioning and
+wxNviz is emphasized on the ease and speed of viewer positioning and
provided flexibility for using a wide range of data. A low resolution
surface or wire grid (optional) provides real-time viewer positioning
capabilities. Coarse and fine resolution controls allow the user to
@@ -21,89 +24,76 @@
vertical dimension.
<p>
-For each session of Nviz, you might want the same set of 2D/3D raster
-and vector data, view parameters, or other attributes. For consistency
-between sessions, you can store this information in
-the <em>workspace</em> file (gxw). Workspace file contains information
-to restore "state" of the system in 2D and if Nviz is enabled also in
+For each session of wxNviz, you might want the same set of 2D/3D
+raster and vector data, view parameters, or other attributes. For
+consistency between sessions, you can store this information in the
+GRASS <em>workspace</em> file (gxw). Workspace contains information to
+restore "state" of the system in 2D and if wxNviz is enabled also in
the 3D display mode.
-<h2>Data visualization</h2>
+<h2>3D View Toolbar</h2>
-<h3>Surfaces</h3>
+<center>
+<br><img src="wxGUI_nviz_toolbar.jpg" border="1"><br><br>
+</center>
-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:
+<dl>
+ <dt><img src="icons/grass2/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/grass2/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/grass2/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/grass2/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/grass2/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/grass2/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/grass2/settings.png">
+ <em>Show 3D view mode settings</em></dt>
+ <dd>Show dialog with settings for wxGUI 3D view mode. The user
+ settings can be stored in wxGUI settings file.</dd>
+ <dt><img src="icons/grass2/help.png">
+ <em>Show help</em></dt>
+ <dd>Show this help.</dd>
+ <dt><img src="icons/grass2/quit.png">
+ <em>Quit</em></dt>
+ <dd>Quit 3D view mode and switch map display to the 2D view
+ mode.</dd>
+</dl>
-<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>
+<h2>3D View Layer Manager Toolbox</h2>
-<h3>Vector data</h3>
+The 3D view toolbox is integrated in the Layer Manager. The toolbox
+has several tabs:
-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.
-
-3D vector data including volumes (closed group of faces with one
-kernel inside) is also supported.
-
-<h3>Volumes</h3>
-
-Volumes can be displayed either as isosurfaces or slices. Various
-attributes of the isosurface can be defined, similarly to surface
-attributes:
-
<ul>
- <li><b>level</b> - reference isosurface level (height in map
- units).</li>
- <li><b>color</b> - raster map or constant color to drape over the
- current volume.</li>
- <li><b>mask</b> - raster map that controls the areas displayed from
- 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>
- <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>
+ <li><b>View</b> for view controling,</li>
+ <li><b>Data</b> for data properties,</li>
+ <li><b>Appearance</b> for appearance settings (lighting, fringes, ...).</li>
</ul>
-<h2>Nviz Toolbox Window</h2>
-
-The toolbox window has currently three tabs:
-
-<ul>
- <li>View<li>
- <li>Layer properties<li>
- <li>Settings</li>
-</ul>
-
<h3>View</h3>
You can use this panel to set the <em>position, direction, and
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
+ 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.
<center>
@@ -115,20 +105,42 @@
0 is flat. The scene rotates between -90 and 90 degrees.
<p>
- You can also adjusts the vertical exaggeration of the surface. As an
- 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.
+You can also adjusts the vertical exaggeration of the surface. As an
+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.
+<em>Reset</em> returns all current settings to their default values.
-<h3>Surface properties</h3>
+<h3>Data properties - Surface</h3>
+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:
+
+<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>
+
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.
+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>
@@ -139,10 +151,10 @@
display mode), <em>fine</em> (draws surface as filled polygons with
fine resolution) or <em>both</em> (which combines coarse and fine
mode). Additionally set coarse <b>style</b> to <em>wire</em> to draw
-the surface as wire mesh (you can also choose color of the
-wire) or <em>surface</em> to draw the surface using coarse resolution
-filled polygons. This is a low resolution version of the polygon
-surface style.
+the surface as wire mesh (you can also choose color of the wire)
+or <em>surface</em> to draw the surface using coarse resolution filled
+polygons. This is a low resolution version of the polygon surface
+style.
E.g. surface is drawn as a wire mesh if you set <b>mode</b>
to <em>coarse</em> and <b>style</b> to <em>wire</em>. Note that it
@@ -158,11 +170,16 @@
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 "All".
-<h3>Vector properties</h3>
+<h3>Data properties - Vector</h3>
+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.
+
+3D vector data including volumes (closed group of faces with one
+kernel inside) is also supported.
This panel controls how loaded 2D or 3D vector data are drawn.
<p>
@@ -190,17 +207,39 @@
markers:
<ul>
- <li><b>x</b> sets the current points markers to a 2D "X";</li>
- <li><b>sphere</b> - solid 3D sphere;</li>
- <li><b>diamond</b> - solid 3D diamond;</li>
- <li><b>cube</b> - solid 3D cube;</li>
- <li><b>box</b> - hollow 3D cube;</li>
- <li><b>gyroscope</b> - hollow 3D sphere;</li>
- <li><b>asterisk</b> - 3D line-star;</li>
+ <li><b>x</b> sets the current points markers to a 2D "X",</li>
+ <li><b>sphere</b> - solid 3D sphere,</li>
+ <li><b>diamond</b> - solid 3D diamond,</li>
+ <li><b>cube</b> - solid 3D cube,</li>
+ <li><b>box</b> - hollow 3D cube,</li>
+ <li><b>gyroscope</b> - hollow 3D sphere,</li>
+ <li><b>asterisk</b> - 3D line-star.</li>
</ul>
-<h3>Volume properties</h3>
+<h3>Data properties - Volume</h3>
+Volumes can be displayed either as isosurfaces or slices. Various
+attributes of the isosurface can be defined, similarly to surface
+attributes:
+
+<ul>
+ <li><b>level</b> - reference isosurface level (height in map
+ units).</li>
+ <li><b>color</b> - raster map or constant color to drape over the
+ current volume.</li>
+ <li><b>mask</b> - raster map that controls the areas displayed from
+ 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>
+ <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>
+</ul>
+
+<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
@@ -221,7 +260,7 @@
<ul>
<li><b>isosurface</b> - the levels of values for drawing the
- volume(s) as isosurfaces;</li>
+ volume(s) as isosurfaces,</li>
<li>and <b>slice</b> - the levels of values for drawing the volume
as cross-sections.</li>
</ul>
@@ -238,14 +277,11 @@
<ul>
<li>Improve intuitive navigation (mouse, fly mode)</li>
- <li>Interactive lighting controls</li>
<li>Animation capabilities</li>
- <li>Data querying and measuring</li>
<li>Arbitrary cutting planes</li>
<li>Labels, decoration, etc.</li>
<li>Scripting capabilities</li>
<li>Better workspace support (view settings, lighting)
- <li>Image Dump</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>
@@ -253,12 +289,12 @@
</ul>
<p>
-<b>Please note that the wxGUI Nviz extension is under active development and
+<b>Please note that wxNviz is under active development and
distributed as "Experimental Prototype".</b>
<h2>SEE ALSO</h2>
-See also <a href="http://grass.osgeo.org/wiki/WxNVIZ">Wiki</a> page.
+See also <a href="http://grass.osgeo.org/wiki/WxNVIZ">wiki</a> page.
<br><br>
Command-line module <em><a href="nviz_cmd.html">nviz_cmd</a></em>.
@@ -268,7 +304,11 @@
<h2>AUTHORS</h2>
-Martin Landa, Google Summer of Code 2008 (Mentor: Michael Barton)
+Martin
+Landa, <a href="http://grass.osgeo.org/wiki/WxNviz_GSoC_2008">Google
+Summer of Code 2008</a> (mentor: Michael Barton)
+and <a href="http://grass.osgeo.org/wiki/WxNviz_GSoC_2010">Google
+Summer of Code 2010</a> (mentor: Helena Mitasova)
<p>
<i>$Date$</i>
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizing_Tool.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizing_Tool.html 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.Vector_Digitizing_Tool.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -229,7 +229,7 @@
</em>
<p>
-See also <a href="http://grass.osgeo.org/wiki/WxPython-based_GUI_for_GRASS#Vector_digitizer">Wiki</a> page.
+See also <a href="http://grass.osgeo.org/wiki/WxPython-based_GUI_for_GRASS#Vector_digitizer">wiki</a> page.
<p>
TCL/TK-based <a href="v.digit.html">v.digit</a>.
Modified: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI.html 2010-10-14 15:39:14 UTC (rev 43911)
@@ -8,7 +8,7 @@
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
@@ -35,7 +35,7 @@
defined by the <tt>-wxpython</tt> switch:
<div class="code"><pre>
- grass64 -wxpython
+ grass65 -wxpython
</pre></div>
<p>
@@ -52,6 +52,10 @@
under different tabs in the Layer Manager.</li>
</ul>
+<p>
+wxGUI comes with more <em>icon themes</em>, for detailed information
+see this <a href="wxGUI.Icons.html">page</a>.
+
<h3>Layer Manager</h3>
The <em>Layer Manager</em> provides an interactive graphical interface for
@@ -254,6 +258,48 @@
</dl>
+<h4>Key shortcuts</h4>
+
+<b>Menu</b>
+<dl>
+ <dt>Ctrl+N</dt>
+ <dd>Create new workspace</dd>
+ <dt>Ctrl+O</dt>
+ <dd>Load workspace from file</dd>
+ <dt>Ctrl+S</dt>
+ <dd>Close workspace</dd>
+ <dt>Ctrl+L</dt>
+ <dd>Load map layers</dd>
+ <dt>Ctrl+W</dt>
+ <dd>Exit GUI</dd>
+ <dt>Ctrl+Q</dt>
+ <dd>Quit GRASS</dd>
+</dl>
+
+<b>Global</b>
+<dl>
+ <dt>Ctrl+Tab</dt>
+ <dd>Switch 'Map layers' and 'Command output' tab</dd>
+ <dt>Ctrl+R</dt>
+ <dd>Add raster map layer</dd>
+ <dt>Ctrl+V</dt>
+ <dd>Add vector map layer</dd>
+</dl>
+
+<b>Command line prompt</b>
+<dl>
+ <dt>Tab</dt>
+ <dd>Show command tooltips</dd>
+ <dt>Esc</dt>
+ <dd>Hide command tooltips</dd>
+ <dt>Ctrl+Space</dt>
+ <dd>Map entries without arguments (as in <tt>r.info [mapname]</tt>)</dd>
+ <dt>Up/Down</dt>
+ <dd>List command history</dd>
+ <dt>Enter</dt>
+ <dd>Run command</dd>
+</dl>
+
<h3>Map Display Window</h3>
The map display window includes toolbar that can be docked and undocked from
@@ -466,27 +512,19 @@
</ul>
</dl>
-<h2>CONFIGURATION</h2>
-
-<em>User GIS settings</em> dialog ('Config->Preferences') enables
-configuration of various options.
-
-<p>
-For information about available <em>icon themes</em> see
-this <a href="wxGUI.Icons.html">page</a>.
-
<h2>SEE ALSO</h2>
<em>
<a href="wxGUI.Vector_Digitizing_Tool.html">Vector Digitizer</a><br>
<a href="wxGUI.Attribute_Table_Manager.html">Attribute Table Manager</a><br>
<a href="wxGUI.Nviz.html">3D Viewer</a><br>
+ <a href="wxGUI.Modeler.html">Graphical Modeler</a><br>
<a href="wxGUI.GCP_Manager.html">Manage Ground Control Points</a><br>
<a href="wxGUI.Icons.html">Icon themes</a>
</em>
<p>
-See also <a href="http://grass.osgeo.org/wiki/WxGUI">Wiki</a> page.
+See also <a href="http://grass.osgeo.org/wiki/WxGUI">wiki</a> page.
<p>
<em>
Added: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_toolbar.jpg
===================================================================
(Binary files differ)
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/docs/wxGUI_nviz_toolbar.jpg
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
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/gis_set.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gis_set.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,4 +1,4 @@
-"""
+"""!
@package gis_set.py
GRASS start-up screen.
@@ -8,10 +8,10 @@
Classes:
- GRASSStartup
- - HelpWindow
+ - GListBox
- StartUp
-(C) 2006-2009 by the GRASS Development Team
+(C) 2006-2010 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -29,21 +29,26 @@
### i18N
import gettext
-gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
from gui_modules import globalvar
if not os.getenv("GRASS_WXBUNDLED"):
globalvar.CheckForWx()
+import gui_modules.goutput
+from gui_modules.ghelp import HelpFrame
+from gui_modules.gcmd import GMessage
+
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
class GRASSStartup(wx.Frame):
- """GRASS start-up screen"""
- def __init__(self, parent=None, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE):
+ """!GRASS start-up screen"""
+ def __init__(self, parent = None, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE):
#
# GRASS variables
@@ -59,15 +64,15 @@
self.listOfMapsets = []
self.listOfMapsetsSelectable = []
- wx.Frame.__init__(self, parent=parent, id=id, style=style)
+ wx.Frame.__init__(self, parent = parent, id = id, style = style)
self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)
-
- self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
-
+
+ self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
+
# i18N
import gettext
- gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
#
# graphical elements
@@ -76,88 +81,84 @@
try:
name = os.path.join(globalvar.ETCDIR, "gui", "images", "gintro.gif")
self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY,
- wx.Bitmap(name=name,
- type=wx.BITMAP_TYPE_GIF))
+ wx.Bitmap(name = name,
+ type = wx.BITMAP_TYPE_GIF))
except:
self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, wx.EmptyBitmap(530,150))
# labels
### crashes when LOCATION doesn't exist
- # versionCmd = gcmd.Command(['g.version'], log=None)
- # grassVersion = versionCmd.ReadStdOutput()[0].replace('GRASS', '').strip()
versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
grassVersion = versionFile.readline().replace('%s' % os.linesep, '').strip()
versionFile.close()
- self.select_box = wx.StaticBox (parent=self.panel, id=wx.ID_ANY,
- label=" %s " % _("Choose project location and mapset"))
+ self.select_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Choose project location and mapset"))
- self.manage_box = wx.StaticBox (parent=self.panel, id=wx.ID_ANY,
- label=" %s " % _("Manage"))
- self.lwelcome = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Welcome to GRASS GIS %s\n"
+ self.manage_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
+ label = " %s " % _("Manage"))
+ self.lwelcome = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Welcome to GRASS GIS %s\n"
"The world's leading open source GIS") % grassVersion,
- style=wx.ALIGN_CENTRE)
- #self.SetFont(wx.Font(pointSize=9, family=wx.FONTFAMILY_DEFAULT,
- # style=wx.NORMAL, weight=wx.NORMAL))
- self.ltitle = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Select an existing project location and mapset\n"
+ style = wx.ALIGN_CENTRE)
+ self.ltitle = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Select an existing project location and mapset\n"
"or define a new location"),
- style=wx.ALIGN_CENTRE)
- self.ldbase = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("GIS Data Directory:"))
- self.llocation = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Project location\n(projection/coordinate system)"),
- style=wx.ALIGN_CENTRE)
- self.lmapset = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Accessible mapsets\n(directories of GIS files)"),
- style=wx.ALIGN_CENTRE)
- self.lcreate = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Create new mapset\nin selected location"),
- style=wx.ALIGN_CENTRE)
- self.ldefine = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Define new location"),
- style=wx.ALIGN_CENTRE)
- self.lmanageloc = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Rename/delete selected\nmapset or location"),
- style=wx.ALIGN_CENTRE)
+ style = wx.ALIGN_CENTRE)
+ self.ldbase = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("GIS Data Directory:"))
+ self.llocation = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Project location\n(projection/coordinate system)"),
+ style = wx.ALIGN_CENTRE)
+ self.lmapset = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Accessible mapsets\n(directories of GIS files)"),
+ style = wx.ALIGN_CENTRE)
+ self.lcreate = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Create new mapset\nin selected location"),
+ style = wx.ALIGN_CENTRE)
+ self.ldefine = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Define new location"),
+ style = wx.ALIGN_CENTRE)
+ self.lmanageloc = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Rename/delete selected\nmapset or location"),
+ style = wx.ALIGN_CENTRE)
# buttons
- self.bstart = wx.Button(parent=self.panel, id=wx.ID_ANY,
- label=_("Start GRASS"))
+ self.bstart = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("Start &GRASS"))
self.bstart.SetDefault()
- self.bexit = wx.Button(parent=self.panel, id=wx.ID_EXIT)
+ self.bexit = wx.Button(parent = self.panel, id = wx.ID_EXIT)
self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
- self.bhelp = wx.Button(parent=self.panel, id=wx.ID_HELP)
- self.bbrowse = wx.Button(parent=self.panel, id=wx.ID_ANY,
- label=_("Browse"))
- self.bmapset = wx.Button(parent=self.panel, id=wx.ID_ANY,
- label=_("Create mapset"))
- self.bwizard = wx.Button(parent=self.panel, id=wx.ID_ANY,
- label=_("Location wizard"))
- self.manageloc = wx.Choice(parent=self.panel, id=wx.ID_ANY,
- choices=[_('Rename mapset'), _('Rename location'),
+ self.bhelp = wx.Button(parent = self.panel, id = wx.ID_HELP)
+ self.bbrowse = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("&Browse"))
+ self.bmapset = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("&Create mapset"))
+ self.bwizard = wx.Button(parent = self.panel, id = wx.ID_ANY,
+ label = _("&Location wizard"))
+ self.manageloc = wx.Choice(parent = self.panel, id = wx.ID_ANY,
+ choices = [_('Rename mapset'), _('Rename location'),
_('Delete mapset'), _('Delete location')])
self.manageloc.SetSelection(0)
# textinputs
- self.tgisdbase = wx.TextCtrl(parent=self.panel, id=wx.ID_ANY, value="", size=(300, -1),
- style=wx.TE_PROCESS_ENTER)
+ self.tgisdbase = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, value = "", size = (300, -1),
+ style = wx.TE_PROCESS_ENTER)
# Locations
- self.lpanel = wx.Panel(parent=self.panel, id=wx.ID_ANY)
- self.lblocations = GListBox(parent=self.lpanel,
- id=wx.ID_ANY, size=(180, 200),
- choices=self.listOfLocations)
+ self.lpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
+ self.lblocations = GListBox(parent = self.lpanel,
+ id = wx.ID_ANY, size = (180, 200),
+ choices = self.listOfLocations)
self.lblocations.SetColumnWidth(0, 180)
# TODO: sort; but keep PERMANENT on top of list
# Mapsets
- self.mpanel = wx.Panel(parent=self.panel, id=wx.ID_ANY)
- self.lbmapsets = GListBox(parent=self.mpanel,
- id=wx.ID_ANY, size=(180, 200),
- choices=self.listOfMapsets)
+ self.mpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
+ self.lbmapsets = GListBox(parent = self.mpanel,
+ id = wx.ID_ANY, size = (180, 200),
+ choices = self.listOfMapsets)
self.lbmapsets.SetColumnWidth(0, 180)
@@ -180,13 +181,13 @@
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def _set_properties(self):
- """Set frame properties"""
+ """!Set frame properties"""
self.SetTitle(_("Welcome to GRASS GIS"))
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, "grass.ico"),
wx.BITMAP_TYPE_ICO))
self.lwelcome.SetForegroundColour(wx.Colour(35, 142, 35))
- self.lwelcome.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+ self.lwelcome.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
self.bstart.SetToolTipString(_("Enter GRASS session"))
@@ -207,174 +208,166 @@
wx.MessageBox(parent = self, caption = _("Error"),
message = _("Unable to set GRASS database. "
"Check your locale settings."),
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
self.OnSetDatabase(None)
location = self.GetRCValue("LOCATION_NAME")
if location == "<UNKNOWN>" or \
not os.path.isdir(os.path.join(self.gisdbase, location)):
location = None
+
if location:
# list of locations
self.UpdateLocations(self.gisdbase)
try:
self.lblocations.SetSelection(self.listOfLocations.index(location),
- force=True)
+ force = True)
self.lblocations.EnsureVisible(self.listOfLocations.index(location))
except ValueError:
print >> sys.stderr, _("ERROR: Location <%s> not found") % \
- (location)
+ (utils.UnicodeString(location))
# list of mapsets
- self.UpdateMapsets(os.path.join(self.gisdbase,location))
+ self.UpdateMapsets(os.path.join(self.gisdbase, location))
mapset = self.GetRCValue("MAPSET")
if mapset:
try:
self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
- force=True)
+ force = True)
self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
except ValueError:
self.lbmapsets.Clear()
print >> sys.stderr, _("ERROR: Mapset <%s> not found") % \
- (mapset)
-
- # self.bstart.Enable(True)
-
+ (utils.UnicodeString(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.FlexGridSizer(rows = 1, cols = 2, vgap = 4, hgap = 4)
select_boxsizer = wx.StaticBoxSizer(self.select_box, wx.VERTICAL)
- select_sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=4, hgap=4)
+ 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)
- btns_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ btns_sizer = wx.BoxSizer(wx.HORIZONTAL)
# gis data directory
- dbase_sizer.Add(item=self.ldbase, proportion=0,
- flag=wx.ALIGN_CENTER_VERTICAL |
+ dbase_sizer.Add(item = self.ldbase, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
- border=5)
- dbase_sizer.Add(item=self.tgisdbase, proportion=0,
- flag=wx.ALIGN_CENTER_VERTICAL |
+ border = 3)
+ dbase_sizer.Add(item = self.tgisdbase, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
- border=5)
- dbase_sizer.Add(item=self.bbrowse, proportion=0,
- flag=wx.ALIGN_CENTER_VERTICAL |
+ border = 3)
+ dbase_sizer.Add(item = self.bbrowse, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
- border=5)
+ border = 3)
# select sizer
- select_sizer.Add(item=self.llocation, proportion=0,
- flag=label_style | wx.ALL,
- border=5)
- select_sizer.Add(item=self.lmapset, proportion=0,
- flag=label_style | wx.ALL,
- border=5)
- select_sizer.Add(item=self.lpanel, proportion=0,
- flag=wx.ADJUST_MINSIZE |
+ select_sizer.Add(item = self.llocation, proportion = 0,
+ flag = label_style | wx.ALL,
+ border = 3)
+ select_sizer.Add(item = self.lmapset, proportion = 0,
+ flag = label_style | 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 |
+ 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_boxsizer.Add(item = select_sizer, proportion = 0)
# define new location and mapset
- manage_sizer.Add(item=self.ldefine, proportion=0,
- flag=label_style | wx.ALL,
- border=5)
- manage_sizer.Add(item=self.bwizard, proportion=0,
- flag=label_style | wx.BOTTOM,
- border=8)
- manage_sizer.Add(item=self.lcreate, proportion=0,
- flag=label_style | wx.ALL,
- border=5)
- manage_sizer.Add(item=self.bmapset, proportion=0,
- flag=label_style | wx.BOTTOM,
- border=8)
- manage_sizer.Add(item=self.lmanageloc, proportion=0,
- flag=label_style | wx.ALL,
- border=5)
- manage_sizer.Add(item=self.manageloc, proportion=0,
- flag=label_style | wx.BOTTOM,
- border=8)
+ manage_sizer.Add(item = self.ldefine, proportion = 0,
+ flag = label_style | wx.ALL,
+ border = 3)
+ manage_sizer.Add(item = self.bwizard, proportion = 0,
+ flag = label_style | wx.BOTTOM,
+ border = 5)
+ manage_sizer.Add(item = self.lcreate, proportion = 0,
+ flag = label_style | wx.ALL,
+ border = 3)
+ manage_sizer.Add(item = self.bmapset, proportion = 0,
+ flag = label_style | wx.BOTTOM,
+ border = 5)
+ manage_sizer.Add(item = self.lmanageloc, proportion = 0,
+ flag = label_style | wx.ALL,
+ border = 3)
+ manage_sizer.Add(item = self.manageloc, proportion = 0,
+ flag = label_style | wx.BOTTOM,
+ border = 5)
- manage_boxsizer.Add(item=manage_sizer, proportion=0)
+ manage_boxsizer.Add(item = manage_sizer, proportion = 0)
# location sizer
- location_sizer.Add(item=select_boxsizer, proportion=0,
- flag=wx.ADJUST_MINSIZE |
+ 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=5) # GISDBASE setting
- location_sizer.Add(item=manage_boxsizer, proportion=0,
- flag=wx.ADJUST_MINSIZE |
+ 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,
- border=5)
+ border = 3)
# buttons
- btns_sizer.Add(item=self.bstart, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL |
+ btns_sizer.Add(item = self.bstart, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL |
wx.ALIGN_CENTER_VERTICAL |
wx.ALL,
- border=10)
- btns_sizer.Add(item=self.bexit, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL |
+ border = 5)
+ btns_sizer.Add(item = self.bexit, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL |
wx.ALIGN_CENTER_VERTICAL |
wx.ALL,
- border=10)
- btns_sizer.Add(item=self.bhelp, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL |
+ border = 5)
+ btns_sizer.Add(item = self.bhelp, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL |
wx.ALIGN_CENTER_VERTICAL |
wx.ALL,
- border=10)
+ border = 5)
# main sizer
- sizer.Add(item=self.hbitmap, proportion=0,
- flag=wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
+ sizer.Add(item = self.hbitmap,
+ proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL |
wx.ALL,
- border=5) # image
- sizer.Add(item=self.lwelcome, # welcome message
- proportion=0,
- flag= wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
+ border = 3) # image
+ sizer.Add(item = self.lwelcome, # welcome message
+ proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL |
wx.BOTTOM,
- border=10)
- sizer.Add(item=self.ltitle, # title
- proportion=0,
- flag=wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL |
- wx.BOTTOM,
- border=5)
- sizer.Add(item=dbase_sizer, proportion=0,
- flag=wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
- wx.ALIGN_CENTER_HORIZONTAL |
+ border=1)
+ sizer.Add(item = self.ltitle, # title
+ proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
+ wx.ALIGN_CENTER_HORIZONTAL)
+ sizer.Add(item = dbase_sizer, proportion = 0,
+ flag = wx.ALIGN_CENTER_HORIZONTAL |
wx.RIGHT | wx.LEFT,
- border=5) # GISDBASE setting
- sizer.Add(item=location_sizer, proportion=1,
- flag=wx.ADJUST_MINSIZE |
- wx.ALIGN_CENTER_VERTICAL |
+ border = 1) # GISDBASE setting
+ sizer.Add(item = location_sizer, proportion = 1,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL |
wx.RIGHT | wx.LEFT,
- border=5)
- sizer.Add(item=btns_sizer, proportion=0,
- flag=wx.ALIGN_CENTER_VERTICAL |
+ border = 1)
+ sizer.Add(item = btns_sizer, proportion = 0,
+ flag = wx.ALIGN_CENTER_VERTICAL |
wx.ALIGN_CENTER_HORIZONTAL |
wx.RIGHT | wx.LEFT,
- border=5)
+ border = 1)
self.panel.SetAutoLayout(True)
self.panel.SetSizer(sizer)
@@ -416,7 +409,7 @@
from gui_modules import location_wizard
gWizard = location_wizard.LocationWizard(parent = self,
grassdatabase = self.tgisdbase.GetValue())
- if gWizard.location != None:
+ if gWizard.location != None:
self.OnSetDatabase(event)
self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
self.lblocations.SetSelection(self.listOfLocations.index(gWizard.location))
@@ -426,13 +419,13 @@
"""!Location management choice control handler
"""
sel = event.GetSelection()
- if sel == 0:
+ if sel == 0:
self.RenameMapset()
- elif sel == 1:
+ elif sel == 1:
self.RenameLocation()
- elif sel == 2:
+ elif sel == 2:
self.DeleteMapset()
- elif sel == 3:
+ elif sel == 3:
self.DeleteLocation()
event.Skip()
@@ -442,29 +435,28 @@
"""
location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
mapset = utils.UnicodeString(self.listOfMapsets[self.lbmapsets.GetSelection()])
- if mapset == 'PERMANENT':
- wx.MessageBox(parent = self,
- message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
- 'This mapset cannot be renamed.'),
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+ if mapset == 'PERMANENT':
+ GMessage(parent = self,
+ message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
+ 'This mapset cannot be renamed.'))
return
- dlg = wx.TextEntryDialog(parent=self,
- message=_('Current name: %s\n\nEnter new name:') % mapset,
- caption=_('Rename selected mapset'))
+ dlg = wx.TextEntryDialog(parent = self,
+ message = _('Current name: %s\n\nEnter new name:') % mapset,
+ caption = _('Rename selected mapset'))
- if dlg.ShowModal() == wx.ID_OK:
+ if dlg.ShowModal() == wx.ID_OK:
newmapset = dlg.GetValue()
- if newmapset == mapset:
+ if newmapset == mapset:
dlg.Destroy()
return
if newmapset in self.listOfMapsets:
wx.MessageBox(parent = self,
caption = _('Message'),
- message=_('Unable to rename mapset.\n\n'
+ message = _('Unable to rename mapset.\n\n'
'Mapset <%s> already exists in location.') % newmapset,
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+ style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
else:
try:
os.rename(os.path.join(self.gisdbase, location, mapset),
@@ -474,8 +466,8 @@
except StandardError, e:
wx.MessageBox(parent = self,
caption = _('Error'),
- message=_('Unable to rename mapset.\n\n%s') % e,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ message = _('Unable to rename mapset.\n\n%s') % e,
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
dlg.Destroy()
@@ -484,22 +476,22 @@
"""
location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
- dlg = wx.TextEntryDialog(parent=self,
- message=_('Current name: %s\n\nEnter new name:') % location,
- caption=_('Rename selected location'))
+ dlg = wx.TextEntryDialog(parent = self,
+ message = _('Current name: %s\n\nEnter new name:') % location,
+ caption = _('Rename selected location'))
- if dlg.ShowModal() == wx.ID_OK:
+ if dlg.ShowModal() == wx.ID_OK:
newlocation = dlg.GetValue()
- if newlocation == location:
+ if newlocation == location:
dlg.Destroy()
return
if newlocation in self.listOfLocations:
wx.MessageBox(parent = self,
caption = _('Message'),
- message=_('Unable to rename location.\n\n'
+ message = _('Unable to rename location.\n\n'
'Location <%s> already exists in GRASS database.') % newlocation,
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+ style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
else:
try:
os.rename(os.path.join(self.gisdbase, location),
@@ -510,8 +502,8 @@
except StandardError, e:
wx.MessageBox(parent = self,
caption = _('Error'),
- message=_('Unable to rename location.\n\n%s') % e,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ message = _('Unable to rename location.\n\n%s') % e,
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
dlg.Destroy()
@@ -520,28 +512,27 @@
"""
location = self.listOfLocations[self.lblocations.GetSelection()]
mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
- if mapset == 'PERMANENT':
- wx.MessageBox(parent = self,
- message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
- 'This mapset cannot be deleted.'),
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
+ if mapset == 'PERMANENT':
+ GMessage(parent = self,
+ message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
+ 'This mapset cannot be deleted.'))
return
- dlg = wx.MessageDialog(parent=self, message=_("Do you want to continue with deleting mapset <%(mapset)s> "
+ dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting mapset <%(mapset)s> "
"from location <%(location)s>?\n\n"
"ALL MAPS included in this mapset will be "
"PERMANENTLY DELETED!") % {'mapset' : mapset,
'location' : location},
- caption=_("Delete selected mapset"),
- style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+ caption = _("Delete selected mapset"),
+ style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
- if dlg.ShowModal() == wx.ID_YES:
+ if dlg.ShowModal() == wx.ID_YES:
try:
shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
self.OnSelectLocation(None)
self.lbmapsets.SetSelection(0)
except:
- wx.MessageBox(message=_('Unable to delete mapset'))
+ wx.MessageBox(message = _('Unable to delete mapset'))
dlg.Destroy()
@@ -552,14 +543,14 @@
location = self.listOfLocations[self.lblocations.GetSelection()]
- dlg = wx.MessageDialog(parent=self, message=_("Do you want to continue with deleting "
+ dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting "
"location <%s>?\n\n"
"ALL MAPS included in this location will be "
"PERMANENTLY DELETED!") % (location),
- caption=_("Delete selected location"),
- style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
+ caption = _("Delete selected location"),
+ style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
- if dlg.ShowModal() == wx.ID_YES:
+ if dlg.ShowModal() == wx.ID_YES:
try:
shutil.rmtree(os.path.join(self.gisdbase, location))
self.UpdateLocations(self.gisdbase)
@@ -567,29 +558,20 @@
self.OnSelectLocation(None)
self.lbmapsets.SetSelection(0)
except:
- wx.MessageBox(message=_('Unable to delete location'))
+ wx.MessageBox(message = _('Unable to delete location'))
dlg.Destroy()
def UpdateLocations(self, dbase):
- """Update list of locations"""
- self.listOfLocations = []
-
+ """!Update list of locations"""
try:
- for location in glob.glob(os.path.join(dbase, "*")):
- try:
- if os.path.join(location, "PERMANENT") in glob.glob(os.path.join(location, "*")):
- self.listOfLocations.append(utils.EncodeString(os.path.basename(location)))
- except:
- pass
- except UnicodeError:
+ self.listOfLocations = utils.GetListOfLocations(dbase)
+ except UnicodeEncodeError:
wx.MessageBox(parent = self, caption = _("Error"),
message = _("Unable to set GRASS database. "
"Check your locale settings."),
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
- utils.ListSortLower(self.listOfLocations)
-
self.lblocations.Clear()
self.lblocations.InsertItems(self.listOfLocations, 0)
@@ -601,62 +583,60 @@
return self.listOfLocations
def UpdateMapsets(self, location):
- """Update list of mapsets"""
+ """!Update list of mapsets"""
self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
- self.listOfMapsets = []
- self.listOfMapsetsSelectable = []
-
- for mapset in glob.glob(os.path.join(self.gisdbase, location, "*")):
- if os.path.isdir(mapset) and \
- os.path.isfile(os.path.join(self.gisdbase, location, mapset, "WIND")) and \
- os.path.basename(mapset) != 'PERMANENT':
- self.listOfMapsets.append(utils.EncodeString(os.path.basename(mapset)))
-
- utils.ListSortLower(self.listOfMapsets)
- self.listOfMapsets.insert(0, 'PERMANENT')
-
+ self.listOfMapsetsSelectable = list()
+ self.listOfMapsets = utils.GetListOfMapsets(self.gisdbase, location)
+
self.lbmapsets.Clear()
# disable mapset with denied permission
locationName = os.path.basename(location)
try:
- mapsets = gcmd.Command(['g.mapset',
- '-l',
- 'location=%s' % locationName,
- 'gisdbase=%s' % self.gisdbase],
- stderr=None)
+ ret = gcmd.RunCommand('g.mapset',
+ read = True,
+ flags = 'l',
+ location = locationName,
+ gisdbase = self.gisdbase)
- for line in mapsets.ReadStdOutput():
- self.listOfMapsetsSelectable += line.split(' ')
- except gcmd.CmdError:
- gcmd.Command(["g.gisenv",
- "set=GISDBASE=%s" % self.gisdbase])
- gcmd.Command(["g.gisenv",
- "set=LOCATION_NAME=%s" % locationName])
- gcmd.Command(["g.gisenv",
- "set=MAPSET=PERMANENT"])
+ if not ret:
+ raise gcmd.CmdError("")
+
+ for line in ret.splitlines():
+ self.listOfMapsetsSelectable += line.split(' ')
+ except:
+ 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")
# first run only
self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
disabled = []
idx = 0
for mapset in self.listOfMapsets:
- if mapset not in self.listOfMapsetsSelectable:
+ mapset = utils.UnicodeString(mapset)
+ if mapset not in self.listOfMapsetsSelectable or \
+ os.path.isfile(os.path.join(self.gisdbase,
+ locationName,
+ mapset, ".gislock")):
disabled.append(idx)
- idx += 1
-
- self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)
+ idx += 1
+ self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
+
return self.listOfMapsets
def OnSelectLocation(self, event):
- """Location selected"""
+ """!Location selected"""
if event:
self.lblocations.SetSelection(event.GetIndex())
- if self.lblocations.GetSelection() != wx.NOT_FOUND:
+ if self.lblocations.GetSelection() != wx.NOT_FOUND:
self.UpdateMapsets(os.path.join(self.gisdbase,
self.listOfLocations[self.lblocations.GetSelection()]))
else:
@@ -670,12 +650,15 @@
locationName = ''
for mapset in self.listOfMapsets:
- if mapset not in self.listOfMapsetsSelectable:
+ if mapset not in self.listOfMapsetsSelectable or \
+ os.path.isfile(os.path.join(self.gisdbase,
+ locationName,
+ mapset, ".gislock")):
disabled.append(idx)
- idx += 1
+ idx += 1
self.lbmapsets.Clear()
- self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)
+ self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
if len(self.listOfMapsets) > 0:
self.lbmapsets.SetSelection(0)
@@ -691,7 +674,7 @@
self.manageloc.Enable(False)
def OnSelectMapset(self, event):
- """Mapset selected"""
+ """!Mapset selected"""
self.lbmapsets.SetSelection(event.GetIndex())
if event.GetText() not in self.listOfMapsetsSelectable:
@@ -701,7 +684,7 @@
event.Skip()
def OnSetDatabase(self, event):
- """Database set"""
+ """!Database set"""
self.gisdbase = self.tgisdbase.GetValue()
self.UpdateLocations(self.gisdbase)
@@ -713,8 +696,8 @@
grassdata = None
dlg = wx.DirDialog(self, _("Choose GIS Data Directory:"),
- style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
- if dlg.ShowModal() == wx.ID_OK:
+ style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
+ if dlg.ShowModal() == wx.ID_OK:
self.gisdbase = dlg.GetPath()
self.tgisdbase.SetValue(self.gisdbase)
self.OnSetDatabase(event)
@@ -722,15 +705,15 @@
dlg.Destroy()
def OnCreateMapset(self,event):
- """Create new mapset"""
+ """!Create new mapset"""
self.gisdbase = self.tgisdbase.GetValue()
location = self.listOfLocations[self.lblocations.GetSelection()]
- dlg = wx.TextEntryDialog(parent=self,
- message=_('Enter name for new mapset:'),
- caption=_('Create new mapset'))
+ dlg = wx.TextEntryDialog(parent = self,
+ message = _('Enter name for new mapset:'),
+ caption = _('Create new mapset'))
- if dlg.ShowModal() == wx.ID_OK:
+ if dlg.ShowModal() == wx.ID_OK:
mapset = dlg.GetValue()
try:
os.mkdir(os.path.join(self.gisdbase, location, mapset))
@@ -741,23 +724,28 @@
self.OnSelectLocation(None)
self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
except StandardError, e:
- dlg = wx.MessageDialog(parent=self, message=_("Unable to create new mapset: %s") % e,
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR)
+ dlg = wx.MessageDialog(parent = self, message = _("Unable to create new mapset: %s") % e,
+ caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
return False
-
+
+ self.bstart.SetFocus()
+
return True
def OnStart(self, event):
"""'Start GRASS' button clicked"""
- gcmd.Command(["g.gisenv",
- "set=GISDBASE=%s" % self.tgisdbase.GetValue()])
- gcmd.Command(["g.gisenv",
- "set=LOCATION_NAME=%s" % self.listOfLocations[self.lblocations.GetSelection()]])
- gcmd.Command(["g.gisenv",
- "set=MAPSET=%s" % self.listOfMapsets[self.lbmapsets.GetSelection()]])
-
+ gcmd.RunCommand("g.gisenv",
+ set = "GISDBASE = %s" % \
+ self.tgisdbase.GetValue())
+ gcmd.RunCommand("g.gisenv",
+ set = "LOCATION_NAME = %s" % \
+ self.listOfLocations[self.lblocations.GetSelection()])
+ gcmd.RunCommand("g.gisenv",
+ set = "MAPSET = %s" % \
+ self.listOfMapsets[self.lbmapsets.GetSelection()])
+
self.Destroy()
sys.exit(0)
@@ -769,68 +757,41 @@
def OnHelp(self, event):
"""'Help' button clicked"""
# help text in lib/init/helptext.html
- file=os.path.join(self.gisbase, "docs", "html", "helptext.html")
+ file = os.path.join(self.gisbase, "docs", "html", "helptext.html")
- helpFrame = HelpWindow(parent=self, id=wx.ID_ANY,
- title=_("GRASS Quickstart"),
- size=(640, 480),
- file=file)
+ helpFrame = HelpFrame(parent = self, id = wx.ID_ANY,
+ title = _("GRASS Quickstart"),
+ size = (640, 480),
+ file = file)
helpFrame.Show(True)
event.Skip()
def OnCloseWindow(self, event):
- """Close window event"""
+ """!Close window event"""
event.Skip()
sys.exit(2)
-class HelpWindow(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
- helpFrame = wx.html.HtmlWindow(parent=self, id=wx.ID_ANY)
- helpFrame.SetStandardFonts (size = 10)
- helpFrame.SetBorders(10)
- wx.InitAllImageHandlers()
-
- helpFrame.LoadFile(file)
- self.Ok = True
-
- sizer.Add(item=helpFrame, proportion=1, flag=wx.EXPAND)
-
- self.SetAutoLayout(True)
- self.SetSizer(sizer)
- # sizer.Fit(self)
- # sizer.SetSizeHints(self)
- self.Layout()
-
class GListBox(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
- """Use wx.ListCtrl instead of wx.ListBox, different style for
+ """!Use wx.ListCtrl instead of wx.ListBox, different style for
non-selectable items (e.g. mapsets with denied permission)"""
def __init__(self, parent, id, size,
- choices, disabled=[]):
-
- wx.ListCtrl.__init__(self, parent, id, size=size,
- style=wx.LC_REPORT | wx.LC_NO_HEADER | wx.LC_SINGLE_SEL |
+ choices, disabled = []):
+ wx.ListCtrl.__init__(self, parent, id, size = size,
+ style = wx.LC_REPORT | wx.LC_NO_HEADER | wx.LC_SINGLE_SEL |
wx.BORDER_SUNKEN)
-
+
listmix.ListCtrlAutoWidthMixin.__init__(self)
self.InsertColumn(0, '')
-
+
self.selected = wx.NOT_FOUND
- self.__LoadData(choices, disabled)
+ self._LoadData(choices, disabled)
- def __LoadData(self, choices, disabled=[]):
- """
- Load data into list
-
+ def _LoadData(self, choices, disabled = []):
+ """!Load data into list
+
@param choices list of item
@param disabled list of indeces of non-selectable items
"""
@@ -838,31 +799,30 @@
for item in choices:
index = self.InsertStringItem(sys.maxint, item)
self.SetStringItem(index, 0, item)
+
if idx in disabled:
self.SetItemTextColour(idx, wx.Colour(150, 150, 150))
- idx += 1
-
- #self.SetColumnWidth(0, wx.LIST_AUTOSIZE)
-
+ idx += 1
+
def Clear(self):
self.DeleteAllItems()
-
- def InsertItems(self, choices, pos, disabled=[]):
- self.__LoadData(choices, disabled)
-
+
+ def InsertItems(self, choices, pos, disabled = []):
+ self._LoadData(choices, disabled)
+
def SetSelection(self, item, force = False):
- if item != wx.NOT_FOUND and \
- (platform.system() != 'Windows' or force):
+ if item != wx.NOT_FOUND and \
+ (platform.system() != 'Windows' or force):
### Windows -> FIXME
self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
-
+
self.selected = item
def GetSelection(self):
return self.selected
class StartUp(wx.App):
- """Start-up application"""
+ """!Start-up application"""
def OnInit(self):
wx.InitAllImageHandlers()
@@ -871,26 +831,26 @@
self.SetTopWindow(StartUp)
StartUp.Show()
- if StartUp.GetRCValue("LOCATION_NAME") == "<UNKNOWN>":
- wx.MessageBox(parent=StartUp,
- caption=_('Starting GRASS for the first time'),
- message=_('GRASS needs a directory in which to store its data. '
+ if StartUp.GetRCValue("LOCATION_NAME") == "<UNKNOWN>":
+ wx.MessageBox(parent = StartUp,
+ caption = _('Starting GRASS for the first time'),
+ message = _('GRASS needs a directory in which to store its data. '
'Create one now if you have not already done so. '
'A popular choice is "grassdata", located in '
'your home directory.'),
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
StartUp.OnBrowse(None)
return 1
-if __name__ == "__main__":
+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)
+ gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
import gui_modules.gcmd as gcmd
import gui_modules.utils as utils
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/__init__.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/__init__.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/__init__.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,30 +1,43 @@
-all = [ "dbm",
- "debug",
- "disp_print",
- "gcmd",
- "georect",
- "gcpmanager",
- "gcpmapdisp",
- "globalvar",
- "grassenv",
- "gselect",
- "goutput",
- "histogram",
- "location_wizard",
- "mapdisp",
- "menudata",
- "menuform",
- "nviz",
- "preferences",
- "profile",
- "psmap",
- "render",
- "rules",
- "sqlbuilder",
- "toolbars",
- "toolbox",
- "track",
- "utils",
- "vdigit",
- "workspace",
- "wxgui_utils" ]
+all = [
+ "colorrules.py",
+ "dbm.py",
+ "dbm_base.py",
+ "dbm_dialogs.py",
+ "debug.py",
+ "disp_print.py",
+ "gcmd.py",
+ "gcpmanager.py",
+ "gcpmapdisp.py",
+ "gdialogs.py",
+ "georect.py",
+ "ghelp.py"
+ "globalvar.py",
+ "goutput.py",
+ "gselect.py",
+ "histogram.py",
+ "layertree.py",
+ "location_wizard.py",
+ "mapdisp_command.py",
+ "mapdisp_window.py",
+ "mapdisp.py",
+ "mcalc_builder.py",
+ "menu.py",
+ "menudata.py",
+ "menuform.py",
+ "nviz_mapdisp.py",
+ "nviz_preferences.py",
+ "nviz_tools.py",
+ "ogc_services.py",
+ "preferences.py",
+ "profile.py",
+ "render.py",
+ "rules.py",
+ "sqlbuilder.py",
+ "toolbars.py",
+ "units.py",
+ "utils.py",
+ "vclean.py",
+ "vdigit.py",
+ "workspace.py",
+ "wxnviz.py",
+]
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/colorrules.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/colorrules.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/colorrules.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,14 +1,14 @@
"""
@package colorrules.py
- at brief Dialog for interactive management of raster color tables and vector
-rgb_column
+ at brief Dialog for interactive management of raster color tables and
+vector rgb_column
Classes:
- ColorTable
- BuferedWindow
-(C) 2008 by the GRASS Development Team
+(C) 2008, 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.
@@ -36,24 +36,21 @@
from preferences import globalSettings as UserSettings
class ColorTable(wx.Frame):
- def __init__(self, parent, id=wx.ID_ANY, title='',
- pos=wx.DefaultPosition, size=(-1, -1),
+ def __init__(self, parent, cmd, id=wx.ID_ANY, title = _("Set color table"),
style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER,
**kwargs):
- wx.Frame.__init__(self, parent, id, title, pos, size, style)
- """
- Dialog for interactively entering rules for map management
+ """!Dialog for interactively entering rules for map management
commands
@param cmd command (given as list)
"""
self.parent = parent # GMFrame
-
- self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+ self.cmd = cmd
- # grass command
- self.cmd = kwargs['cmd']
+ 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))
+
# input map to change
self.inmap = ''
@@ -98,14 +95,7 @@
self.SetTitle(_('Create new color table for vector map'))
self.elem = 'vector'
crlabel = _('Enter vector attribute values or ranges (n or n1 to n2)')
-
- #
- # Set the size & cursor
- #
- self.SetClientSize(size)
-
- ### self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
-
+
# top controls
if self.cmd == 'r.colors':
maplabel = _('Select raster map:')
@@ -195,7 +185,8 @@
# layout
self.__doLayout()
-
+ self.SetMinSize(self.GetSize())
+
self.CentreOnScreen()
self.Show()
@@ -220,7 +211,6 @@
# body & preview
#
bodySizer = wx.GridBagSizer(hgap=5, vgap=5)
-
row = 0
bodySizer.Add(item=self.cr_label, pos=(row, 0), span=(1, 3),
flag=wx.ALL, border=5)
@@ -247,6 +237,7 @@
bodySizer.Add(item=self.preview, pos=(row, 2),
flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
+ bodySizer.AddGrowableRow(row)
bodySizer.AddGrowableCol(2)
row += 1
@@ -270,7 +261,7 @@
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,
@@ -296,12 +287,12 @@
return cr_panel
def OnAddRules(self, event):
- """Add rules button pressed"""
+ """!Add rules button pressed"""
nrules = self.numRules.GetValue()
self.AddRules(nrules)
def AddRules(self, nrules):
- """Add rules"""
+ """!Add rules"""
snum = len(self.ruleslines.keys())
for num in range(snum, snum+nrules):
# enable
@@ -330,29 +321,21 @@
self.cr_panel.SetupScrolling()
def InitDisplay(self):
+ """!Initialize preview display, set dimensions and region
"""
- Initialize preview display, set dimensions and region
- """
- #self.width, self.height = self.GetClientSize()
self.width = self.Map.width = 400
self.height = self.Map.height = 300
self.Map.geom = self.width, self.height
def OnErase(self, event):
+ """!Erase the histogram display
"""
- Erase the histogram display
- """
self.PreviewWindow.Draw(self.HistWindow.pdc, pdctype='clear')
def OnCloseWindow(self, event):
- """
- Window closed
+ """!Window closed
Also remove associated rendered images
"""
- #try:
- # self.propwin.Close(True)
- #except:
- # pass
self.Map.Clean()
self.Destroy()
@@ -367,19 +350,19 @@
return
if self.elem == 'cell':
- cmdlist = ['r.info',
- '-r',
- 'map=%s' % self.inmap]
+ info = gcmd.RunCommand('r.info',
+ parent = self,
+ read = True,
+ flags = 'r',
+ map = self.inmap)
- try:
- p = gcmd.Command(cmdlist)
-
- for line in p.ReadStdOutput():
+ if info:
+ for line in info.splitlines():
if 'min' in line:
self.rast['min'] = float(line.split('=')[1])
elif 'max' in line:
self.rast['max'] = float(line.split('=')[1])
- except gcmd.CmdError:
+ else:
self.inmap = ''
self.rast['min'] = self.rast['max'] = None
self.btnPreview.Enable(False)
@@ -422,7 +405,7 @@
self.vect['rgb'] = event.GetString()
def OnRuleEnable(self, event):
- """Rule enabled/disabled"""
+ """!Rule enabled/disabled"""
id = event.GetId()
if event.IsChecked():
@@ -439,7 +422,7 @@
del self.ruleslines[id]
def OnRuleValue(self, event):
- """Rule value changed"""
+ """!Rule value changed"""
num = event.GetId()
vals = event.GetString().strip()
@@ -477,7 +460,7 @@
return
def OnRuleColor(self, event):
- """Rule color changed"""
+ """!Rule color changed"""
num = event.GetId()
rgba_color = event.GetValue()
@@ -503,7 +486,10 @@
def OnApply(self, event):
self.CreateColorTable()
-
+ display = self.parent.GetLayerTree().GetMapDisplay()
+ if display:
+ display.GetWindow().UpdateMap(render = True)
+
def OnOK(self, event):
self.OnApply(event)
self.Destroy()
@@ -512,7 +498,7 @@
self.Destroy()
def OnPreview(self, event):
- """Update preview"""
+ """!Update preview"""
# raster
if self.elem == 'cell':
cmdlist = ['d.rast',
@@ -557,18 +543,20 @@
shutil.copyfile(colrtemp, old_colrtable)
os.remove(colrtemp)
else:
- gcmd.Command(['r.colors',
- '-r',
- 'map=%s' % self.inmap])
+ gcmd.RunCommand('r.colors',
+ parent = self,
+ flags = 'r',
+ map = self.inmap)
def OnHelp(self, event):
- """Show GRASS manual page"""
- gcmd.Command(['g.manual',
- '--quiet',
- '%s' % self.cmd])
-
+ """!Show GRASS manual page"""
+ gcmd.RunCommand('g.manual',
+ quiet = True,
+ parent = self,
+ entry = self.cmd)
+
def CreateColorTable(self, force=False):
- """Creates color table"""
+ """!Creates color table"""
rulestxt = ''
for rule in self.ruleslines.itervalues():
@@ -593,22 +581,25 @@
output.close()
if self.elem == 'cell':
- cmdlist = ['r.colors',
- 'map=%s' % self.inmap,
- 'rules=%s' % gtemp]
-
if not force and \
not self.ovrwrtcheck.IsChecked():
- cmdlist.append('-w')
+ flags = 'w'
+ else:
+ flags = ''
+ gcmd.RunCommand('r.colors',
+ parent = self,
+ flags = flags,
+ map = self.inmap,
+ rules = gtemp)
+
elif self.elem == 'vector':
- cmdlist = ['db.execute',
- 'input=%s' % gtemp]
+ gcmd.RunCommand('db.execute',
+ parent = self,
+ input = gtemp)
- p = gcmd.Command(cmdlist)
-
class BufferedWindow(wx.Window):
- """A Buffered window class"""
+ """!A Buffered window class"""
def __init__(self, parent, id,
pos = wx.DefaultPosition,
size = wx.DefaultSize,
@@ -649,7 +640,7 @@
self.Map.SetRegion()
def Draw(self, pdc, img=None, pdctype='image'):
- """Draws preview or clears window"""
+ """!Draws preview or clears window"""
pdc.BeginDrawing()
Debug.msg (3, "BufferedWindow.Draw(): pdctype=%s" % (pdctype))
@@ -673,7 +664,7 @@
self.Refresh()
def OnPaint(self, event):
- """Draw pseudo DC to buffer"""
+ """!Draw pseudo DC to buffer"""
self._Buffer = wx.EmptyBitmap(self.Map.width, self.Map.height)
dc = wx.BufferedPaintDC(self, self._Buffer)
@@ -694,7 +685,7 @@
self.pdc.DrawToDCClipped(dc, r)
def OnSize(self, event):
- """Init image size to match window size"""
+ """!Init image size to match window size"""
# set size of the input image
self.Map.width, self.Map.height = self.GetClientSize()
@@ -716,7 +707,7 @@
self.resize = True
def OnIdle(self, event):
- """Only re-render a preview image from GRASS during
+ """!Only re-render a preview image from GRASS during
idle time instead of multiple times during resizing.
"""
if self.resize:
@@ -725,7 +716,7 @@
event.Skip()
def GetImage(self):
- """Converts files to wx.Image"""
+ """!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)
@@ -735,7 +726,7 @@
return img
def UpdatePreview(self, img=None):
- """Update canvas if window changes geometry"""
+ """!Update canvas if window changes geometry"""
Debug.msg (2, "BufferedWindow.UpdatePreview(%s): render=%s" % (img, self.render))
oldfont = ""
oldencoding = ""
@@ -762,6 +753,6 @@
self.resize = False
def EraseMap(self):
- """Erase preview"""
+ """!Erase preview"""
self.Draw(self.pdc, pdctype='clear')
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/colorrules.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -17,9 +17,6 @@
- Log
- VirtualAttributeList
- AttributeManager
- - DisplayAttributesDialog
- - VectorDBInfo
- - ModifyTableRecord
(C) 2007-2009 by the GRASS Development Team
@@ -36,6 +33,7 @@
import locale
import tempfile
import copy
+import types
### i18N
import gettext
@@ -48,58 +46,18 @@
import wx
import wx.lib.mixins.listctrl as listmix
import wx.lib.flatnotebook as FN
-import wx.lib.scrolledpanel as scrolled
import grass.script as grass
import sqlbuilder
-import grassenv
import gcmd
import utils
import gdialogs
-import gselect
-from debug import Debug as Debug
+import dbm_base
+from debug import Debug
+from dbm_dialogs import ModifyTableRecord
from preferences import globalSettings as UserSettings
-def unicodeValue(value):
- """Encode value"""
- enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
- if enc:
- value = unicode(value, enc)
- elif os.environ.has_key('GRASS_DB_ENCODING'):
- 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 Log:
"""
The log output is redirected to the status bar of the containing frame.
@@ -108,7 +66,7 @@
self.parent = parent
def write(self, text_string):
- """Update status bar"""
+ """!Update status bar"""
self.parent.SetStatusText(text_string.strip())
@@ -135,8 +93,9 @@
try:
keyColumn = self.LoadData(layer)
- except gcmd.DBMError, e:
- e.Show()
+ except gcmd.GException, e:
+ GError(parent = self,
+ message = e)
return
#
@@ -166,19 +125,21 @@
# 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.OnColumnClick) # sorting
+ 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"""
+ """!Update list according new mapDBInfo description"""
self.mapDBInfo = mapDBInfo
self.LoadData(self.layer)
- def LoadData(self, layer, columns=None, where=None):
- """Load data into list
+ 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 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
@@ -190,21 +151,14 @@
try:
self.columns = self.mapDBInfo.tables[tableName]
except KeyError:
- raise gcmd.DBMError(message=_("Attribute table <%s> not found. "
- "For creating the table switch to "
- "'Manage layers' tab.") % tableName,
- parent=self.parent)
+ raise gcmd.GException(_("Attribute table <%s> not found. "
+ "For creating the table switch to "
+ "'Manage layers' tab.") % tableName)
- cmd = ["v.db.select",
- "-c", "--q",
- "map=%s" % self.mapDBInfo.map,
- "layer=%d" % layer]
-
if not columns:
columns = self.mapDBInfo.GetColumns(tableName)
else:
all = self.mapDBInfo.GetColumns(tableName)
- cmd.append("columns=%s" % ','.join(columns))
for col in columns:
if col not in all:
wx.MessageBox(parent=self,
@@ -213,10 +167,6 @@
{ 'column' : col, 'table' : tableName },
caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
return
-
-
- if where:
- cmd.append("where=%s" % where)
try:
# for maps connected via v.external
@@ -233,9 +183,32 @@
# TODO: more effective way should be implemented...
outFile = tempfile.NamedTemporaryFile(mode='w+b')
- selectCommand = gcmd.Command(cmd,
- stdout=outFile)
-
+ if sql:
+ ret = gcmd.RunCommand('db.select',
+ quiet = True,
+ parent = self,
+ flags = 'c',
+ sql = sql,
+ output = outFile.name)
+ else:
+ if columns:
+ ret = gcmd.RunCommand('v.db.select',
+ quiet = True,
+ flags = 'c',
+ map = self.mapDBInfo.map,
+ layer = layer,
+ columns = ','.join(columns),
+ where = where,
+ stdout=outFile)
+ else:
+ ret = gcmd.RunCommand('v.db.select',
+ quiet = True,
+ 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 = {}
@@ -267,61 +240,17 @@
while True:
# os.linesep doesn't work here (MSYS)
record = outFile.readline().replace('\n', '')
+
if not record:
break
-
- self.itemDataMap[i] = []
- j = 0
-
- for value in record.split('|'):
- if self.columns[columns[j]]['ctype'] != type(''):
- # encode numeric values
- 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 keyId > -1 and keyId == j:
- try:
- cat = self.columns[columns[j]]['ctype'] (value)
- except ValueError, e:
- cat = -1
- wx.MessageBox(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},
- caption=_("Error"),
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
- j += 1
+
+ self.AddDataRow(i, record, columns, keyId)
- # insert to table
- # index = self.InsertStringItem(index=sys.maxint, label=str(self.itemDataMap[i][0]))
- # for j in range(len(self.itemDataMap[i][1:])):
- # self.SetStringItem(index=index, col=j+1, label=str(self.itemDataMap[i][j+1]))
-
- # self.SetItemData(item=index, data=i)
-
- self.itemIndexMap.append(i)
- if keyId > -1: # load cats only when LoadData() is called first time
- self.itemCatsMap[i] = cat
-
i += 1
if i >= 100000:
self.log.write(_("Limit 100000 records."))
break
-
+
self.SetItemCount(i)
i = 0
@@ -333,16 +262,62 @@
width = 300
self.SetColumnWidth(col=i, width=width)
i += 1
-
+
self.SendSizeEvent()
-
+
self.log.write(_("Number of loaded records: %d") % \
self.GetItemCount())
return keyId
+ def AddDataRow(self, i, record, columns, keyId):
+ """!Add row to the data list"""
+ self.itemDataMap[i] = []
+ keyColumn = self.mapDBInfo.layers[self.layer]['key']
+ j = 0
+ cat = None
+
+ if keyColumn == 'OGC_FID':
+ self.itemDataMap[i].append(i+1)
+ j += 1
+ cat = i + 1
+
+ for value in record.split('|'):
+ if self.columns[columns[j]]['ctype'] != types.StringType:
+ try:
+ ### casting disabled (2009/03)
+ ### self.itemDataMap[i].append(self.columns[columns[j]]['ctype'](value))
+ self.itemDataMap[i].append(value)
+ except ValueError:
+ self.itemDataMap[i].append(_('Unknown value'))
+ else:
+ # encode string values
+ try:
+ self.itemDataMap[i].append(dbm_base.unicodeValue(value))
+ except UnicodeDecodeError:
+ self.itemDataMap[i].append(_("Unable to decode value. "
+ "Set encoding in GUI preferences ('Attributes')."))
+
+ if not cat and keyId > -1 and keyId == j:
+ try:
+ cat = self.columns[columns[j]]['ctype'] (value)
+ except ValueError, e:
+ cat = -1
+ gcmd.GError(parent = self,
+ message=_("Error loading attribute data. "
+ "Record number: %(rec)d. Unable to convert value '%(val)s' in "
+ "key column (%(key)s) to integer.\n\n"
+ "Details: %(detail)s") % \
+ { 'rec' : i + 1, 'val' : value,
+ 'key' : keyColumn, 'detail' : e})
+ j += 1
+
+ self.itemIndexMap.append(i)
+ if keyId > -1: # load cats only when LoadData() is called first time
+ self.itemCatsMap[i] = cat
+
def OnItemSelected(self, event):
- """Item selected. Add item to selected cats..."""
+ """!Item selected. Add item to selected cats..."""
# cat = int(self.GetItemText(event.m_itemIndex))
# if cat not in self.selectedCats:
# self.selectedCats.append(cat)
@@ -351,7 +326,7 @@
event.Skip()
def OnItemDeselected(self, event):
- """Item deselected. Remove item from selected cats..."""
+ """!Item deselected. Remove item from selected cats..."""
# cat = int(self.GetItemText(event.m_itemIndex))
# if cat in self.selectedCats:
# self.selectedCats.remove(cat)
@@ -360,7 +335,7 @@
event.Skip()
def GetSelectedItems(self):
- """Return list of selected items (category numbers)"""
+ """!Return list of selected items (category numbers)"""
cats = []
item = self.GetFirstSelected()
while item != -1:
@@ -370,32 +345,134 @@
return cats
def GetColumnText(self, index, col):
- """Return column text"""
+ """!Return column text"""
item = self.GetItem(index, col)
return item.GetText()
def GetListCtrl(self):
- """Returt list"""
+ """!Returt list"""
return self
def OnGetItemText(self, item, col):
- """Get item text"""
+ """!Get item text"""
index = self.itemIndexMap[item]
s = self.itemDataMap[index][col]
return s
def OnGetItemAttr(self, item):
- """Get item attributes"""
+ """!Get item attributes"""
index = self.itemIndexMap[item]
if ( index % 2) == 0:
return self.attr2
else:
return self.attr1
- def OnColumnClick(self, event):
- """Column heading clicked -> sorting"""
+ def OnColumnMenu(self, event):
+ """!Column heading right mouse button -> pop-up menu"""
self._col = event.GetColumn()
+
+ popupMenu = wx.Menu()
+ if not hasattr (self, "popupID1"):
+ self.popupID1 = wx.NewId()
+ self.popupID2 = wx.NewId()
+ self.popupID3 = wx.NewId()
+ self.popupID4 = wx.NewId()
+ self.popupID5 = wx.NewId()
+ self.popupID6 = wx.NewId()
+ self.popupID7 = wx.NewId()
+ self.popupID8 = wx.NewId()
+ self.popupID9 = wx.NewId()
+ self.popupID10 = wx.NewId()
+ self.popupID11 = wx.NewId()
+ self.popupID12 = wx.NewId()
+
+ popupMenu.Append(self.popupID1, text=_("Sort ascending"))
+ popupMenu.Append(self.popupID2, text=_("Sort descending"))
+ popupMenu.AppendSeparator()
+ subMenu = wx.Menu()
+ popupMenu.AppendMenu(self.popupID3, _("Calculate (only numeric columns)"),
+ subMenu)
+ if not self.log.parent.editable or \
+ self.columns[self.GetColumn(self._col).GetText()]['ctype'] not in (types.IntType, types.FloatType):
+ popupMenu.Enable(self.popupID3, False)
+
+ subMenu.Append(self.popupID4, text=_("Area size"))
+ subMenu.Append(self.popupID5, text=_("Line length"))
+ subMenu.Append(self.popupID6, text=_("Compactness of an area"))
+ subMenu.Append(self.popupID7, text=_("Fractal dimension of boundary defining a polygon"))
+ subMenu.Append(self.popupID8, text=_("Perimeter length of an area"))
+ subMenu.Append(self.popupID9, text=_("Number of features for each category"))
+ subMenu.Append(self.popupID10, text=_("Slope steepness of 3D line"))
+ subMenu.Append(self.popupID11, text=_("Line sinuousity"))
+ subMenu.Append(self.popupID12, text=_("Line azimuth"))
+
+ self.Bind (wx.EVT_MENU, self.OnColumnSortAsc, id=self.popupID1)
+ self.Bind (wx.EVT_MENU, self.OnColumnSortDesc, id=self.popupID2)
+ for id in (self.popupID4, self.popupID5, self.popupID6,
+ self.popupID7, self.popupID8, self.popupID9,
+ self.popupID10, self.popupID11, self.popupID12):
+ self.Bind(wx.EVT_MENU, self.OnColumnCompute, id = id)
+
+ self.PopupMenu(popupMenu)
+ popupMenu.Destroy()
+
+ def OnColumnSort(self, event):
+ """!Column heading left mouse button -> sorting"""
+ self._col = event.GetColumn()
+
+ self.ColumnSort()
+
+ event.Skip()
+
+ def OnColumnSortAsc(self, event):
+ """!Sort values of selected column (ascending)"""
+ self.SortListItems(col = self._col, ascending = True)
+ event.Skip()
+
+ def OnColumnSortDesc(self, event):
+ """!Sort values of selected column (descending)"""
+ self.SortListItems(col = self._col, ascending = False)
+ event.Skip()
+
+ def OnColumnCompute(self, event):
+ """!Compute values of selected column"""
+ id = event.GetId()
+
+ option = None
+ if id == self.popupID4:
+ option = 'area'
+ elif id == self.popupID5:
+ option = 'length'
+ elif id == self.popupID6:
+ option = 'compact'
+ elif id == self.popupID7:
+ option = 'fd'
+ elif id == self.popupID8:
+ option = 'perimeter'
+ elif id == self.popupID9:
+ option = 'count'
+ elif id == self.popupID10:
+ option = 'slope'
+ elif id == self.popupID11:
+ option = 'sinuous'
+ elif id == self.popupID12:
+ option = 'azimuth'
+
+ if not option:
+ return
+
+ gcmd.RunCommand('v.to.db',
+ parent = self.parent,
+ map = self.mapDBInfo.map,
+ layer = self.layer,
+ option = option,
+ columns = self.GetColumn(self._col).GetText())
+
+ self.LoadData(self.layer)
+
+ def ColumnSort(self):
+ """!Sort values of selected column (self._col)"""
# remove duplicated arrow symbol from column header
# FIXME: should be done automatically
info = wx.ListItem()
@@ -404,11 +481,9 @@
for column in range(self.GetColumnCount()):
info.m_text = self.GetColumn(column).GetText()
self.SetColumn(column, info)
-
- event.Skip()
-
+
def SortItems(self, sorter=cmp):
- """Sort items"""
+ """!Sort items"""
items = list(self.itemDataMap.keys())
items.sort(self.Sorter)
self.itemIndexMap = items
@@ -435,18 +510,18 @@
# 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"""
+ """!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"""
+ """!Check if list if empty"""
if self.columns:
return False
@@ -456,24 +531,37 @@
"""
GRASS Attribute manager main window
"""
- def __init__(self, parent, id, title, vectmap,
+ def __init__(self, parent, id=wx.ID_ANY,
size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE,
- item=None, log=None):
+ title=None, vectorName=None, item=None, log=None):
- self.vectmap = vectmap
- self.parent = parent # GMFrame
- self.treeItem = item # item in layer tree
- self.cmdLog = log # self.parent.goutput
-
+ 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.vectmap, element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
+ if grass.find_file(name = self.vectorName, element = 'vector')['mapset'] == grass.gisenv()['MAPSET']:
self.editable = True
else:
self.editable = False
-
- wx.Frame.__init__(self, parent, id, title, style=style)
+ self.cmdLog = log # self.parent.goutput
+
+ wx.Frame.__init__(self, parent, id, style=style)
+
+ # 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))
@@ -492,8 +580,8 @@
self.qlayer = None
# -> layers / tables description
- self.mapDBInfo = VectorDBInfo(self.vectmap)
-
+ self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
+
# sqlbuilder
self.builder = None
@@ -502,7 +590,7 @@
message=_("Database connection for vector map <%s> "
"is not defined in DB file. "
"You can define new connection in "
- "'Manage layers' tab.") % self.vectmap,
+ "'Manage layers' tab.") % self.vectorName,
caption=_("Attribute Table Manager"),
style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
@@ -591,7 +679,7 @@
self.SetMinSize(self.GetSize())
def __createBrowsePage(self, onlyLayer=-1):
- """Create browse tab page"""
+ """!Create browse tab page"""
for layer in self.mapDBInfo.layers.keys():
if onlyLayer > 0 and layer != onlyLayer:
continue
@@ -733,7 +821,7 @@
self.layer = None
def __createManageTablePage(self, onlyLayer=-1):
- """Create manage page (create/link and alter tables)"""
+ """!Create manage page (create/link and alter tables)"""
for layer in self.mapDBInfo.layers.keys():
if onlyLayer > 0 and layer != onlyLayer:
continue
@@ -756,7 +844,7 @@
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),
+ dbSizer.Add(item=dbm_base.createDbInfoDesc(panel, self.mapDBInfo, layer),
proportion=1,
flag=wx.EXPAND | wx.ALL,
border=3)
@@ -903,7 +991,7 @@
self.layer = None
def __createTableDesc(self, parent, table):
- """Create list with table description"""
+ """!Create list with table description"""
list = TableListCtrl(parent=parent, id=wx.ID_ANY,
table=self.mapDBInfo.tables[table],
columns=self.mapDBInfo.GetColumns(table))
@@ -915,7 +1003,7 @@
return list
def __createManageLayerPage(self):
- """Create manage page"""
+ """!Create manage page"""
splitterWin = wx.SplitterWindow(parent=self.manageLayerPage, id=wx.ID_ANY)
splitterWin.SetMinimumPaneSize(100)
@@ -968,7 +1056,7 @@
splitterWin.Fit()
def __createLayerDesc(self, parent):
- """Create list of linked layers"""
+ """!Create list of linked layers"""
list = LayerListCtrl(parent=parent, id=wx.ID_ANY,
layers=self.mapDBInfo.layers)
@@ -980,7 +1068,7 @@
return list
def __layout(self):
- """Do layout"""
+ """!Do layout"""
# frame body
mainSizer = wx.BoxSizer(wx.VERTICAL)
@@ -1000,7 +1088,7 @@
self.Layout()
def OnDataRightUp(self, event):
- """Table description area, context menu"""
+ """!Table description area, context menu"""
if not hasattr(self, "popupDataID1"):
self.popupDataID1 = wx.NewId()
self.popupDataID2 = wx.NewId()
@@ -1068,7 +1156,7 @@
list.GetItemCount())
def OnDataItemDelete(self, event):
- """Delete selected item(s) from the list (layer/category pair)"""
+ """!Delete selected item(s) from the list (layer/category pair)"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
item = list.GetFirstSelected()
@@ -1132,7 +1220,7 @@
return True
def OnDataItemDeleteAll(self, event):
- """Delete all items from the list"""
+ """!Delete all items from the list"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
if UserSettings.Get(group='atm', key='askOnDeleteRec', subkey='enabled'):
deleteDialog = wx.MessageBox(parent=self,
@@ -1157,7 +1245,7 @@
event.Skip()
def _drawSelected(self, zoom):
- """Highlight selected features"""
+ """!Highlight selected features"""
if not self.map or not self.mapdisplay:
return
@@ -1166,7 +1254,7 @@
digitToolbar = self.mapdisplay.toolbars['vdigit']
if digitToolbar and digitToolbar.GetLayer() and \
- digitToolbar.GetLayer().GetName() == self.vectmap:
+ digitToolbar.GetLayer().GetName() == self.vectorName:
self.mapdisplay.digit.driver.SetSelected(cats, field=self.layer)
if zoom:
@@ -1196,16 +1284,19 @@
where += '%s = %d or ' % (keyColumn, int(range))
where = where.rstrip('or ')
- cmd = gcmd.Command(["v.db.select",
- "-r", "--q",
- "map=%s" % self.mapDBInfo.map,
- "layer=%d" % self.layer,
- "where=%s" % where])
+ select = gcmd.RunCommand('v.db.select',
+ parent = self,
+ read = True,
+ quiet = True,
+ flags = 'r',
+ map = self.mapDBInfo.map,
+ layer = int(self.layer),
+ where = where)
region = {}
- for line in cmd.ReadStdOutput():
+ for line in select.splitlines():
key, value = line.split('=')
- region[key] = float(value)
+ region[key.strip()] = float(value.strip())
self.mapdisplay.Map.GetRegion(n=region['n'], s=region['s'],
w=region['w'], e=region['e'],
@@ -1219,7 +1310,7 @@
self.mapdisplay.MapWindow.UpdateMap(render=False, renderVector=True)
def OnDataDrawSelected(self, event):
- """Reload table description"""
+ """!Reload table description"""
self._drawSelected(zoom=False)
event.Skip()
@@ -1228,11 +1319,11 @@
event.Skip()
def OnDataItemAdd(self, event):
- """Add new record to the attribute table"""
+ """!Add new record to the attribute table"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
table = self.mapDBInfo.layers[self.layer]['table']
keyColumn = self.mapDBInfo.layers[self.layer]['key']
-
+
# (column name, value)
data = []
@@ -1301,6 +1392,7 @@
else:
value = values[i]
values[i] = list.columns[columnName[i]]['ctype'] (value)
+
except:
raise ValueError(_("Value '%(value)s' needs to be entered as %(type)s.") %
{'value' : str(values[i]),
@@ -1340,7 +1432,7 @@
self.ApplyCommands()
def OnDataItemEdit(self, event):
- """Edit selected record of the attribute table"""
+ """!Edit selected record of the attribute table"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
item = list.GetFirstSelected()
if item == -1:
@@ -1435,15 +1527,13 @@
list.Update(self.mapDBInfo)
- list.Update(self.mapDBInfo)
-
def OnDataReload(self, event):
- """Reload list of records"""
+ """!Reload list of records"""
self.OnApplySqlStatement(None)
self.listOfSQLStatements = []
def OnDataSelectAll(self, event):
- """Select all items"""
+ """!Select all items"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
item = -1
@@ -1456,7 +1546,7 @@
event.Skip()
def OnDataSelectNone(self, event):
- """Deselect items"""
+ """!Deselect items"""
list = self.FindWindowById(self.layerPage[self.layer]['data'])
item = -1
@@ -1470,7 +1560,7 @@
def OnTableChangeType(self, event):
- """Data type for new column changed. Enable or disable
+ """!Data type for new column changed. Enable or disable
data length widget"""
win = self.FindWindowById(self.layerPage[self.layer]['addColLength'])
if event.GetString() == "varchar":
@@ -1479,7 +1569,7 @@
win.Enable(False)
def OnTableRenameColumnName(self, event):
- """Editing column name to be added to the table"""
+ """!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'])
@@ -1491,7 +1581,7 @@
event.Skip()
def OnTableAddColumnName(self, event):
- """Editing column name to be added to the table"""
+ """!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)
@@ -1501,7 +1591,7 @@
event.Skip()
def OnTableItemChange(self, event):
- """Rename column in the table"""
+ """!Rename column in the table"""
list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
name = self.FindWindowById(self.layerPage[self.layer]['renameCol']).GetValue()
nameTo = self.FindWindowById(self.layerPage[self.layer]['renameColTo']).GetValue()
@@ -1529,10 +1619,11 @@
else:
list.SetItemText(item, nameTo)
- self.listOfCommands.append(['v.db.renamecol',
- 'map=%s' % self.vectmap,
- 'layer=%d' % self.layer,
- 'column=%s,%s' % (name, nameTo)])
+ self.listOfCommands.append(('v.db.renamecol',
+ { 'map' : self.vectorName,
+ 'layer' : self.layer,
+ 'column' : '%s,%s' % (name, nameTo) }
+ ))
else:
wx.MessageBox(parent=self,
message=_("Unable to rename column. "
@@ -1552,7 +1643,7 @@
event.Skip()
def OnTableRightUp(self, event):
- """Table description area, context menu"""
+ """!Table description area, context menu"""
if not hasattr(self, "popupTableID"):
self.popupTableID1 = wx.NewId()
self.popupTableID2 = wx.NewId()
@@ -1574,7 +1665,7 @@
menu.Destroy()
def OnTableItemDelete(self, event):
- """Delete selected item(s) from the list"""
+ """!Delete selected item(s) from the list"""
list = self.FindWindowById(self.layerPage[self.layer]['tableData'])
item = list.GetFirstSelected()
@@ -1590,10 +1681,11 @@
return False
while item != -1:
- self.listOfCommands.append(['v.db.dropcol',
- 'map=%s' % self.vectmap,
- 'layer=%d' % self.layer,
- 'column=%s' % list.GetItemText(item)])
+ self.listOfCommands.append(('v.db.dropcol',
+ { 'map' : self.vectorName,
+ 'layer' : self.layer,
+ 'column' : list.GetItemText(item) }
+ ))
list.DeleteItem(item)
item = list.GetFirstSelected()
@@ -1608,7 +1700,7 @@
event.Skip()
def OnTableItemDeleteAll(self, event):
- """Delete all items from the list"""
+ """!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']
@@ -1626,10 +1718,11 @@
return False
for col in cols:
- self.listOfCommands = [['v.db.dropcol',
- 'map=%s' % self.vectmap,
- 'layer=%d' % self.layer,
- 'column=%s' % col]]
+ self.listOfCommands.append(('v.db.dropcol',
+ { 'map' : self.vectorName,
+ 'layer' : self.layer,
+ 'column' : col }
+ ))
self.FindWindowById(self.layerPage[self.layer]['tableData']).DeleteAllItems()
# apply changes
@@ -1643,12 +1736,12 @@
event.Skip()
def OnTableReload(self, event=None):
- """Reload table description"""
+ """!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"""
+ """!Add new column to the table"""
table = self.mapDBInfo.layers[self.layer]['table']
name = self.FindWindowById(self.layerPage[self.layer]['addColName']).GetValue()
@@ -1688,11 +1781,11 @@
# add v.db.addcol command to the list
if type == 'varchar':
type += ' (%d)' % length
- self.listOfCommands.append(['v.db.addcol',
- 'map=%s' % self.vectmap,
- 'layer=%d' % self.layer,
- 'columns=%s %s' % (name, type)])
-
+ self.listOfCommands.append(('v.db.addcol',
+ { 'map' : self.vectorName,
+ 'layer' : self.layer,
+ 'columns' : '%s %s' % (name, type) }
+ ))
# apply changes
self.ApplyCommands()
@@ -1704,7 +1797,7 @@
event.Skip()
def OnLayerPageChanged(self, event):
- """Layer tab changed"""
+ """!Layer tab changed"""
pageNum = event.GetSelection()
self.layer = self.mapDBInfo.layers.keys()[pageNum]
@@ -1749,11 +1842,11 @@
event.Skip()
def OnLayerRightUp(self, event):
- """Layer description area, context menu"""
+ """!Layer description area, context menu"""
pass
def OnChangeSql(self, event):
- """Switch simple/advanced sql statement"""
+ """!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)
@@ -1764,15 +1857,16 @@
self.FindWindowById(self.layerPage[self.layer]['builder']).Enable(True)
def ApplyCommands(self):
- """Apply changes"""
+ """!Apply changes"""
# perform GRASS commands (e.g. v.db.addcol)
if len(self.listOfCommands) > 0:
for cmd in self.listOfCommands:
- Debug.msg(3, 'AttributeManager.ApplyCommands() cmd=\'%s\'' %
- ' '.join(cmd))
- gcmd.Command(cmd)
-
- self.mapDBInfo = VectorDBInfo(self.vectmap)
+ gcmd.RunCommand(prog = cmd[0],
+ quiet = True,
+ parent = self,
+ **cmd[1])
+
+ self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
table = self.mapDBInfo.layers[self.layer]['table']
# update table description
@@ -1806,23 +1900,24 @@
driver = self.mapDBInfo.layers[self.layer]["driver"]
database = self.mapDBInfo.layers[self.layer]["database"]
- cmd = ['db.execute',
- 'input=%s' % sqlFile.name,
- 'driver=%s' % driver,
- 'database=%s' % database]
-
Debug.msg(3, 'AttributeManger.ApplyCommands(): %s' %
';'.join(["%s" % s for s in self.listOfSQLStatements]))
- gcmd.Command(cmd)
-
+ gcmd.RunCommand('db.execute',
+ parent = self,
+ input = sqlFile.name,
+ driver = driver,
+ database = database)
+
# reset list of statements
self.listOfSQLStatements = []
def OnApplySqlStatement(self, event):
- """Apply simple/advanced sql statement"""
+ """!Apply simple/advanced sql statement"""
keyColumn = -1 # index of key column
listWin = self.FindWindowById(self.layerPage[self.layer]['data'])
+ sql = None
+
if self.FindWindowById(self.layerPage[self.layer]['simple']).GetValue():
# simple sql statement
whereCol = self.FindWindowById(self.layerPage[self.layer]['whereColumn']).GetStringSelection()
@@ -1832,16 +1927,17 @@
keyColumn = listWin.LoadData(self.layer, where=whereCol + whereVal)
else:
keyColumn = listWin.LoadData(self.layer)
- except gcmd.CmdError, e:
- wx.MessageBox(parent=self,
- message=_("Loading attribute data failed.\n\n%s") % e.message,
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ except gcmd.GException, e:
+ gcmd.GError(parent = self,
+ message = _("Loading attribute data failed.\n\n%s") % e.value)
self.FindWindowById(self.layerPage[self.layer]['where']).SetValue('')
else:
# advanced sql statement
win = self.FindWindowById(self.layerPage[self.layer]['statement'])
try:
cols, where = self.ValidateSelectStatement(win.GetValue())
+ if cols is None and where is None:
+ sql = win.GetValue()
except TypeError:
wx.MessageBox(parent=self,
message=_("Loading attribute data failed.\n"
@@ -1851,28 +1947,30 @@
cols = None
where = None
- if cols or where:
+ if cols or where or sql:
try:
keyColumn = listWin.LoadData(self.layer, columns=cols,
- where=where)
- except gcmd.CmdError, e:
- wx.MessageBox(parent=self,
- message=_("Loading attribute data failed.\n\n%s") % e.message,
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ where=where, sql=sql)
+ except gcmd.GException, e:
+ gcmd.GError(parent = self,
+ message = _("Loading attribute data failed.\n\n%s") % e.value)
win.SetValue("SELECT * FROM %s" % self.mapDBInfo.layers[self.layer]['table'])
# sort by key column
- if keyColumn > -1:
- listWin.SortListItems(col=keyColumn, ascending=True)
+ if sql and 'order by' in sql.lower():
+ pass # don't order by key column
else:
- listWin.SortListItems(col=0, ascending=True)
-
+ if keyColumn > -1:
+ listWin.SortListItems(col=keyColumn, ascending=True)
+ else:
+ listWin.SortListItems(col=0, ascending=True)
+
# 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
+ """!Validate SQL select statement
@return (columns, where)
@return None on error
@@ -1904,23 +2002,27 @@
if index > -1:
where = statement[index+6:]
else:
- return None
+ where = None
else:
where = None
return (cols, where)
def OnCloseWindow(self, event):
- """Cancel button pressed"""
+ """!Cancel button pressed"""
self.Close()
- event.Skip()
+ if self.parent and self.parent.GetName() == 'LayerManager':
+ # deregister ATM
+ self.parent.dialogs['atm'].remove(self)
+ event.Skip()
+
def OnBuilder(self,event):
"""!SQL Builder button pressed -> show the SQLBuilder dialog"""
if not self.builder:
self.builder = sqlbuilder.SQLFrame(parent = self, id = wx.ID_ANY,
title = _("SQL Builder"),
- vectmap = self.vectmap,
+ vectmap = self.vectorName,
evtheader = self.OnBuilderEvt)
self.builder.Show()
else:
@@ -1937,12 +2039,9 @@
def OnTextEnter(self, event):
pass
-
- def OnSQLBuilder(self, event):
- pass
-
+
def OnDataItemActivated(self, event):
- """Item activated, highlight selected item"""
+ """!Item activated, highlight selected item"""
self.OnDataDrawSelected(event)
event.Skip()
@@ -1962,12 +2061,12 @@
return
else:
# dialog to get file name
- name, add = gdialogs.CreateNewVector(parent=self, title=_('Extract selected features'),
- log=self.cmdLog,
- cmdDef=(["v.extract",
- "input=%s" % self.vectmap,
- "list=%s" % utils.ListOfCatsToRange(cats)],
- "output"),
+ name, add = gdialogs.CreateNewVector(parent = self, title = _('Extract selected features'),
+ log = self.cmdLog,
+ cmd = (('v.extract',
+ { 'input' : self.vectorName,
+ 'list' : utils.ListOfCatsToRange(cats) },
+ 'output')),
disableTable = True)
if name and add:
# add layer to map layer tree
@@ -1976,7 +2075,7 @@
lchecked=True,
lopacity=1.0,
lcmd=['d.vect', 'map=%s' % name])
-
+
def OnDeleteSelected(self, event):
"""
Delete vector objects selected in attribute browse window
@@ -1992,20 +2091,21 @@
if self.OnDataItemDelete(None):
digitToolbar = self.mapdisplay.toolbars['vdigit']
if digitToolbar and digitToolbar.GetLayer() and \
- digitToolbar.GetLayer().GetName() == self.vectmap:
+ digitToolbar.GetLayer().GetName() == self.vectorName:
self.mapdisplay.digit.driver.SetSelected(map(int, cats), field=self.layer)
self.mapdisplay.digit.DeleteSelectedLines()
else:
- gcmd.Command(['v.edit',
- '--q',
- 'map=%s' % self.vectmap,
- 'tool=delete',
- 'cats=%s' % utils.ListOfCatsToRange(cats)])
-
+ gcmd.RunCommand('v.edit',
+ parent = self,
+ quiet = True,
+ map = self.vectorName,
+ tool = 'delete',
+ cats = utils.ListOfCatsToRange(cats))
+
self.mapdisplay.MapWindow.UpdateMap(render=True, renderVector=True)
def AddQueryMapLayer(self):
- """Redraw a map
+ """!Redraw a map
Return True if map has been redrawn, False if no map is given
"""
@@ -2018,14 +2118,14 @@
self.qlayer = None
if self.qlayer:
- self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.vectmap, cats, addLayer=False))
+ self.qlayer.SetCmd(self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats, addLayer=False))
else:
- self.qlayer = self.mapdisplay.AddTmpVectorMapLayer(self.vectmap, cats)
+ self.qlayer = self.mapdisplay.AddTmpVectorMapLayer(self.vectorName, cats)
return self.qlayer
def UpdateDialog(self, layer):
- """Updates dialog layout for given layer"""
+ """!Updates dialog layout for given layer"""
#
# delete page
#
@@ -2041,7 +2141,7 @@
self.notebook.SetSelection(2)
# fetch fresh db info
- self.mapDBInfo = VectorDBInfo(self.vectmap)
+ self.mapDBInfo = dbm_base.VectorDBInfo(self.vectorName)
#
# add new page
@@ -2080,11 +2180,29 @@
### 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"""
+ """!Table description list"""
def __init__(self, parent, id, table, columns, pos=wx.DefaultPosition,
size=wx.DefaultSize):
@@ -2100,12 +2218,12 @@
# listmix.TextEditMixin.__init__(self)
def Update(self, table, columns):
- """Update column description"""
+ """!Update column description"""
self.table = table
self.columns = columns
def Populate(self, update=False):
- """Populate the list"""
+ """!Populate the list"""
itemData = {} # requested by sorter
if not update:
@@ -2138,7 +2256,7 @@
listmix.ListCtrlAutoWidthMixin):
# listmix.ColumnSorterMixin):
# listmix.TextEditMixin):
- """Layer description list"""
+ """!Layer description list"""
def __init__(self, parent, id, layers,
pos=wx.DefaultPosition,
@@ -2154,11 +2272,11 @@
# listmix.TextEditMixin.__init__(self)
def Update(self, layers):
- """Update description"""
+ """!Update description"""
self.layers = layers
def Populate(self, update=False):
- """Populate the list"""
+ """!Populate the list"""
itemData = {} # requested by sorter
if not update:
@@ -2200,7 +2318,7 @@
return itemData
class LayerBook(wx.Notebook):
- """Manage layers (add, delete, modify)"""
+ """!Manage layers (add, delete, modify)"""
def __init__(self, parent, id,
parentDialog,
style=wx.BK_DEFAULT):
@@ -2213,24 +2331,28 @@
#
# drivers
#
- cmdDriver = gcmd.Command(['db.drivers',
- '-p',
- '--q'])
+ drivers = gcmd.RunCommand('db.drivers',
+ quiet = True,
+ read = True,
+ flags = 'p')
+
self.listOfDrivers = []
- for drv in cmdDriver.ReadStdOutput():
+ for drv in drivers.splitlines():
self.listOfDrivers.append(drv.strip())
-
+
#
# get default values
#
self.defaultConnect = {}
- cmdConnect = gcmd.Command(['db.connect',
- '-p',
- '--q'])
- for line in cmdConnect.ReadStdOutput():
+ connect = gcmd.RunCommand('db.connect',
+ flags = 'p',
+ read = True,
+ quiet = True)
+
+ for line in connect.splitlines():
item, value = line.split(':')
self.defaultConnect[item.strip()] = value.strip()
-
+
if len(self.defaultConnect['driver']) == 0 or \
len(self.defaultConnect['database']) == 0:
wx.MessageBox(parent=self.parent,
@@ -2253,7 +2375,7 @@
self.__createModifyPage()
def __createAddPage(self):
- """Add new layer"""
+ """!Add new layer"""
self.addPanel = wx.Panel(parent=self, id=wx.ID_ANY)
self.AddPage(page=self.addPanel, text=_("Add layer"))
@@ -2444,7 +2566,7 @@
pageSizer.Fit(self.addPanel)
def __createDeletePage(self):
- """Delete layer"""
+ """!Delete layer"""
self.deletePanel = wx.Panel(parent=self, id=wx.ID_ANY)
self.AddPage(page=self.deletePanel, text=_("Delete layer"))
@@ -2512,7 +2634,7 @@
self.deletePanel.SetSizer(pageSizer)
def __createModifyPage(self):
- """Modify layer"""
+ """!Modify layer"""
self.modifyPanel = wx.Panel(parent=self, id=wx.ID_ANY)
self.AddPage(page=self.modifyPanel, text=_("Modify layer"))
@@ -2622,45 +2744,51 @@
self.modifyPanel.SetSizer(pageSizer)
def __getTables(self, driver, database):
- """Get list of tables for given driver and database"""
+ """!Get list of tables for given driver and database"""
tables = []
- cmdTable = gcmd.Command(['db.tables',
- '-p', '--q',
- 'driver=%s' % driver,
- 'database=%s' % database], rerr=None)
-
- if cmdTable.returncode != 0:
+ ret = gcmd.RunCommand('db.tables',
+ parent = self,
+ read = True,
+ flags = 'p',
+ driver = driver,
+ database = database)
+
+ if ret is None:
wx.MessageBox(parent=self,
message=_("Unable to get list of tables.\n"
"Please use db.connect to set database parameters."),
caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-
+
return tables
- for table in cmdTable.ReadStdOutput():
+ for table in ret.splitlines():
tables.append(table)
-
+
return tables
def __getColumns(self, driver, database, table):
- """Get list of column of given table"""
+ """!Get list of column of given table"""
columns = []
- cmdColumn = gcmd.Command(['db.columns',
- '--q',
- 'driver=%s' % driver,
- 'database=%s' % database,
- 'table=%s' % table],
- rerr = None)
-
- for column in cmdColumn.ReadStdOutput():
+ ret = gcmd.RunCommand('db.columns',
+ parent = self,
+ quiet = True,
+ read = True,
+ driver = driver,
+ database = database,
+ table = table)
+
+ if ret == None:
+ return columns
+
+ for column in ret.splitlines():
columns.append(column)
-
+
return columns
def OnDriverChanged(self, event):
- """Driver selection changed, update list of tables"""
+ """!Driver selection changed, update list of tables"""
driver = event.GetString()
database = self.addLayerWidgets['database'][1].GetValue()
@@ -2677,11 +2805,11 @@
event.Skip()
def OnDatabaseChanged(self, event):
- """Database selection changed, update list of tables"""
+ """!Database selection changed, update list of tables"""
event.Skip()
def OnTableChanged(self, event):
- """Table name changed, update list of columns"""
+ """!Table name changed, update list of columns"""
driver = self.addLayerWidgets['driver'][1].GetStringSelection()
database = self.addLayerWidgets['database'][1].GetValue()
table = event.GetString()
@@ -2694,7 +2822,7 @@
event.Skip()
def OnSetDefault(self, event):
- """Set default values"""
+ """!Set default values"""
driver = self.addLayerWidgets['driver'][1]
database = self.addLayerWidgets['database'][1]
table = self.addLayerWidgets['table'][1]
@@ -2718,7 +2846,7 @@
event.Skip()
def OnCreateTable(self, event):
- """Create new table (name and key column given)"""
+ """!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()
@@ -2741,12 +2869,13 @@
# create table
sql = 'CREATE TABLE %s (%s INTEGER)' % (table, key)
- gcmd.Command(['db.execute',
- '--q',
- 'driver=%s' % driver,
- 'database=%s' % database],
- stdin=sql)
-
+ gcmd.RunCommand('db.execute',
+ quiet = True,
+ parent = self,
+ stdin = sql,
+ driver = driver,
+ database = database)
+
# update list of tables
tableList = self.addLayerWidgets['table'][1]
tableList.SetItems(self.__getTables(driver, database))
@@ -2760,7 +2889,7 @@
event.Skip()
def OnAddLayer(self, event):
- """Add new layer to vector map"""
+ """!Add new layer to vector map"""
layer = int(self.addLayerWidgets['layer'][1].GetValue())
layerWin = self.addLayerWidgets['layer'][1]
driver = self.addLayerWidgets['driver'][1].GetStringSelection()
@@ -2777,26 +2906,28 @@
return
# add new layer
- connectCmd = gcmd.Command(['v.db.connect',
- '--q',
- 'map=%s' % self.mapDBInfo.map,
- 'driver=%s' % driver,
- 'database=%s' % database,
- 'table=%s' % table,
- 'key=%s' % key,
- 'layer=%d' % layer])
+ ret = gcmd.RunCommand('v.db.connect',
+ parent = self,
+ quiet = True,
+ map = self.mapDBInfo.map,
+ driver = driver,
+ database = database,
+ table = table,
+ key = key,
+ layer = layer)
# insert records into table if required
if self.addLayerWidgets['addCat'][0].IsChecked():
- gcmd.Command(['v.to.db',
- '--q',
- 'map=%s' % self.mapDBInfo.map,
- 'layer=%d' % layer,
- 'qlayer=%d' % layer,
- 'option=cat',
- 'columns=%s' % key])
+ gcmd.RunCommand('v.to.db',
+ parent = self,
+ quiet = True,
+ map = self.mapDBInfo.map,
+ layer = layer,
+ qlayer = layer,
+ option = 'cat',
+ columns = key)
- if connectCmd.returncode == 0:
+ if ret == 0:
# update dialog (only for new layer)
self.parentDialog.UpdateDialog(layer=layer)
# update db info
@@ -2812,16 +2943,17 @@
self.modifyLayerWidgets[label][1].Enable()
def OnDeleteLayer(self, event):
- """Delete layer"""
+ """!Delete layer"""
try:
layer = int(self.deleteLayer.GetValue())
except:
return
- gcmd.Command(['v.db.connect',
- '-d', '--q',
- 'map=%s' % self.mapDBInfo.map,
- 'layer=%d' % layer])
+ gcmd.RunCommand('v.db.connect',
+ parent = self,
+ flags = 'd',
+ map = self.mapDBInfo.map,
+ layer = layer)
# drop also table linked to layer which is deleted
if self.deleteTable.IsChecked():
@@ -2830,12 +2962,13 @@
table = self.mapDBInfo.layers[layer]['table']
sql = 'DROP TABLE %s' % (table)
- gcmd.Command(['db.execute',
- '--q',
- 'driver=%s' % driver,
- 'database=%s' % database],
- stdin=sql)
-
+ gcmd.RunCommand('db.execute',
+ parent = self,
+ stdin = sql,
+ quiet = True,
+ driver = driver,
+ database = database)
+
# update list of tables
tableList = self.addLayerWidgets['table'][1]
tableList.SetItems(self.__getTables(driver, database))
@@ -2856,7 +2989,7 @@
event.Skip()
def OnChangeLayer(self, event):
- """Layer number of layer to be deleted is changed"""
+ """!Layer number of layer to be deleted is changed"""
try:
layer = int(event.GetString())
except:
@@ -2882,7 +3015,7 @@
event.Skip()
def OnModifyLayer(self, event):
- """Modify layer connection settings"""
+ """!Modify layer connection settings"""
layer = int(self.modifyLayerWidgets['layer'][1].GetStringSelection())
@@ -2899,25 +3032,23 @@
if modify:
# delete layer
- gcmd.Command(['v.db.connect',
- '-d', '--q',
- 'map=%s' % self.mapDBInfo.map,
- 'layer=%d' % layer])
+ gcmd.RunCommand('v.db.connect',
+ parent = self,
+ quiet = True,
+ flag = 'd',
+ map = self.mapDBInfo.map,
+ layer = layer)
# add modified layer
- gcmd.Command(['v.db.connect',
- '--q',
- 'map=%s' % self.mapDBInfo.map,
- 'driver=%s' % \
- self.modifyLayerWidgets['driver'][1].GetStringSelection(),
- 'database=%s' % \
- self.modifyLayerWidgets['database'][1].GetValue(),
- 'table=%s' % \
- self.modifyLayerWidgets['table'][1].GetStringSelection(),
- 'key=%s' % \
- self.modifyLayerWidgets['key'][1].GetStringSelection(),
- 'layer=%d' % layer])
-
+ gcmd.RunCommand('v.db.connect',
+ quiet = True,
+ map = self.mapDBInfo.map,
+ driver = self.modifyLayerWidgets['driver'][1].GetStringSelection(),
+ database = self.modifyLayerWidgets['database'][1].GetValue(),
+ table = self.modifyLayerWidgets['table'][1].GetStringSelection(),
+ key = self.modifyLayerWidgets['key'][1].GetStringSelection(),
+ layer = int(layer))
+
# update dialog (only for new layer)
self.parentDialog.UpdateDialog(layer=layer)
# update db info
@@ -2925,730 +3056,6 @@
event.Skip()
-class DisplayAttributesDialog(wx.Dialog):
- """
- 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)
- """
- def __init__(self, parent, map,
- query=None, cats=None, line=None,
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
- pos=wx.DefaultPosition,
- action="add"):
- 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:
- label = _("Database connection "
- "is not defined in DB file.")
-
- wx.MessageBox(parent=self.parent,
- message=_("No attribute table linked to "
- "vector map <%(vector)s> found. %(msg)s"
- "\nYou can disable this message from digitization settings. Or "
- "you can create and link attribute table to the vector map "
- "using Attribute Table Manager.") %
- {'vector' : self.map, 'msg' : label},
- caption=_("Message"), style=wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE)
- 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)
-
- # 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(_("Add 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"))
-
- btnSizer = wx.StdDialogButtonSizer()
- btnSizer.AddButton(btnCancel)
- btnSizer.AddButton(btnReset)
- btnSizer.SetNegativeButton(btnReset)
- btnSubmit.SetDefault()
- btnSizer.AddButton(btnSubmit)
- btnSizer.Realize()
-
- mainSizer.Add(item=self.noFoundMsg, proportion=0,
- flag=wx.EXPAND | wx.ALL, border=5)
- mainSizer.Add(item=self.notebook, proportion=1,
- flag=wx.EXPAND | wx.ALL, border=5)
- fidSizer = wx.BoxSizer(wx.HORIZONTAL)
- fidSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY,
- label=_("Feature id:")),
- proportion=0, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL)
- fidSizer.Add(item=self.fidMulti, proportion=0,
- flag=wx.EXPAND | wx.ALL, border=5)
- fidSizer.Add(item=self.fidText, proportion=0,
- flag=wx.EXPAND | wx.ALL, border=5)
- mainSizer.Add(item=fidSizer, proportion=0,
- flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
- mainSizer.Add(item=self.closeDialog, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT,
- border=5)
- mainSizer.Add(item=btnSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-
- # bindigs
- btnReset.Bind(wx.EVT_BUTTON, self.OnReset)
- btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit)
- btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-
- self.SetSizer(mainSizer)
- mainSizer.Fit(self)
-
- # set min size for dialog
- w, h = self.GetBestSize()
- if h < 200:
- self.SetMinSize((w, 200))
- else:
- self.SetMinSize(self.GetBestSize())
-
- if self.notebook.GetPageCount() == 0:
- Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
- ### self.mapDBInfo = None
-
- def __SelectAttributes(self, layer):
- """Select attributes"""
- pass
-
- def OnSQLStatement(self, event):
- """Update SQL statement"""
- pass
-
- def GetSQLString(self, updateValues=False):
- """Create SQL statement string based on self.sqlStatement
-
- If updateValues is True, update dataFrame according to values
- in textfields.
- """
- sqlCommands = []
- # find updated values for each layer/category
- for layer in self.mapDBInfo.layers.keys(): # for each layer
- table = self.mapDBInfo.layers[layer]["table"]
- key = self.mapDBInfo.layers[layer]["key"]
- columns = self.mapDBInfo.tables[table]
- for idx in range(len(columns[key]['values'])): # for each category
- updatedColumns = []
- updatedValues = []
- for name in columns.keys():
- if name == key:
- cat = columns[name]['values'][idx]
- continue
- type = columns[name]['type']
- value = columns[name]['values'][idx]
- id = columns[name]['ids'][idx]
- try:
- newvalue = self.FindWindowById(id).GetValue()
- except:
- newvalue = self.FindWindowById(id).GetLabel()
-
- if newvalue == '':
- newvalue = None
-
- if newvalue != value:
- updatedColumns.append(name)
- if newvalue is None:
- updatedValues.append('NULL')
- else:
- if type != 'character':
- updatedValues.append(newvalue)
- else:
- updatedValues.append("'" + newvalue + "'")
- columns[name]['values'][idx] = newvalue
-
- if self.action != "add" and len(updatedValues) == 0:
- continue
-
- if self.action == "add":
- sqlString = "INSERT INTO %s (%s," % (table, key)
- else:
- sqlString = "UPDATE %s SET " % table
-
- for idx in range(len(updatedColumns)):
- name = updatedColumns[idx]
- if self.action == "add":
- sqlString += name + ","
- else:
- sqlString += name + "=" + updatedValues[idx] + ","
-
- sqlString = sqlString[:-1] # remove last comma
-
- if self.action == "add":
- sqlString += ") VALUES (%s," % cat
- for value in updatedValues:
- sqlString += str(value) + ","
- sqlString = sqlString[:-1] # remove last comma
- sqlString += ")"
- else:
- sqlString += " WHERE cat=%s" % cat
- sqlCommands.append(sqlString)
- # for each category
- # for each layer END
-
- Debug.msg(3, "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
-
- return sqlCommands
-
- def OnReset(self, event):
- """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]
- 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 self.parent.parent.digit:
- self.parent.parent.digit.driver.SetSelected([])
- self.parent.UpdateMap(render=False)
- else:
- self.parent.parent.OnRender(None)
-
- self.Close()
-
- def OnSubmit(self, event):
- """Submit records"""
- for sql in self.GetSQLString(updateValues=True):
- enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
- if not enc and \
- os.environ.has_key('GRASS_DB_ENCODING'):
- enc = os.environ['GRASS_DB_ENCODING']
- if enc:
- sql = sql.encode(enc)
-
- gcmd.Command(cmd=["db.execute",
- "--q"],
- stdin=sql)
-
- if self.closeDialog.IsChecked():
- self.OnCancel(event)
-
- def OnFeature(self, event):
- self.fid = int(event.GetString())
- self.UpdateDialog(cats=self.cats, fid=self.fid)
-
- def GetCats(self):
- """Get id of selected vector object or 'None' if nothing selected
-
- @param id if true return ids otherwise cats
- """
- if self.fid < 0:
- return None
-
- return self.cats[self.fid]
-
- def GetFid(self):
- """Get selected feature id"""
- return self.fid
-
- def UpdateDialog(self, map=None, query=None, cats=None, fid=-1):
- """Update dialog
-
- Return True if updated otherwise False
- """
- 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 data.has_key('Layer'):
- idx = 0
- for layer in data['Layer']:
- layer = int(layer)
- if data.has_key('Id'):
- tfid = int(data['Id'][idx])
- else:
- tfid = 0 # Area / Volume
- if not self.cats.has_key(tfid):
- self.cats[tfid] = {}
- if not self.cats[tfid].has_key(layer):
- 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 self.cats[self.fid].has_key(layer):
- 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 self.cats[self.fid].has_key(layer):
- table = self.mapDBInfo.layers[layer]["table"]
- key = self.mapDBInfo.layers[layer]["key"]
- columns = self.mapDBInfo.tables[table]
- for name in columns.keys():
- if name == key:
- for cat in self.cats[self.fid][layer]:
- self.mapDBInfo.tables[table][name]['values'].append(cat)
- else:
- self.mapDBInfo.tables[table][name]['values'].append(None)
- else: # change status 'add' -> 'update'
- self.action = "update"
-
- table = self.mapDBInfo.layers[layer]["table"]
- key = self.mapDBInfo.layers[layer]["key"]
- columns = self.mapDBInfo.tables[table]
-
- for idx in range(len(columns[key]['values'])):
- for name in columns.keys():
- if name == key:
- cat = int(columns[name]['values'][idx])
- break
-
- # use scrolled panel instead (and fix initial max height of the window to 480px)
- panel = scrolled.ScrolledPanel(parent=self.notebook, id=wx.ID_ANY,
- size=(-1, 150))
- panel.SetupScrolling(scroll_x=False)
-
- self.notebook.AddPage(page=panel, text=" %s %d / %s %d" % (_("Layer"), layer,
- _("Category"), cat))
-
- # notebook body
- border = wx.BoxSizer(wx.VERTICAL)
-
- flexSizer = wx.FlexGridSizer (cols=4, hgap=3, vgap=3)
- flexSizer.AddGrowableCol(3)
- # columns (sorted by index)
- names = [''] * len(columns.keys())
- for name in columns.keys():
- names[columns[name]['index']] = name
-
- for name in names:
- if name == key: # skip key column (category)
- continue
-
- vtype = columns[name]['type']
-
- if columns[name]['values'][idx] is not None:
- if columns[name]['ctype'] != type(''):
- value = str(columns[name]['values'][idx])
- else:
- value = columns[name]['values'][idx]
- else:
- value = ''
-
- colName = wx.StaticText(parent=panel, id=wx.ID_ANY,
- label=name)
- colType = wx.StaticText(parent=panel, id=wx.ID_ANY,
- label="[" + vtype.lower() + "]")
- delimiter = wx.StaticText(parent=panel, id=wx.ID_ANY, label=":")
-
- colValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=value)
-
- colValue.SetName(name)
- self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
-
- flexSizer.Add(colName, proportion=0,
- flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
- flexSizer.Add(colType, proportion=0,
- flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
- flexSizer.Add(delimiter, proportion=0,
- flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
- flexSizer.Add(colValue, proportion=1,
- flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
- # add widget reference to self.columns
- columns[name]['ids'].append(colValue.GetId()) # name, type, values, id
- # for each attribute (including category) END
- border.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
- panel.SetSizer(border)
- # for each category END
- # for each layer END
-
- if self.notebook.GetPageCount() == 0:
- self.noFoundMsg.Show(True)
- else:
- self.noFoundMsg.Show(False)
-
- self.Layout()
-
- return True
-
-class VectorDBInfo(gselect.VectorDBInfo):
- """Class providing information about attribute tables
- linked to the vector map"""
- def __init__(self, map):
- gselect.VectorDBInfo.__init__(self, map)
-
- def GetColumns(self, table):
- """Return list of columns names (based on their index)"""
- try:
- names = [''] * len(self.tables[table].keys())
- except KeyError:
- return []
-
- for name, desc in self.tables[table].iteritems():
- names[desc['index']] = name
-
- return names
-
- def SelectByPoint(self, queryCoords, qdist):
- """Get attributes by coordinates (all available layers)
-
- Return line id or None if no line is found"""
- line = None
- nselected = 0
- if os.environ.has_key("LC_ALL"):
- locale = os.environ["LC_ALL"]
- os.environ["LC_ALL"] = "C"
-
- ### FIXME (implement script-style output)
- cmdWhat = gcmd.Command(cmd=['v.what',
- '-a', '--q',
- 'map=%s' % self.map,
- 'east_north=%f,%f' % \
- (float(queryCoords[0]), float(queryCoords[1])),
- 'distance=%f' % qdist], stderr=None)
-
- if os.environ.has_key("LC_ALL"):
- os.environ["LC_ALL"] = locale
-
- data = {}
- if cmdWhat.returncode == 0:
- readAttrb = False
- for item in cmdWhat.ReadStdOutput():
- if len(item) < 1:
- continue
-
- key, value = item.split(':', 1)
-
- if key == 'Layer' and readAttrb:
- readAttrb = False
-
- if readAttrb:
- name, value = item.split(':', 1)
- name = name.strip()
- # append value to the column
- if len(value) < 1:
- value = None
- else:
- if self.tables[table][name]['ctype'] != type(''):
- value = self.tables[table][name]['ctype'] (value.strip())
- else:
- value = unicodeValue(value.strip())
- self.tables[table][name]['values'].append(value)
- else:
- if not data.has_key(key):
- data[key] = []
- data[key].append(value.strip())
-
- if key == 'Table':
- table = value.strip()
-
- if key == 'Key column': # skip attributes
- readAttrb = True
-
- return data
-
- 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)
-
- selectCommand = gcmd.Command(["db.select", "-v", "--q",
- "sql=%s" % sql,
- "database=%s" % self.layers[layer]["database"],
- "driver=%s" % self.layers[layer]["driver"]])
-
- # self.tables[table][key][1] = str(cat)
- if selectCommand.returncode == 0:
- for line in selectCommand.ReadStdOutput():
- 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
-
-class ModifyTableRecord(wx.Dialog):
- """Dialog for inserting/updating table record"""
- def __init__(self, parent, id, title, data, keyEditable=(-1, True),
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
- """
- Notes:
- 'Data' is a list: [(column, value)]
- 'KeyEditable' (id, editable?) indicates if textarea for key column
- is editable(True) or not.
- """
- wx.Dialog.__init__(self, parent, id, title, style=style)
-
- self.CenterOnParent()
-
- self.keyId = keyEditable[0]
-
- self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
-
- box = wx.StaticBox(parent=self.panel, id=wx.ID_ANY, label='')
-
- self.dataPanel = scrolled.ScrolledPanel(parent=self.panel, id=wx.ID_ANY,
- style=wx.TAB_TRAVERSAL)
- self.dataPanel.SetupScrolling(scroll_x=False)
-
- #
- # buttons
- #
- self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
- self.btnSubmit = wx.Button(self.panel, wx.ID_OK, _("Submit"))
- self.btnSubmit.SetDefault()
-
- #
- # data area
- #
- self.widgets = []
- id = 0
- self.usebox = False
- self.cat = None
- for column, value in data:
- if keyEditable[0] == id:
- self.cat = int(value)
- if keyEditable[1] == False:
- self.usebox = True
- box.SetLabel =" %s %d " % (_("Category"), self.cat)
- self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
- id += 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))
-
- label = wx.StaticText(parent=self.dataPanel, id=wx.ID_ANY,
- label=column + ":")
-
- self.widgets.append((label.GetId(),
- valueWin.GetId()))
-
- id += 1
-
- self.__Layout()
-
- # winSize = self.GetSize()
- # fix height of window frame if needed
- # if winSize[1] > 480:
- # winSize[1] = 480
- # self.SetSize(winSize)
- # self.SetMinSize(winSize)
-
- def __Layout(self):
- """Do layout"""
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- # data area
- dataSizer = wx.FlexGridSizer (cols=2, hgap=3, vgap=3)
- dataSizer.AddGrowableCol(1)
-
- for labelId, valueId in self.widgets:
- label = self.FindWindowById(labelId)
- value = self.FindWindowById(valueId)
-
- dataSizer.Add(label, proportion=0,
- flag=wx.ALIGN_CENTER_VERTICAL)
- dataSizer.Add(value, proportion=0,
- flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
-
- self.dataPanel.SetAutoLayout(True)
- self.dataPanel.SetSizer(dataSizer)
- dataSizer.Fit(self.dataPanel)
-
- if self.usebox:
- self.boxSizer.Add(item=self.dataPanel, proportion=1,
- flag=wx.EXPAND | wx.ALL, border=5)
-
- # buttons
- btnSizer = wx.StdDialogButtonSizer()
- btnSizer.AddButton(self.btnCancel)
- btnSizer.AddButton(self.btnSubmit)
- btnSizer.Realize()
-
- if not self.usebox:
- sizer.Add(item=self.dataPanel, proportion=1,
- flag=wx.EXPAND | wx.ALL, border=5)
- else:
- sizer.Add(item=self.boxSizer, proportion=1,
- flag=wx.EXPAND | wx.ALL, border=5)
-
-
- sizer.Add(item=btnSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL, border=5)
-
- framewidth = self.GetSize()[0]
- self.SetMinSize((framewidth,150))
- self.SetMaxSize((framewidth,300))
-
- #sizer.SetSizeHints(self.panel)
- self.panel.SetAutoLayout(True)
- self.panel.SetSizer(sizer)
- sizer.Fit(self.panel)
-
- self.Layout()
-
-# # set window frame size (min & max)
-# minFrameHeight = 150
-# maxFrameHeight = 2 * minFrameHeight
-# if self.GetSize()[1] > minFrameHeight:
-# self.SetMinSize((self.GetSize()[0], minFrameHeight))
-# else:
-# self.SetMinSize(self.GetSize())
-
-# if self.GetSize()[1] > maxFrameHeight:
-# self.SetSize((self.GetSize()[0], maxFrameHeight))
-# else:
-# self.SetSize(self.panel.GetSize())
-
- def GetValues(self, columns=None):
- """Return list of values (casted to string).
-
- If columns is given (list), return only values of given columns.
- """
- valueList = []
- for labelId, valueId in self.widgets:
- column = self.FindWindowById(labelId).GetLabel().replace(':', '')
- if columns is None or column in columns:
- value = str(self.FindWindowById(valueId).GetValue())
- valueList.append(value)
-
- # add key value
- if self.usebox:
- valueList.insert(self.keyId, str(self.cat))
-
- return valueList
-
def main(argv=None):
if argv is None:
argv = sys.argv
@@ -3669,7 +3076,7 @@
f = AttributeManager(parent=None, id=wx.ID_ANY,
title="%s - <%s>" % (_("GRASS GIS Attribute Table Manager"),
argv[1]),
- size=(900,600), vectmap=argv[1])
+ size=(900,600), vectorName=argv[1])
f.Show()
app.MainLoop()
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_base.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_base.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_base.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,186 @@
+"""
+ at package dbm_base.py
+
+ at brief Support classes for dbm.py
+
+List of classes:
+ - VectorDBInfo
+
+(C) 2007-2009 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+
+import gselect
+import gcmd
+from preferences import globalSettings as UserSettings
+
+def unicodeValue(value):
+ """!Encode value"""
+ enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
+ if enc:
+ value = unicode(value, enc)
+ elif os.environ.has_key('GRASS_DB_ENCODING'):
+ value = unicode(value, os.environ['GRASS_DB_ENCODING'])
+ else:
+ try:
+ value = unicode(value, 'ascii')
+ except UnicodeDecodeError:
+ value = _("Unable to decode value. Set encoding in GUI preferences ('Attributes').")
+
+ return value
+
+def createDbInfoDesc(panel, mapDBInfo, layer):
+ """!Create database connection information content"""
+ infoFlexSizer = wx.FlexGridSizer (cols=2, hgap=1, vgap=1)
+ infoFlexSizer.AddGrowableCol(1)
+
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label="Driver:"))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=mapDBInfo.layers[layer]['driver']))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label="Database:"))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=mapDBInfo.layers[layer]['database']))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label="Table:"))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=mapDBInfo.layers[layer]['table']))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label="Key:"))
+ infoFlexSizer.Add(item=wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=mapDBInfo.layers[layer]['key']))
+
+ return infoFlexSizer
+
+class VectorDBInfo(gselect.VectorDBInfo):
+ """!Class providing information about attribute tables
+ linked to the vector map"""
+ def __init__(self, map):
+ gselect.VectorDBInfo.__init__(self, map)
+
+ def GetColumns(self, table):
+ """!Return list of columns names (based on their index)"""
+ try:
+ names = [''] * len(self.tables[table].keys())
+ except KeyError:
+ return []
+
+ for name, desc in self.tables[table].iteritems():
+ names[desc['index']] = name
+
+ return names
+
+ def SelectByPoint(self, queryCoords, qdist):
+ """!Get attributes by coordinates (all available layers)
+
+ Return line id or None if no line is found"""
+ line = None
+ nselected = 0
+
+ if os.environ.has_key("LC_ALL"):
+ locale = os.environ["LC_ALL"]
+ os.environ["LC_ALL"] = "C"
+
+ ### FIXME (implement script-style output)
+ ret = gcmd.RunCommand('v.what',
+ quiet = True,
+ read = True,
+ flags = 'a',
+ map = self.map,
+ east_north = '%f,%f' % \
+ (float(queryCoords[0]), float(queryCoords[1])),
+ distance = float(qdist))
+
+ if os.environ.has_key("LC_ALL"):
+ os.environ["LC_ALL"] = locale
+
+ data = {}
+ if ret:
+ readAttrb = False
+ for item in ret.splitlines():
+ try:
+ key, value = item.split(':', 1)
+ except ValueError:
+ continue
+
+ if key == 'Layer' and readAttrb:
+ readAttrb = False
+
+ if readAttrb:
+ name, value = item.split(':', 1)
+ name = name.strip()
+ value = value.strip()
+ # append value to the column
+ if len(value) < 1:
+ value = None
+ else:
+ if self.tables[table][name]['ctype'] != type(''):
+ value = self.tables[table][name]['ctype'] (value.strip())
+ else:
+ value = unicodeValue(value.strip())
+ self.tables[table][name]['values'].append(value)
+ else:
+ if not data.has_key(key):
+ data[key] = []
+ data[key].append(value.strip())
+
+ if key == 'Table':
+ table = value.strip()
+
+ if key == 'Key column': # skip attributes
+ readAttrb = True
+
+ return data
+
+ def SelectFromTable(self, layer, cols='*', where=None):
+ """!Select records from the table
+
+ Return number of selected records, -1 on error
+ """
+ if layer <= 0:
+ return -1
+
+ nselected = 0
+
+ table = self.layers[layer]["table"] # get table desc
+ # select values (only one record)
+ if where is None or where is '':
+ sql="SELECT %s FROM %s" % (cols, table)
+ else:
+ sql="SELECT %s FROM %s WHERE %s" % (cols, table, where)
+
+ ret = gcmd.RunCommand('db.select',
+ parent = self,
+ read = True,
+ quiet = True,
+ flags = 'v',
+ sql= sql,
+ database = self.layers[layer]["database"],
+ driver = self.layers[layer]["driver"])
+
+ # self.tables[table][key][1] = str(cat)
+ if ret:
+ for line in ret.splitlines():
+ name, value = line.split('|')
+ # casting ...
+ if value:
+ if self.tables[table][name]['ctype'] != type(''):
+ value = self.tables[table][name]['ctype'] (value)
+ else:
+ value = unicodeValue(value)
+ else:
+ value = None
+ self.tables[table][name]['values'].append(value)
+ nselected = 1
+
+ return nselected
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_base.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_dialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_dialogs.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_dialogs.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,663 @@
+"""
+ at package dbm_dialogs.py
+
+ at brief DBM-related dialogs
+
+List of classes:
+ - DisplayAttributesDialog
+ - ModifyTableRecord
+
+(C) 2007-2009 by the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import globalvar
+if not os.getenv("GRASS_WXBUNDLED"):
+ globalvar.CheckForWx()
+
+import wx
+import wx.lib.scrolledpanel as scrolled
+
+import gcmd
+from debug import Debug
+from preferences import globalSettings as UserSettings
+from dbm_base import VectorDBInfo
+
+class DisplayAttributesDialog(wx.Dialog):
+ """
+ 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)
+ """
+ def __init__(self, parent, map,
+ query=None, cats=None, line=None,
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+ pos=wx.DefaultPosition,
+ action="add"):
+ 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:
+ label = _("Database connection "
+ "is not defined in DB file.")
+
+ wx.MessageBox(parent=self.parent,
+ message=_("No attribute table linked to "
+ "vector map <%(vector)s> found. %(msg)s"
+ "\nYou can disable this message from digitization settings. Or "
+ "you can create and link attribute table to the vector map "
+ "using Attribute Table Manager.") %
+ {'vector' : self.map, 'msg' : label},
+ caption=_("Message"), style=wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE)
+ 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)
+
+ # 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(_("Add 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"))
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(btnCancel)
+ btnSizer.AddButton(btnReset)
+ btnSizer.SetNegativeButton(btnReset)
+ btnSubmit.SetDefault()
+ btnSizer.AddButton(btnSubmit)
+ btnSizer.Realize()
+
+ mainSizer.Add(item=self.noFoundMsg, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ mainSizer.Add(item=self.notebook, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ fidSizer = wx.BoxSizer(wx.HORIZONTAL)
+ fidSizer.Add(item=wx.StaticText(parent=self, id=wx.ID_ANY,
+ label=_("Feature id:")),
+ proportion=0, border=5,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+ fidSizer.Add(item=self.fidMulti, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ fidSizer.Add(item=self.fidText, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ mainSizer.Add(item=fidSizer, proportion=0,
+ flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
+ mainSizer.Add(item=self.closeDialog, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT,
+ border=5)
+ mainSizer.Add(item=btnSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+ # bindigs
+ btnReset.Bind(wx.EVT_BUTTON, self.OnReset)
+ btnSubmit.Bind(wx.EVT_BUTTON, self.OnSubmit)
+ btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ # set min size for dialog
+ w, h = self.GetBestSize()
+ if h < 200:
+ self.SetMinSize((w, 200))
+ else:
+ self.SetMinSize(self.GetBestSize())
+
+ if self.notebook.GetPageCount() == 0:
+ Debug.msg(2, "DisplayAttributesDialog(): Nothing found!")
+ ### self.mapDBInfo = None
+
+ def __SelectAttributes(self, layer):
+ """!Select attributes"""
+ pass
+
+ def OnSQLStatement(self, event):
+ """!Update SQL statement"""
+ pass
+
+ def GetSQLString(self, updateValues=False):
+ """!Create SQL statement string based on self.sqlStatement
+
+ If updateValues is True, update dataFrame according to values
+ in textfields.
+ """
+ sqlCommands = []
+ # find updated values for each layer/category
+ for layer in self.mapDBInfo.layers.keys(): # for each layer
+ table = self.mapDBInfo.GetTable(layer)
+ key = self.mapDBInfo.GetKeyColumn(layer)
+ columns = self.mapDBInfo.GetTableDesc(table)
+ for idx in range(len(columns[key]['values'])): # for each category
+ updatedColumns = []
+ updatedValues = []
+ for name in columns.keys():
+ if name == key:
+ cat = columns[name]['values'][idx]
+ continue
+ type = columns[name]['type']
+ value = columns[name]['values'][idx]
+ id = columns[name]['ids'][idx]
+ try:
+ newvalue = self.FindWindowById(id).GetValue()
+ except:
+ newvalue = self.FindWindowById(id).GetLabel()
+
+ if newvalue == '':
+ newvalue = None
+
+ if newvalue != value:
+ updatedColumns.append(name)
+ if newvalue is None:
+ updatedValues.append('NULL')
+ else:
+ if type != 'character':
+ updatedValues.append(newvalue)
+ else:
+ updatedValues.append("'" + newvalue + "'")
+ columns[name]['values'][idx] = newvalue
+
+ if self.action != "add" and len(updatedValues) == 0:
+ continue
+
+ if self.action == "add":
+ sqlString = "INSERT INTO %s (%s," % (table, key)
+ else:
+ sqlString = "UPDATE %s SET " % table
+
+ for idx in range(len(updatedColumns)):
+ name = updatedColumns[idx]
+ if self.action == "add":
+ sqlString += name + ","
+ else:
+ sqlString += name + "=" + updatedValues[idx] + ","
+
+ sqlString = sqlString[:-1] # remove last comma
+
+ if self.action == "add":
+ sqlString += ") VALUES (%s," % cat
+ for value in updatedValues:
+ sqlString += str(value) + ","
+ sqlString = sqlString[:-1] # remove last comma
+ sqlString += ")"
+ else:
+ sqlString += " WHERE cat=%s" % cat
+ sqlCommands.append(sqlString)
+ # for each category
+ # for each layer END
+
+ Debug.msg(3, "DisplayAttributesDialog.GetSQLString(): %s" % sqlCommands)
+
+ return sqlCommands
+
+ def OnReset(self, event = None):
+ """!Reset form"""
+ for layer in self.mapDBInfo.layers.keys():
+ table = self.mapDBInfo.layers[layer]["table"]
+ key = self.mapDBInfo.layers[layer]["key"]
+ columns = self.mapDBInfo.tables[table]
+ for idx in range(len(columns[key]['values'])):
+ for name in columns.keys():
+ type = columns[name]['type']
+ value = columns[name]['values'][idx]
+ if value is None:
+ value = ''
+ try:
+ id = columns[name]['ids'][idx]
+ except IndexError:
+ id = wx.NOT_FOUND
+
+ if name != key and id != wx.NOT_FOUND:
+ self.FindWindowById(id).SetValue(str(value))
+
+ def OnCancel(self, event):
+ """!Cancel button pressed"""
+ self.parent.parent.dialogs['attributes'] = None
+ if self.parent.parent.digit:
+ self.parent.parent.digit.driver.SetSelected([])
+ self.parent.UpdateMap(render=False)
+ else:
+ self.parent.parent.OnRender(None)
+
+ self.Close()
+
+ def OnSubmit(self, event):
+ """!Submit records"""
+ for sql in self.GetSQLString(updateValues=True):
+ enc = UserSettings.Get(group='atm', key='encoding', subkey='value')
+ if not enc and \
+ os.environ.has_key('GRASS_DB_ENCODING'):
+ enc = os.environ['GRASS_DB_ENCODING']
+ if enc:
+ sql = sql.encode(enc)
+
+ gcmd.RunCommand('db.execute',
+ quiet = True,
+ stdin = sql)
+
+ if self.closeDialog.IsChecked():
+ self.OnCancel(event)
+
+ def OnFeature(self, event):
+ self.fid = int(event.GetString())
+ self.UpdateDialog(cats=self.cats, fid=self.fid)
+
+ def GetCats(self):
+ """!Get id of selected vector object or 'None' if nothing selected
+
+ @param id if true return ids otherwise cats
+ """
+ if self.fid < 0:
+ return None
+
+ return self.cats[self.fid]
+
+ def GetFid(self):
+ """!Get selected feature id"""
+ return self.fid
+
+ def UpdateDialog(self, map=None, query=None, cats=None, fid=-1):
+ """!Update dialog
+
+ Return True if updated otherwise False
+ """
+ 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 data.has_key('Layer'):
+ idx = 0
+ for layer in data['Layer']:
+ layer = int(layer)
+ if data.has_key('Id'):
+ tfid = int(data['Id'][idx])
+ else:
+ tfid = 0 # Area / Volume
+ if not self.cats.has_key(tfid):
+ self.cats[tfid] = {}
+ if not self.cats[tfid].has_key(layer):
+ 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 self.cats[self.fid].has_key(layer):
+ 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 self.cats[self.fid].has_key(layer):
+ table = self.mapDBInfo.layers[layer]["table"]
+ key = self.mapDBInfo.layers[layer]["key"]
+ columns = self.mapDBInfo.tables[table]
+ for name in columns.keys():
+ if name == key:
+ for cat in self.cats[self.fid][layer]:
+ self.mapDBInfo.tables[table][name]['values'].append(cat)
+ else:
+ self.mapDBInfo.tables[table][name]['values'].append(None)
+ else: # change status 'add' -> 'update'
+ self.action = "update"
+
+ table = self.mapDBInfo.layers[layer]["table"]
+ key = self.mapDBInfo.layers[layer]["key"]
+ columns = self.mapDBInfo.tables[table]
+
+ for idx in range(len(columns[key]['values'])):
+ for name in columns.keys():
+ if name == key:
+ cat = int(columns[name]['values'][idx])
+ break
+
+ # use scrolled panel instead (and fix initial max height of the window to 480px)
+ panel = scrolled.ScrolledPanel(parent=self.notebook, id=wx.ID_ANY,
+ size=(-1, 150))
+ panel.SetupScrolling(scroll_x=False)
+
+ self.notebook.AddPage(page=panel, text=" %s %d / %s %d" % (_("Layer"), layer,
+ _("Category"), cat))
+
+ # notebook body
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ flexSizer = wx.FlexGridSizer (cols=4, hgap=3, vgap=3)
+ flexSizer.AddGrowableCol(3)
+ # columns (sorted by index)
+ names = [''] * len(columns.keys())
+ for name in columns.keys():
+ names[columns[name]['index']] = name
+
+ for name in names:
+ if name == key: # skip key column (category)
+ continue
+
+ vtype = columns[name]['type']
+
+ if columns[name]['values'][idx] is not None:
+ if columns[name]['ctype'] != type(''):
+ value = str(columns[name]['values'][idx])
+ else:
+ value = columns[name]['values'][idx]
+ else:
+ value = ''
+
+ colName = wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label=name)
+ colType = wx.StaticText(parent=panel, id=wx.ID_ANY,
+ label="[" + vtype.lower() + "]")
+ delimiter = wx.StaticText(parent=panel, id=wx.ID_ANY, label=":")
+
+ colValue = wx.TextCtrl(parent=panel, id=wx.ID_ANY, value=value)
+
+ colValue.SetName(name)
+ self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
+
+ flexSizer.Add(colName, proportion=0,
+ flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(colType, proportion=0,
+ flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(delimiter, proportion=0,
+ flag=wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
+ flexSizer.Add(colValue, proportion=1,
+ flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+ # add widget reference to self.columns
+ columns[name]['ids'].append(colValue.GetId()) # name, type, values, id
+ # for each attribute (including category) END
+ border.Add(item=flexSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
+ panel.SetSizer(border)
+ # for each category END
+ # for each layer END
+
+ if self.notebook.GetPageCount() == 0:
+ self.noFoundMsg.Show(True)
+ else:
+ self.noFoundMsg.Show(False)
+
+ self.Layout()
+
+ return True
+
+ def SetColumnValue(self, layer, column, value):
+ """!Set attrbute value
+
+ @param column column name
+ @param value value
+ """
+ table = self.mapDBInfo.GetTable(layer)
+ columns = self.mapDBInfo.GetTableDesc(table)
+
+ for key, col in columns.iteritems():
+ if key == column:
+ col['values'] = [col['ctype'](value),]
+ break
+
+class ModifyTableRecord(wx.Dialog):
+ """!Dialog for inserting/updating table record"""
+ def __init__(self, parent, id, title, data, keyEditable=(-1, True),
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+ """
+ Notes:
+ 'Data' is a list: [(column, value)]
+ 'KeyEditable' (id, editable?) indicates if textarea for key column
+ is editable(True) or not.
+ """
+ wx.Dialog.__init__(self, parent, id, title, style=style)
+
+ self.CenterOnParent()
+
+ self.keyId = keyEditable[0]
+
+ self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
+
+ box = wx.StaticBox(parent=self.panel, id=wx.ID_ANY, label='')
+
+ self.dataPanel = scrolled.ScrolledPanel(parent=self.panel, id=wx.ID_ANY,
+ style=wx.TAB_TRAVERSAL)
+ self.dataPanel.SetupScrolling(scroll_x=False)
+
+ #
+ # buttons
+ #
+ self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
+ self.btnSubmit = wx.Button(self.panel, wx.ID_OK, _("Submit"))
+ self.btnSubmit.SetDefault()
+
+ #
+ # data area
+ #
+ self.widgets = []
+ id = 0
+ self.usebox = False
+ self.cat = None
+ for column, value in data:
+ if keyEditable[0] == id:
+ self.cat = int(value)
+ if keyEditable[1] == False:
+ self.usebox = True
+ box.SetLabel =" %s %d " % (_("Category"), self.cat)
+ self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+ id += 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))
+
+ label = wx.StaticText(parent=self.dataPanel, id=wx.ID_ANY,
+ label=column + ":")
+
+ self.widgets.append((label.GetId(),
+ valueWin.GetId()))
+
+ id += 1
+
+ self.__Layout()
+
+ # winSize = self.GetSize()
+ # fix height of window frame if needed
+ # if winSize[1] > 480:
+ # winSize[1] = 480
+ # self.SetSize(winSize)
+ # self.SetMinSize(winSize)
+
+ def __Layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # data area
+ dataSizer = wx.FlexGridSizer (cols=2, hgap=3, vgap=3)
+ dataSizer.AddGrowableCol(1)
+
+ for labelId, valueId in self.widgets:
+ label = self.FindWindowById(labelId)
+ value = self.FindWindowById(valueId)
+
+ dataSizer.Add(label, proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+ dataSizer.Add(value, proportion=0,
+ flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+
+ self.dataPanel.SetAutoLayout(True)
+ self.dataPanel.SetSizer(dataSizer)
+ dataSizer.Fit(self.dataPanel)
+
+ if self.usebox:
+ self.boxSizer.Add(item=self.dataPanel, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
+ # buttons
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnSubmit)
+ btnSizer.Realize()
+
+ if not self.usebox:
+ sizer.Add(item=self.dataPanel, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+ else:
+ sizer.Add(item=self.boxSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
+
+ sizer.Add(item=btnSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
+ framewidth = self.GetSize()[0]
+ self.SetMinSize((framewidth,150))
+ self.SetMaxSize((framewidth,300))
+
+ #sizer.SetSizeHints(self.panel)
+ self.panel.SetAutoLayout(True)
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+
+ self.Layout()
+
+# # set window frame size (min & max)
+# minFrameHeight = 150
+# maxFrameHeight = 2 * minFrameHeight
+# if self.GetSize()[1] > minFrameHeight:
+# print 'size ='+str(self.GetSize()[1])
+# print 'if 1'
+# self.SetMinSize((self.GetSize()[0], minFrameHeight))
+# else:
+# print 'else 1'
+# self.SetMinSize(self.GetSize())
+
+# if self.GetSize()[1] > maxFrameHeight:
+# print 'if 2'
+# self.SetSize((self.GetSize()[0], maxFrameHeight))
+# else:
+# print 'else 2'
+# self.SetSize(self.panel.GetSize())
+
+
+
+ def GetValues(self, columns=None):
+ """!Return list of values (casted to string).
+
+ If columns is given (list), return only values of given columns.
+ """
+ valueList = []
+ for labelId, valueId in self.widgets:
+ column = self.FindWindowById(labelId).GetLabel().replace(':', '')
+ if columns is None or column in columns:
+ value = str(self.FindWindowById(valueId).GetValue())
+ valueList.append(value)
+
+ # add key value
+ if self.usebox:
+ valueList.insert(self.keyId, str(self.cat))
+
+ return valueList
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/dbm_dialogs.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/debug.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/debug.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/debug.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,21 +1,21 @@
-"""
-MODULE: debug
+"""!
+ at package debug
-CLASSES:
- * DebugMsg
+ at brief Debugging
-PURPOSE: GRASS debugging
+Classes:
+ - DebugMsg
- from debug import Debug as Debug
- Debug.msg (3, 'debug message')
+ at code
+from debug import Debug as Debug
+Debug.msg (3, 'debug message')
+ at endcode
-AUTHORS: The GRASS Development Team
- Martin Landa <landa.martin gmail.com>
+COPYRIGHT: (C) 2007-2009 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
-COPYRIGHT: (C) 2007-2008 by the GRASS Development Team
- 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
@@ -24,10 +24,12 @@
import globalvar
class DebugMsg:
- """
- GRASS Debugging
+ """!
+ wxGUI debugging
+ @code
export GRASS_WX_DEBUG=[0-5]
+ @endcode
"""
def __init__(self):
# default level
@@ -46,24 +48,31 @@
if self.debuglevel != level:
self.debuglevel = level
-
- def msg (self, level, message):
+
+ def msg (self, level, message, *args):
self._update_level()
if self.debuglevel > 0 and level > 0 and level <= self.debuglevel:
- print >> sys.stderr, "GUI D%d/%d: %s" % (level, self.debuglevel, message)
+ if args:
+ print >> sys.stderr, "GUI D%d/%d: " % (level, self.debuglevel) + \
+ message % args
+ else:
+ print >> sys.stderr, "GUI D%d/%d: " % (level, self.debuglevel) + \
+ message
sys.stderr.flush() # force flush (required for MS Windows)
def get_level(self):
- """Return current GUI debug level"""
+ """!Return current GUI debug level"""
return self.debuglevel
-
+
# Debug instance
Debug = DebugMsg()
# testing
if __name__ == "__main__":
import gcmd
- gcmd.Command (cmd=["g.gisenv", "set=DEBUG=3"])
+ gcmd.RunCommand('g.gisenv',
+ set = 'DEBUG=3')
for level in range (4):
Debug.msg (level, "message level=%d" % level)
+
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcmd.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,21 +1,21 @@
-"""
+"""!
@package gcmd
- at brief GRASS command interface
+ at brief wxGUI command interface
Classes:
+ - GError
+ - GWarning
+ - GMessage
- GException
- - GStdError
- - CmdError
- - SettingsError
- - DigitError
- - DBMError
- - NvizError
- Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
- Command
- CommandThread
-(C) 2007-2009 by the GRASS Development Team
+Functions:
+ - RunCommand
+
+(C) 2007-2008, 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.
@@ -30,6 +30,7 @@
import errno
import signal
import locale
+import traceback
import wx
@@ -56,79 +57,58 @@
import utils
from debug import Debug as Debug
-class GException(Exception):
- """Generic exception"""
- def __init__(self, message, title=_("Error"), parent=None):
- self.msg = message
- self.parent = parent
- self.title = title
+class GError:
+ def __init__(self, message, parent = None):
+ 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()
- def Show(self):
- dlg = wx.MessageDialog(parent=self.parent,
- caption=self.title,
- message=self.msg,
- style=wx.ICON_ERROR | wx.CENTRE)
- dlg.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_error.ico'), wx.BITMAP_TYPE_ICO))
- if self.parent:
- dlg.CentreOnParent()
+ if Debug.get_level() > 0 and exc_traceback:
+ sys.stderr.write(exception)
+
+ if exc_traceback:
+ wx.MessageBox(parent = parent,
+ message = message + '\n\n%s: %s\n\n%s' % \
+ (_('Reason'),
+ reason, exception),
+ caption = caption,
+ style = style)
else:
- dlg.CentreOnScreen()
+ wx.MessageBox(parent = parent,
+ message = message,
+ caption = caption,
+ style = style)
- dlg.ShowModal()
+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)
- def __str__(self):
- self.Show()
-
- return ''
-
-class GStdError(GException):
- """Generic exception"""
+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)
- def __init__(self, message, title=_("Error"), parent=None):
- GException.__init__(self, message, title=title, parent=parent)
+class GException(Exception):
+ def __init__(self, value):
+ self.value = value
-class CmdError(GException):
- """Exception used for GRASS commands.
+ def __str__(self):
+ return str(self.value)
- See Command class (command exits with EXIT_FAILURE,
- G_fatal_error() is called)."""
- def __init__(self, cmd, message, parent=None):
- self.cmd = cmd
- GException.__init__(self, message,
- title=_("Error in command execution %s" % self.cmd[0]),
- parent=parent)
-
-class SettingsError(GException):
- """Exception used for GRASS settings, see
- gui_modules/preferences.py."""
- def __init__(self, message, parent=None):
- GException.__init__(self, message,
- title=_("Preferences error"),
- parent=parent)
-
-class DigitError(GException):
- """Exception raised during digitization session"""
- def __init__(self, message, parent=None):
- GException.__init__(self, message,
- title=_("Vector digitizer error"),
- parent=parent)
-
-class DBMError(GException):
- """Attribute Table Manager exception class"""
- def __init__(self, message, parent=None):
- GException.__init__(self, message,
- title=_("Attribute table manager error"),
- parent=parent)
-
-class NvizError(GException):
- """Nviz exception class"""
- def __init__(self, message, parent=None):
- GException.__init__(self, message,
- title=_("Nviz error"),
- parent=parent)
-
class Popen(subprocess.Popen):
- """Subclass subprocess.Popen"""
+ """!Subclass subprocess.Popen"""
def __init__(self, *args, **kwargs):
if subprocess.mswindows:
try:
@@ -162,7 +142,7 @@
setattr(self, which, None)
def kill(self):
- """Try to kill running process"""
+ """!Try to kill running process"""
if subprocess.mswindows:
import win32api
handle = win32api.OpenProcess(1, 0, self.pid)
@@ -287,9 +267,9 @@
data = buffer(data, sent)
class Command:
- """
- Run GRASS command in separate thread
-
+ """!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.
@@ -359,18 +339,17 @@
(' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
if rerr is not None and self.returncode != 0:
if rerr is False: # GUI dialog
- raise CmdError(cmd=self.cmd,
- message="%s '%s'%s%s%s %s%s" %
- (_("Execution failed:"),
- ' '.join(self.cmd),
- os.linesep, os.linesep,
- _("Details:"),
- os.linesep,
- _("Error: ") + self.GetError()))
+ 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(),
+ _("Error: ") + self.__GetError(),
os.linesep))
else:
pass # nop
@@ -384,7 +363,7 @@
del os.environ["GRASS_VERBOSE"]
def __ReadOutput(self, stream):
- """Read stream and return list of lines
+ """!Read stream and return list of lines
@param stream stream to be read
"""
@@ -402,18 +381,8 @@
return lineList
- def ReadStdOutput(self):
- """Read standard output and return list of lines"""
- if self.cmdThread.stdout:
- stream = self.cmdThread.stdout # use redirected stream instead
- stream.seek(0)
- else:
- stream = self.cmdThread.module.stdout
-
- return self.__ReadOutput(stream)
-
- def ReadErrOutput(self):
- """Read standard error output and return list of lines"""
+ def __ReadErrOutput(self):
+ """!Read standard error output and return list of lines"""
return self.__ReadOutput(self.cmdThread.module.stderr)
def __ProcessStdErr(self):
@@ -423,7 +392,7 @@
@return list of (type, message)
"""
if self.stderr is None:
- lines = self.ReadErrOutput()
+ lines = self.__ReadErrOutput()
else:
lines = self.cmdThread.error.strip('%s' % os.linesep). \
split('%s' % os.linesep)
@@ -452,8 +421,8 @@
return msg
- def GetError(self):
- """Get error message or ''"""
+ def __GetError(self):
+ """!Get error message or ''"""
if not self.cmdThread.module:
return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
@@ -467,31 +436,9 @@
return ''
- def PrintModuleOutput(self, error=True, warning=False, message=False):
- """Print module errors, warnings, messages to output
-
- @param error print errors
- @param warning print warnings
- @param message print messages
-
- @return string
- """
-
- msgString = ""
- for type, msg in self.__ProcessStdErr():
- if type:
- if (type == 'ERROR' and error) or \
- (type == 'WARNING' and warning) or \
- (type == 'MESSAGE' and message):
- msgString += " " + type + ": " + msg + "%s" % os.linesep
- else:
- msgString += " " + msg + "%s" % os.linesep
-
- return msgString
-
class CommandThread(Thread):
- """!Create separate thread for command
- """
+ """!Create separate thread for command. Used for commands launched
+ on the background."""
def __init__ (self, cmd, stdin=None,
stdout=sys.stdout, stderr=sys.stderr):
"""
@@ -526,6 +473,7 @@
del os.environ["GRASS_MESSAGE_FORMAT"]
def run(self):
+ """!Run command"""
if len(self.cmd) == 0:
return
@@ -549,7 +497,7 @@
self.__redirect_stream()
def __redirect_stream(self):
- """Redirect stream"""
+ """!Redirect stream"""
if self.stdout:
# make module stdout/stderr non-blocking
out_fileno = self.module.stdout.fileno()
@@ -590,12 +538,12 @@
self.error = line
def abort(self):
- """Abort running process, used by main thread to signal an abort"""
+ """!Abort running process, used by main thread to signal an abort"""
self._want_abort = True
def RunCommand(prog, flags = "", overwrite = False, quiet = False, verbose = False,
- parent = None, read = False, stdin = None, **kwargs):
- """Run GRASS command"""
+ parent = None, read = False, stdin = None, getErrorMsg = False, **kwargs):
+ """!Run GRASS command"""
Debug.msg(1, "gcmd.RunCommand(): %s" % ' '.join(grass.make_command(prog, flags, overwrite,
quiet, verbose, **kwargs)))
@@ -615,16 +563,23 @@
ps.stdin = None
stdout, stderr = ps.communicate()
-
+
ret = ps.returncode
- if ret != 0 and parent:
- e = CmdError(cmd = prog,
- message = stderr,
- parent = parent)
- e.Show()
-
+ if ret != 0 and parent:
+ GError(parent = parent,
+ message = stderr)
+
if not read:
- return ret
+ if not getErrorMsg:
+ return ret
+ else:
+ return ret, stderr
- return stdout
+ if not getErrorMsg:
+ return stdout
+
+ if read and getErrorMsg:
+ return ret, stdout, stderr
+
+ return stdout, stderr
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmanager.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmanager.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmanager.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -50,7 +50,7 @@
from location_wizard import TitledPage as TitledPage
from preferences import globalSettings as UserSettings
from gcpmapdisp import MapFrame
-from mapdisp import BufferedWindow
+from mapdisp_window import BufferedWindow
try:
import subprocess # Not needed if GRASS commands could actually be quiet
@@ -288,15 +288,9 @@
if grc == 'target':
os.environ['GISRC'] = str(self.target_gisrc)
- gisrcfile = str(self.target_gisrc)
elif grc == 'source':
os.environ['GISRC'] = str(self.source_gisrc)
- gisrcfile = str(self.source_gisrc)
- # do it the hard way
- gcmd.RunCommand('g.gisenv', 'set=LOCATION_NAME=%s' % self.newlocation)
- gcmd.RunCommand('g.gisenv', 'set=MAPSET=%s' % self.newmapset)
-
return True
def OnWizFinished(self):
@@ -331,21 +325,7 @@
self.xylocation = ''
self.xymapset = ''
- tmplist = os.listdir(self.grassdatabase)
- self.locList = []
- self.mapsetList = []
-
#
- # create a list of valid locations
- #
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase, item)) and \
- os.path.exists(os.path.join(self.grassdatabase, item, 'PERMANENT')):
- self.locList.append(item)
-
- utils.ListSortLower(self.locList)
-
- #
# layout
#
self.sizer.AddGrowableCol(2)
@@ -362,9 +342,7 @@
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 = wx.ComboBox(parent=self, id=wx.ID_ANY,
- choices = self.locList, size=(300, -1),
- style=wx.CB_DROPDOWN | wx.CB_READONLY)
+ self.cb_location = gselect.LocationSelect(parent = self, gisdbase = self.grassdatabase)
self.sizer.Add(item=self.cb_location,
flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
pos=(2, 2))
@@ -373,9 +351,8 @@
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 = wx.ComboBox(parent=self, id=wx.ID_ANY,
- choices = self.mapsetList, size=(300, -1),
- style=wx.CB_DROPDOWN | wx.CB_READONLY)
+ self.cb_mapset = gselect.MapsetSelect(parent = self, gisdbase = self.grassdatabase,
+ setItems = False)
self.sizer.Add(item=self.cb_mapset,
flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
pos=(3,2))
@@ -730,83 +707,13 @@
return
# filter out all maps not in group
- # not available in 64
- #self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
- # modified from gselect
- self.srcselection.tcp.seltree.DeleteAllItems()
- # get current mapset
- curr_mapset = grass.gisenv()['MAPSET']
- mapsets = utils.ListOfMapsets()
- for i in range(len(mapsets)):
- if i > 0 and mapsets[i] == curr_mapset:
- mapsets[i] = mapsets[0]
- mapsets[0] = curr_mapset
-
- elementdict = {'cell':'rast',
- 'raster':'rast',
- 'rast':'rast',
- 'raster files':'rast',
- 'vector':'vect',
- 'vect':'vect'
- }
- if globalvar.have_mlist:
- filesdict = grass.mlist_grouped(elementdict[maptype])
- else:
- filesdict = grass.list_grouped(elementdict[maptype])
-
- first_dir = None
- for dir in mapsets:
- dir_node = self.srcselection.tcp.AddItem('Mapset: ' + dir)
- if not first_dir:
- first_dir = dir_node
-
- self.srcselection.tcp.seltree.SetItemTextColour(dir_node, wx.Colour(50, 50, 200))
- try:
- elem_list = filesdict[dir]
- elem_list.sort(key=str.lower)
- for elem in elem_list:
- if elem != '':
- fullqElem = elem + '@' + dir
- if fullqElem in self.parent.src_maps:
- self.srcselection.tcp.AddItem(fullqElem, parent=dir_node)
- except:
- continue
-
- if self.srcselection.tcp.seltree.ItemHasChildren(dir_node):
- sel = UserSettings.Get(group='general', key='elementListExpand',
- subkey='selection')
- collapse = True
-
- if sel == 0: # collapse all except PERMANENT and current
- if dir in ('PERMANENT', curr_mapset):
- collapse = False
- elif sel == 1: # collapse all except PERMANENT
- if dir == 'PERMANENT':
- collapse = False
- elif sel == 2: # collapse all except current
- if dir == curr_mapset:
- collapse = False
- elif sel == 3: # collapse all
- pass
- elif sel == 4: # expand all
- collapse = False
-
- if collapse:
- self.srcselection.tcp.seltree.Collapse(dir_node)
- else:
- self.srcselection.tcp.seltree.Expand(dir_node)
-
- if first_dir:
- # select first mapset (MSW hack)
- self.srcselection.tcp.seltree.SelectItem(first_dir)
-
- # end copy from gselect
+ 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.tgtselection.GetElementList()
self.parent.SwitchEnv('source')
if src_map == '':
@@ -954,13 +861,12 @@
#
# show new display & draw map
#
+ self.MapWindow = self.TgtMapWindow
+ self.Map = self.TgtMap
+ self.OnZoomToMap(None)
self.MapWindow = self.SrcMapWindow
self.Map = self.SrcMap
self.OnZoomToMap(None)
- if self.show_target:
- self.MapWindow = self.TgtMapWindow
- self.Map = self.TgtMap
- self.OnZoomToMap(None)
#
# bindings
@@ -1028,7 +934,7 @@
0.0, # forward error
0.0 ] ) # backward error
- if self.toggleStatus.GetSelection() == 7: # go to
+ if self.statusbarWin['toggle'].GetSelection() == 7: # go to
self.StatusbarUpdate()
def DeleteGCP(self, event):
@@ -1069,11 +975,11 @@
self.UpdateColours()
- if self.toggleStatus.GetSelection() == 7: # go to
+ if self.statusbarWin['toggle'].GetSelection() == 7: # go to
self.StatusbarUpdate()
if self.list.selectedkey > 0:
- self.gotogcp.SetValue(self.list.selectedkey)
- #self.gotogcp.SetValue(0)
+ self.statusbarWin['goto'].SetValue(self.list.selectedkey)
+ #self.statusbarWin['goto'].SetValue(0)
def ClearGCP(self, event):
"""
@@ -1202,11 +1108,15 @@
else:
currloc = _("target")
ret = wx.MessageBox(parent=self,
- caption=_("Set GCP coordinates"),
- message=_('Set %s coordinates for GCP No. %s? \n\n'
- 'East: %s \n'
- 'North: %s') % (currloc, str(key), str(coord0), str(coord1)),
- style=wx.ICON_QUESTION | wx.YES_NO | wx.CENTRE)
+ 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':
@@ -1631,6 +1541,7 @@
self.SrcMap.Clean()
self.TgtMap.Clean()
+
self.grwiz.Cleanup()
self.Destroy()
@@ -1852,11 +1763,10 @@
def OnHelp(self, event):
"""!Show GCP Manager manual page"""
-
- cmdlist = ['g.manual','entry=wxGUI.GCP_Manager']
+ cmdlist = ['g.manual', 'entry=wxGUI.GCP_Manager']
self.parent.goutput.RunCmd(cmdlist, compReg=False,
- switchPage=False)
-
+ switchPage=False)
+
def OnUpdateActive(self, event):
if self.activemap.GetSelection() == 0:
@@ -1874,8 +1784,7 @@
def UpdateActive(self, win):
# optionally disable tool zoomback tool
- self.toolbars['gcpdisp'].toolbar.EnableTool(self.toolbars['gcpdisp'].zoomback,
- enable = (len(self.MapWindow.zoomhistory) > 1))
+ self.toolbars['gcpdisp'].Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
if self.activemap.GetSelection() != (win == self.TgtMapWindow):
self.activemap.SetSelection(win == self.TgtMapWindow)
@@ -1970,7 +1879,6 @@
"""!GCP Map Display resized, adjust Map Windows
"""
if self.toolbars['gcpdisp']:
- time.sleep(0.5)
srcwidth, srcheight = self.SrcMapWindow.GetSize()
tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
tgtwidth = (srcwidth + tgtwidth) / 2
@@ -2638,84 +2546,14 @@
self.parent.grwiz.SwitchEnv('source')
self.srcselection.SetElementList(maptype)
# filter out all maps not in group
- # not available in 64
- #self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
- # modified from gselect
- self.srcselection.tcp.seltree.DeleteAllItems()
- # get current mapset
- curr_mapset = grass.gisenv()['MAPSET']
- mapsets = utils.ListOfMapsets()
- for i in range(len(mapsets)):
- if i > 0 and mapsets[i] == curr_mapset:
- mapsets[i] = mapsets[0]
- mapsets[0] = curr_mapset
-
- elementdict = {'cell':'rast',
- 'raster':'rast',
- 'rast':'rast',
- 'raster files':'rast',
- 'vector':'vect',
- 'vect':'vect'
- }
- if globalvar.have_mlist:
- filesdict = grass.mlist_grouped(elementdict[maptype])
- else:
- filesdict = grass.list_grouped(elementdict[maptype])
-
- first_dir = None
- for dir in mapsets:
- dir_node = self.srcselection.tcp.AddItem('Mapset: ' + dir)
- if not first_dir:
- first_dir = dir_node
-
- self.srcselection.tcp.seltree.SetItemTextColour(dir_node, wx.Colour(50, 50, 200))
- try:
- elem_list = filesdict[dir]
- elem_list.sort(key=str.lower)
- for elem in elem_list:
- if elem != '':
- fullqElem = elem + '@' + dir
- if fullqElem in self.parent.src_maps:
- self.srcselection.tcp.AddItem(fullqElem, parent=dir_node)
- except:
- continue
+ self.srcselection.tcp.GetElementList(elements = self.parent.src_maps)
- if self.srcselection.tcp.seltree.ItemHasChildren(dir_node):
- sel = UserSettings.Get(group='general', key='elementListExpand',
- subkey='selection')
- collapse = True
-
- if sel == 0: # collapse all except PERMANENT and current
- if dir in ('PERMANENT', curr_mapset):
- collapse = False
- elif sel == 1: # collapse all except PERMANENT
- if dir == 'PERMANENT':
- collapse = False
- elif sel == 2: # collapse all except current
- if dir == curr_mapset:
- collapse = False
- elif sel == 3: # collapse all
- pass
- elif sel == 4: # expand all
- collapse = False
-
- if collapse:
- self.srcselection.tcp.seltree.Collapse(dir_node)
- else:
- self.srcselection.tcp.seltree.Expand(dir_node)
-
- if first_dir:
- # select first mapset (MSW hack)
- self.srcselection.tcp.seltree.SelectItem(first_dir)
-
- # end copy from gselect
-
# target map to display
self.tgtselection = gselect.Select(panel, id=wx.ID_ANY,
size=globalvar.DIALOG_GSELECT_SIZE, type='cell', updateOnPopup = False)
self.parent.grwiz.SwitchEnv('target')
self.tgtselection.SetElementList(maptype)
- #self.tgtselection.GetElementList()
+ 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)
@@ -2896,9 +2734,9 @@
if self.parent.show_target == False:
self.parent.show_target = True
self.parent._mgr.GetPane("target").Show()
- self.parent.toolbars['gcpdisp'].toolbar.EnableTool(self.parent.toolbars['gcpdisp'].zoommenu, enable = True)
+ self.parent.toolbars['gcpdisp'].Enable('zoommenu', enable = True)
self.parent.activemap.Enable()
- self.parent.TgtMapWindow.ZoomToMap(layer = self.parent.TgtMap.GetListOfLayers())
+ self.parent.TgtMapWindow.ZoomToMap(layers = self.parent.TgtMap.GetListOfLayers())
self.parent._mgr.Update()
else: # tgt_map == ''
if self.parent.show_target == True:
@@ -2906,7 +2744,7 @@
self.parent._mgr.GetPane("target").Hide()
self.parent.activemap.SetSelection(0)
self.parent.activemap.Enable(False)
- self.parent.toolbars['gcpdisp'].toolbar.EnableTool(self.parent.toolbars['gcpdisp'].zoommenu, enable = False)
+ self.parent.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
self.parent._mgr.Update()
self.parent.UpdateColours(srcrender, srcrenderVector, tgtrender, tgtrenderVector)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmapdisp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmapdisp.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gcpmapdisp.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,24 +1,20 @@
"""!
@package gcpmapdisp.py
- at brief GIS map display canvas, with toolbar for various display
-management functions, and additional toolbars (vector digitizer, 3d
-view).
+ at brief display to manage ground control points with two toolbars, one for
+various display management functions, one for manipulating GCPs.
Classes:
- MapFrame
-
(C) 2006-2010 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
+Derived from mapdisp.py
+
@author Markus Metz
-based on mapdisp.py by
- at author Michael Barton
- at author Jachym Cepicky
- at author Martin Landa <landa.martin gmail.com>
"""
import os
@@ -54,8 +50,7 @@
import disp_print
import gcmd
import dbm
-import histogram
-import profile
+import dbm_dialogs
import globalvar
import utils
import gdialogs
@@ -64,25 +59,31 @@
from icon import Icons
from preferences import globalSettings as UserSettings
-from gcmd import Command
-from mapdisp import BufferedWindow
+from mapdisp_command import Command
+from mapdisp_window import BufferedWindow
import images
imagepath = images.__path__[0]
sys.path.append(imagepath)
+###
+### global variables
+###
+# for standalone app
+cmdfilename = None
+
class MapFrame(wx.Frame):
"""!Main frame for map display window. Drawing takes place in
child double buffered drawing window.
"""
- def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS - Map display"),
+ def __init__(self, parent=None, id=wx.ID_ANY, title=_("Manage Ground Control Points"),
style=wx.DEFAULT_FRAME_STYLE, toolbars=["gcpdisp"],
tree=None, notebook=None, lmgr=None, page=None,
Map=None, auimgr=None, **kwargs):
"""!Main map display window with toolbars, statusbar and
DrawWindow
- @param toolbars array of activated toolbars, here 'gcpdisp'
+ @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
@@ -92,7 +93,6 @@
@param kwargs wx.Frame attribures
"""
self._layerManager = lmgr # Layer Manager object
- self.gismanager = lmgr # GIS Manager object
self.Map = Map # instance of render.Map
self.tree = tree # Layer Manager layer tree object
self.page = page # Notebook page holding the layer tree
@@ -100,7 +100,7 @@
self.parent = parent
if not kwargs.has_key('name'):
- kwargs['name'] = 'GCPDisplay'
+ kwargs['name'] = 'GCPMapWindow'
wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
# available cursors
@@ -151,7 +151,8 @@
#
self.statusbar = self.CreateStatusBar(number=4, style=0)
self.statusbar.SetStatusWidths([-5, -2, -1, -1])
- self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY,
+ self.statusbarWin = dict()
+ self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
choices = [_("Coordinates"),
_("Extent"),
_("Comp. region"),
@@ -162,71 +163,83 @@
_("Go to GCP No."),
_("RMS error")])
# set StatusBar to Go to GCP No.
- self.toggleStatus.SetSelection(7)
+ self.statusbarWin['toggle'].SetSelection(7)
- self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.toggleStatus)
+ self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
# auto-rendering checkbox
- self.autoRender = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ self.statusbarWin['render'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
label=_("Render"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.autoRender)
- self.autoRender.SetValue(UserSettings.Get(group='display',
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
+ self.statusbarWin['render'].SetValue(UserSettings.Get(group='display',
key='autoRendering',
subkey='enabled'))
- self.autoRender.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
+ self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
# show region
- self.showRegion = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ self.statusbarWin['region'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
label=_("Show computational extent"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.showRegion)
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
- self.showRegion.SetValue(False)
- self.showRegion.Hide()
- self.showRegion.SetToolTip(wx.ToolTip (_("Show/hide computational "
+ self.statusbarWin['region'].SetValue(False)
+ self.statusbarWin['region'].Hide()
+ self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
"region extent (set with g.region). "
"Display region drawn as a blue box inside the "
"computational region, "
"computational region inside a display region "
"as a red box).")))
# set resolution
- self.compResolution = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ self.statusbarWin['resolution'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
label=_("Constrain display resolution to computational settings"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.compResolution)
- self.compResolution.SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
- self.compResolution.Hide()
- self.compResolution.SetToolTip(wx.ToolTip (_("Constrain display resolution "
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
+ self.statusbarWin['resolution'].SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
+ self.statusbarWin['resolution'].Hide()
+ self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
"to computational region settings. "
"Default value for new map displays can "
"be set up in 'User GUI settings' dialog.")))
# map scale
- self.mapScale = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
+ self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
style = wx.TE_PROCESS_ENTER,
size=(150, -1))
- self.mapScale.SetItems(['1:1000',
+ self.statusbarWin['mapscale'].SetItems(['1:1000',
'1:5000',
'1:10000',
'1:25000',
'1:50000',
'1:100000',
'1:1000000'])
- self.mapScale.Hide()
- self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.mapScale)
- self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.mapScale)
+ self.statusbarWin['mapscale'].Hide()
+ self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
+ self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
- # go to GCP
- self.gotogcp = wx.SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
+ # go to
+ self.statusbarWin['goto'] = wx.SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
min=0)
- self.statusbar.Bind(wx.EVT_SPINCTRL, self.OnGoTo, self.gotogcp)
- self.gotogcp.Hide()
- self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.gotogcp)
+ self.statusbar.Bind(wx.EVT_SPINCTRL, self.OnGoTo, self.statusbarWin['goto'])
+ self.statusbarWin['goto'].Hide()
+ self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
+ # projection, unused but BufferedWindow checks for it
+ self.statusbarWin['projection'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ label=_("Use defined projection"))
+ self.statusbarWin['projection'].SetValue(False)
+ size = self.statusbarWin['projection'].GetSize()
+ self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
+ self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
+ "in the statusbar. Projection can be "
+ "defined in GUI preferences dialog "
+ "(tab 'Display')")))
+ self.statusbarWin['projection'].Hide()
+
# mask
- self.maskInfo = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
+ self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
label = '')
- self.maskInfo.SetForegroundColour(wx.Colour(255, 0, 0))
+ self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
# on-render gauge
- self.onRenderGauge = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
+ self.statusbarWin['progress'] = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
range=0, style=wx.GA_HORIZONTAL)
- self.onRenderGauge.Hide()
+ self.statusbarWin['progress'].Hide()
self.StatusbarReposition() # reposition statusbar
@@ -235,15 +248,13 @@
#
self.grwiz.SwitchEnv('source')
self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
- Map=self.SrcMap, tree=self.tree, gismgr=self._layerManager)
+ 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, gismgr=self._layerManager)
+ Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
self.MapWindow = self.SrcMapWindow
self.Map = self.SrcMap
- self.SrcMapWindow.Bind(wx.EVT_MOTION, self.OnMotion)
- self.TgtMapWindow.Bind(wx.EVT_MOTION, self.OnMotion)
self.SrcMapWindow.SetCursor(self.cursors["cross"])
self.TgtMapWindow.SetCursor(self.cursors["cross"])
@@ -263,7 +274,7 @@
#
# Update fancy gui style
#
- # AuiManager wants a CentrePane , workaround to get two equally sized windows
+ # AuiManager wants a CentrePane, workaround to get two equally sized windows
self.list = self.CreateGCPList()
#self.SrcMapWindow.SetSize((300, 300))
@@ -294,7 +305,6 @@
self._mgr.GetPane("target").Show()
else:
self.activemap.Enable(False)
-
# called by GCPWizard
#self._mgr.Update()
@@ -303,16 +313,24 @@
#
self.printopt = disp_print.PrintOptions(self, self.MapWindow)
+ #
+ # Initialization of digitization tool
+ #
+ self.digit = None
+
# set active map
self.MapWindow = self.SrcMapWindow
self.Map = self.SrcMap
#
- # Init zoom history
+ # Init zoom history for TgtMapWindow
#
self.TgtMapWindow.ZoomHistory(self.Map.region['n'],
self.Map.region['s'],
self.Map.region['e'],
self.Map.region['w'])
+ #
+ # Init zoom history
+ #
self.MapWindow.ZoomHistory(self.Map.region['n'],
self.Map.region['s'],
self.Map.region['e'],
@@ -340,11 +358,24 @@
- 'georect' - georectifier
- 'nviz' - 3D view mode
"""
- # default toolbars for GCP display
- if name == "gcpdisp":
+ # default toolbar
+ if name == "map":
+ self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
+
+ self._mgr.AddPane(self.toolbars['map'],
+ wx.aui.AuiPaneInfo().
+ Name("maptoolbar").Caption(_("Map Toolbar")).
+ ToolbarPane().Top().
+ LeftDockable(False).RightDockable(False).
+ BottomDockable(False).TopDockable(True).
+ CloseButton(False).Layer(2).
+ BestSize((self.toolbars['map'].GetSize())))
+
+ # GCP display
+ elif name == "gcpdisp":
self.toolbars['gcpdisp'] = toolbars.GCPDisplayToolbar(self)
- self._mgr.AddPane(self.toolbars['gcpdisp'].toolbar,
+ self._mgr.AddPane(self.toolbars['gcpdisp'],
wx.aui.AuiPaneInfo().
Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
ToolbarPane().Top().
@@ -353,30 +384,18 @@
CloseButton(False).Layer(2))
if self.show_target == False:
- self.toolbars['gcpdisp'].toolbar.EnableTool(self.toolbars['gcpdisp'].zoommenu, enable = False)
+ self.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
self.toolbars['gcpman'] = toolbars.GCPManToolbar(self)
- self._mgr.AddPane(self.toolbars['gcpman'].toolbar,
+ 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))
-
- # georectifier
- elif name == "georect":
- self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
-
- self._mgr.AddPane(self.toolbars['georect'].toolbar,
- wx.aui.AuiPaneInfo().
- Name("georecttoolbar").Caption(_("Georectification toolbar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2))
-
+
self._mgr.Update()
def __InitDisplay(self):
@@ -399,7 +418,7 @@
"""
Update progress bar info
"""
- self.onRenderGauge.SetValue(event.value)
+ self.statusbarWin['progress'].SetValue(event.value)
event.Skip()
@@ -409,49 +428,20 @@
Or set display for georectifying
"""
if self._layerManager and \
- self._layerManager.georectifying:
- # in georectifying session; display used to get geographic
- # coordinates for GCPs
- self.OnPointer(event)
- elif self._layerManager and \
self._layerManager.gcpmanagement:
- # in georectifying session; display used to get geographic
- # coordinates for GCPs
+ # 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 OnMotion(self, event):
- """
- Mouse moved
- Track mouse motion and update status bar
- """
- # update statusbar if required
- if self.toggleStatus.GetSelection() == 0: # Coordinates
- e, n = self.MapWindow.Pixel2Cell(event.GetPositionTuple())
- if self.toolbars['vdigit'] and \
- self.toolbars['vdigit'].GetAction() == 'addLine' and \
- self.toolbars['vdigit'].GetAction('type') in ('line', 'boundary') and \
- len(self.MapWindow.polycoords) > 0:
- # for linear feature show segment and total length
- distance_seg = self.MapWindow.Distance(self.MapWindow.polycoords[-1],
- (e, n), screen=False)[0]
- distance_tot = distance_seg
- for idx in range(1, len(self.MapWindow.polycoords)):
- distance_tot += self.MapWindow.Distance(self.MapWindow.polycoords[idx-1],
- self.MapWindow.polycoords[idx],
- screen=False )[0]
- self.statusbar.SetStatusText("%.2f, %.2f (seg: %.2f; tot: %.2f)" % \
- (e, n, distance_seg, distance_tot), 0)
- else:
- if self.Map.projinfo['proj'] == 'll':
- self.statusbar.SetStatusText("%s" % utils.Deg2DMS(e, n), 0)
- else:
- self.statusbar.SetStatusText("%.2f, %.2f" % (e, n), 0)
-
- event.Skip()
-
def OnDraw(self, event):
"""!Re-display current map composition
"""
@@ -465,47 +455,23 @@
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()
+ self.SrcMapWindow.UpdateMap(render=True)
+ self.TgtMapWindow.UpdateMap(render=True)
+ self._mgr.Update()
- if self.toolbars['gcpdisp']:
- self.SrcMapWindow.UpdateMap(render=True)
- self.TgtMapWindow.UpdateMap(render=True)
- self._mgr.Update()
- else:
- self.MapWindow.UpdateMap(render=True)
-
# update statusbar
self.StatusbarUpdate()
def OnPointer(self, event):
"""!Pointer button clicked
"""
- if self.toolbars['map']:
- 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._layerManager.gcpmanagement:
- 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"
-
- elif self._layerManager and self._layerManager.georectifying:
- self.MapWindow.SetCursor(self.cursors["cross"])
-
- else:
- self.MapWindow.SetCursor(self.cursors["default"])
+ 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):
"""
@@ -524,19 +490,18 @@
# change the cursor
self.MapWindow.SetCursor(self.cursors["cross"])
- if self._layerManager and self._layerManager.gcpmanagement:
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
+ 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"])
+ 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):
"""
@@ -555,19 +520,18 @@
# change the cursor
self.MapWindow.SetCursor(self.cursors["cross"])
- if self._layerManager and self._layerManager.gcpmanagement:
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
+ 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"])
+ win.mouse['use'] = "zoom"
+ win.mouse['box'] = "box"
+ win.zoomtype = -1
+ win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
+
+ # change the cursor
+ win.SetCursor(self.cursors["cross"])
def OnZoomBack(self, event):
"""
@@ -590,18 +554,17 @@
# change the cursor
self.MapWindow.SetCursor(self.cursors["hand"])
- if self._layerManager and self._layerManager.gcpmanagement:
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
+ 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"])
+ win.mouse['use'] = "pan"
+ win.mouse['box'] = "pan"
+ win.zoomtype = 0
+
+ # change the cursor
+ win.SetCursor(self.cursors["hand"])
def OnErase(self, event):
"""
@@ -609,13 +572,12 @@
"""
self.MapWindow.EraseMap()
- if self._layerManager and self._layerManager.gcpmanagement:
- if self.MapWindow == self.SrcMapWindow:
- win = self.TgtMapWindow
- elif self.MapWindow == self.TgtMapWindow:
- win = self.SrcMapWindow
+ if self.MapWindow == self.SrcMapWindow:
+ win = self.TgtMapWindow
+ elif self.MapWindow == self.TgtMapWindow:
+ win = self.SrcMapWindow
- win.EraseMap()
+ win.EraseMap()
def OnZoomRegion(self, event):
"""
@@ -640,21 +602,21 @@
"""
Enable/disable auto-rendering
"""
- if self.autoRender.GetValue():
+ if self.statusbarWin['render'].GetValue():
self.OnRender(None)
def OnToggleShowRegion(self, event):
"""
Show/Hide extent in map canvas
"""
- if self.showRegion.GetValue():
+ if self.statusbarWin['region'].GetValue():
# show extent
self.MapWindow.regionCoords = []
else:
del self.MapWindow.regionCoords
# redraw map if auto-rendering is enabled
- if self.autoRender.GetValue():
+ if self.statusbarWin['render'].GetValue():
self.OnRender(None)
def OnToggleResolution(self, event):
@@ -663,7 +625,7 @@
for redering image instead of display resolution
"""
# redraw map if auto-rendering is enabled
- if self.autoRender.GetValue():
+ if self.statusbarWin['render'].GetValue():
self.OnRender(None)
def OnToggleStatus(self, event):
@@ -683,7 +645,7 @@
raise ValueError
value = int(scale[2:])
except ValueError:
- self.mapScale.SetValue('1:%ld' % int(self.mapScaleValue))
+ self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
return
dEW = value * (self.Map.region['cols'] / self.ppm[0])
@@ -699,14 +661,14 @@
# redraw a map
self.MapWindow.UpdateMap()
- self.mapScale.SetFocus()
+ self.statusbarWin['mapscale'].SetFocus()
def OnGoTo(self, event):
"""
- Go to GCP No
+ Go to position
"""
#GCPNo = int(event.GetString())
- GCPNo = self.gotogcp.GetValue()
+ GCPNo = self.statusbarWin['goto'].GetValue()
if GCPNo < 0 or GCPNo > len(self.mapcoordlist):
wx.MessageBox(parent=self,
@@ -745,58 +707,83 @@
# redraw map
self.TgtMapWindow.UpdateMap()
- self.gotogcp.SetFocus()
+ self.statusbarWin['goto'].SetFocus()
def StatusbarUpdate(self):
"""!Update statusbar content"""
- self.showRegion.Hide()
- self.compResolution.Hide()
- self.mapScale.Hide()
- self.gotogcp.Hide()
+ self.statusbarWin['region'].Hide()
+ self.statusbarWin['resolution'].Hide()
+ self.statusbarWin['mapscale'].Hide()
+ self.statusbarWin['goto'].Hide()
self.mapScaleValue = self.ppm = None
- if self.toggleStatus.GetSelection() == 0: # Coordinates
+ if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
self.statusbar.SetStatusText("", 0)
# enable long help
self.StatusbarEnableLongHelp()
- elif self.toggleStatus.GetSelection() == 1: # Extent
- self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f" %
- (self.Map.region["w"], self.Map.region["e"],
- self.Map.region["s"], self.Map.region["n"]), 0)
- # enable long help
- self.StatusbarEnableLongHelp()
+ elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
+ sel = self.statusbarWin['toggle'].GetSelection()
+ if sel == 1:
+ region = self.Map.region
+ else:
+ region = self.Map.GetRegion() # computation region
- elif self.toggleStatus.GetSelection() == 2: # Comp. region
- compregion = self.Map.GetRegion()
- self.statusbar.SetStatusText("%.2f - %.2f, %.2f - %.2f (%.2f, %.2f)" %
- (compregion["w"], compregion["e"],
- compregion["s"], compregion["n"],
- compregion["ewres"], compregion["nsres"]), 0)
+ precision = int(UserSettings.Get(group = 'projection', key = 'format',
+ subkey = 'precision'))
+ format = UserSettings.Get(group = 'projection', key = 'format',
+ subkey = 'll')
+
+ if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
+ w, s = utils.Deg2DMS(region["w"], region["s"],
+ string = False, precision = precision)
+ e, n = utils.Deg2DMS(region["e"], region["n"],
+ string = False, precision = precision)
+ if sel == 1:
+ self.statusbar.SetStatusText("%s - %s, %s - %s" %
+ (w, e, s, n), 0)
+ else:
+ ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
+ string = False, precision = precision)
+ self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
+ (w, e, s, n, ewres, nsres), 0)
+ else:
+ w, s = region["w"], region["s"]
+ e, n = region["e"], region["n"]
+ if sel == 1:
+ self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
+ (precision, w, precision, e,
+ precision, s, precision, n), 0)
+ else:
+ ewres, nsres = region['ewres'], region['nsres']
+ self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
+ (precision, w, precision, e,
+ precision, s, precision, n,
+ precision, ewres, precision, nsres), 0)
# enable long help
self.StatusbarEnableLongHelp()
- elif self.toggleStatus.GetSelection() == 3: # Show comp. extent
+ elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
self.statusbar.SetStatusText("", 0)
- self.showRegion.Show()
+ self.statusbarWin['region'].Show()
# disable long help
self.StatusbarEnableLongHelp(False)
- elif self.toggleStatus.GetSelection() == 4: # Display mode
+ elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
self.statusbar.SetStatusText("", 0)
- self.compResolution.Show()
+ self.statusbarWin['resolution'].Show()
# disable long help
self.StatusbarEnableLongHelp(False)
- elif self.toggleStatus.GetSelection() == 5: # Display geometry
+ elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
(self.Map.region["rows"], self.Map.region["cols"],
self.Map.region["nsres"], self.Map.region["ewres"]), 0)
# enable long help
self.StatusbarEnableLongHelp()
- elif self.toggleStatus.GetSelection() == 6: # Map scale
+ elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
# TODO: need to be fixed...
### screen X region problem
### user should specify ppm
@@ -836,30 +823,34 @@
self.statusbar.SetStatusText("")
try:
- self.mapScale.SetValue("1:%ld" % (scale + 0.5))
+ self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
except TypeError:
pass
self.mapScaleValue = scale
- self.mapScale.Show()
+ self.statusbarWin['mapscale'].Show()
# disable long help
self.StatusbarEnableLongHelp(False)
- elif self.toggleStatus.GetSelection() == 7: # go to
+ elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
self.statusbar.SetStatusText("")
max = self.list.GetItemCount()
if max < 1:
max = 1
- self.gotogcp.SetRange(0, max)
- self.gotogcp.Show()
+ self.statusbarWin['goto'].SetRange(0, max)
+ self.statusbarWin['goto'].Show()
+
# disable long help
self.StatusbarEnableLongHelp(False)
- elif self.toggleStatus.GetSelection() == 8: # RMS error
- self.statusbar.SetStatusText(_("Forward: %s, Backward: %s") %
- (self.fwd_rmserror, self.bkw_rmserror))
+ elif self.statusbarWin['toggle'].GetSelection() == 8: # RMS error
+ self.statusbar.SetStatusText(_("Forward: %(forw)s, Backward: %(back)s") %
+ { 'forw' : self.fwd_rmserror,
+ 'back' : self.bkw_rmserror })
+ # disable long help
+ # self.StatusbarEnableLongHelp(False)
else:
self.statusbar.SetStatusText("", 1)
@@ -873,23 +864,23 @@
def StatusbarReposition(self):
"""!Reposition checkbox in statusbar"""
# reposition checkbox
- widgets = [(0, self.showRegion),
- (0, self.compResolution),
- (0, self.mapScale),
- (0, self.onRenderGauge),
- (0, self.gotogcp),
- (1, self.toggleStatus),
- (2, self.maskInfo),
- (3, self.autoRender)]
+ widgets = [(0, self.statusbarWin['region']),
+ (0, self.statusbarWin['resolution']),
+ (0, self.statusbarWin['mapscale']),
+ (0, self.statusbarWin['progress']),
+ (0, self.statusbarWin['goto']),
+ (1, self.statusbarWin['toggle']),
+ (2, self.statusbarWin['mask']),
+ (3, self.statusbarWin['render'])]
for idx, win in widgets:
rect = self.statusbar.GetFieldRect(idx)
wWin, hWin = win.GetBestSize()
if idx == 0: # show region / mapscale / process bar
# -> size
- if win == self.onRenderGauge:
+ if win == self.statusbarWin['progress']:
wWin = rect.width - 6
# -> position
- # if win == self.showRegion:
+ # if win == self.statusbarWin['region']:
# x, y = rect.x + rect.width - wWin, rect.y - 1
# align left
# else:
@@ -915,8 +906,7 @@
img = self.MapWindow.img
if not img:
gcmd.GMessage(parent = self,
- message = _("Nothing to render (empty map). Operation canceled."),
- msgType = 'info')
+ message = _("Nothing to render (empty map). Operation canceled."))
return
filetype, ltype = gdialogs.GetImageHandlers(img)
@@ -986,449 +976,6 @@
"""!Get map window"""
return self.MapWindow
- def OnQueryDisplay(self, event):
- """!Query currrent raster/vector map layers (display mode)
- """
- if self.toolbars['map'].GetAction() == 'displayAttrb': # select previous action
- self.toolbars['map'].SelectDefault(event)
- return
-
- self.toolbars['map'].action['desc'] = 'displayAttrb'
-
- # switch GIS Manager to output console to show query results
- self._layerManager.notebook.SetSelection(1)
-
- self.MapWindow.mouse['use'] = "query"
- self.MapWindow.mouse['box'] = "point"
- self.MapWindow.zoomtype = 0
-
- # change the cursor
- self.MapWindow.SetCursor(self.cursors["cross"])
-
- def OnQueryModify(self, event):
- """
- Query vector map layer (edit mode)
- """
- if self.toolbars['map'].GetAction() == 'modifyAttrb': # select previous action
- self.toolbars['map'].SelectDefault(event)
- return
-
- self.toolbars['map'].action['desc'] = 'modifyAttrb'
-
- self.MapWindow.mouse['use'] = "queryVector"
- self.MapWindow.mouse['box'] = "point"
- self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
- self.MapWindow.zoomtype = 0
-
- # change the cursor
- self.MapWindow.SetCursor(self.cursors["cross"])
-
- def QueryMap(self, x, y):
- """!Query map layer features
-
- Currently only raster and vector map layers are supported.
-
- @param x,y coordinates
- """
- #set query snap distance for v.what at mapunit 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))
-
- num = 0
- for layer in self.tree.GetSelections():
- type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
- if type in ('raster', 'rgb', 'his',
- 'vector', 'thememap', 'themechart'):
- num += 1
-
- if num < 1:
- dlg = wx.MessageDialog(parent = self,
- message = _('No raster or vector map layer selected for querying.'),
- caption = _('No map layer selected'),
- style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
- dlg.ShowModal()
- dlg.Destroy()
- return
-
- mapname = None
- raststr = ''
- vectstr = ''
- rcmd = ['r.what', '--q']
- vcmd = ['v.what', '--q']
- for layer in self.tree.GetSelections():
- type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
- dcmd = self.tree.GetPyData(layer)[0]['cmd']
- name = utils.GetLayerNameFromCmd(dcmd)
- if name == '':
- continue
- if type in ('raster', 'rgb', 'his'):
- raststr += "%s," % name
- elif type in ('vector', 'thememap', 'themechart'):
- vectstr += "%s," % name
-
- # 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 raststr != '':
- rcmd.append('-f')
- rcmd.append('input=%s' % raststr.rstrip(','))
- rcmd.append('east_north=%f,%f' % (float(east), float(north)))
-
- if vectstr != '':
- # check for vector maps open to be edited
- digitToolbar = self.toolbars['vdigit']
- if digitToolbar:
- map = digitToolbar.GetLayer().GetName()
- vect = []
- for vector in vectstr.split(','):
- if map == vector:
- self._layerManager.goutput.WriteWarning("Vector map <%s> "
- "opened for editing - skipped." % map)
- continue
- vect.append(vector)
- vectstr = ','.join(vect)
-
- if len(vectstr) <= 1:
- self._layerManager.goutput.WriteCmdLog("Nothing to query.")
- return
-
- vcmd.append('-a')
- vcmd.append('map=%s' % vectstr.rstrip(','))
- vcmd.append('east_north=%f,%f' % (float(east), float(north)))
- vcmd.append('distance=%f' % float(qdist))
-
- # parse query command(s)
- if self._layerManager:
- if raststr:
- self._layerManager.goutput.RunCmd(rcmd,
- compReg=False,
- onDone = self._QueryMapDone)
- if vectstr:
- self._layerManager.goutput.RunCmd(vcmd,
- onDone = self._QueryMapDone)
- else:
- if raststr:
- gcmd.RunCommand(rcmd)
- if vectstr:
- gcmd.RunCommand(vcmd)
-
- def _QueryMapDone(self, 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 os.environ.has_key('GRASS_REGION'):
- del os.environ["GRASS_REGION"]
- elif os.environ.has_key('GRASS_REGION'):
- 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':
- wx.MessageBox(parent=self,
- message=_("No vector map selected for querying."),
- caption=_("Vector querying"),
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
- return
-
- if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
- grass.gisenv()['MAPSET']:
- wx.MessageBox(parent=self,
- message=_("Only vector map from the current mapset can be modified."),
- caption=_("Vector querying"),
- style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
- 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.dialogs['attributes'] is None:
- self.dialogs['attributes'] = \
- dbm_dialogs.DisplayAttributesDialog(parent=self.MapWindow,
- map=mapName,
- query=((east, north), qdist),
- pos=posWindow,
- action="update")
- 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))
- else:
- self.dialogs['attributes'].UpdateDialog(query=((east, north), qdist))
-
- cats = self.dialogs['attributes'].GetCats()
-
- try:
- qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)[0]
- except IndexError:
- qlayer = None
-
- if self.dialogs['attributes'].mapDBInfo and cats:
- # 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.toolbars['map']:
- self.toolbars['map'].OnTool(event)
- action = self.toolbars['map'].GetAction()
-
- point = wx.GetMousePosition()
- toolsmenu = wx.Menu()
- # Add items to the menu
- display = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
- text=_("Query raster/vector map(s) (display mode)"),
- kind=wx.ITEM_CHECK)
- toolsmenu.AppendItem(display)
- self.Bind(wx.EVT_MENU, self.OnQueryDisplay, display)
- numLayers = 0
- for layer in self.tree.GetSelections():
- type = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
- if type in ('raster', 'rgb', 'his',
- 'vector', 'thememap', 'themechart'):
- numLayers += 1
- if numLayers < 1:
- display.Enable(False)
-
- if action == "displayAttrb":
- display.Check(True)
-
- modify = wx.MenuItem(parentMenu=toolsmenu, id=wx.ID_ANY,
- text=_("Query vector map (edit mode)"),
- kind=wx.ITEM_CHECK)
- toolsmenu.AppendItem(modify)
- self.Bind(wx.EVT_MENU, self.OnQueryModify, modify)
- digitToolbar = self.toolbars['vdigit']
- if self.tree.layer_selected:
- layer_selected = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer']
- if layer_selected.GetType() != 'vector' or \
- (digitToolbar and \
- digitToolbar.GetLayer() == layer_selected):
- modify.Enable(False)
- else:
- if action == "modifyAttrb":
- modify.Check(True)
-
- self.PopupMenu(toolsmenu)
- toolsmenu.Destroy()
-
- def AddTmpVectorMapLayer(self, name, cats, useId=False, addLayer=True):
- """
- Add temporal vector map layer to map composition
-
- @param name name of map layer
- @param useId use feature id instead of category
- """
- # color settings from ATM
- color = UserSettings.Get(group='atm', key='highlight', subkey='color')
- colorStr = str(color[0]) + ":" + \
- str(color[1]) + ":" + \
- str(color[2])
-
- # icon used in vector display and its size
- icon = ''
- size = 0
- vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
- for p in vparam:
- if '=' in p:
- parg,pval = p.split('=')
- if parg == 'icon': icon = pval
- elif parg == 'size': size = int(pval)
-
- pattern = ["d.vect",
- "map=%s" % name,
- "color=%s" % colorStr,
- "fcolor=%s" % colorStr,
- "width=%d" % UserSettings.Get(group='atm', key='highlight', subkey='width')]
- if icon != '':
- pattern.append('icon=%s' % icon)
- if size > 0:
- pattern.append('size=%i' % size)
-
- if useId:
- cmd = pattern
- cmd.append('-i')
- cmd.append('cats=%s' % str(cats))
- else:
- cmd = []
- for layer in cats.keys():
- cmd.append(copy.copy(pattern))
- lcats = cats[layer]
- cmd[-1].append("layer=%d" % layer)
- cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
-
- # if self.icon:
- # cmd.append("icon=%s" % (self.icon))
- # if self.pointsize:
- # cmd.append("size=%s" % (self.pointsize))
-
- if addLayer:
- if useId:
- return self.Map.AddLayer(type='vector', name=globalvar.QUERYLAYER, command=cmd,
- l_active=True, l_hidden=True, l_opacity=1.0)
- else:
- return self.Map.AddLayer(type='command', name=globalvar.QUERYLAYER, command=cmd,
- l_active=True, l_hidden=True, l_opacity=1.0)
- else:
- return cmd
-
- def OnAnalyze(self, event):
- """
- Analysis tools menu
- """
- point = wx.GetMousePosition()
- toolsmenu = wx.Menu()
- # Add items to the menu
- measure = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["measure"].GetLabel())
- measure.SetBitmap(Icons["measure"].GetBitmap(self.iconsize))
- toolsmenu.AppendItem(measure)
- self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
-
- profile = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["profile"].GetLabel())
- profile.SetBitmap(Icons["profile"].GetBitmap(self.iconsize))
- toolsmenu.AppendItem(profile)
- self.Bind(wx.EVT_MENU, self.Profile, profile)
-
- histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, Icons["histogram"].GetLabel())
- histogram.SetBitmap(Icons["histogram"].GetBitmap(self.iconsize))
- toolsmenu.AppendItem(histogram)
- self.Bind(wx.EVT_MENU, self.Histogram, histogram)
-
- # Popup the menu. If an item is selected then its handler
- # will be called before PopupMenu returns.
- self.PopupMenu(toolsmenu)
- toolsmenu.Destroy()
-
- def OnMeasure(self, event):
- """
- Init measurement routine that calculates
- map distance along transect drawn on
- map display
- """
-
- self.totaldist = 0.0 # total measured distance
-
- # switch GIS Manager to output console to show measure results
- self._layerManager.notebook.SetSelection(1)
-
- # 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']
- style = self._layerManager.goutput.cmd_output.StyleCommand
- self._layerManager.goutput.WriteLog(_('Measuring distance') + ' ('
- + units + '):',
- style)
- else:
- self._layerManager.goutput.WriteLog(_('Measuring distance:'),
- style)
-
- def MeasureDist(self, beginpt, endpt):
- """!Calculate map distance from screen distance
- and print to output window
- """
- if self._layerManager.notebook.GetSelection() != 1:
- self._layerManager.notebook.SetSelection(1)
-
- 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 = 'segment = %s %s\ttotal distance = %s %s\tbearing = %d deg' \
- % (strdist,dunits,strtotdist,tdunits,angle)
- else:
- mstring = 'segment = %s %s\ttotal distance = %s %s' \
- % (strdist,dunits,strtotdist,tdunits)
-
- self._layerManager.goutput.WriteLog(mstring)
-
- return dist
-
- def Profile(self, event):
- """
- Init profile canvas and tools
- """
- raster = []
- if self.tree.layer_selected and \
- self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
- raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-
- self.profile = profile.ProfileFrame(self,
- id=wx.ID_ANY, pos=wx.DefaultPosition, size=(700,300),
- style=wx.DEFAULT_FRAME_STYLE, rasterList=raster)
- self.profile.Show()
- # Open raster select dialog to make sure that a raster (and the desired raster)
- # is selected to be profiled
- self.profile.OnSelectRaster(None)
-
def FormatDist(self, dist):
"""!Format length numbers and units in a nice way,
as a function of length. From code by Hamish Bowman
@@ -1475,178 +1022,12 @@
return (outdist, outunits)
-
- def Histogram(self, event):
- """
- Init histogram display canvas and tools
- """
- self.histogram = histogram.HistFrame(self,
- id=wx.ID_ANY, size=globalvar.HIST_WINDOW_SIZE,
- style=wx.DEFAULT_FRAME_STYLE)
-
- #show new display
- self.histogram.Show()
- self.histogram.Refresh()
- self.histogram.Update()
-
-
- def OnDecoration(self, event):
- """
- Decorations overlay menu
- """
- point = wx.GetMousePosition()
- decmenu = wx.Menu()
- # Add items to the menu
- AddScale = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addbarscale"].GetLabel())
- AddScale.SetBitmap(Icons["addbarscale"].GetBitmap(self.iconsize))
- decmenu.AppendItem(AddScale)
- self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
-
- AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addlegend"].GetLabel())
- AddLegend.SetBitmap(Icons["addlegend"].GetBitmap(self.iconsize))
- decmenu.AppendItem(AddLegend)
- self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
-
- AddText = wx.MenuItem(decmenu, wx.ID_ANY, Icons["addtext"].GetLabel())
- AddText.SetBitmap(Icons["addtext"].GetBitmap(self.iconsize))
- decmenu.AppendItem(AddText)
- self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
-
- # Popup the menu. If an item is selected then its handler
- # will be called before PopupMenu returns.
- self.PopupMenu(decmenu)
- decmenu.Destroy()
-
- def OnAddBarscale(self, event):
- """
- Handler for scale/arrow map decoration menu selection.
- """
- if self.dialogs['barscale']:
- return
-
- id = 0 # unique index for overlay layer
-
- # If location is latlon, only display north arrow (scale won't work)
- # proj = self.Map.projinfo['proj']
- # if proj == 'll':
- # barcmd = 'd.barscale -n'
- # else:
- # barcmd = 'd.barscale'
-
- # decoration overlay control dialog
- self.dialogs['barscale'] = \
- gdialogs.DecorationDialog(parent=self, title=_('Scale and North arrow'),
- size=(350, 200),
- style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
- cmd=['d.barscale', 'at=0,5'],
- ovlId=id,
- name='barscale',
- checktxt = _("Show/hide scale and North arrow"),
- ctrltxt = _("scale object"))
-
- self.dialogs['barscale'].CentreOnParent()
- ### dialog cannot be show as modal - in the result d.barscale is not selectable
- ### self.dialogs['barscale'].ShowModal()
- self.dialogs['barscale'].Show()
- self.MapWindow.mouse['use'] = 'pointer'
-
- def OnAddLegend(self, event):
- """
- Handler for legend map decoration menu selection.
- """
- if self.dialogs['legend']:
- return
-
- id = 1 # index for overlay layer in render
-
- cmd = ['d.legend', 'at=5,50,2,5']
- if self.tree.layer_selected and \
- self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
- cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
-
- # Decoration overlay control dialog
- self.dialogs['legend'] = \
- gdialogs.DecorationDialog(parent=self, title=('Legend'),
- size=(350, 200),
- style=wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
- cmd=cmd,
- ovlId=id,
- name='legend',
- checktxt = _("Show/hide legend"),
- ctrltxt = _("legend object"))
-
- self.dialogs['legend'].CentreOnParent()
- ### dialog cannot be show as modal - in the result d.legend is not selectable
- ### self.dialogs['legend'].ShowModal()
- self.dialogs['legend'].Show()
- self.MapWindow.mouse['use'] = 'pointer'
-
- def OnAddText(self, event):
- """
- Handler for text decoration menu selection.
- """
- if self.MapWindow.dragid > -1:
- id = self.MapWindow.dragid
- else:
- # index for overlay layer in render
- if len(self.MapWindow.textdict.keys()) > 0:
- id = self.MapWindow.textdict.keys()[-1] + 1
- else:
- id = 101
-
- self.dialogs['text'] = gdialogs.TextLayerDialog(parent=self, ovlId=id,
- title=_('Add text layer'),
- size=(400, 200))
- self.dialogs['text'].CenterOnParent()
-
- # If OK button pressed in decoration control dialog
- if self.dialogs['text'].ShowModal() == wx.ID_OK:
- text = self.dialogs['text'].GetValues()['text']
- active = self.dialogs['text'].GetValues()['active']
- coords, w, h = self.MapWindow.TextBounds(self.dialogs['text'].GetValues())
-
- # delete object if it has no text or is not active
- if text == '' or active == False:
- try:
- self.MapWindow.pdc.ClearId(id)
- self.MapWindow.pdc.RemoveId(id)
- del self.MapWindow.textdict[id]
- except:
- pass
- return
-
- self.MapWindow.pdc.ClearId(id)
- self.MapWindow.pdc.SetId(id)
- self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
-
- self.MapWindow.Draw(self.MapWindow.pdcDec, img=self.MapWindow.textdict[id],
- drawid=id, pdctype='text', coords=coords)
-
- self.MapWindow.UpdateMap(render=False, renderVector=False)
-
- self.MapWindow.mouse['use'] = 'pointer'
-
- 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.
"""
- if self.toolbars['gcpdisp']:
- self.MapWindow.ZoomToMap(layer = self.Map.GetListOfLayers())
- else:
- self.MapWindow.ZoomToMap()
+ self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
def OnZoomToRaster(self, event):
"""!
@@ -1717,12 +1098,11 @@
def SetProperties(self, render=False, mode=0, showCompExtent=False,
constrainRes=False, projection=False):
"""!Set properies of map display window"""
- self.autoRender.SetValue(render)
- self.toggleStatus.SetSelection(mode)
+ self.statusbarWin['render'].SetValue(render)
+ self.statusbarWin['toggle'].SetSelection(mode)
self.StatusbarUpdate()
- self.showRegion.SetValue(showCompExtent)
- self.compResolution.SetValue(constrainRes)
- self.projInfo.SetValue(projection)
+ self.statusbarWin['region'].SetValue(showCompExtent)
+ self.statusbarWin['resolution'].SetValue(constrainRes)
if showCompExtent:
self.MapWindow.regionCoords = []
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gdialogs.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gdialogs.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gdialogs.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,19 +1,26 @@
-"""
+"""!
@package gdialogs.py
- at brief Common dialog used in wxGUI.
+ at brief Various dialogs used in wxGUI.
List of classes:
+ - ElementDialog
+ - LocationDialog
+ - MapsetDialog
- NewVectorDialog
- SavedRegion
- DecorationDialog
- TextLayerDialog
- LoadMapLayersDialog
- - MultiImportDialog
+ - ImportDialog
+ - GdalImportDialog
+ - DxfImportDialog
- LayersList (used by MultiImport)
- SetOpacityDialog
+ - StaticWrapText
+ - ImageSizeDialog
-(C) 2008 by the GRASS Development Team
+(C) 2008-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
@@ -25,7 +32,6 @@
import os
import sys
import re
-import glob
import wx
import wx.lib.filebrowsebutton as filebrowse
@@ -34,109 +40,211 @@
from grass.script import core as grass
import gcmd
-import grassenv
import globalvar
import gselect
import menuform
import utils
from preferences import globalSettings as UserSettings
-class NewVectorDialog(wx.Dialog):
- """Create new vector map layer"""
- def __init__(self, parent, id, title, disableAdd=False, disableTable=False,
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+class ElementDialog(wx.Dialog):
+ """!General dialog to choose given element (location, mapset, vector map, etc.)"""
+ def __init__(self, parent, title, label, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+ **kwargs):
+
+ wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
+
+ 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)
+
+ self.label = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = label)
+
+ self.element = None # must be defined
+
+ self.__Layout()
+
+ def PostInit(self):
+ self.element.SetFocus()
+ self.element.Bind(wx.EVT_TEXT, self.OnElement)
+
+ 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)
+ self.dataSizer.Add(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()
+
+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:"))
- wx.Dialog.__init__(self, parent, id, title, style=style)
+ self.element = gselect.LocationSelect(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE)
- self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
+ self.element1 = gselect.MapsetSelect(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE,
+ setItems = False)
+
+ self.PostInit()
+
+ self.__Layout()
+ self.SetMinSize(self.GetSize())
- 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)
+ 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.label = wx.StaticText(parent=self.panel, id=wx.ID_ANY,
- label=_("Name for new vector map:"))
- self.mapName = gselect.Select(parent=self.panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
- type='vector', mapsets=[grassenv.GetGRASSVariable('MAPSET'),])
- self.mapName.SetFocus()
+ 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()
- self.table = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
- label=_("Create attribute table"))
+ if location:
+ dbase = grass.gisenv()['GISDBASE']
+ self.element1.SetItems(utils.GetListOfMapsets(dbase, location, selectable = True))
+ self.element1.SetSelection(0)
+ mapset = self.element1.GetStringSelection()
+
+ if location and mapset:
+ self.btnOK.Enable(True)
+ else:
+ self.btnOK.Enable(False)
+
+ def GetValues(self):
+ """!Get location, mapset"""
+ return (self.GetElement(), self.element1.GetStringSelection())
+
+class MapsetDialog(ElementDialog):
+ """!Dialog used to select mapset"""
+ def __init__(self, parent, title = _("Select mapset in GRASS location"),
+ location = None, id = wx.ID_ANY):
+ ElementDialog.__init__(self, parent, title, label = _("Name of mapset:"))
+ if location:
+ self.SetTitle(self.GetTitle() + ' <%s>' % location)
+ else:
+ self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
+
+ self.element = gselect.MapsetSelect(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE)
+
+ self.PostInit()
+
+ self.__Layout()
+ self.SetMinSize(self.GetSize())
+
+ def __Layout(self):
+ """!Do layout"""
+ self.dataSizer.Add(self.element, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=1)
+
+ self.panel.SetSizer(self.sizer)
+ self.sizer.Fit(self)
+
+ def GetMapset(self):
+ return self.GetElement()
+
+class NewVectorDialog(ElementDialog):
+ """!Dialog for creating new vector map"""
+ def __init__(self, parent, id, title, disableAdd=False, disableTable=False,
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+
+ ElementDialog.__init__(self, parent, title, label = _("Name for new vector map:"))
+
+ self.element = gselect.Select(parent=self.panel, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+ type='vector', mapsets=[grass.gisenv()['MAPSET'],])
+
+ self.table = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
+ label = _("Create attribute table"))
self.table.SetValue(True)
if disableTable:
self.table.Enable(False)
- self.addbox = wx.CheckBox(parent=self.panel,
- label=_('Add created map into layer tree'), style = wx.NO_BORDER)
+ 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.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
- self.mapName.Bind(wx.EVT_TEXT, self.OnMapName)
+ self.PostInit()
self.__Layout()
-
self.SetMinSize(self.GetSize())
-
+
def OnMapName(self, event):
- """Name for vector map layer given"""
- if len(event.GetString()) > 0:
- self.btnOK.Enable(True)
- else:
- self.btnOK.Enable(False)
-
+ """!Name for vector map layer given"""
+ self.OnElement(event)
+
def __Layout(self):
- """Do layout"""
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- dataSizer = wx.BoxSizer(wx.VERTICAL)
- dataSizer.Add(self.label, proportion=0,
- flag=wx.ALL, border=1)
- dataSizer.Add(self.mapName, proportion=0,
+ """!Do layout"""
+ self.dataSizer.Add(self.element, proportion=0,
flag=wx.EXPAND | wx.ALL, border=1)
- dataSizer.Add(self.table, proportion=0,
+ self.dataSizer.Add(self.table, proportion=0,
flag=wx.EXPAND | wx.ALL, border=1)
-
- dataSizer.AddSpacer(5)
- dataSizer.Add(item=self.addbox, proportion=0,
+ self.dataSizer.AddSpacer(5)
+
+ self.dataSizer.Add(item=self.addbox, proportion=0,
flag=wx.EXPAND | wx.ALL, border=1)
-
- # buttons
- btnSizer = wx.StdDialogButtonSizer()
- btnSizer.AddButton(self.btnCancel)
- btnSizer.AddButton(self.btnOK)
- btnSizer.Realize()
+
+ self.panel.SetSizer(self.sizer)
+ self.sizer.Fit(self)
- sizer.Add(item=dataSizer, proportion=1,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-
- sizer.Add(item=btnSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
-
- self.panel.SetSizer(sizer)
- sizer.Fit(self)
-
def GetName(self):
- """Return (mapName, overwrite)"""
- mapName = self.mapName.GetValue().split('@', 1)[0]
-
- return mapName
-
-def CreateNewVector(parent, cmdDef, title=_('Create new vector map'),
+ """!Return (mapName, overwrite)"""
+ return self.GetElement().split('@', 1)[0]
+
+def CreateNewVector(parent, cmd, title=_('Create new vector map'),
exceptMap=None, log=None, disableAdd=False, disableTable=False):
- """Create new vector map layer
+ """!Create new vector map layer
- @cmdList tuple/list (cmd list, output paramater)
+ @cmd cmd (prog, **kwargs)
@return tuple (name of create vector map, add to layer tree)
@return None of failure
"""
- cmd = cmdDef[0]
dlg = NewVectorDialog(parent, wx.ID_ANY, title,
disableAdd, disableTable)
if dlg.ShowModal() == wx.ID_OK:
@@ -151,13 +259,14 @@
if outmap == '': # should not happen
return (None, None)
- cmd.append("%s=%s" % (cmdDef[1], outmap))
+ cmd[1][cmd[2]] = outmap
try:
listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
except KeyError:
listOfVectors = []
+ 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 "
@@ -166,21 +275,23 @@
caption=_("Overwrite?"),
style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
if dlgOw.ShowModal() == wx.ID_YES:
- cmd.append('--overwrite')
+ overwrite = True
else:
dlgOw.Destroy()
return (None, None)
if UserSettings.Get(group='cmd', key='overwrite', subkey='enabled') is True:
- cmd.append('--overwrite')
+ overwrite = True
try:
- gcmd.Command(cmd)
+ gcmd.RunCommand(prog = cmd[0],
+ overwrite = overwrite,
+ **cmd[1])
except gcmd.GException, e:
gcmd.GError(parent = self,
message = e)
return (None, None)
-
+
#
# create attribute table
#
@@ -203,79 +314,74 @@
table = outmap,
key = key,
layer = '1')
-
+
# return fully qualified map name
if '@' not in outmap:
- outmap += '@' + grassenv.GetGRASSVariable('MAPSET')
+ outmap += '@' + grass.gisenv()['MAPSET']
if log:
log.WriteLog(_("New vector map <%s> created") % outmap)
return (outmap, dlg.addbox.IsChecked())
-
+
return (None, dlg.addbox.IsChecked())
class SavedRegion(wx.Dialog):
- def __init__(self, parent, id, title="", pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.DEFAULT_DIALOG_STYLE,
- loadsave='load'):
+ 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?
"""
- Loading and saving of display extents to saved region file
- """
- wx.Dialog.__init__(self, parent, id, title, pos, size, style)
+ 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 = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Load region:"))
- box.Add(item=label, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
- self.selection = gselect.Select(parent=self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
- type='windows')
- self.selection.SetFocus()
- box.Add(item=self.selection, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
- self.selection.Bind(wx.EVT_TEXT, self.OnSelection)
-
+ label.SetLabel(_("Load region:"))
+ selection = gselect.Select(parent=self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+ type='windows')
elif loadsave == 'save':
- label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Save region:"))
- box.Add(item=label, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
- self.textentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="",
- size=globalvar.DIALOG_TEXTCTRL_SIZE)
- self.textentry.SetFocus()
- box.Add(item=self.textentry, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
- self.textentry.Bind(wx.EVT_TEXT, self.OnText)
-
+ label.SetLabel(_("Save region:"))
+ selection = gselect.Select(parent=self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE,
+ type='windows', mapsets = [grass.gisenv()['MAPSET']])
+
+ box.Add(item=selection, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
+ selection.SetFocus()
+ selection.Bind(wx.EVT_TEXT, self.OnRegion)
+
sizer.Add(item=box, proportion=0, flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL,
border=5)
-
+
line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
sizer.Add(item=line, proportion=0,
flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=5)
-
+
btnsizer = wx.StdDialogButtonSizer()
-
- btn = wx.Button(self, wx.ID_OK)
+
+ btn = wx.Button(parent = self, id = wx.ID_OK)
btn.SetDefault()
btnsizer.AddButton(btn)
-
- btn = wx.Button(self, wx.ID_CANCEL)
+
+ 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)
-
- def OnSelection(self, event):
+ self.Layout()
+
+ def OnRegion(self, event):
self.wind = event.GetString()
-
- def OnText(self, event):
- self.wind = event.GetString()
-
+
class DecorationDialog(wx.Dialog):
"""
Controls setting options and displaying/hiding map overlay decorations
@@ -408,13 +514,13 @@
self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
def OnCancel(self, event):
- """Cancel dialog"""
+ """!Cancel dialog"""
self.parent.dialogs['barscale'] = None
self.Destroy()
def OnOK(self, event):
- """Button 'OK' pressed"""
+ """!Button 'OK' pressed"""
# enable or disable overlay
self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
@@ -425,7 +531,7 @@
self.OnCancel(None)
def GetOptData(self, dcmd, layer, params, propwin):
- """Process decoration layer data"""
+ """!Process decoration layer data"""
# update layer data
if params:
self.parent.MapWindow.overlays[self.ovlId]['params'] = params
@@ -566,21 +672,21 @@
self.Bind(wx.EVT_SPINCTRL, self.OnRotation, self.rotation)
def OnRefit(self, event):
- """Resize text entry to match text"""
+ """!Resize text entry to match text"""
self.sizer.Fit(self)
def OnText(self, event):
- """Change text string"""
+ """!Change text string"""
self.currText = event.GetString()
def OnRotation(self, event):
- """Change rotation"""
+ """!Change rotation"""
self.currRot = event.GetInt()
event.Skip()
def OnSelectFont(self, event):
- """Change font"""
+ """!Change font"""
data = wx.FontData()
data.EnableEffects(True)
data.SetColour(self.currClr) # set colour
@@ -601,7 +707,7 @@
dlg.Destroy()
def GetValues(self):
- """Get text properties"""
+ """!Get text properties"""
return { 'text' : self.currText,
'font' : self.currFont,
'color' : self.currClr,
@@ -610,7 +716,7 @@
'active' : self.chkbox.IsChecked() }
class LoadMapLayersDialog(wx.Dialog):
- """Load selected map layers (raster, vector) into layer tree"""
+ """!Load selected map layers (raster, vector) into layer tree"""
def __init__(self, parent, title, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title, style=style)
@@ -628,16 +734,10 @@
# buttons
#
btnCancel = wx.Button(self, wx.ID_CANCEL)
- btnOk = wx.Button(self, wx.ID_OK, _("Load") )
+ btnOk = wx.Button(self, wx.ID_OK, _("&Load") )
btnOk.SetDefault()
-
+
#
- # bindigs
- #
- #btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
- #btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
-
- #
# sizers & do layout
#
btnSizer = wx.StdDialogButtonSizer()
@@ -672,19 +772,24 @@
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(True)
+ 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 = wx.ComboBox(parent=self, id=wx.ID_ANY,
- style=wx.CB_SIMPLE | wx.CB_READONLY,
- choices=utils.ListOfMapsets(get = 'accessible'),
- size=(250,-1))
- self.mapset.SetStringSelection(grassenv.GetGRASSVariable("MAPSET"))
+ self.mapset = gselect.MapsetSelect(parent = self)
+ self.mapset.SetStringSelection(grass.gisenv()['MAPSET'])
bodySizer.Add(item=self.mapset,
- pos=(1,1))
+ pos=(1,1), span=(1, 2))
# map name filter
bodySizer.Add(item=wx.StaticText(parent=self, label=_("Filter:")),
@@ -696,7 +801,7 @@
size=(250,-1))
bodySizer.Add(item=self.filter,
flag=wx.EXPAND,
- pos=(2,1))
+ pos=(2,1), span=(1, 2))
# layer list
bodySizer.Add(item=wx.StaticText(parent=self, label=_("List of maps:")),
@@ -707,29 +812,27 @@
choices=[])
bodySizer.Add(item=self.layers,
flag=wx.EXPAND,
- pos=(3,1))
+ 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
+ """!Load list of map layers
@param type layer type ('raster' or 'vector')
@param mapset mapset name
"""
- list = gcmd.Command(['g.mlist',
- 'type=%s' % type,
- 'mapset=%s' % mapset])
-
- self.map_layers = []
- for map in list.ReadStdOutput():
- self.map_layers.append(map)
-
+ try:
+ self.map_layers = grass.mlist_grouped(type=type, mapset=mapset)[mapset]
+ except KeyError:
+ self.map_layers = []
+
self.layers.Set(self.map_layers)
# check all items by default
@@ -737,7 +840,7 @@
self.layers.Check(item)
def OnChangeParams(self, event):
- """Filter parameters changed by user"""
+ """!Filter parameters changed by user"""
# update list of layer to be loaded
self.LoadMapLayers(self.layerType.GetStringSelection()[:4],
self.mapset.GetStringSelection())
@@ -745,34 +848,45 @@
event.Skip()
def OnMenu(self, event):
- """Table description area, context menu"""
+ """!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.OnDeselectAll, id=self.popupDataID2)
+ 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, _("Deselect 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"""
+ """!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"""
+ """!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"""
+ """!Apply filter for map names"""
if len(event.GetString()) == 0:
self.layers.Set(self.map_layers)
return
@@ -790,8 +904,16 @@
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"""
+ """!Return list of checked map layers"""
layerNames = []
for indx in self.layers.GetSelections():
# layers.append(self.layers.GetStringSelec(indx))
@@ -807,249 +929,39 @@
return layerNames
def GetLayerType(self):
- """Get selected layer type"""
+ """!Get selected layer type"""
return self.layerType.GetStringSelection()
-class MultiImportDialog(wx.Dialog):
- """!Import dxf layers"""
+class ImportDialog(wx.Dialog):
+ """!Dialog for bulk import of various data (base class)"""
def __init__(self, parent, type,
- id=wx.ID_ANY, title=_("Multiple import"),
- link = False,
- style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
-
+ id = wx.ID_ANY, title = _("Multiple import"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
self.parent = parent # GMFrame
self.importType = type
- self.link = link # Link or import data (only for GDAL/OGR)
self.commandId = -1 # id of running command
-
- wx.Dialog.__init__(self, parent, id, title, style=style)
-
- self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
- self.inputTitle = _("Source name")
+ wx.Dialog.__init__(self, parent, id, title, style=style,
+ name = "MultiImportDialog")
- self.inputBox = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
- label=" %s " % self.inputTitle)
+ 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())
-
- #
- # input
- #
- if self.importType == 'dxf':
- inputFile = 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.OnSetInput,
- fileMask="DXF File (*.dxf)|*.dxf")
- self.input = { 'file' : [_("DXF file:"),
- inputFile,
- list()] }
- self.inputType = 'file'
- else:
- self.typeRadio = wx.RadioBox(parent = self.panel, id = wx.ID_ANY,
- label = _('Source type'),
- style = wx.RA_SPECIFY_COLS,
- choices = [_("File"),
- _("Directory"),
- _("Database"),
- _("Protocol")])
- self.typeRadio.SetSelection(0)
- self.Bind(wx.EVT_RADIOBOX, self.OnChangeType)
-
- # input widgets
- if self.importType == 'gdal':
- filemask = 'GeoTIFF (*.tif)|*.tif'
- else:
- filemask = 'ESRI Shapefile (*.shp)|*.shp'
- inputFile = filebrowse.FileBrowseButton(parent=self.panel, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
- dialogTitle=_('Choose input file'),
- buttonText=_('Browse'),
- startDirectory=os.getcwd(),
- changeCallback=self.OnSetInput,
- fileMask=filemask)
-
- inputDir = filebrowse.DirBrowseButton(parent=self.panel, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
- dialogTitle=_('Choose input directory'),
- buttonText=_('Browse'),
- startDirectory=os.getcwd(),
- changeCallback=self.OnSetInput)
- inputDir.Hide()
-
- inputDbFile = filebrowse.FileBrowseButton(parent=self.panel, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
- dialogTitle=_('Choose file'),
- buttonText=_('Browse'),
- startDirectory=os.getcwd(),
- changeCallback=self.OnSetInput)
- inputDbFile.Hide()
-
- inputDbText = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
- inputDbText.Hide()
- inputDbText.Bind(wx.EVT_TEXT, self.OnSetInput)
-
- inputDbChoice = wx.Choice(parent = self.panel, id = wx.ID_ANY)
- inputDbChoice.Hide()
- inputDbChoice.Bind(wx.EVT_CHOICE, self.OnSetInput)
-
- inputPro = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
- inputPro.Hide()
- inputPro.Bind(wx.EVT_TEXT, self.OnSetInput)
-
- # format widget
- self.formatText = wx.StaticText(self.panel, id=wx.ID_ANY, label=_("Format:"))
- self.format = wx.Choice(parent = self.panel, id = wx.ID_ANY, size=(300, -1))
- self.format.Bind(wx.EVT_CHOICE, self.OnSetFormat)
-
- if self.importType == 'gdal':
- ret = gcmd.RunCommand('r.in.gdal',
- quiet = True, read = True,
- flags = 'f')
- else: # ogr
- ret = gcmd.RunCommand('v.in.ogr',
- quiet = True, read = True,
- flags = 'f')
-
- self.input = { 'file' : [_("File:"),
- inputFile,
- list()],
- 'dir' : [_("Directory:"),
- inputDir,
- list()],
- 'db' : [_("Database:"),
- inputDbFile,
- list()],
- 'pro' : [_("Protocol:"),
- inputPro,
- list()],
- 'db-win' : { 'file' : inputDbFile,
- 'text' : inputDbText,
- 'choice' : inputDbChoice },
- }
-
- self.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' }
-
- if ret:
- for line in ret.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'):
- self.input['db'][2].append(format)
- elif format in ('GeoJSON',
- 'OGC Web Coverage Service',
- 'OGC Web Map Service',
- 'HTTP Fetching Wrapper'):
- self.input['pro'][2].append(format)
- else:
- self.input['file'][2].append(format)
- self.input['dir'][2].append(format)
-
- self.inputType = 'file'
-
- self.format.SetItems(self.input[self.inputType][2])
-
- if self.importType == 'gdal':
- self.format.SetStringSelection('GeoTIFF')
- elif self.importType == 'ogr':
- self.format.SetStringSelection('ESRI Shapefile')
- self.inputText = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
- label = self.input[self.inputType][0],
- size = (75, -1))
-
#
# list of layers
#
self.list = LayersList(self.panel)
self.list.LoadData()
-
- self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY)
- if link:
- self.add.SetLabel(_("Add linked layers into layer tree"))
- else:
- self.add.SetLabel(_("Add imported layers into layer tree"))
-
- if not link and self.importType in ('gdal', 'ogr'):
- self.overrideCheck = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
- label=_("Override projection (use location's projection)"))
- self.overrideCheck.SetValue(True)
-
- self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
-
+
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
#
@@ -1058,52 +970,19 @@
self.btn_cancel.SetToolTipString(_("Close dialog"))
self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnCancel)
# run
- if link:
- self.btn_run = wx.Button(parent=self.panel, id=wx.ID_OK, label= _("&Link"))
- self.btn_run.SetToolTipString(_("Link selected layers"))
- else:
- self.btn_run = wx.Button(parent=self.panel, id=wx.ID_OK, label= _("&Import"))
- self.btn_run.SetToolTipString(_("Import selected layers"))
+ self.btn_run = wx.Button(parent=self.panel, id=wx.ID_OK)
self.btn_run.SetDefault()
self.btn_run.Enable(False)
self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
-
- self.__doLayout()
- self.Layout()
- def __doLayout(self):
+ def doLayout(self):
+ """!Do layout"""
dialogSizer = wx.BoxSizer(wx.VERTICAL)
- #
- # input
- #
- inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
- gridSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
-
- gridSizer.Add(item=self.inputText,
- flag=wx.ALIGN_CENTER_VERTICAL)
- gridSizer.AddGrowableCol(1)
- self.inputTypeSizer = wx.BoxSizer(wx.HORIZONTAL)
- self.inputTypeSizer.Add(item=self.input[self.inputType][1], proportion = 1,
- flag = wx.ALIGN_CENTER_VERTICAL)
+ # dsn input
+ dialogSizer.Add(item = self.dsnInput, proportion = 0,
+ flag = wx.EXPAND)
- gridSizer.Add(item=self.inputTypeSizer,
- flag=wx.EXPAND | wx.ALL)
-
- if self.importType != 'dxf':
- gridSizer.Add(item=self.formatText,
- flag=wx.ALIGN_CENTER_VERTICAL)
- gridSizer.Add(item=self.format)
-
- inputSizer.Add(item=gridSizer, proportion=1,
- flag=wx.EXPAND | wx.ALL)
-
- if self.importType != 'dxf':
- dialogSizer.Add(item=self.typeRadio, proportion=0,
- flag=wx.ALL | wx.EXPAND, border=5)
- dialogSizer.Add(item=inputSizer, proportion=0,
- flag=wx.ALL | wx.EXPAND, border=5)
-
#
# list of DXF layers
#
@@ -1114,17 +993,17 @@
dialogSizer.Add(item=layerSizer, proportion=1,
flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-
+
if hasattr(self, "overrideCheck"):
dialogSizer.Add(item=self.overrideCheck, 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 | wx.EXPAND, border=5)
dialogSizer.Add(item=self.add, proportion=0,
flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5)
-
+
#
# buttons
#
@@ -1146,64 +1025,100 @@
self.panel.SetSizer(dialogSizer)
dialogSizer.Fit(self.panel)
- self.Layout()
# auto-layout seems not work here - FIXME
size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 175, 400)
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 OnChangeType(self, event):
- """!Datasource type changed"""
- sel = event.GetSelection()
- win = self.input[self.inputType][1]
- self.inputTypeSizer.Remove(win)
- win.Hide()
+ def OnCancel(self, event=None):
+ """!Close dialog"""
+ self.Close()
+
+ def OnRun(self, event):
+ """!Import/Link data (each layes as separate vector map)"""
+ pass
+
+ def AddLayers(self, returncode):
+ """!Add imported/linked layers into layer tree"""
+ self.commandId += 1
- if sel == 0: # file
- self.inputType = 'file'
- format = self.input[self.inputType][2][0]
- try:
- ext = self.formatToExt[format]
- if not ext:
- raise KeyError
- format += ' (*.%s)|*.%s' % (ext, ext)
- except KeyError:
- format += ' (*.*)|*.*'
-
- win = filebrowse.FileBrowseButton(parent=self.panel, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
- dialogTitle=_('Choose input file'),
- buttonText=_('Browse'),
- startDirectory=os.getcwd(),
- changeCallback=self.OnSetInput,
- fileMask = format)
- self.input[self.inputType][1] = win
- elif sel == 1: # directory
- self.inputType = 'dir'
- elif sel == 2: # database
- self.inputType = 'db'
- elif sel == 3: # protocol
- self.inputType = 'pro'
+ if not self.add.IsChecked() or returncode != 0:
+ return
- win = self.input[self.inputType][1]
- self.inputTypeSizer.Add(item = win, proportion = 1,
- flag = wx.ALIGN_CENTER_VERTICAL)
- win.SetValue('')
- self.list.DeleteAllItems()
- win.Show()
+ maptree = self.parent.curr_page.maptree
- self.inputText.SetLabel(self.input[self.inputType][0])
- self.format.SetItems(self.input[self.inputType][2])
- self.format.SetSelection(0)
+ layer, output = self.list.GetLayers()[self.commandId]
- self.inputTypeSizer.Layout()
+ 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,
+ lcmd=cmd)
+ else:
+ item = maptree.AddLayer(ltype='vector',
+ lname=name,
+ lcmd=['d.vect',
+ 'map=%s' % name])
+ maptree.mapdisplay.MapWindow.ZoomToMap()
- def OnCancel(self, event=None):
- """!Close dialog"""
- self.Close()
+ 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
+ if ogr:
+ ImportDialog.__init__(self, parent, type = 'ogr')
+ if link:
+ self.SetTitle(_("Link vector data"))
+ else:
+ self.SetTitle(_("Import vector data"))
+ else:
+ ImportDialog.__init__(self, parent, type = 'gdal')
+ if link:
+ self.SetTitle(_("Link raster data"))
+ else:
+ self.SetTitle(_("Import raster data"))
+
+ self.dsnInput = gselect.GdalSelect(parent = self, panel = self.panel, ogr = ogr)
+
+ if not link:
+ self.overrideCheck = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
+ label=_("Override projection (use location's projection)"))
+
+ 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"))
+ else:
+ self.btn_run.SetLabel(_("&Import"))
+ self.btn_run.SetToolTipString(_("Import selected layers"))
+
+ self.doLayout()
+
def OnRun(self, event):
"""!Import/Link data (each layes as separate vector map)"""
data = self.list.GetLayers()
@@ -1211,30 +1126,13 @@
# hide dialog
self.Hide()
- if self.importType == 'dxf':
- inputDxf = self.input[self.inputType][1].GetValue()
- else:
- if self.inputType == 'file':
- dsn = os.path.dirname(self.input[self.inputType][1].GetValue())
- else:
- if self.format.GetStringSelection() == 'PostgreSQL':
- dsn = 'PG:dbname=%s' % self.input[self.inputType][1].GetStringSelection()
- else:
- dsn = self.input[self.inputType][1].GetValue()
- try:
- ext = '.' + self.formatToExt[self.format.GetStringSelection()]
- except KeyError:
- ext = ''
-
+ dsn = self.dsnInput.GetDsn()
+ ext = self.dsnInput.GetFormatExt()
+
for layer, output in data:
- if self.importType == 'dxf':
- cmd = ['v.in.dxf',
- 'input=%s' % inputDxf,
- 'layers=%s' % layer,
- 'output=%s' % output]
- elif self.importType == 'ogr':
- if layer.rfind(ext) > -1:
- layer = layer.replace(ext, '')
+ if self.importType == 'ogr':
+ if ext and layer.rfind(ext) > -1:
+ layer = layer.replace('.' + ext, '')
if self.link:
cmd = ['v.external',
'dsn=%s' % dsn,
@@ -1246,19 +1144,22 @@
'layer=%s' % layer,
'output=%s' % output]
else: # gdal
+ if self.dsnInput.GetType() == 'dir':
+ idsn = os.path.join(dsn, layer)
+
if self.link:
cmd = ['r.external',
- 'input=%s' % (os.path.join(dsn, layer)),
+ 'input=%s' % idsn,
'output=%s' % output]
else:
cmd = ['r.in.gdal',
- 'input=%s' % (os.path.join(dsn, layer)),
+ 'input=%s' % idsn,
'output=%s' % output]
if self.overwrite.IsChecked():
cmd.append('--overwrite')
- if hasattr(self, "overrideCheck") and self.overrideCheck.IsChecked():
+ if not self.link and self.overrideCheck.IsChecked():
cmd.append('-o')
if UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'):
@@ -1266,186 +1167,90 @@
# run in Layer Manager
self.parent.goutput.RunCmd(cmd, switchPage=True,
- onDone = self._addLayers)
+ onDone = self.AddLayers)
self.OnCancel()
- def _addLayers(self, returncode):
- """!Add imported/linked layers to layer tree"""
- self.commandId += 1
+class DxfImportDialog(ImportDialog):
+ """!Dialog for bulk import of DXF layers"""
+ def __init__(self, parent):
+ ImportDialog.__init__(self, parent, type = 'dxf',
+ title = _("Import DXF layers"))
- if not self.add.IsChecked():
- return
-
- maptree = self.parent.curr_page.maptree
+ 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")
- layer, output = self.list.GetLayers()[self.commandId]
+ self.add.SetLabel(_("Add imported layers into layer tree"))
- 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,
- lcmd=cmd)
- else:
- item = maptree.AddLayer(ltype='vector',
- lname=name,
- lcmd=['d.vect',
- 'map=%s' % name])
- maptree.mapdisplay.MapWindow.ZoomToMap()
+ self.add.SetValue(UserSettings.Get(group='cmd', key='addNewLayer', subkey='enabled'))
- def OnAbort(self, event):
- """!Abort running import
-
- @todo not yet implemented
- """
- pass
+ self.doLayout()
- def OnSetFormat(self, event):
- """!Format changed"""
- if self.inputType not in ['file', 'db']:
- return
+ def OnRun(self, event):
+ """!Import/Link data (each layes as separate vector map)"""
+ data = self.list.GetLayers()
- win = self.input[self.inputType][1]
- self.inputTypeSizer.Remove(win)
+ # hide dialog
+ self.Hide()
- if self.inputType == 'file':
- win.Destroy()
- else: # database
- win.Hide()
+ inputDxf = self.dsnInput.GetValue()
- format = event.GetString()
-
- if self.inputType == 'file':
- try:
- ext = self.formatToExt[format]
- if not ext:
- raise KeyError
- format += ' (*.%s)|*.%s' % (ext, ext)
- except KeyError:
- format += ' (*.*)|*.*'
+ for layer, output in data:
+ cmd = ['v.in.dxf',
+ 'input=%s' % inputDxf,
+ 'layers=%s' % layer,
+ 'output=%s' % output]
- win = filebrowse.FileBrowseButton(parent=self.panel, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
- dialogTitle=_('Choose file'),
- buttonText=_('Browse'),
- startDirectory=os.getcwd(),
- changeCallback=self.OnSetInput,
- fileMask = format)
- else: # database
- if format == 'SQLite':
- win = self.input['db-win']['file']
- elif format == 'PostgreSQL':
- if grass.find_program('psql'):
- 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']
+ 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.input[self.inputType][1] = win
- if not win.IsShown():
- win.Show()
- self.inputTypeSizer.Add(item = win, proportion = 1,
- flag = wx.ALIGN_CENTER_VERTICAL)
- self.inputTypeSizer.Layout()
-
- def OnSetInput(self, event):
- """!Input DXF file/OGR dsn defined, update list of layer widget"""
+ self.OnCancel()
+
+ def OnSetDsn(self, event):
+ """!Input DXF file defined, update list of layer widget"""
path = event.GetString()
if not path:
return
-
+
data = list()
- if self.importType == 'dxf':
- ret = gcmd.RunCommand('v.in.dxf',
- quiet = True,
- parent = self,
- read = True,
- flags = 'l',
- input = path)
- if not ret:
- self.list.LoadData()
- self.btn_run.Enable(False)
- return
+ ret = gcmd.RunCommand('v.in.dxf',
+ quiet = True,
+ parent = self,
+ read = True,
+ flags = 'l',
+ input = path)
+ if not ret:
+ self.list.LoadData()
+ self.btn_run.Enable(False)
+ return
- for line in ret.splitlines():
- layerId = line.split(':')[0].split(' ')[1]
- layerName = line.split(':')[1].strip()
- grassName = utils.GetValidLayerName(layerName)
- data.append((layerId, layerName.strip(), grassName.strip()))
+ for line in ret.splitlines():
+ layerId = line.split(':')[0].split(' ')[1]
+ layerName = line.split(':')[1].strip()
+ grassName = utils.GetValidLayerName(layerName)
+ data.append((layerId, layerName.strip(), grassName.strip()))
- else: # gdal/ogr (for ogr maybe to use v.in.ogr -l)
- layerId = 1
- if self.format.GetStringSelection() == 'PostgreSQL':
- dsn = 'PG:dbname=%s' % self.input[self.inputType][1].GetStringSelection()
- else:
- dsn = self.input[self.inputType][1].GetValue()
- if self.inputType == 'file':
- baseName = os.path.basename(dsn)
- grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
- data.append((layerId, baseName, grassName))
- elif self.inputType == 'dir':
- try:
- ext = self.formatToExt[self.format.GetStringSelection()]
- except KeyError:
- ext = ''
- for file in glob.glob(os.path.join(dsn, "*.%s") % ext):
- baseName = os.path.basename(file)
- grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
- data.append((layerId, baseName, grassName))
- layerId += 1
- elif self.inputType == 'db':
- ret = gcmd.RunCommand('v.in.ogr',
- quiet = True,
- parent = self,
- read = True,
- flags = 'l',
- dsn = dsn)
- if not ret:
- self.list.LoadData()
- self.btn_run.Enable(False)
- return
- layerId = 1
- for line in ret.split(','):
- layerName = line.strip()
- grassName = utils.GetValidLayerName(layerName)
- data.append((layerId, layerName.strip(), grassName.strip()))
- layerId += 1
-
self.list.LoadData(data)
if len(data) > 0:
self.btn_run.Enable(True)
else:
self.btn_run.Enable(False)
-
+
class LayersList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin,
- listmix.CheckListCtrlMixin):
-# listmix.CheckListCtrlMixin, listmix.TextEditMixin):
- """List of layers to be imported (dxf, shp...)"""
- def __init__(self, parent, pos=wx.DefaultPosition,
- log=None):
+ 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,
@@ -1455,8 +1260,8 @@
# setup mixins
listmix.ListCtrlAutoWidthMixin.__init__(self)
- # listmix.TextEditMixin.__init__(self)
-
+ listmix.TextEditMixin.__init__(self)
+
self.InsertColumn(0, _('Layer'))
self.InsertColumn(1, _('Layer name'))
self.InsertColumn(2, _('Name for GRASS map'))
@@ -1465,7 +1270,7 @@
self.Bind(wx.EVT_RIGHT_UP, self.OnPopupMenu) #wxGTK
def LoadData(self, data=None):
- """Load data into list"""
+ """!Load data into list"""
if data is None:
return
@@ -1481,7 +1286,7 @@
self.SetColumnWidth(col=0, width=wx.LIST_AUTOSIZE_USEHEADER)
def OnPopupMenu(self, event):
- """Show popup menu"""
+ """!Show popup menu"""
if self.GetItemCount() < 1:
return
@@ -1501,7 +1306,7 @@
menu.Destroy()
def OnSelectAll(self, event):
- """Select all items"""
+ """!Select all items"""
item = -1
while True:
@@ -1513,7 +1318,7 @@
event.Skip()
def OnSelectNone(self, event):
- """Deselect items"""
+ """!Deselect items"""
item = -1
while True:
@@ -1525,7 +1330,7 @@
event.Skip()
def GetLayers(self):
- """Get list of layers (layer name, output name)"""
+ """!Get list of layers (layer name, output name)"""
data = []
item = -1
while True:
@@ -1540,7 +1345,7 @@
return data
class SetOpacityDialog(wx.Dialog):
- """Set opacity of map layers"""
+ """!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):
@@ -1602,9 +1407,180 @@
self.Layout()
def GetOpacity(self):
- """Button 'OK' pressed"""
+ """!Button 'OK' pressed"""
# return opacity value
opacity = float(self.value.GetValue()) / 100
return opacity
+def GetImageHandlers(image):
+ """!Get list of supported image handlers"""
+ lext = list()
+ ltype = list()
+ for h in image.GetHandlers():
+ lext.append(h.GetExtension())
+
+ filetype = ''
+ if 'png' in lext:
+ filetype += "PNG file (*.png)|*.png|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
+ 'ext' : 'png' })
+ filetype += "BMP file (*.bmp)|*.bmp|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
+ 'ext' : 'bmp' })
+ if 'gif' in lext:
+ filetype += "GIF file (*.gif)|*.gif|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
+ 'ext' : 'gif' })
+
+ if 'jpg' in lext:
+ filetype += "JPG file (*.jpg)|*.jpg|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
+ 'ext' : 'jpg' })
+ if 'pcx' in lext:
+ filetype += "PCX file (*.pcx)|*.pcx|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
+ 'ext' : 'pcx' })
+
+ if 'pnm' in lext:
+ filetype += "PNM file (*.pnm)|*.pnm|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
+ 'ext' : 'pnm' })
+
+ if 'tif' in lext:
+ filetype += "TIF file (*.tif)|*.tif|"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
+ 'ext' : 'tif' })
+
+ if 'xpm' in lext:
+ filetype += "XPM file (*.xpm)|*.xpm"
+ ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
+ 'ext' : 'xpm' })
+
+ return filetype, ltype
+
+class StaticWrapText(wx.StaticText):
+ """! A Static Text field that wraps its text to fit its width,
+ enlarging its height if necessary.
+ """
+ def __init__(self, parent, id = wx.ID_ANY, label = '', *args, **kwds):
+ self.parent = parent
+ self.originalLabel = label
+
+ wx.StaticText.__init__(self, parent, id, label = '', *args, **kwds)
+
+ self.SetLabel(label)
+ self.Bind(wx.EVT_SIZE, self.OnResize)
+
+ def SetLabel(self, label):
+ self.originalLabel = label
+ self.wrappedSize = None
+ self.OnResize(None)
+
+ def OnResize(self, event):
+ if not getattr(self, "resizing", False):
+ self.resizing = True
+ newSize = wx.Size(self.parent.GetSize().width,
+ self.GetSize().height)
+ if self.wrappedSize != newSize:
+ wx.StaticText.SetLabel(self, self.originalLabel)
+ self.Wrap(newSize.width)
+ self.wrappedSize = newSize
+
+ self.SetSize(self.wrappedSize)
+ del self.resizing
+
+class ImageSizeDialog(wx.Dialog):
+ """!Set size for saved graphic file"""
+ def __init__(self, parent, id = wx.ID_ANY, title=_("Set image size"),
+ style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
+ self.parent = parent
+
+ wx.Dialog.__init__(self, parent, id = id, style=style, title=title, **kwargs)
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label = ' % s' % _("Image size"))
+
+ size = self.parent.GetWindow().GetClientSize()
+ self.width = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
+ style = wx.SP_ARROW_KEYS)
+ self.width.SetRange(20, 1e6)
+ self.width.SetValue(size.width)
+ wx.CallAfter(self.width.SetFocus)
+ self.height = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
+ style = wx.SP_ARROW_KEYS)
+ self.height.SetRange(20, 1e6)
+ self.height.SetValue(size.height)
+ self.template = wx.Choice(parent = self.panel, id = wx.ID_ANY,
+ size = (125, -1),
+ choices = [ "",
+ "640x480",
+ "800x600",
+ "1024x768",
+ "1280x960",
+ "1600x1200",
+ "1920x1440" ])
+
+ self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
+ self.btnOK.SetDefault()
+ self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+
+ self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
+
+ self._layout()
+ self.SetSize(self.GetBestSize())
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # body
+ box = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
+ fbox = wx.FlexGridSizer(cols = 2, vgap = 5, hgap = 5)
+ fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Width:")),
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ fbox.Add(item = self.width)
+ fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Height:")),
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ fbox.Add(item = self.height)
+ fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
+ label = _("Template:")),
+ flag = wx.ALIGN_CENTER_VERTICAL)
+ fbox.Add(item = self.template)
+
+ box.Add(item = fbox, proportion = 1,
+ flag = wx.EXPAND | wx.ALL, border = 5)
+ sizer.Add(item = box, proportion = 1,
+ flag=wx.EXPAND | wx.ALL, border = 3)
+
+ # buttons
+ btnsizer = wx.StdDialogButtonSizer()
+ btnsizer.AddButton(self.btnOK)
+ btnsizer.AddButton(self.btnCancel)
+ btnsizer.Realize()
+
+ sizer.Add(item = btnsizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
+
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+ self.Layout()
+
+ def GetValues(self):
+ """!Get width/height values"""
+ return self.width.GetValue(), self.height.GetValue()
+
+ def OnTemplate(self, event):
+ """!Template selected"""
+ sel = event.GetString()
+ if not sel:
+ width, height = self.parent.GetWindow().GetClientSize()
+ else:
+ width, height = map(int, sel.split('x'))
+ self.width.SetValue(width)
+ self.height.SetValue(height)
+
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/georect.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/georect.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/georect.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -16,7 +16,6 @@
- GrSettingsDialog
(C) 2006-2010 by the GRASS Development Team
-
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -80,9 +79,8 @@
#
# get environmental variables
#
- p = gcmd.Command(['g.gisenv', 'get=GISDBASE'])
- self.grassdatabase = p.ReadStdOutput()[0]
-
+ self.grassdatabase = grass.gisenv()['GISDBASE']
+
#
# read original environment settings
#
@@ -189,15 +187,15 @@
#
# start map display
#
- self.xy_mapdisp = mapdisp.MapFrame(self.gcpmgr, title=_("Set ground control points (GCPs)"),
+ self.xy_mapdisp = mapdisp.MapFrame(self.gcpmgr, name = "GRMapWindow",
size=globalvar.MAP_WINDOW_SIZE,
toolbars=["georect"],
- Map=self.Map, gismgr=self.parent)
+ Map=self.Map, lmgr=self.parent)
self.xy_mapdisp.SetTitle(_("GRASS GIS Map Display: 1" +
" - Location: " + self.newlocation +
" (source location)"))
- self.xy_mapdisp.SetName("GRMapWindow")
-
+ self.xy_mapdisp.GetWindow().ResetZoomHistory()
+
self.gcpmgr.SetMapDisplay(self.xy_mapdisp)
self.mapwin = self.xy_mapdisp.MapWindow
@@ -221,7 +219,7 @@
self.Cleanup()
def SetSrcEnv(self, location, mapset):
- """Create environment to use for location and mapset
+ """!Create environment to use for location and mapset
that are the source of the file(s) to georectify
@param location source location
@@ -274,18 +272,18 @@
return True
def OnGLMFocus(self, event):
- """Layer Manager focus"""
+ """!Layer Manager focus"""
# self.SwitchEnv('original')
event.Skip()
def Cleanup(self):
- """Return to current location and mapset"""
+ """!Return to current location and mapset"""
self.SwitchEnv('original')
-
self.parent.georectifying = None
- if hasattr(self, "xy_mapdisp"):
+ if hasattr(self, "xy_mapdisp") and \
+ self.xy_mapdisp:
self.xy_mapdisp.Close()
self.xy_mapdisp = None
@@ -307,22 +305,8 @@
self.xylocation = ''
self.xymapset = ''
-
- tmplist = os.listdir(self.grassdatabase)
- self.locList = []
- self.mapsetList = []
#
- # create a list of valid locations
- #
- for item in tmplist:
- if os.path.isdir(os.path.join(self.grassdatabase, item)) and \
- os.path.exists(os.path.join(self.grassdatabase, item, 'PERMANENT')):
- self.locList.append(item)
-
- utils.ListSortLower(self.locList)
-
- #
# layout
#
self.sizer.AddGrowableCol(2)
@@ -339,9 +323,7 @@
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 = wx.ComboBox(parent=self, id=wx.ID_ANY,
- choices = self.locList, size=(300, -1),
- style=wx.CB_DROPDOWN | wx.CB_READONLY)
+ self.cb_location = gselect.LocationSelect(parent = self, gisdbase = self.grassdatabase)
self.sizer.Add(item=self.cb_location,
flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
pos=(2, 2))
@@ -350,9 +332,8 @@
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 = wx.ComboBox(parent=self, id=wx.ID_ANY,
- choices = self.mapsetList, size=(300, -1),
- style=wx.CB_DROPDOWN | wx.CB_READONLY)
+ self.cb_mapset = gselect.MapsetSelect(parent = self, gisdbase = self.grassdatabase,
+ setItems = False)
self.sizer.Add(item=self.cb_mapset,
flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
pos=(3,2))
@@ -368,7 +349,7 @@
# self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
def OnMaptype(self,event):
- """Change map type"""
+ """!Change map type"""
global maptype
if event.GetInt() == 0:
@@ -377,7 +358,7 @@
maptype = 'vector'
def OnLocation(self, event):
- """Sets source location for map(s) to georectify"""
+ """!Sets source location for map(s) to georectify"""
self.xylocation = event.GetString()
#create a list of valid mapsets
@@ -399,7 +380,7 @@
wx.FindWindowById(wx.ID_FORWARD).Enable(True)
def OnMapset(self, event):
- """Sets source mapset for map(s) to georectify"""
+ """!Sets source mapset for map(s) to georectify"""
if self.xylocation == '':
wx.MessageBox(_('You must select a valid location before selecting a mapset'))
return
@@ -465,7 +446,6 @@
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..."))
- self.btn_vgroup.Hide()
btnSizer.Add(item=self.btn_mkgroup,
flag=wx.RIGHT, border=5)
@@ -495,17 +475,20 @@
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"""
+ """!Create new group in source location/mapset"""
menuform.GUI().ParseCommand(['i.group'],
completed=(self.GetOptData, None, ''),
parentframe=self.parent.parent, modal=True)
-
+
def OnVGroup(self, event):
- """Add vector maps to group"""
+ """!Add vector maps to group"""
dlg = VectGroup(parent = self,
id = wx.ID_ANY,
grassdb = self.grassdatabase,
@@ -520,7 +503,7 @@
self.OnEnterPage()
def GetOptData(self, dcmd, layer, params, propwin):
- """Process i.group"""
+ """!Process i.group"""
# update the page
if dcmd:
gcmd.Command(dcmd)
@@ -613,7 +596,7 @@
pos=(1, 1))
self.selection = gselect.Select(self, id=wx.ID_ANY,
- size=globalvar.DIALOG_GSELECT_SIZE)
+ size=globalvar.DIALOG_GSELECT_SIZE, type='cell')
self.sizer.Add(item=self.selection,
flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
@@ -628,7 +611,7 @@
self.Bind(wx.EVT_CLOSE, self.parent.Cleanup)
def OnSelection(self,event):
- """Map to display selected"""
+ """!Map to display selected"""
global xy_map
global maptype
@@ -642,9 +625,13 @@
try:
# set computational region to match selected map and zoom display to region
if maptype == 'cell':
- p = gcmd.RunCommand('g.region', rast = xy_map)
+ p = gcmd.Command(['g.region', 'rast=xy_map'])
elif maptype == 'vector':
- p = gcmd.RunCommand('g.region', vect = xy_map)
+ p = gcmd.Command(['g.region', 'vect=xy_map'])
+
+ if p.returncode == 0:
+ print 'returncode = ', str(p.returncode)
+ self.parent.Map.region = self.parent.Map.GetRegion()
except:
pass
@@ -655,12 +642,13 @@
wx.MessageBox(_('You must select a valid image/map in order to continue'))
event.Veto()
return
+
self.parent.SwitchEnv('original')
def OnEnterPage(self, event=None):
global maptype
global xy_map
-
+
self.selection.SetElementList(maptype,
mapsets = [self.parent.newmapset, ])
@@ -670,17 +658,16 @@
wx.FindWindowById(wx.ID_FORWARD).Enable(True)
class GCP(wx.Frame):
- """
+ """!
Manages ground control points for georectifying. Calculates RMS statics.
Calls i.rectify or v.transform to georectify map.
"""
+ def __init__(self, parent, grwiz, mapdisp = None, id = wx.ID_ANY,
+ title = _("Define/manage ground control points"),
+ size = (625, 300)):
- def __init__(self, parent, grwiz, mapdisp=None, id=wx.ID_ANY,
- title=_("Define/manage ground control points"),
- size=wx.DefaultSize):
+ wx.Frame.__init__(self, parent, id, title, size = size, name = "GCPFrame")
- wx.Frame.__init__(self, parent, id, title, size=(625, 300))
-
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
#
@@ -704,6 +691,7 @@
self.xymapset = self.grwiz.gisrc_dict['MAPSET']
self.xygroup = self.grwiz.grouppage.xygroup
self.extension = self.grwiz.grouppage.extension
+ self.outname = ''
self.VectGRList = []
self.file = {
@@ -751,7 +739,7 @@
#
# toolbar and display for xy map
#
- self.toolbar = toolbars.GCPToolbar(parent=self, tbframe=self).GetToolbar()
+ self.toolbar = toolbars.GCPToolbar(parent=self)
self.SetToolBar(self.toolbar)
self.SetMapDisplay(self.mapdisp)
@@ -809,7 +797,7 @@
# sizer.Fit(self)
def __del__(self):
- """Disable georectification mode"""
+ """!Disable georectification mode"""
self.parent.georectifying = None
def ClipRegion(self, event):
@@ -826,19 +814,19 @@
"""
# check to see if we are georectifying map in current working location/mapset
if self.newlocation == self.currentlocation and self.newmapset == self.currentmapset:
- cmdlist = ['i.target',
- '-c',
- 'group=%s' % tgroup]
+ gcmd.RunCommand('i.target',
+ parent = self,
+ flags = 'c',
+ group = tgroup)
else:
self.grwiz.SwitchEnv('new')
- cmdlist = ['i.target',
- 'group=%s' % tgroup,
- 'location=%s' % tlocation,
- 'mapset=%s' % tmapset]
- gcmd.Command(cmd=cmdlist, stderr=None)
+ gcmd.RunCommand('i.target',
+ parent = self,
+ group = tgroup,
+ location = tlocation,
+ mapset = tmapset)
+ self.grwiz.SwitchEnv('original')
- self.grwiz.SwitchEnv('original')
-
def AddGCP(self, event):
"""
Appends an item to GCP list
@@ -1036,13 +1024,13 @@
# self.RMSError(self.xygroup, self.gr_order)
def ReloadGCPs(self, event):
- """Reload data from file"""
+ """!Reload data from file"""
- # delete all items in mapcoordlist
- del self.mapcoordlist
- self.mapcoordlist = []
-
- self.list.LoadData()
+ # delete all items in mapcoordlist
+ del self.mapcoordlist
+ self.mapcoordlist = []
+
+ self.list.LoadData()
def OnFocus(self, event):
# self.grwiz.SwitchEnv('new')
@@ -1091,30 +1079,11 @@
'extension=%s' % self.extension,'order=%s' % self.gr_order]
if self.clip_to_region:
cmdlist.append('-c')
-
- p = gcmd.Command(cmdlist)
- output = p.ReadStdOutput()
- error = p.ReadErrOutput()
+ self.parent.goutput.RunCmd(cmdlist, compReg=False,
+ switchPage=True)
- # printing to console
- for i in error:
- try:
- msgtype, msg = i.split(':')
- if msgtype != 'GRASS_INFO_PERCENT':
- self.parent.goutput.WriteLog(text = _(msg), switchPage = True)
- except:
- continue
- for i in output:
- self.parent.goutput.WriteLog(text = _(msg), switchPage = True)
-
- if p.returncode == 0:
- wx.MessageBox('Maps in group %s georectified successfully' % self.xygroup)
- else:
- wx.MessageBox('ERROR...',error)
-
time.sleep(.1)
- self.grwiz.SwitchEnv('original')
elif maptype == 'vector':
outmsg = ''
@@ -1150,32 +1119,26 @@
self.outname = vect + '_' + self.extension
self.parent.goutput.WriteLog(text = _('Transforming <%s>...') % vect,
switchPage = True)
-
- p = gcmd.Command(['v.transform',
- '--o',
- 'input=%s' % vect,
- 'output=%s' % self.outname,
- 'points=%s' % self.file['points']])
+ msg = err = ''
- output = p.ReadStdOutput()
- error = p.ReadErrOutput()
-
- # printing to console
- for i in error:
- try:
- msgtype, msg = i.split(':')
- if msgtype != 'GRASS_INFO_PERCENT':
- self.parent.goutput.WriteLog(text = _(msg), switchPage = True)
- except:
- continue
- for i in output:
- self.parent.goutput.WriteLog(text = _(i), switchPage = True)
-
- if p.returncode == 0:
+ ret, out, err = gcmd.RunCommand('v.transform',
+ flags = '-o',
+ input=vect,
+ output=self.outname,
+ pointsfile=self.file['points'],
+ getErrorMsg=True, read=True)
+
+
+ if ret == 0:
self.VectGRList.append(self.outname)
+ print err
+ # note: WriteLog doesn't handle GRASS_INFO_PERCENT well, so using a print here
+# self.parent.goutput.WriteLog(text = _(err), switchPage = True)
+ self.parent.goutput.WriteLog(text = _(out), switchPage = True)
else:
self.parent.goutput.WriteError(_('Georectification of vector map <%s> failed') %
self.outname)
+ self.parent.goutput.WriteError(_(err))
# FIXME
# Copying database information not working.
@@ -1221,14 +1184,30 @@
else:
shutil.move(xyvpath, vpath)
- wx.MessageBox('For all vector maps georectified successfully, ' + '\n' +
- 'you will need to copy any associated attribute tables' + '\n' +
- 'and reconnect them to the georectified vectors')
+ wx.MessageBox('For all vector maps georectified successfully, ' + '\n' +
+ 'you will need to copy any attribute tables' + '\n' +
+ 'and reconnect them to the georectified vectors')
self.grwiz.SwitchEnv('original')
+
+ 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):
- """Georectifier settings"""
+ """!Georectifier settings"""
dlg = GrSettingsDialog(parent=self, id=wx.ID_ANY, title=_('Georectifier settings'))
if dlg.ShowModal() == wx.ID_OK:
@@ -1237,7 +1216,7 @@
dlg.Destroy()
def OnQuit(self, event):
- """Quit georectifier"""
+ """!Quit georectifier"""
self.grwiz.Cleanup()
self.Destroy()
@@ -1287,13 +1266,17 @@
# get list of forward and reverse rms error values for each point
self.grwiz.SwitchEnv('new')
- p = gcmd.Command(['g.transform',
- 'group=%s' % xygroup,
- 'order=%s' % order])
+ ret = gcmd.RunCommand('g.transform',
+ parent = self,
+ read = True,
+ group = xygroup,
+ order = order)
self.grwiz.SwitchEnv('original')
- errlist = p.ReadStdOutput()
+ if ret:
+ errlist = ret.splitlines()
+
if errlist == []:
return
@@ -1362,7 +1345,7 @@
idx_col += 1
def LoadData(self):
- """Load data into list"""
+ """!Load data into list"""
self.DeleteAllItems()
if os.path.isfile(self.gcp.file['points']):
@@ -1381,7 +1364,7 @@
self.ResizeColumns()
def OnCheckItem(self, index, flag):
- """Item is checked/unchecked"""
+ """!Item is checked/unchecked"""
pass
def AddGCPItem(self):
@@ -1425,7 +1408,7 @@
return self.selected
def ResizeColumns(self):
- """Resize columns"""
+ """!Resize columns"""
minWidth = 90
for i in range(self.GetColumnCount()):
self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
@@ -1435,7 +1418,7 @@
self.SendSizeEvent()
def GetSelected(self):
- """Get index of selected item"""
+ """!Get index of selected item"""
return self.selected
def OnItemSelected(self, event):
@@ -1584,7 +1567,7 @@
self.Layout()
def MakeVGroup(self):
- """Create VREF file"""
+ """!Create VREF file"""
vgrouplist = []
for item in range(self.listMap.GetCount()):
if not self.listMap.IsChecked(item):
@@ -1602,7 +1585,7 @@
def __init__(self, parent, data, id=wx.ID_ANY,
title=_("Edit GCP"),
style=wx.DEFAULT_DIALOG_STYLE):
- """Dialog for editing GPC and map coordinates in list control"""
+ """!Dialog for editing GPC and map coordinates in list control"""
wx.Dialog.__init__(self, parent, id, title=title, style=style)
@@ -1673,7 +1656,7 @@
sizer.Fit(self)
def GetValues(self, columns=None):
- """Return list of values (as strings).
+ """!Return list of values (as strings).
"""
valuelist = []
try:
@@ -1709,7 +1692,7 @@
self._do_layout()
def _do_layout(self):
- """Do layout"""
+ """!Do layout"""
# dialog layout
sizer = wx.BoxSizer(wx.VERTICAL)
@@ -1794,7 +1777,7 @@
value=wx.FindWindowById(self.symbol['width']).GetValue())
def OnSave(self, event):
- """Button 'Save' pressed"""
+ """!Button 'Save' pressed"""
self.UpdateSettings()
fileSettings = {}
UserSettings.ReadSettingsFile(settings=fileSettings)
@@ -1804,10 +1787,10 @@
self.Close()
def OnApply(self, event):
- """Button 'Apply' pressed"""
+ """!Button 'Apply' pressed"""
self.UpdateSettings()
self.Close()
def OnCancel(self, event):
- """Button 'Cancel' pressed"""
+ """!Button 'Cancel' pressed"""
self.Close()
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,1194 @@
+"""!
+ at package help.py
+
+ at brief Help window
+
+Classes:
+ - SearchModuleWindow
+ - ItemTree
+ - MenuTreeWindow
+ - MenuTree
+ - AboutWindow
+ - InstallExtensionWindow
+ - ExtensionTree
+ - HelpFrame
+ - HelpWindow
+ - HelpPanel
+
+(C) 2008-2010 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+
+import wx
+try:
+ import wx.lib.agw.customtreectrl as CT
+# import wx.lib.agw.hyperlink as hl
+except ImportError:
+ import wx.lib.customtreectrl as CT
+# import wx.lib.hyperlink as hl
+import wx.lib.flatnotebook as FN
+import wx.lib.scrolledpanel as scrolled
+
+import menudata
+import gcmd
+import globalvar
+import gdialogs
+
+class HelpFrame(wx.Frame):
+ """!GRASS Quickstart help window"""
+ def __init__(self, parent, id, title, size, file):
+ wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # text
+ content = HelpPanel(parent = self)
+ content.LoadPage(file)
+
+ sizer.Add(item = content, proportion=1, flag=wx.EXPAND)
+
+ self.SetAutoLayout(True)
+ self.SetSizer(sizer)
+ self.Layout()
+
+class SearchModuleWindow(wx.Panel):
+ """!Search module window (used in MenuTreeWindow)"""
+ def __init__(self, parent, id = wx.ID_ANY, cmdPrompt = None,
+ showChoice = True, showTip = False, **kwargs):
+ self.showTip = showTip
+ self.showChoice = showChoice
+ self.cmdPrompt = cmdPrompt
+
+ wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+
+ self._searchDict = { _('description') : 'description',
+ _('command') : 'command',
+ _('keywords') : 'keywords' }
+
+ self.box = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label=" %s " % _("Find module(s)"))
+
+ self.searchBy = wx.Choice(parent = self, id = wx.ID_ANY,
+ choices = [_('description'),
+ _('keywords'),
+ _('command')])
+ self.searchBy.SetSelection(0)
+
+ self.search = wx.TextCtrl(parent = self, id = wx.ID_ANY,
+ value = "", size = (-1, 25),
+ style = wx.TE_PROCESS_ENTER)
+ self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
+
+ if self.showTip:
+ self.searchTip = gdialogs.StaticWrapText(parent = self, id = wx.ID_ANY,
+ size = (-1, 35))
+
+ if self.showChoice:
+ self.searchChoice = wx.Choice(parent = self, id = wx.ID_ANY)
+ if self.cmdPrompt:
+ self.searchChoice.SetItems(self.cmdPrompt.GetCommandItems())
+ self.searchChoice.Bind(wx.EVT_CHOICE, self.OnSelectModule)
+
+ self._layout()
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
+ gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3)
+ gridSizer.AddGrowableCol(1)
+
+ gridSizer.Add(item = self.searchBy,
+ flag=wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
+ gridSizer.Add(item = self.search,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (0, 1))
+ row = 1
+ if self.showTip:
+ gridSizer.Add(item = self.searchTip,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
+ row += 1
+
+ if self.showChoice:
+ gridSizer.Add(item = self.searchChoice,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, pos = (row, 0), span = (1, 2))
+
+ sizer.Add(item = gridSizer, proportion = 1)
+
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+
+ def GetSelection(self):
+ """!Get selected element"""
+ selection = self.searchBy.GetStringSelection()
+
+ return self._searchDict[selection]
+
+ def SetSelection(self, i):
+ """!Set selection element"""
+ self.searchBy.SetSelection(i)
+
+ def OnSearchModule(self, event):
+ """!Search module by keywords or description"""
+ if not self.cmdPrompt:
+ event.Skip()
+ return
+
+ text = event.GetString()
+ if not text:
+ self.cmdPrompt.SetFilter(None)
+ mList = self.cmdPrompt.GetCommandItems()
+ self.searchChoice.SetItems(mList)
+ if self.showTip:
+ self.searchTip.SetLabel(_("%d modules found") % len(mList))
+ event.Skip()
+ return
+
+ modules = dict()
+ iFound = 0
+ for module, data in self.cmdPrompt.moduleDesc.iteritems():
+ found = False
+ sel = self.searchBy.GetSelection()
+ if sel == 0: # -> description
+ if text in data['desc']:
+ found = True
+ elif sel == 1: # keywords
+ if self.cmdPrompt.CheckKey(text, 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 not modules.has_key(group):
+ 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('')
+
+class MenuTreeWindow(wx.Panel):
+ """!Show menu tree"""
+ def __init__(self, parent, id = wx.ID_ANY, **kwargs):
+ self.parent = parent # LayerManager
+
+ wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+
+ self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label=" %s " % _("Menu tree (double-click to run command)"))
+ # tree
+ self.tree = MenuTree(parent = self, data = menudata.ManagerData())
+ self.tree.Load()
+
+ # search widget
+ self.search = SearchModuleWindow(parent = self, showChoice = False)
+
+ # buttons
+ self.btnRun = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
+ self.btnRun.SetToolTipString(_("Run selected command"))
+ self.btnRun.Enable(False)
+
+ # bindings
+ self.btnRun.Bind(wx.EVT_BUTTON, self.OnRun)
+ self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
+ self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
+ self.search.Bind(wx.EVT_TEXT_ENTER, self.OnShowItem)
+ self.search.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
+
+ self._layout()
+
+ self.search.SetFocus()
+
+ def _layout(self):
+ """!Do dialog layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ # body
+ dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
+ dataSizer.Add(item = self.tree, proportion =1,
+ flag = wx.EXPAND)
+
+ # buttons
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+ btnSizer.Add(item = self.btnRun, proportion = 0)
+
+ sizer.Add(item = dataSizer, proportion = 1,
+ flag = wx.EXPAND | wx.ALL, border = 5)
+
+ sizer.Add(item = self.search, proportion=0,
+ flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
+
+ sizer.Add(item = btnSizer, proportion=0,
+ flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
+
+ sizer.Fit(self)
+ sizer.SetSizeHints(self)
+
+ self.SetSizer(sizer)
+
+ self.Fit()
+ self.SetAutoLayout(True)
+ self.Layout()
+
+ def OnCloseWindow(self, event):
+ """!Close window"""
+ self.Destroy()
+
+ def OnRun(self, event):
+ """!Run selected command"""
+ if not self.tree.GetSelected():
+ return # should not happen
+
+ data = self.tree.GetPyData(self.tree.GetSelected())
+ if not data:
+ return
+
+ handler = 'self.parent.' + data['handler'].lstrip('self.')
+ if data['handler'] == 'self.OnXTerm':
+ wx.MessageBox(parent = self,
+ message = _('You must run this command from the menu or command line',
+ 'This command require an XTerm'),
+ caption = _('Message'), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ elif data['command']:
+ eval(handler)(event = None, cmd = data['command'].split())
+ else:
+ eval(handler)(None)
+
+ def OnShowItem(self, event):
+ """!Show selected item"""
+ self.tree.OnShowItem(event)
+ if self.tree.GetSelected():
+ self.btnRun.Enable()
+ else:
+ self.btnRun.Enable(False)
+
+ def OnItemActivated(self, event):
+ """!Item activated (double-click)"""
+ item = event.GetItem()
+ if not item or not item.IsOk():
+ return
+
+ data = self.tree.GetPyData(item)
+ if not data or not data.has_key('command'):
+ 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 not data.has_key('command'):
+ return
+
+ if data['command']:
+ label = data['command'] + ' -- ' + data['description']
+ else:
+ label = data['description']
+
+ self.parent.SetStatusText(label, 0)
+
+ def OnUpdateStatusBar(self, event):
+ """!Update statusbar text"""
+ element = self.search.GetSelection()
+ self.tree.SearchItems(element = element,
+ value = event.GetString())
+
+ nItems = len(self.tree.itemsMarked)
+ if event.GetString():
+ self.parent.SetStatusText(_("%d modules match") % nItems, 0)
+ else:
+ self.parent.SetStatusText("", 0)
+
+ event.Skip()
+
+class ItemTree(CT.CustomTreeCtrl):
+ def __init__(self, parent, id = wx.ID_ANY,
+ ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
+ CT.TR_LINES_AT_ROOT | CT.TR_SINGLE, **kwargs):
+ if globalvar.hasAgw:
+ super(ItemTree, self).__init__(parent, id, agwStyle = ctstyle, **kwargs)
+ else:
+ super(ItemTree, self).__init__(parent, id, style = ctstyle, **kwargs)
+
+ self.root = self.AddRoot(_("Menu tree"))
+ self.itemsMarked = [] # list of marked items
+ self.itemSelected = None
+
+ def SearchItems(self, element, value):
+ """!Search item
+
+ @param element element index (see self.searchBy)
+ @param value
+
+ @return list of found tree items
+ """
+ items = list()
+ if not value:
+ return items
+
+ item = self.GetFirstChild(self.root)[0]
+ self._processItem(item, element, value, items)
+
+ self.itemsMarked = items
+ self.itemSelected = None
+
+ return items
+
+ def _processItem(self, item, element, value, listOfItems):
+ """!Search items (used by SearchItems)
+
+ @param item reference item
+ @param listOfItems list of found items
+ """
+ while item and item.IsOk():
+ subItem = self.GetFirstChild(item)[0]
+ if subItem:
+ self._processItem(subItem, element, value, listOfItems)
+ data = self.GetPyData(item)
+
+ if data and data.has_key(element) and \
+ value.lower() in data[element].lower():
+ listOfItems.append(item)
+
+ item = self.GetNextSibling(item)
+
+ def GetSelected(self):
+ """!Get selected item"""
+ return self.itemSelected
+
+ def OnShowItem(self, event):
+ """!Highlight first found item in menu tree"""
+ if len(self.itemsMarked) > 0:
+ if self.GetSelected():
+ self.ToggleItemSelection(self.GetSelected())
+ idx = self.itemsMarked.index(self.GetSelected()) + 1
+ else:
+ idx = 0
+ try:
+ self.ToggleItemSelection(self.itemsMarked[idx])
+ self.itemSelected = self.itemsMarked[idx]
+ self.EnsureVisible(self.itemsMarked[idx])
+ except IndexError:
+ self.ToggleItemSelection(self.itemsMarked[0]) # reselect first item
+ self.EnsureVisible(self.itemsMarked[0])
+ self.itemSelected = self.itemsMarked[0]
+ else:
+ for item in self.root.GetChildren():
+ self.Collapse(item)
+ itemSelected = self.GetSelection()
+ if itemSelected:
+ self.ToggleItemSelection(itemSelected)
+ self.itemSelected = None
+
+class MenuTree(ItemTree):
+ """!Menu tree class"""
+ def __init__(self, parent, data, **kwargs):
+ self.parent = parent
+ self.menudata = data
+
+ super(MenuTree, self).__init__(parent, **kwargs)
+
+ def Load(self, data = None):
+ """!Load menu data tree
+
+ @param data menu data (None to use self.menudata)
+ """
+ if not data:
+ data = self.menudata
+
+ self.itemsMarked = [] # list of marked items
+ for eachMenuData in data.GetMenu():
+ for label, items in eachMenuData:
+ item = self.AppendItem(parentId = self.root,
+ text = label.replace('&', ''))
+ self.__AppendItems(item, items)
+
+ def __AppendItems(self, item, data):
+ """!Append items into tree (used by Load()
+
+ @param item tree item (parent)
+ @parent data menu data"""
+ for eachItem in data:
+ if len(eachItem) == 2:
+ if eachItem[0]:
+ itemSub = self.AppendItem(parentId = item,
+ text = eachItem[0])
+ self.__AppendItems(itemSub, eachItem[1])
+ else:
+ if eachItem[0]:
+ itemNew = self.AppendItem(parentId = item,
+ text = eachItem[0])
+
+ data = { 'item' : eachItem[0],
+ 'description' : eachItem[1],
+ 'handler' : eachItem[2],
+ 'command' : eachItem[3],
+ 'keywords' : eachItem[4] }
+
+ self.SetPyData(itemNew, data)
+
+class AboutWindow(wx.Frame):
+ def __init__(self, parent):
+ """!Create custom About Window
+
+ @todo improve styling
+ """
+ wx.Frame.__init__(self, parent=parent, id=wx.ID_ANY, size=(550,400),
+ title=_('About GRASS GIS'))
+
+ 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
+ version, svn_gis_h_rev, svn_gis_h_date = gcmd.RunCommand('g.version',
+ flags = 'r',
+ read = True).splitlines()
+
+ infoTxt = wx.Panel(parent = panel, id = wx.ID_ANY)
+ infoSizer = wx.BoxSizer(wx.VERTICAL)
+ infoGridSizer = wx.GridBagSizer(vgap=5, hgap=5)
+ infoGridSizer.AddGrowableCol(0)
+ infoGridSizer.AddGrowableCol(1)
+ logo = os.path.join(globalvar.ETCDIR, "gui", "icons", "grass.ico")
+ logoBitmap = wx.StaticBitmap(parent = infoTxt, id = wx.ID_ANY,
+ bitmap = wx.Bitmap(name = logo,
+ type = wx.BITMAP_TYPE_ICO))
+ infoSizer.Add(item = logoBitmap, proportion = 0,
+ flag = wx.ALL | wx.ALIGN_CENTER, border = 25)
+
+ info = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = version.replace('GRASS', 'GRASS GIS').strip() + '\n\n')
+ info.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+ infoSizer.Add(item = info, proportion = 0,
+ flag = wx.BOTTOM | wx.ALIGN_CENTER, border = 15)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = _('Official GRASS site:')),
+ pos = (0, 0),
+ flag = wx.ALIGN_RIGHT)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = 'http://grass.osgeo.org'),
+ pos = (0, 1),
+ flag = wx.ALIGN_LEFT)
+
+ # infoGridSizer.Add(item = hl.HyperLinkCtrl(parent = self, id = wx.ID_ANY,
+ # label = 'http://grass.osgeo.org',
+ # URL = 'http://grass.osgeo.org'),
+ # pos = (0, 1),
+ # flag = wx.LEFT)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = _('GIS Library Revision:')),
+ pos = (2, 0),
+ flag = wx.ALIGN_RIGHT)
+
+ infoGridSizer.Add(item = wx.StaticText(parent = infoTxt, id = wx.ID_ANY,
+ label = svn_gis_h_rev.split(' ')[1] + ' (' +
+ svn_gis_h_date.split(' ')[1] + ')'),
+ pos = (2, 1),
+ flag = wx.ALIGN_LEFT)
+
+ infoSizer.Add(item = infoGridSizer,
+ proportion = 1,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL,
+ border = 25)
+
+ #
+ # create pages
+ #
+ copyrightwin = self.PageCopyright()
+ licensewin = self.PageLicense()
+ authorwin = self.PageCredit()
+ contribwin = self.PageContributors()
+ transwin = self.PageTranslators()
+
+ # create a flat notebook for displaying information about GRASS
+ nbstyle = FN.FNB_VC8 | \
+ FN.FNB_BACKGROUND_GRADIENT | \
+ FN.FNB_TABS_BORDER_SIMPLE | \
+ FN.FNB_NO_X_BUTTON
+
+ if globalvar.hasAgw:
+ aboutNotebook = FN.FlatNotebook(panel, id = wx.ID_ANY, agwStyle = nbstyle)
+ else:
+ aboutNotebook = FN.FlatNotebook(panel, id = wx.ID_ANY, style = nbstyle)
+ aboutNotebook.SetTabAreaColour(globalvar.FNPageColor)
+
+ # make pages for About GRASS notebook
+ pg1 = aboutNotebook.AddPage(infoTxt, text=_("Info"))
+ pg2 = aboutNotebook.AddPage(copyrightwin, text=_("Copyright"))
+ pg3 = aboutNotebook.AddPage(licensewin, text=_("License"))
+ pg4 = aboutNotebook.AddPage(authorwin, text=_("Authors"))
+ pg5 = aboutNotebook.AddPage(contribwin, text=_("Contributors"))
+ pg5 = aboutNotebook.AddPage(transwin, text=_("Translators"))
+
+ 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
+ # self.aboutNotebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnAGPageChanged)
+ btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+
+ infoTxt.SetSizer(infoSizer)
+ infoSizer.Fit(infoTxt)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(item=aboutNotebook, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=1)
+ sizer.Add(item=btnSizer, proportion=0,
+ flag=wx.ALL | wx.ALIGN_RIGHT, border=1)
+ panel.SetSizer(sizer)
+ self.Layout()
+
+ def PageCopyright(self):
+ """Copyright information"""
+ copyfile = os.path.join(os.getenv("GISBASE"), "COPYING")
+ if os.path.exists(copyfile):
+ copyrightFile = open(copyfile, 'r')
+ copytext = copyrightFile.read()
+ copyrightFile.close()
+ else:
+ copytext = _('%s file missing') % 'COPYING'
+
+ # put text into a scrolling panel
+ copyrightwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
+ size=wx.DefaultSize,
+ style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+ copyrighttxt = wx.StaticText(copyrightwin, id=wx.ID_ANY, label=copytext)
+ copyrightwin.SetAutoLayout(True)
+ copyrightwin.sizer = wx.BoxSizer(wx.VERTICAL)
+ copyrightwin.sizer.Add(item=copyrighttxt, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ copyrightwin.SetSizer(copyrightwin.sizer)
+ copyrightwin.Layout()
+ copyrightwin.SetupScrolling()
+
+ return copyrightwin
+
+ def PageLicense(self):
+ """Licence about"""
+ licfile = os.path.join(os.getenv("GISBASE"), "GPL.TXT")
+ if os.path.exists(licfile):
+ licenceFile = open(licfile, 'r')
+ license = ''.join(licenceFile.readlines())
+ licenceFile.close()
+ else:
+ license = _('%s file missing') % 'GPL.TXT'
+ # put text into a scrolling panel
+ licensewin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
+ style = wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
+ licensetxt = wx.StaticText(licensewin, id=wx.ID_ANY, label=license)
+ licensewin.SetAutoLayout(True)
+ licensewin.sizer = wx.BoxSizer(wx.VERTICAL)
+ licensewin.sizer.Add(item=licensetxt, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ licensewin.SetSizer(licensewin.sizer)
+ licensewin.Layout()
+ licensewin.SetupScrolling()
+
+ return licensewin
+
+ def PageCredit(self):
+ """Credit about"""
+ # credits
+ authfile = os.path.join(os.getenv("GISBASE"), "AUTHORS")
+ if os.path.exists(authfile):
+ authorsFile = open(authfile, 'r')
+ authors = unicode(''.join(authorsFile.readlines()), "utf-8")
+ authorsFile.close()
+ else:
+ authors = _('%s file missing') % 'AUTHORS'
+ authorwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
+ style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+ authortxt = wx.StaticText(authorwin, id=wx.ID_ANY, label=authors)
+ authorwin.SetAutoLayout(1)
+ authorwin.SetupScrolling()
+ authorwin.sizer = wx.BoxSizer(wx.VERTICAL)
+ authorwin.sizer.Add(item=authortxt, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ authorwin.SetSizer(authorwin.sizer)
+ authorwin.Layout()
+
+ return authorwin
+
+ def PageContributors(self):
+ """Contributors info"""
+ contribfile = os.path.join(os.getenv("GISBASE"), "contributors.csv")
+ if os.path.exists(contribfile):
+ contribFile = open(contribfile, 'r')
+ contribs = list()
+ for line in contribFile.readlines():
+ cvs_id, name, email, country, osgeo_id, rfc2_agreed = line.split(',')
+ contribs.append((name, email, country, osgeo_id))
+ contribs[0] = (_('Name'), _('E-mail'), _('Country'), _('OSGeo_ID'))
+ contribFile.close()
+ else:
+ contribs = None
+
+ contribwin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
+ style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+ contribwin.SetAutoLayout(1)
+ contribwin.SetupScrolling()
+ contribwin.sizer = wx.BoxSizer(wx.VERTICAL)
+
+ if not contribs:
+ contribtxt = wx.StaticText(contribwin, id=wx.ID_ANY,
+ label=_('%s file missing') % 'contibutors.csv')
+ contribwin.sizer.Add(item=contribtxt, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ else:
+ contribBox = wx.FlexGridSizer(cols=4, vgap=5, hgap=5)
+ for developer in contribs:
+ for item in developer:
+ 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()
+ for line in translatorsFile.readlines()[1:]:
+ name, email, languages = line.rstrip('\n').split(',')
+ for language in languages.split(' '):
+ if not translators.has_key(language):
+ translators[language] = list()
+ translators[language].append((name, email))
+ translatorsFile.close()
+ else:
+ translators = None
+
+ translatorswin = scrolled.ScrolledPanel(self, id=wx.ID_ANY,
+ style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+ translatorswin.SetAutoLayout(1)
+ translatorswin.SetupScrolling()
+ translatorswin.sizer = wx.BoxSizer(wx.VERTICAL)
+
+ if not translators:
+ translatorstxt = wx.StaticText(translatorswin, id=wx.ID_ANY,
+ label=_('%s file missing') % 'translators.csv')
+ translatorswin.sizer.Add(item=translatorstxt, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ else:
+ translatorsBox = wx.FlexGridSizer(cols=3, vgap=5, hgap=5)
+ languages = translators.keys()
+ languages.sort()
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = _('Name')))
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = _('E-mail')))
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = _('Language')))
+ for lang in languages:
+ for translator in translators[lang]:
+ name, email = translator
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = unicode(name, "utf-8")))
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = email))
+ translatorsBox.Add(item = wx.StaticText(parent = translatorswin, id = wx.ID_ANY,
+ label = lang))
+
+ translatorswin.sizer.Add(item=translatorsBox, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+
+ translatorswin.SetSizer(translatorswin.sizer)
+ translatorswin.Layout()
+
+ return translatorswin
+
+ def OnCloseWindow(self, event):
+ """!Close window"""
+ self.Close()
+
+class InstallExtensionWindow(wx.Frame):
+ def __init__(self, parent, id = wx.ID_ANY,
+ title = _("Fetch & install new extension from GRASS Addons"), **kwargs):
+ self.parent = parent
+
+ wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.repoBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("Repository"))
+ self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("List of extensions"))
+
+ self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+ value = 'https://svn.osgeo.org/grass/grass-addons')
+ self.fullDesc = wx.CheckBox(parent = self.panel, id=wx.ID_ANY,
+ label = _("Fetch full info including description and keywords (takes time)"))
+ self.fullDesc.SetValue(False)
+
+ self.search = SearchModuleWindow(parent = self.panel)
+ self.search.SetSelection(2)
+
+ self.tree = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
+
+ self.statusbar = self.CreateStatusBar(0)
+
+ 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.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
+ self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
+ self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
+ 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)
+
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+ 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 = btnSizer, proportion=0,
+ flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+
+ self.Layout()
+
+ def _install(self, name):
+ if not name:
+ return
+ log = self.parent.GetLogWindow()
+ log.RunCmd(['g.extension', 'extension=' + name,
+ 'svnurl=' + self.repo.GetValue().strip()])
+ self.OnCloseWindow(None)
+
+ 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"""
+ 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)
+
+ def OnItemActivated(self, event):
+ item = event.GetItem()
+ data = self.tree.GetPyData(item)
+ if data and data.has_key('command'):
+ self._install(data['command'])
+
+ def OnInstall(self, event):
+ """!Install selected extension"""
+ item = self.tree.GetSelected()
+ if not item.IsOk():
+ return
+ self._install(self.tree.GetItemText(item))
+
+ def OnItemSelected(self, event):
+ """!Item selected"""
+ item = event.GetItem()
+ self.tree.itemSelected = item
+ data = self.tree.GetPyData(item)
+ if not data:
+ self.SetStatusText('', 0)
+ self.btnInstall.Enable(False)
+ else:
+ self.SetStatusText(data.get('description', ''), 0)
+ self.btnInstall.Enable(True)
+
+ def OnShowItem(self, event):
+ """!Show selected item"""
+ self.tree.OnShowItem(event)
+ if self.tree.GetSelected():
+ self.btnInstall.Enable()
+ else:
+ self.btnInstall.Enable(False)
+
+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'):
+ 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' }
+
+ if name.has_key(c):
+ return name[c]
+
+ return c
+
+ def _findItem(self, text):
+ """!Find item"""
+ item = self.GetFirstChild(self.root)[0]
+ while item and item.IsOk():
+ if text == self.GetItemText(item):
+ return item
+
+ item = self.GetNextSibling(item)
+
+ return None
+
+ def Load(self, url, full = False):
+ """!Load list of extensions"""
+ self.DeleteAllItems()
+ self.root = self.AddRoot(_("Menu tree"))
+ self._initTree()
+
+ if full:
+ flags = 'g'
+ else:
+ flags = 'l'
+ ret = gcmd.RunCommand('g.extension', read = True,
+ svnurl = url,
+ flags = flags, quiet = True)
+ if not ret:
+ return
+
+ mdict = dict()
+ for line in ret.splitlines():
+ if full:
+ key, value = line.split('=', 1)
+ if key == 'name':
+ prefix, name = value.split('.', 1)
+ if not mdict.has_key(prefix):
+ mdict[prefix] = dict()
+ mdict[prefix][name] = dict()
+ else:
+ mdict[prefix][name][key] = value
+ else:
+ prefix, name = line.strip().split('.', 1)
+ if not mdict.has_key(prefix):
+ mdict[prefix] = dict()
+
+ mdict[prefix][name] = { 'command' : prefix + '.' + name }
+
+ for prefix in mdict.keys():
+ prefixName = self._expandPrefix(prefix)
+ item = self._findItem(prefixName)
+ names = mdict[prefix].keys()
+ names.sort()
+ for name in names:
+ new = self.AppendItem(parentId = item,
+ text = prefix + '.' + name)
+ data = dict()
+ for key in mdict[prefix][name].keys():
+ data[key] = mdict[prefix][name][key]
+
+ self.SetPyData(new, data)
+
+ self._loaded = True
+
+ def IsLoaded(self):
+ """Check if items are loaded"""
+ return self._loaded
+
+class HelpWindow(wx.html.HtmlWindow):
+ """!This panel holds the text from GRASS docs.
+
+ GISBASE must be set in the environment to find the html docs dir.
+ The SYNOPSIS section is skipped, since this Panel is supposed to
+ be integrated into the cmdPanel and options are obvious there.
+ """
+ def __init__(self, parent, grass_command, text, skip_description,
+ **kwargs):
+ """!If grass_command is given, the corresponding HTML help
+ file will be presented, with all links pointing to absolute
+ paths of local files.
+
+ If 'skip_description' is True, the HTML corresponding to
+ SYNOPSIS will be skipped, thus only presenting the help file
+ from the DESCRIPTION section onwards.
+
+ If 'text' is given, it must be the HTML text to be presented
+ in the Panel.
+ """
+ self.parent = parent
+ wx.InitAllImageHandlers()
+ wx.html.HtmlWindow.__init__(self, parent = parent, **kwargs)
+
+ gisbase = os.getenv("GISBASE")
+ self.loaded = False
+ self.history = list()
+ self.historyIdx = 0
+ self.fspath = os.path.join(gisbase, "docs", "html")
+
+ self.SetStandardFonts (size = 10)
+ self.SetBorders(10)
+
+ if text is None:
+ if skip_description:
+ url = os.path.join(self.fspath, grass_command + ".html")
+ self.fillContentsFromFile(url,
+ skip_description = skip_description)
+ self.history.append(url)
+ self.loaded = True
+ else:
+ ### FIXME: calling LoadPage() is strangely time-consuming (only first call)
+ # self.LoadPage(self.fspath + grass_command + ".html")
+ self.loaded = False
+ else:
+ self.SetPage(text)
+ self.loaded = True
+
+ def OnLinkClicked(self, linkinfo):
+ url = linkinfo.GetHref()
+ if url[:4] != 'http':
+ url = os.path.join(self.fspath, url)
+ self.history.append(url)
+ self.historyIdx += 1
+ self.parent.OnHistory()
+
+ super(HelpWindow, self).OnLinkClicked(linkinfo)
+
+ def fillContentsFromFile(self, htmlFile, skip_description=True):
+ """!Load content from file"""
+ aLink = re.compile(r'(<a href="?)(.+\.html?["\s]*>)', re.IGNORECASE)
+ imgLink = re.compile(r'(<img src="?)(.+\.[png|gif])', re.IGNORECASE)
+ try:
+ contents = []
+ skip = False
+ for l in file(htmlFile, "rb").readlines():
+ if "DESCRIPTION" in l:
+ skip = False
+ if not skip:
+ # do skip the options description if requested
+ if "SYNOPSIS" in l:
+ skip = skip_description
+ else:
+ # FIXME: find only first item
+ findALink = aLink.search(l)
+ if findALink is not None:
+ contents.append(aLink.sub(findALink.group(1)+
+ self.fspath+findALink.group(2),l))
+ findImgLink = imgLink.search(l)
+ if findImgLink is not None:
+ contents.append(imgLink.sub(findImgLink.group(1)+
+ self.fspath+findImgLink.group(2),l))
+
+ if findALink is None and findImgLink is None:
+ contents.append(l)
+ self.SetPage("".join(contents))
+ self.loaded = True
+ except: # The Manual file was not found
+ self.loaded = False
+
+class HelpPanel(wx.Panel):
+ def __init__(self, parent, grass_command = "index", text = None,
+ skip_description = False, **kwargs):
+ self.grass_command = grass_command
+ wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
+
+ self.content = HelpWindow(self, grass_command, text,
+ skip_description)
+
+ self.btnNext = wx.Button(parent = self, id = wx.ID_ANY,
+ label = _("&Next"))
+ self.btnNext.Enable(False)
+ self.btnPrev = wx.Button(parent = self, id = wx.ID_ANY,
+ label = _("&Previous"))
+ self.btnPrev.Enable(False)
+
+ self.btnNext.Bind(wx.EVT_BUTTON, self.OnNext)
+ self.btnPrev.Bind(wx.EVT_BUTTON, self.OnPrev)
+
+ self._layout()
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+ btnSizer.Add(item = self.btnPrev, proportion = 0,
+ flag = wx.ALL, border = 5)
+ btnSizer.Add(item = wx.Size(1, 1), proportion = 1)
+ btnSizer.Add(item = self.btnNext, proportion = 0,
+ flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
+
+ sizer.Add(item = self.content, proportion = 1,
+ flag = wx.EXPAND)
+ sizer.Add(item = btnSizer, proportion = 0,
+ flag = wx.EXPAND)
+
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+
+ def LoadPage(self, path = None):
+ """!Load page"""
+ if not path:
+ path = os.path.join(self.content.fspath, self.grass_command + ".html")
+ self.content.history.append(path)
+ self.content.LoadPage(path)
+
+ def IsFile(self):
+ """!Check if file exists"""
+ return os.path.isfile(os.path.join(self.content.fspath, self.grass_command + ".html"))
+
+ def IsLoaded(self):
+ return self.content.loaded
+
+ def OnHistory(self):
+ """!Update buttons"""
+ nH = len(self.content.history)
+ iH = self.content.historyIdx
+ if iH == nH - 1:
+ self.btnNext.Enable(False)
+ elif iH > -1:
+ self.btnNext.Enable(True)
+ if iH < 1:
+ self.btnPrev.Enable(False)
+ else:
+ self.btnPrev.Enable(True)
+
+ def OnNext(self, event):
+ """Load next page"""
+ self.content.historyIdx += 1
+ idx = self.content.historyIdx
+ path = self.content.history[idx]
+ self.content.LoadPage(path)
+ self.OnHistory()
+
+ event.Skip()
+
+ def OnPrev(self, event):
+ """Load previous page"""
+ self.content.historyIdx -= 1
+ idx = self.content.historyIdx
+ path = self.content.history[idx]
+ self.content.LoadPage(path)
+ self.OnHistory()
+
+ event.Skip()
Property changes on: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/ghelp.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/globalvar.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/globalvar.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/globalvar.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -8,9 +8,8 @@
(C) 2007-2010 by the GRASS Development Team
-This program is free software under the GNU General Public
-License (>=v2). Read the file COPYING that comes with GRASS
-for details.
+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>
"""
@@ -19,10 +18,20 @@
import sys
import locale
+if not os.getenv("GISBASE"):
+ sys.exit("GRASS is not running. Exiting...")
### i18N
import gettext
gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode=True)
+# 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")
+
+sys.path.append(os.path.join(ETCDIR, "python"))
+import grass.script as grass
+
# wxversion.select() called once at the beginning
check = True
@@ -35,7 +44,7 @@
return True
def CheckForWx():
- """Try to import wx module and check its version"""
+ """!Try to import wx module and check its version"""
global check
if not check:
return
@@ -84,24 +93,26 @@
# temporal query layer (removed on re-render action)
QUERYLAYER = 'qlayer'
-# 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")
-
-"""Style definition for FlatNotebook pages"""
+"""!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 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 = (770, 570)
HIST_WINDOW_SIZE = (500, 350)
@@ -112,9 +123,11 @@
_("Show comp. extent"),
_("Display mode"),
_("Display geometry"),
- _("Map scale")]
+ _("Map scale"),
+ _("Go to"),
+ _("Projection"),]
-"""File name extension binaries/scripts"""
+"""!File name extension binaries/scripts"""
if subprocess.mswindows:
EXT_BIN = '.exe'
EXT_SCT = '.bat'
@@ -122,7 +135,7 @@
EXT_BIN = ''
EXT_SCT = ''
-def GetGRASSCmds(bin=True, scripts=True, gui_scripts=True):
+def GetGRASSCmds(bin = True, scripts = True, gui_scripts = True):
"""!Create list of all available GRASS commands to use when
parsing string from the command line
"""
@@ -137,10 +150,11 @@
# add special call for setting vector colors
cmd.append('vcolors')
- if scripts is True:
+ if scripts:
cmd = cmd + os.listdir(os.path.join(gisbase, 'scripts'))
- if gui_scripts is True:
+ if gui_scripts:
os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'gui', 'scripts')
+ os.environ["PATH"] = os.getenv("PATH") + os.pathsep + os.path.join(gisbase, 'etc', 'wxpython', 'scripts')
cmd = cmd + os.listdir(os.path.join(gisbase, 'etc', 'gui', 'scripts'))
if subprocess.mswindows:
@@ -153,7 +167,7 @@
"""@brief Collected GRASS-relared binaries/scripts"""
grassCmd = {}
grassCmd['all'] = GetGRASSCmds()
-grassCmd['script'] = GetGRASSCmds(bin=False)
+grassCmd['script'] = GetGRASSCmds(bin = False)
"""@Toolbar icon size"""
toolbarSize = (24, 24)
@@ -166,3 +180,6 @@
"""@Check version of wxPython, use agwStyle for 2.8.11+"""
hasAgw = CheckWxVersion()
+
+"""@List of commands for auto-rendering"""
+cmdAutoRender = [ 'r.colors', 'i.landsat.rgb' ]
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gmodeler.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gmodeler.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gmodeler.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,4534 @@
+"""!
+ at package gmodeler.py
+
+ at brief wxGUI Graphical Modeler for creating, editing, and managing models
+
+Classes:
+ - Model
+ - ModelFrame
+ - ModelCanvas
+ - ModelObject
+ - ModelAction
+ - ModelSearchDialog
+ - ModelData
+ - ModelDataDialog
+ - ModelRelation
+ - ProcessModelFile
+ - WriteModelFile
+ - PreferencesDialog
+ - PropertiesDialog
+ - ModelParamDialog
+ - ModelListCtrl
+ - VariablePanel
+ - ValiableListCtrl
+ - ModelItem
+ - ModelItemDialog
+ - ModelLoop
+ - ModelLoopDialog
+ - ItemPanel
+ - ItemListCtrl
+ - ItemCheckListCtrl
+ - ModelCondition
+ - ModelConditionDialog
+ - WritePythonFile
+
+(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>
+"""
+
+import os
+import sys
+import shlex
+import time
+import traceback
+import getpass
+import stat
+import textwrap
+import tempfile
+import copy
+import re
+
+try:
+ import xml.etree.ElementTree as etree
+except ImportError:
+ import elementtree.ElementTree as etree # Python <= 2.4
+
+import globalvar
+if not os.getenv("GRASS_WXBUNDLED"):
+ globalvar.CheckForWx()
+import wx
+import wx.lib.ogl as ogl
+import wx.lib.flatnotebook as FN
+import wx.lib.colourselect as csel
+import wx.lib.mixins.listctrl as listmix
+
+import menu
+import menudata
+import toolbars
+import menuform
+import prompt
+import utils
+import goutput
+import gselect
+from debug import Debug
+from gcmd import GMessage, GException, GWarning, GError
+from gdialogs import ElementDialog, GetImageHandlers
+from preferences import PreferencesBaseDialog, globalSettings as UserSettings
+from ghelp import SearchModuleWindow
+
+from grass.script import core as grass
+
+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 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())
+
+ 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()
+ for action in self.GetItems(objType = ModelAction):
+ for rel in action.GetRelations():
+ dataItem = rel.GetData()
+ if dataItem not in result:
+ result.append(dataItem)
+
+ 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)
+
+ task = actionItem.GetTask()
+ parameterized = False
+ valid = True
+ for f in task.get_options()['flags']:
+ if f.get('parameterized', False):
+ parameterized = True
+ break
+ for p in task.get_options()['params']:
+ if p.get('required', 'no') != 'no' and \
+ p.get('value', '') == '' and \
+ p.get('default', '') == '':
+ valid = False
+ if p.get('parameterized', False):
+ parameterized = True
+
+ actionItem.SetValid(valid)
+ actionItem.SetParameterized(parameterized)
+ 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(dataItem, actionItem, rel['name'])
+ else:
+ relation = ModelRelation(actionItem, dataItem, rel['name'])
+ relation.SetControlPoints(rel['points'])
+ actionItem.AddRelation(relation)
+ dataItem.AddRelation(relation)
+
+ 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()
+ for action in self.GetItems(objType = ModelAction):
+ task = menuform.GUI().ParseCommand(cmd = action.GetLog(string = False),
+ show = None)
+ errList += task.getCmdError()
+
+ return errList
+
+ def Run(self, log, onDone):
+ """!Run model"""
+ for action in self.actions:
+ if not action.IsEnabled():
+ continue
+ log.RunCmd(command = action.GetLog(string = False),
+ onDone = onDone)
+
+ 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'):
+ gisprompt = True
+ prompt = gtype
+ if gtype == 'raster':
+ element = 'cell'
+ else:
+ element = 'vector'
+ ptype = 'string'
+ else:
+ gisprompt = False
+ prompt = None
+ element = None
+ ptype = gtype
+ params.append({ 'gisprompt' : gisprompt,
+ 'multiple' : 'no',
+ 'description' : values.get('description', ''),
+ 'guidependency' : '',
+ 'default' : '',
+ 'age' : None,
+ 'required' : 'yes',
+ '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 not result.has_key(name):
+ result[name] = { 'flags' : list(),
+ 'params': list(),
+ 'idx' : idx }
+ result[name]['flags'].append(f)
+ for p in params['params']:
+ if p.get('parameterized', False):
+ if not result.has_key(name):
+ result[name] = { 'flags' : list(),
+ 'params': list(),
+ 'idx' : idx }
+ result[name]['params'].append(p)
+ idx += 1
+
+ self.variablesParams = result # record parameters
+
+ return result
+
+class ModelFrame(wx.Frame):
+ def __init__(self, parent, id = wx.ID_ANY,
+ title = _("GRASS GIS Graphical Modeler"), **kwargs):
+ """!Graphical modeler main window
+
+ @param parent parent window
+ @param id window id
+ @param title window title
+
+ @param kwargs wx.Frames' arguments
+ """
+ self.parent = parent
+ self.searchDialog = None # module search dialog
+ self.baseTitle = title
+ self.modelFile = None # loaded model
+ self.modelChanged = False
+
+ self.cursors = {
+ "default" : wx.StockCursor(wx.CURSOR_ARROW),
+ "cross" : wx.StockCursor(wx.CURSOR_CROSS),
+ }
+
+ wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
+ self.SetName("Modeler")
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+ self.menubar = menu.Menu(parent = self, data = menudata.ModelerData())
+
+ self.SetMenuBar(self.menubar)
+
+ self.toolbar = toolbars.ModelToolbar(parent = self)
+ self.SetToolBar(self.toolbar)
+
+ self.statusbar = self.CreateStatusBar(number = 1)
+
+ if globalvar.hasAgw:
+ self.notebook = FN.FlatNotebook(parent = self, id = wx.ID_ANY,
+ agwStyle = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
+ FN.FNB_NO_NAV_BUTTONS | FN.FNB_NO_X_BUTTON)
+ else:
+ self.notebook = FN.FlatNotebook(parent = self, id = wx.ID_ANY,
+ style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
+ FN.FNB_NO_NAV_BUTTONS | FN.FNB_NO_X_BUTTON)
+
+ self.canvas = ModelCanvas(self)
+ self.canvas.SetBackgroundColour(wx.WHITE)
+ self.canvas.SetCursor(self.cursors["default"])
+
+ self.model = Model(self.canvas)
+
+ self.variablePanel = VariablePanel(parent = self)
+
+ self.itemPanel = ItemPanel(parent = self)
+
+ self.goutput = goutput.GMConsole(parent = self, pageid = 3,
+ notebook = self.notebook)
+
+ self.notebook.AddPage(self.canvas, text=_('Model'))
+ self.notebook.AddPage(self.itemPanel, text=_('Items'))
+ self.notebook.AddPage(self.variablePanel, text=_('Variables'))
+ self.notebook.AddPage(self.goutput, text=_('Command output'))
+ wx.CallAfter(self.notebook.SetSelection, 0)
+ 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.SetSelection(2)
+
+ 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 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:
+ gcmd.RunCommand('g.manual',
+ quiet = True,
+ entry = 'wxGUI.Modeler')
+
+ def OnModelProperties(self, event):
+ """!Model properties dialog"""
+ dlg = PropertiesDialog(parent = self)
+ dlg.CentreOnParent()
+ properties = self.model.GetProperties()
+ dlg.Init(properties)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.ModelChanged()
+ for key, value in dlg.GetValues().iteritems():
+ properties[key] = value
+ for action in self.model.GetItems(objType = ModelAction):
+ action.GetTask().set_flag('overwrite', properties['overwrite'])
+
+ dlg.Destroy()
+
+ def OnDeleteData(self, event):
+ """!Delete intermediate data"""
+ rast, vect, rast3d, msg = self.model.GetIntermediateData()
+
+ if not rast and not vect and not rast3d:
+ GMessage(parent = self,
+ message = _('Nothing to delete.'))
+ return
+
+ dlg = wx.MessageDialog(parent = self,
+ message= _("Do you want to permanently delete data?%s" % msg),
+ caption=_("Delete intermediate data?"),
+ style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+
+ ret = dlg.ShowModal()
+ if ret == wx.ID_YES:
+ dlg.Destroy()
+
+ if rast:
+ self.goutput.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
+ if rast3d:
+ self.goutput.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
+ if vect:
+ self.goutput.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
+
+ self.SetStatusText(_("%d maps deleted from current mapset") % \
+ int(len(rast) + len(rast3d) + len(vect)))
+ return
+
+ dlg.Destroy()
+
+ def OnModelNew(self, event):
+ """!Create new model"""
+ Debug.msg(4, "ModelFrame.OnModelNew():")
+
+ # ask user to save current model
+ if self.modelFile and self.modelChanged:
+ self.OnModelSave()
+ elif self.modelFile is None and \
+ (self.model.GetNumItems() > 0 or len(self.model.GetData()) > 0):
+ dlg = wx.MessageDialog(self, message=_("Current model is not empty. "
+ "Do you want to store current settings "
+ "to model file?"),
+ caption=_("Create new model?"),
+ style=wx.YES_NO | wx.YES_DEFAULT |
+ wx.CANCEL | wx.ICON_QUESTION)
+ ret = dlg.ShowModal()
+ if ret == wx.ID_YES:
+ self.OnModelSaveAs()
+ elif ret == wx.ID_CANCEL:
+ dlg.Destroy()
+ return
+
+ dlg.Destroy()
+
+ # delete all items
+ self.canvas.GetDiagram().DeleteAllShapes()
+ self.model.Reset()
+ self.canvas.Refresh()
+
+ # 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"""
+ if self.model.GetNumItems() < 1:
+ GMessage(parent = self,
+ message = _('Model is empty. Nothing to run.'))
+ return
+
+ # validation
+ errList = self._validateModel()
+ if errList:
+ dlg = wx.MessageDialog(parent = self,
+ message = _('Model is not valid. Do you want to '
+ 'run the model anyway?\n\n%s') % '\n'.join(errList),
+ caption=_("Run model?"),
+ style = wx.YES_NO | wx.NO_DEFAULT |
+ wx.ICON_QUESTION | wx.CENTRE)
+ ret = dlg.ShowModal()
+ if ret != wx.ID_YES:
+ return
+
+ # parametrization
+ params = self.model.Parameterize()
+ if params:
+ dlg = ModelParamDialog(parent = self,
+ params = params)
+ dlg.CenterOnParent()
+
+ ret = dlg.ShowModal()
+ if ret != wx.ID_OK:
+ dlg.Destroy()
+ return
+
+ err = dlg.GetErrors()
+ if err:
+ GError(parent = self,
+ message = unicode('\n'.join(err)))
+ return
+
+ self.goutput.cmdThread.SetId(-1)
+ for item in self.model.GetItems():
+ if not item.IsEnabled():
+ continue
+ if isinstance(item, ModelAction):
+ if item.GetLoopId():
+ continue
+ self._runAction(item, params)
+ elif isinstance(item, ModelLoop):
+ cond = item.GetText()
+ # substitute variables in condition
+ variables = self.model.GetVariables()
+ for variable in variables:
+ pattern = re.compile('%' + variable)
+ if pattern.search(cond):
+ value = variables[variable].get('value', '')
+ vtype = variables[variable].get('type', 'string')
+ if vtype == 'string':
+ value = '"' + value + '"'
+ cond = pattern.sub(value, cond)
+ # split condition
+ condVar, condText = re.split('\s*in\s*', cond)
+
+ for action in item.GetItems():
+ for vars()[condVar] in eval(condText):
+ if isinstance(action, ModelAction):
+ self._runAction(action, params)
+
+ if params:
+ dlg.Destroy()
+
+ def _runAction(self, item, params):
+ """!Run given action"""
+ name = item.GetName()
+ if params.has_key(name):
+ paramsOrig = item.GetParams(dcopy = True)
+ item.MergeParams(params[name])
+
+ self.SetStatusText(_('Running model...'), 0)
+ self.goutput.RunCmd(command = item.GetLog(string = False),
+ onDone = self.OnDone)
+
+ if params.has_key(name):
+ item.SetParams(paramsOrig)
+
+ def OnDone(self, cmd, returncode):
+ """!Computation finished"""
+ self.SetStatusText('', 0)
+
+ 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
+
+ errList = self._validateModel()
+
+ 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:
+ xminImg = xmin
+ if ymax < ymaxImg:
+ xminImg = xmin
+
+ size = wx.Size(int(xmaxImg - xminImg),
+ int(ymaxImg - ymaxImg))
+ 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 _validateModel(self):
+ """!Validate model"""
+ self.SetStatusText(_('Validating model...'), 0)
+
+ errList = self.model.Validate()
+
+ self.SetStatusText('', 0)
+
+ return errList
+
+ 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()
+ if cmd[0] == 'r.mapcalc':
+ GMessage(parent = self,
+ message = _("Module r.mapcalc cannot be used in the model. "
+ "Use r.mapcalculator instead."))
+ return
+
+ action = ModelAction(self.model, cmd = cmd, x = width/2, y = height/2,
+ id = self.model.GetNumItems() + 1)
+ 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 and action.GetLog(string = False):
+ module = menuform.GUI().ParseCommand(action.GetLog(string = False),
+ completed = (self.GetOptData, action, action.GetParams()),
+ parentframe = self, show = True)
+ elif win and not win.IsShown():
+ win.Show()
+
+ if win:
+ win.Raise()
+
+ def OnAddData(self, event):
+ """!Add data item to model
+
+ @todo
+ """
+ # add action to canvas
+ width, height = self.canvas.GetSize()
+ data = ModelData(self, x = width/2, y = height/2)
+ self.canvas.diagram.AddShape(data)
+ data.Show(True)
+
+ self._addEvent(data)
+ # self.model.AddData(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')
+ info.SetDescription(_('(C) 2010 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 GetOptData(self, dcmd, layer, params, propwin):
+ """!Process action data"""
+ if params: # add data items
+ for p in params['params']:
+ if p.get('prompt', '') in ('raster', 'vector', 'raster3d'):
+ try:
+ name, mapset = p.get('value', '').split('@', 1)
+ except (ValueError, IndexError):
+ continue
+
+ if mapset != grass.gisenv()['MAPSET']:
+ continue
+
+ # don't use fully qualified names
+ p['value'] = p.get('value', '').split('@')[0]
+ for idx in range(1, len(dcmd)):
+ if p.get('name', '') in dcmd[idx]:
+ dcmd[idx] = p.get('name', '') + '=' + p.get('value', '')
+ break
+
+ 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(data, layer, p.get('name', ''))
+ else:
+ rel = ModelRelation(layer, data, 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(data, layer, p.get('name', ''))
+ else:
+ rel = ModelRelation(layer, data, p.get('name', ''))
+ layer.AddRelation(rel)
+ data.AddRelation(rel)
+ self.AddLine(rel)
+ data.Update()
+
+ # valid ?
+ valid = True
+ for p in params['params']:
+ if p.get('required', 'no') != 'no' and \
+ p.get('value', '') == '' and \
+ p.get('default', '') == '':
+ valid = False
+ break
+ layer.SetValid(valid)
+
+ # parameterized ?
+ parameterized = False
+ for f in params['flags']:
+ if f.get('parameterized', False):
+ parameterized = True
+ break
+ if not parameterized:
+ for p in params['params']:
+ if p.get('parameterized', False):
+ parameterized = True
+ break
+ layer.SetParameterized(parameterized)
+
+ 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)
+
+ 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, 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(item, 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, 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)
+ del shape
+ for item in remList:
+ diagram.RemoveShape(item)
+ item.__del__()
+
+ for item in upList:
+ item.Update()
+
+ self.Refresh()
+
+class ModelObject:
+ def __init__(self, id = -1):
+ self.id = id
+ self.rels = list() # list of ModelRelations
+
+ self.isEnabled = True
+ self.inBlock = list() # list of related loops/conditions
+
+ def __del__(self):
+ pass
+
+ def GetId(self):
+ """!Get id"""
+ return self.id
+
+ def AddRelation(self, rel):
+ """!Record new relation
+ """
+ self.rels.append(rel)
+
+ def GetRelations(self, fdir = None):
+ """!Get list of relations
+
+ @param fdir True for 'from'
+ """
+ if fdir is None:
+ return self.rels
+
+ result = list()
+ for rel in self.rels:
+ if fdir == 'from':
+ if rel.GetFrom() == self:
+ result.append(rel)
+ else:
+ if rel.GetTo() == self:
+ result.append(rel)
+
+ return result
+
+ def IsEnabled(self):
+ """!Get True if action is enabled, otherwise False"""
+ return self.isEnabled
+
+ def Enable(self, enabled = True):
+ """!Enable/disable action"""
+ self.isEnabled = enabled
+ self.Update()
+
+ def Update(self):
+ pass
+
+ def SetBlock(self, item):
+ """!Add object to the block (loop/condition)
+
+ @param item reference to ModelLoop or ModelCondition which
+ defines loops/condition
+ """
+ if item not in self.inBlock:
+ self.inBlock.append(item)
+
+ def UnSetBlock(self, item):
+ """!Remove object from the block (loop/consition)
+
+ @param item reference to ModelLoop or ModelCondition which
+ defines loops/codition
+ """
+ if item in self.inBlock:
+ self.inBlock.remove(item)
+
+ def GetBlock(self):
+ """!Get list of related ModelObject(s) which defines block
+ (loop/condition)
+
+ @return list of ModelObjects
+ """
+ return self.inBlock
+
+ def GetBlockId(self):
+ """!Get list of related ids which defines block
+
+ @return list of ids
+ """
+ ret = list()
+ for mo in self.inBlock:
+ ret.append(mo.GetId())
+
+ return ret
+
+class ModelAction(ModelObject, ogl.RectangleShape):
+ """!Action class (GRASS module)"""
+ def __init__(self, parent, x, y, id = -1, cmd = None, task = None, width = None, height = None):
+ ModelObject.__init__(self, id)
+
+ self.parent = parent
+ self.task = task
+
+ if not width:
+ width = UserSettings.Get(group='modeler', key='action', subkey=('size', 'width'))
+ if not height:
+ height = UserSettings.Get(group='modeler', key='action', subkey=('size', 'height'))
+
+ if cmd:
+ self.task = menuform.GUI().ParseCommand(cmd = cmd,
+ show = None)
+ 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)
+
+ 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='action',
+ subkey=('color', 'disabled'))
+ 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.getCmd(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):
+ """!Get logging info"""
+ cmd = self.task.getCmd(ignoreErrors = True)
+ # substitute variables
+ variables = self.parent.GetVariables()
+ fparams = self.parent.GetVariables(params = True)
+ params = None
+ for values in fparams.itervalues():
+ params = values['params']
+ break
+
+ for variable in variables:
+ pattern= re.compile('%' + variable)
+ value = None
+ if params:
+ for p in params:
+ if variable == p.get('name', ''):
+ value = p.get('value', '')
+ break
+ if not value:
+ value = variables[variable].get('value', '')
+
+ for idx in range(len(cmd)):
+ if pattern.search(cmd[idx]):
+ if value:
+ cmd[idx] = pattern.sub(value, cmd[idx])
+ else:
+ self.isValid = False
+ break
+ idx += 1
+
+ if string:
+ if cmd is None:
+ return ''
+ else:
+ return ' '.join(cmd)
+
+ return cmd
+
+ def GetName(self):
+ """!Get name"""
+ cmd = self.task.getCmd(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 params.has_key('flags'):
+ for f in params['flags']:
+ self.task.set_flag(f['name'],
+ f.get('value', False))
+ if params.has_key('params'):
+ for p in params['params']:
+ self.task.set_param(p['name'],
+ p.get('value', ''))
+
+ def SetValid(self, isvalid):
+ """!Set instance to be valid/invalid"""
+ self.isValid = isvalid
+ self._setBrush()
+
+ def SetParameterized(self, isparameterized):
+ """!Set action parameterized"""
+ self.isParameterized = isparameterized
+ self._setPen()
+
+ def IsParameterized(self):
+ """!Check if action is parameterized"""
+ return self.isParameterized
+
+ def FindData(self, name):
+ """!Find data item by name"""
+ for rel in self.GetRelations():
+ data = rel.GetData()
+ if name == rel.GetName() and name in data.GetName():
+ return data
+
+ return None
+
+ def Update(self, running = False):
+ """!Update action"""
+ if running:
+ self._setBrush(running = True)
+ else:
+ self._setBrush()
+ self._setPen()
+
+ def OnDraw(self, dc):
+ """!Draw action in canvas"""
+ self._setBrush()
+ self._setPen()
+ ogl.RectangleShape.OnDraw(self, dc)
+
+class ModelData(ModelObject, ogl.EllipseShape):
+ def __init__(self, parent, x, y, value = '', prompt = '', width = None, height = None):
+ """Data item class
+
+ @param parent window parent
+ @param x, y position of the shape
+ @param fname, tname list of parameter names from / to
+ @param value value
+ @param prompt type of GIS element
+ @param width, height dimension of the shape
+ """
+ ModelObject.__init__(self)
+
+ self.parent = parent
+ self.value = value
+ self.prompt = prompt
+ self.intermediate = False
+ self.propWin = None
+ if not width:
+ width = UserSettings.Get(group='modeler', key='data', subkey=('size', 'width'))
+ if not height:
+ height = UserSettings.Get(group='modeler', key='data', subkey=('size', 'height'))
+
+ if self.parent.GetCanvas():
+ ogl.EllipseShape.__init__(self, width, height)
+
+ self.SetCanvas(self.parent)
+ self.SetX(x)
+ self.SetY(y)
+ self.SetPen(wx.BLACK_PEN)
+ self._setBrush()
+
+ self._setText()
+
+ def IsIntermediate(self):
+ """!Checks if data item is intermediate"""
+ return self.intermediate
+
+ def SetIntermediate(self, im):
+ """!Set intermediate flag"""
+ self.intermediate = im
+
+ def OnDraw(self, dc):
+ pen = self.GetPen()
+ pen.SetWidth(1)
+ if self.intermediate:
+ pen.SetStyle(wx.SHORT_DASH)
+ else:
+ pen.SetStyle(wx.SOLID)
+ self.SetPen(pen)
+
+ ogl.EllipseShape.OnDraw(self, dc)
+
+ def GetLog(self, string = True):
+ """!Get logging info"""
+ name = list()
+ for rel in self.GetRelations():
+ name.append(rel.GetName())
+ if name:
+ return '/'.join(name) + '=' + self.value + ' (' + self.prompt + ')'
+ else:
+ return _('unknown')
+
+ 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 GetValue(self):
+ """!Get value"""
+ return self.value
+
+ def SetValue(self, value):
+ """!Set value"""
+ self.value = value
+ self._setText()
+ for direction in ('from', 'to'):
+ for rel in self.GetRelations(direction):
+ if direction == 'from':
+ action = rel.GetTo()
+ else:
+ action = rel.GetFrom()
+
+ task = menuform.GUI().ParseCommand(cmd = action.GetLog(string = False),
+ show = None)
+ task.set_param(rel.GetName(), self.value)
+ action.SetParams(params = task.get_options())
+
+ def AddName(self, name, direction):
+ """!Record new name (parameter)
+
+ @param direction direction - 'from' or 'to'
+ """
+ self.name[direction].append(name)
+
+ def GetPropDialog(self):
+ """!Get properties dialog"""
+ return self.propWin
+
+ def SetPropDialog(self, win):
+ """!Get properties dialog"""
+ self.propWin = win
+
+ def _setBrush(self):
+ """!Set brush"""
+ if self.prompt == 'raster':
+ color = UserSettings.Get(group='modeler', key='data',
+ subkey=('color', 'raster'))
+ elif self.prompt == 'raster3d':
+ color = UserSettings.Get(group='modeler', key='data',
+ subkey=('color', 'raster3d'))
+ elif self.prompt == 'vector':
+ color = UserSettings.Get(group='modeler', key='data',
+ subkey=('color', 'vector'))
+ else:
+ color = UserSettings.Get(group='modeler', key='action',
+ subkey=('color', 'invalid'))
+ wxColor = wx.Color(color[0], color[1], color[2])
+ self.SetBrush(wx.Brush(wxColor))
+
+ def _setPen(self):
+ """!Set pen"""
+ isParameterized = False
+ for rel in self.GetRelations('from'):
+ if rel.GetTo().IsParameterized():
+ isParameterized = True
+ break
+ if not isParameterized:
+ for rel in self.GetRelations('to'):
+ if rel.GetFrom().IsParameterized():
+ isParameterized = True
+ break
+
+ if isParameterized:
+ width = int(UserSettings.Get(group='modeler', key='action',
+ subkey=('width', 'parameterized')))
+ else:
+ width = int(UserSettings.Get(group='modeler', key='action',
+ subkey=('width', 'default')))
+ pen = self.GetPen()
+ pen.SetWidth(width)
+ self.SetPen(pen)
+
+ def _setText(self):
+ """!Update text"""
+ self.ClearText()
+ name = []
+ for rel in self.GetRelations():
+ name.append(rel.GetName())
+ self.AddText('/'.join(name))
+ if self.value:
+ self.AddText(self.value)
+ else:
+ self.AddText(_('<not defined>'))
+
+ def Update(self):
+ """!Update action"""
+ self._setBrush()
+ self._setPen()
+ self._setText()
+
+class ModelDataDialog(ElementDialog):
+ """!Data item properties dialog"""
+ def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Data properties"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+ self.parent = parent
+ self.shape = shape
+ prompt = shape.GetPrompt()
+
+ if prompt == 'raster':
+ label = _('Name of raster map:')
+ elif prompt == 'vector':
+ label = _('Name of vector map:')
+ else:
+ label = _('Name of element:')
+
+ ElementDialog.__init__(self, parent, title, label = label)
+
+ self.element = gselect.Select(parent = self.panel, id = wx.ID_ANY,
+ size = globalvar.DIALOG_GSELECT_SIZE,
+ 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 _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())
+ self.parent.canvas.Refresh()
+ self.parent.SetStatusText('', 0)
+ self.OnCancel(event)
+
+ def OnCancel(self, event):
+ """!Cancel pressed"""
+ self.shape.SetPropDialog(None)
+ self.Destroy()
+
+class ModelEvtHandler(ogl.ShapeEvtHandler):
+ """!Model event handler class"""
+ def __init__(self, log, frame):
+ ogl.ShapeEvtHandler.__init__(self)
+ self.log = log
+ self.frame = frame
+ self.x = self.y = None
+
+ def OnLeftClick(self, x, y, keys = 0, attachment = 0):
+ """!Left mouse button pressed -> select item & update statusbar"""
+ shape = self.GetShape()
+ canvas = shape.GetCanvas()
+ dc = wx.ClientDC(canvas)
+ canvas.PrepareDC(dc)
+
+ if hasattr(self.frame, 'defineRelation'):
+ drel = self.frame.defineRelation
+ if drel['from'] is None:
+ drel['from'] = shape
+ elif drel['to'] is None:
+ drel['to'] = shape
+ rel = ModelRelation(drel['from'], drel['to'])
+ drel['from'].AddRelation(rel)
+ self.frame.AddLine(rel)
+ del self.frame.defineRelation
+
+ if shape.Selected():
+ shape.Select(False, dc)
+ else:
+ redraw = False
+ shapeList = canvas.GetDiagram().GetShapeList()
+ toUnselect = list()
+
+ for s in shapeList:
+ if s.Selected():
+ toUnselect.append(s)
+
+ shape.Select(True, dc)
+
+ for s in toUnselect:
+ s.Select(False, dc)
+
+ canvas.Refresh(False)
+
+ if hasattr(shape, "GetLog"):
+ self.log.SetStatusText(shape.GetLog(), 0)
+ else:
+ self.log.SetStatusText('', 0)
+
+ def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
+ """!Left mouse button pressed (double-click) -> show properties"""
+ self.OnProperties()
+
+ def OnProperties(self, event = None):
+ """!Show properties dialog"""
+ self.frame.ModelChanged()
+ shape = self.GetShape()
+ if isinstance(shape, ModelAction):
+ module = menuform.GUI().ParseCommand(shape.GetLog(string = False),
+ completed = (self.frame.GetOptData, shape, shape.GetParams()),
+ parentframe = self.frame, show = True)
+
+ 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.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, "popupID1"):
+ self.popupID1 = wx.NewId()
+ self.popupID2 = wx.NewId()
+ self.popupID3 = wx.NewId()
+ self.popupID4 = wx.NewId()
+
+ # record coordinates
+ self.x = x
+ self.y = y
+
+ shape = self.GetShape()
+ popupMenu = wx.Menu()
+ popupMenu.Append(self.popupID1, text=_('Remove'))
+ self.frame.Bind(wx.EVT_MENU, self.OnRemove, id = self.popupID1)
+ if isinstance(shape, ModelAction):
+ if shape.IsEnabled():
+ popupMenu.Append(self.popupID3, text=_('Disable'))
+ self.frame.Bind(wx.EVT_MENU, self.OnDisable, id = self.popupID3)
+ else:
+ popupMenu.Append(self.popupID3, text=_('Enable'))
+ self.frame.Bind(wx.EVT_MENU, self.OnEnable, id = self.popupID3)
+
+ if isinstance(shape, ModelRelation):
+ popupMenu.AppendSeparator()
+ popupMenu.Append(self.popupID2, text=_('Add control point'))
+ self.frame.Bind(wx.EVT_MENU, self.OnAddPoint, id = self.popupID2)
+ popupMenu.Append(self.popupID3, text=_('Remove control point'))
+ self.frame.Bind(wx.EVT_MENU, self.OnRemovePoint, id = self.popupID3)
+ if len(shape.GetLineControlPoints()) == 2:
+ popupMenu.Enable(self.popupID3, False)
+
+ if isinstance(shape, ModelData) and '@' not in shape.GetValue():
+ popupMenu.AppendSeparator()
+ popupMenu.Append(self.popupID3, text=_('Intermediate'),
+ kind = wx.ITEM_CHECK)
+ if self.GetShape().IsIntermediate():
+ popupMenu.Check(self.popupID3, True)
+
+ self.frame.Bind(wx.EVT_MENU, self.OnIntermediate, id = self.popupID3)
+
+ if isinstance(shape, ModelData) or \
+ isinstance(shape, ModelAction) or \
+ isinstance(shape, ModelLoop):
+ popupMenu.AppendSeparator()
+ popupMenu.Append(self.popupID2, text=_('Properties'))
+ self.frame.Bind(wx.EVT_MENU, self.OnProperties, id = self.popupID2)
+
+ if isinstance(shape, ModelAction):
+ popupMenu.Append(self.popupID4, text=_('Change ID'))
+ self.frame.Bind(wx.EVT_MENU, self.OnChangeId, id = self.popupID3)
+
+ self.frame.PopupMenu(popupMenu)
+ popupMenu.Destroy()
+
+ def OnChangeId(self, event):
+ """!Change action id"""
+ pass
+
+ def OnDisable(self, event):
+ """!Disable action"""
+ action = self.GetShape()
+ action.Enable(False)
+ self.frame.ModelChanged()
+ self.frame.canvas.Refresh()
+
+ def OnEnable(self, event):
+ """!Disable action"""
+ action = self.GetShape()
+ action.Enable(True)
+ self.frame.ModelChanged()
+ self.frame.canvas.Refresh()
+
+ def OnAddPoint(self, event):
+ """!Add control point"""
+ shape = self.GetShape()
+ shape.InsertLineControlPoint(point = wx.RealPoint(self.x, self.y))
+ shape.ResetShapes()
+ shape.Select(True)
+ self.frame.ModelChanged()
+ self.frame.canvas.Refresh()
+
+ def OnRemovePoint(self, event):
+ """!Remove control point"""
+ shape = self.GetShape()
+ shape.DeleteLineControlPoint()
+ shape.Select(False)
+ shape.Select(True)
+ self.frame.ModelChanged()
+ self.frame.canvas.Refresh()
+
+ def OnIntermediate(self, event):
+ """!Mark data as intermediate"""
+ self.frame.ModelChanged()
+ shape = self.GetShape()
+ shape.SetIntermediate(event.IsChecked())
+ self.frame.canvas.Refresh()
+
+ def OnRemove(self, event):
+ """!Remove shape
+ """
+ self.frame.GetCanvas().RemoveSelected()
+ self.frame.itemPanel.Update()
+
+class ModelSearchDialog(wx.Dialog):
+ def __init__(self, parent, id = wx.ID_ANY, title = _("Add new GRASS module to the model"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ """!Graphical modeler module search window
+
+ @param parent parent window
+ @param id window id
+ @param title window title
+ @param kwargs wx.Dialogs' arguments
+ """
+ self.parent = parent
+
+ wx.Dialog.__init__(self, parent = parent, id = id, title = title, **kwargs)
+ self.SetName("ModelerDialog")
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.cmdBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("Command"))
+
+ self.cmd_prompt = prompt.GPromptSTC(parent = self)
+ self.search = SearchModuleWindow(parent = self.panel, cmdPrompt = self.cmd_prompt, showTip = True)
+ wx.CallAfter(self.cmd_prompt.SetFocus)
+
+ # get commands
+ items = self.cmd_prompt.GetCommandItems()
+
+ self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
+ self.btnOk = wx.Button(self.panel, wx.ID_OK)
+ self.btnOk.SetDefault()
+ self.btnOk.Enable(False)
+
+ self.cmd_prompt.Bind(wx.EVT_CHAR, 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 = shlex.split(str(line))
+ except UnicodeError:
+ cmd = shlex.split(utils.EncodeString((line)))
+
+ return cmd
+
+ def OnOk(self, event):
+ self.btnOk.SetFocus()
+ cmd = self.GetCmd()
+
+ if len(cmd) < 1:
+ GError(parent = self,
+ message = _("Command not defined.\n\n"
+ "Unable to add new action to the model."))
+ return
+
+ if cmd[0] not in globalvar.grassCmd['all']:
+ GError(parent = self,
+ message = _("'%s' is not a GRASS module.\n\n"
+ "Unable to add new action to the model.") % cmd[0])
+ return
+
+ self.EndModal(wx.ID_OK)
+
+ def OnText(self, event):
+ """!Text entered"""
+ if self.cmd_prompt.AutoCompActive():
+ event.Skip()
+ return
+
+ if isinstance(event, wx.KeyEvent):
+ entry = self.cmd_prompt.GetTextLeft() # FIXME
+ 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)
+
+class ModelRelation(ogl.LineShape):
+ """!Data - action relation"""
+ def __init__(self, fromShape, toShape, param = ''):
+ self.fromShape = fromShape
+ self.toShape = toShape
+ self.param = param
+
+ self._points = None
+
+ ogl.LineShape.__init__(self)
+
+ def __del__(self):
+ self.fromShape.rels.remove(self)
+ 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)
+
+class ProcessModelFile:
+ """!Process GRASS model file (gxm)"""
+ def __init__(self, tree):
+ """!A ElementTree handler for the GXM XML file, as defined in
+ grass-gxm.dtd.
+ """
+ self.tree = tree
+ self.root = self.tree.getroot()
+
+ # list of actions, data
+ self.properties = dict()
+ self.variables = dict()
+ self.actions = list()
+ self.data = list()
+ self.loops = list()
+ self.conditions = list()
+
+ self._processWindow()
+ self._processProperties()
+ self._processVariables()
+ self._processItems()
+ self._processData()
+
+ def _filterValue(self, value):
+ """!Filter value
+
+ @param value
+ """
+ value = value.replace('<', '<')
+ value = value.replace('>', '>')
+
+ return value
+
+ def _getNodeText(self, node, tag, default = ''):
+ """!Get node text"""
+ p = node.find(tag)
+ if p is not None:
+ if p.text:
+ return utils.normalize_whitespace(p.text)
+ else:
+ return ''
+
+ return default
+
+ def _processWindow(self):
+ """!Process window properties"""
+ node = self.root.find('window')
+ if node is None:
+ self.pos = self.size = None
+ return
+
+ self.pos, self.size = self._getDim(node)
+
+ def _processProperties(self):
+ """!Process model properties"""
+ node = self.root.find('properties')
+ if node is None:
+ return
+ for key in ('name', 'description', 'author'):
+ self._processProperty(node, key)
+
+ for f in node.findall('flag'):
+ name = f.get('name', '')
+ if name == 'overwrite':
+ self.properties['overwrite'] = True
+
+ def _processProperty(self, pnode, name):
+ """!Process given property"""
+ node = pnode.find(name)
+ if node is not None:
+ self.properties[name] = node.text
+ else:
+ self.properties[name] = ''
+
+ def _processVariables(self):
+ """!Process model variables"""
+ vnode = self.root.find('variables')
+ if vnode is None:
+ return
+ for node in vnode.findall('variable'):
+ name = node.get('name', '')
+ if not name:
+ continue # should not happen
+ self.variables[name] = { 'type' : node.get('type', 'string') }
+ for key in ('description', 'value'):
+ self._processVariable(node, name, key)
+
+ def _processVariable(self, pnode, name, key):
+ """!Process given variable"""
+ node = pnode.find(key)
+ if node is not None:
+ if node.text:
+ self.variables[name][key] = node.text
+
+ def _processItems(self):
+ """!Process model items (actions, loops, conditions)"""
+ self._processActions()
+ self._processLoops()
+ self._processConditions()
+
+ def _processActions(self):
+ """!Process model file"""
+ for action in self.root.findall('action'):
+ pos, size = self._getDim(action)
+ disabled = False
+
+ task = action.find('task')
+ if task is not None:
+ if task.find('disabled') is not None:
+ disabled = True
+ task = self._processTask(task)
+ else:
+ task = None
+
+ aId = int(action.get('id', -1))
+
+ self.actions.append({ 'pos' : pos,
+ 'size' : size,
+ 'task' : task,
+ 'id' : aId,
+ 'disabled' : disabled })
+
+ def _getDim(self, node):
+ """!Get position and size of shape"""
+ pos = size = None
+ posAttr = node.get('pos', None)
+ if posAttr:
+ posVal = map(int, posAttr.split(','))
+ try:
+ pos = (posVal[0], posVal[1])
+ except:
+ pos = None
+
+ sizeAttr = node.get('size', None)
+ if sizeAttr:
+ sizeVal = map(int, sizeAttr.split(','))
+ try:
+ size = (sizeVal[0], sizeVal[1])
+ except:
+ size = None
+
+ return pos, size
+
+ def _processData(self):
+ """!Process model file"""
+ for data in self.root.findall('data'):
+ pos, size = self._getDim(data)
+ param = data.find('data-parameter')
+ prompt = value = None
+ if param is not None:
+ prompt = param.get('prompt', None)
+ value = self._filterValue(self._getNodeText(param, 'value'))
+
+ if data.find('intermediate') is None:
+ intermediate = False
+ else:
+ intermediate = True
+
+ rels = list()
+ for rel in data.findall('relation'):
+ defrel = { 'id' : int(rel.get('id', -1)),
+ 'dir' : rel.get('dir', 'to'),
+ 'name' : rel.get('name', '') }
+ points = list()
+ for point in rel.findall('point'):
+ x = self._filterValue(self._getNodeText(point, 'x'))
+ y = self._filterValue(self._getNodeText(point, 'y'))
+ points.append((float(x), float(y)))
+ defrel['points'] = points
+ rels.append(defrel)
+
+ self.data.append({ 'pos' : pos,
+ 'size': size,
+ 'prompt' : prompt,
+ 'value' : value,
+ 'intermediate' : intermediate,
+ 'rels' : rels })
+
+ def _processTask(self, node):
+ """!Process task
+
+ @return grassTask instance
+ @return None on error
+ """
+ cmd = list()
+ parameterized = list()
+
+ name = node.get('name', None)
+ if not name:
+ return None
+
+ cmd.append(name)
+
+ # flags
+ for f in node.findall('flag'):
+ flag = f.get('name', '')
+ if f.get('parameterized', '0') == '1':
+ parameterized.append(('flag', flag))
+ if f.get('value', '1') == '0':
+ continue
+ if len(flag) > 1:
+ cmd.append('--' + flag)
+ else:
+ cmd.append('-' + flag)
+ # parameters
+ for p in node.findall('parameter'):
+ name = p.get('name', '')
+ if p.find('parameterized') is not None:
+ parameterized.append(('param', name))
+ cmd.append('%s=%s' % (name,
+ self._filterValue(self._getNodeText(p, 'value'))))
+
+ task, err = menuform.GUI().ParseCommand(cmd = cmd,
+ show = None, checkError = True)
+ 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, self.properties['description']))
+ if self.properties['author']:
+ self.fd.write('%s<author>%s</author>\n' % (' ' * self.indent, self.properties['author']))
+
+ if self.properties.has_key('overwrite') 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 values.has_key('value'):
+ self.fd.write('%s<value>%s</value>\n' % \
+ (' ' * self.indent, values['value']))
+ if values.has_key('description'):
+ 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', ''):
+ continue
+ self.fd.write('%s<parameter name="%s">\n' %
+ (' ' * self.indent, p.get('name', '')))
+ self.indent += 4
+ if p.get('parameterized', False):
+ self.fd.write('%s<parameterized />\n' % (' ' * self.indent))
+ self.fd.write('%s<value>%s</value>\n' %
+ (' ' * self.indent, self._filterValue(p.get('value', ''))))
+ self.indent -= 4
+ self.fd.write('%s</parameter>\n' % (' ' * self.indent))
+ self.indent -= 4
+ self.fd.write('%s</task>\n' % (' ' * self.indent))
+ self.indent -= 4
+ self.fd.write('%s</action>\n' % (' ' * self.indent))
+
+ def _data(self, dataList):
+ """!Write data"""
+ for data in dataList:
+ self.fd.write('%s<data pos="%d,%d" size="%d,%d">\n' % \
+ (' ' * self.indent, data.GetX(), data.GetY(),
+ data.GetWidth(), data.GetHeight()))
+ self.indent += 4
+ self.fd.write('%s<data-parameter prompt="%s">\n' % \
+ (' ' * self.indent, data.GetPrompt()))
+ self.indent += 4
+ self.fd.write('%s<value>%s</value>\n' %
+ (' ' * self.indent, self._filterValue(data.GetValue())))
+ self.indent -= 4
+ self.fd.write('%s</data-parameter>\n' % (' ' * self.indent))
+
+ if data.IsIntermediate():
+ self.fd.write('%s<intermediate />\n' % (' ' * self.indent))
+
+ # relations
+ for ft in ('from', 'to'):
+ for rel in data.GetRelations(ft):
+ if ft == 'from':
+ aid = rel.GetTo().GetId()
+ else:
+ aid = rel.GetFrom().GetId()
+ self.fd.write('%s<relation dir="%s" id="%d" name="%s">\n' % \
+ (' ' * self.indent, ft, aid, rel.GetName()))
+ self.indent += 4
+ for point in rel.GetLineControlPoints()[1:-1]:
+ self.fd.write('%s<point>\n' % (' ' * self.indent))
+ self.indent += 4
+ x, y = point.Get()
+ self.fd.write('%s<x>%d</x>\n' % (' ' * self.indent, int(x)))
+ self.fd.write('%s<y>%d</y>\n' % (' ' * self.indent, int(y)))
+ self.indent -= 4
+ self.fd.write('%s</point>\n' % (' ' * self.indent))
+ self.indent -= 4
+ self.fd.write('%s</relation>\n' % (' ' * self.indent))
+
+ self.indent -= 4
+ self.fd.write('%s</data>\n' % (' ' * self.indent))
+
+ def _loop(self, loop):
+ """!Write loops"""
+ self.fd.write('%s<loop id="%d" pos="%d,%d" size="%d,%d">\n' % \
+ (' ' * self.indent, loop.GetId(), loop.GetX(), loop.GetY(),
+ loop.GetWidth(), loop.GetHeight()))
+ text = loop.GetText()
+ self.indent += 4
+ if text:
+ self.fd.write('%s<condition>%s</condition>\n' %
+ (' ' * self.indent, self._filterValue(text)))
+ for item in loop.GetItems():
+ self.fd.write('%s<item>%d</item>\n' %
+ (' ' * self.indent, item.GetId()))
+ self.indent -= 4
+ self.fd.write('%s</loop>\n' % (' ' * self.indent))
+
+ def _condition(self, condition):
+ """!Write conditions"""
+ bbox = condition.GetBoundingBoxMin()
+ self.fd.write('%s<if-else id="%d" pos="%d,%d" size="%d,%d">\n' % \
+ (' ' * self.indent, condition.GetId(), condition.GetX(), condition.GetY(),
+ bbox[0], bbox[1]))
+ text = condition.GetText()
+ self.indent += 4
+ if text:
+ self.fd.write('%s<condition>%s</condition>\n' %
+ (' ' * self.indent, self._filterValue(text)))
+ items = condition.GetItems()
+ for b in items.keys():
+ if len(items[b]) < 1:
+ continue
+ self.fd.write('%s<%s>\n' % (' ' * self.indent, b))
+ self.indent += 4
+ for item in items[b]:
+ self.fd.write('%s<item>%d</item>\n' %
+ (' ' * self.indent, item.GetId()))
+ self.indent -= 4
+ self.fd.write('%s</%s>\n' % (' ' * self.indent, b))
+
+ self.indent -= 4
+ self.fd.write('%s</if-else>\n' % (' ' * self.indent))
+
+class PreferencesDialog(PreferencesBaseDialog):
+ """!User preferences dialog"""
+ def __init__(self, parent, settings = UserSettings,
+ title = _("Modeler settings")):
+
+ PreferencesBaseDialog.__init__(self, parent = parent, title = title,
+ settings = settings)
+
+ # create notebook pages
+ self._createActionPage(self.notebook)
+ self._createDataPage(self.notebook)
+
+ self.SetMinSize(self.GetBestSize())
+ self.SetSize(self.size)
+
+ 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 " % _("Validity"))
+ 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))
+
+ row += 1
+ 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='action', subkey=('color', 'disabled')),
+ size = globalvar.DIALOG_COLOR_SIZE)
+ rColor.SetName('GetColour')
+ self.winId['modeler:action:color:disabled'] = 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 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 prop.has_key('overwrite'):
+ self.overwrite.SetValue(prop['overwrite'])
+
+class ModelParamDialog(wx.Dialog):
+ def __init__(self, parent, params, id = wx.ID_ANY, title = _("Model parameters"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ """!Model parameters dialog
+ """
+ self.parent = parent
+ self.params = params
+ self.tasks = list() # list of tasks/pages
+
+ wx.Dialog.__init__(self, parent = parent, id = id, title = title, style = style, **kwargs)
+
+ if globalvar.hasAgw:
+ self.notebook = FN.FlatNotebook(self, id = wx.ID_ANY,
+ agwStyle = FN.FNB_FANCY_TABS |
+ FN.FNB_BOTTOM |
+ FN.FNB_NO_NAV_BUTTONS |
+ FN.FNB_NO_X_BUTTON)
+ else:
+ self.notebook = FN.FlatNotebook(self, id = wx.ID_ANY,
+ style = FN.FNB_FANCY_TABS |
+ FN.FNB_BOTTOM |
+ FN.FNB_NO_NAV_BUTTONS |
+ FN.FNB_NO_X_BUTTON)
+
+ panel = self._createPages()
+ wx.CallAfter(self.notebook.SetSelection, 0)
+
+ self.btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
+ self.btnRun = wx.Button(parent = self, id = wx.ID_OK,
+ label = _("&Run"))
+ self.btnRun.SetDefault()
+
+ self._layout()
+
+ size = self.GetBestSize()
+ self.SetMinSize(size)
+ self.SetSize((size.width, size.height +
+ panel.constrained_size[1] -
+ panel.panelMinHeight))
+
+ def _layout(self):
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnRun)
+ btnSizer.Realize()
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = self.notebook, proportion = 1,
+ flag = wx.EXPAND)
+ mainSizer.Add(item=btnSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def _createPages(self):
+ """!Create for each parameterized module its own page"""
+ nameOrdered = [''] * len(self.params.keys())
+ for name, params in self.params.iteritems():
+ nameOrdered[params['idx']] = name
+ for name in nameOrdered:
+ params = self.params[name]
+ panel = self._createPage(name, params)
+ self.notebook.AddPage(panel, text = name)
+
+ return panel
+
+ def _createPage(self, name, params):
+ """!Define notebook page"""
+ if name in globalvar.grassCmd['all']:
+ task = menuform.grassTask(name)
+ else:
+ task = menuform.grassTask()
+ task.flags = params['flags']
+ task.params = params['params']
+
+ panel = menuform.cmdPanel(parent = self, id = wx.ID_ANY, task = task)
+ self.tasks.append(task)
+
+ return panel
+
+ def GetErrors(self):
+ """!Check for errors, get list of messages"""
+ errList = list()
+ for task in self.tasks:
+ errList += task.getCmdError()
+
+ return errList
+
+class ModelListCtrl(wx.ListCtrl,
+ listmix.ListCtrlAutoWidthMixin,
+ listmix.TextEditMixin,
+ listmix.ColumnSorterMixin):
+ def __init__(self, parent, columns, id = wx.ID_ANY,
+ style = wx.LC_REPORT | wx.BORDER_NONE |
+ wx.LC_SORT_ASCENDING |wx.LC_HRULES |
+ wx.LC_VRULES, **kwargs):
+ """!List of model variables"""
+ self.parent = parent
+ self.columns = columns
+ self.shape = None
+ try:
+ self.frame = parent.parent
+ except AttributeError:
+ self.frame = None
+
+ wx.ListCtrl.__init__(self, parent, id = id, style = style, **kwargs)
+ listmix.ListCtrlAutoWidthMixin.__init__(self)
+ listmix.TextEditMixin.__init__(self)
+ listmix.ColumnSorterMixin.__init__(self, 4)
+
+ i = 0
+ for col in columns:
+ self.InsertColumn(i, col)
+ self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
+ i += 1
+
+ self.itemDataMap = {} # requested by sorter
+ self.itemCount = 0
+
+ self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit)
+ self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit)
+ self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
+ self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
+ self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
+
+ def OnBeginEdit(self, event):
+ """!Editing of item started"""
+ event.Allow()
+
+ def OnEndEdit(self, event):
+ """!Finish editing of item"""
+ pass
+
+ def OnColClick(self, event):
+ """!Click on column header (order by)"""
+ event.Skip()
+
+class VariablePanel(wx.Panel):
+ def __init__(self, parent, id = wx.ID_ANY,
+ **kwargs):
+ """!Manage model variables panel
+ """
+ self.parent = parent
+
+ wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+
+ self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label=" %s " % _("List of variables - right-click to delete"))
+
+ self.list = VariableListCtrl(parent = self,
+ columns = [_("Name"), _("Data type"),
+ _("Default value"), _("Description")])
+
+ # add new category
+ self.addBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label = " %s " % _("Add new variable"))
+ self.name = wx.TextCtrl(parent = self, id = wx.ID_ANY)
+ wx.CallAfter(self.name.SetFocus)
+ self.type = wx.Choice(parent = self, id = wx.ID_ANY,
+ choices = [_("integer"),
+ _("float"),
+ _("string"),
+ _("raster"),
+ _("vector")])
+ 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(0)
+ 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)
+
+class VariableListCtrl(ModelListCtrl):
+ def __init__(self, parent, columns, **kwargs):
+ """!List of model variables"""
+ ModelListCtrl.__init__(self, parent, columns, **kwargs)
+
+ def GetListCtrl(self):
+ """!Used by ColumnSorterMixin"""
+ return self
+
+ def GetData(self):
+ """!Get list data"""
+ return self.itemDataMap
+
+ def Populate(self, data):
+ """!Populate the list"""
+ self.itemDataMap = dict()
+ i = 0
+ for name, values in data.iteritems():
+ self.itemDataMap[i] = [name, values['type'],
+ values.get('value', ''),
+ values.get('description', '')]
+ i += 1
+
+ self.itemCount = len(self.itemDataMap.keys())
+ self.DeleteAllItems()
+ i = 0
+ for name, vtype, value, desc in self.itemDataMap.itervalues():
+ index = self.InsertStringItem(sys.maxint, name)
+ self.SetStringItem(index, 0, name)
+ self.SetStringItem(index, 1, vtype)
+ self.SetStringItem(index, 2, value)
+ self.SetStringItem(index, 3, desc)
+ self.SetItemData(index, i)
+ i += 1
+
+ def Append(self, name, vtype, value, desc):
+ """!Append new item to the list
+
+ @return None on success
+ @return error string
+ """
+ for iname, ivtype, ivalue, idesc in self.itemDataMap.itervalues():
+ if iname == name:
+ return _("Variable <%s> already exists in the model. "
+ "Adding variable failed.") % name
+
+ index = self.InsertStringItem(sys.maxint, name)
+ self.SetStringItem(index, 0, name)
+ self.SetStringItem(index, 1, vtype)
+ self.SetStringItem(index, 2, value)
+ self.SetStringItem(index, 3, desc)
+ self.SetItemData(index, self.itemCount)
+
+ self.itemDataMap[self.itemCount] = [name, vtype, value, desc]
+ self.itemCount += 1
+
+ return None
+
+ def OnRemove(self, event):
+ """!Remove selected variable(s) from the model"""
+ item = self.GetFirstSelected()
+ while item != -1:
+ self.DeleteItem(item)
+ del self.itemDataMap[item]
+ item = self.GetFirstSelected()
+ self.parent.UpdateModelVariables()
+
+ event.Skip()
+
+ def OnRemoveAll(self, event):
+ """!Remove all variable(s) from the model"""
+ dlg = wx.MessageBox(parent=self,
+ message=_("Do you want to delete all variables from "
+ "the model?"),
+ caption=_("Delete variables"),
+ style=wx.YES_NO | wx.CENTRE)
+ if dlg != wx.YES:
+ return
+
+ self.DeleteAllItems()
+ self.itemDataMap = dict()
+
+ self.parent.UpdateModelVariables()
+
+ def OnEndEdit(self, event):
+ """!Finish editing of item"""
+ itemIndex = event.GetIndex()
+ columnIndex = event.GetColumn()
+ nameOld = self.GetItem(itemIndex, 0).GetText()
+
+ if columnIndex == 0: # TODO
+ event.Veto()
+
+ self.itemDataMap[itemIndex][columnIndex] = event.GetText()
+
+ self.parent.UpdateModelVariables()
+
+ def OnReload(self, event):
+ """!Reload list of variables"""
+ self.Populate(self.parent.parent.GetModel().GetVariables())
+
+ def OnRightUp(self, event):
+ """!Mouse right button up"""
+ if not hasattr(self, "popupID1"):
+ self.popupID1 = wx.NewId()
+ self.popupID2 = wx.NewId()
+ self.popupID3 = wx.NewId()
+ self.Bind(wx.EVT_MENU, self.OnRemove, id = self.popupID1)
+ self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
+ self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
+
+ # generate popup-menu
+ menu = wx.Menu()
+ menu.Append(self.popupID1, _("Delete selected"))
+ menu.Append(self.popupID2, _("Delete all"))
+ if self.GetFirstSelected() == -1:
+ menu.Enable(self.popupID1, False)
+ menu.Enable(self.popupID2, False)
+
+ menu.AppendSeparator()
+ menu.Append(self.popupID3, _("Reload"))
+
+ self.PopupMenu(menu)
+ menu.Destroy()
+
+class ModelItem(ModelObject):
+ def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
+ """!Abstract class for loops and conditions"""
+ ModelObject.__init__(self, id)
+ self.parent = parent
+ self.text = text
+ self.items = items # list of items in the loop
+
+ def GetText(self):
+ """!Get loop text"""
+ return self.text
+
+ def GetItems(self):
+ """!Get items (id)"""
+ return self.items
+
+ def SetId(self, id):
+ """!Set loop id"""
+ self.id = id
+
+ def SetText(self, cond):
+ """!Set loop text (condition)"""
+ self.text = cond
+ self.ClearText()
+ self.AddText('(' + str(self.id) + ') ' + self.text)
+
+ def GetLog(self):
+ """!Get log info"""
+ if self.text:
+ return _("Condition: ") + self.text
+ else:
+ return _("Condition: not defined")
+
+ def AddRelation(self, rel):
+ """!Record relation"""
+ self.rels.append(rel)
+
+ def Clear(self):
+ """!Clear object, remove rels"""
+ self.rels = list()
+
+class ModelItemDialog(wx.Dialog):
+ """!Abstract item properties dialog"""
+ def __init__(self, parent, shape, title, id = wx.ID_ANY,
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ self.parent = parent
+ self.shape = shape
+
+ wx.Dialog.__init__(self, parent, id, title = title, style = style, **kwargs)
+
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+ self.condBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("Condition"))
+ self.condText = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
+ value = shape.GetText())
+
+ self.itemList = ItemCheckListCtrl(parent = self.panel,
+ window = self,
+ columns = [_("ID"), _("Name"),
+ _("Command")],
+ shape = shape)
+ self.itemList.Populate(self.parent.GetModel().GetItems())
+
+ self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+ self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
+ self.btnOk.SetDefault()
+
+ def _layout(self):
+ """!Do layout (virtual method)"""
+ pass
+
+ def GetCondition(self):
+ """!Get loop condition"""
+ return self.condText.GetValue()
+
+class ModelLoop(ModelItem, ogl.RectangleShape):
+ def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '', items = []):
+ """!Defines a loop"""
+ ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
+
+ if not width:
+ width = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'width'))
+ if not height:
+ height = UserSettings.Get(group='modeler', key='loop', subkey=('size', 'height'))
+
+ if self.parent.GetCanvas():
+ ogl.RectangleShape.__init__(self, width, height)
+
+ self.SetCanvas(self.parent)
+ self.SetX(x)
+ self.SetY(y)
+ self.SetPen(wx.BLACK_PEN)
+ self.SetCornerRadius(100)
+ if text:
+ self.AddText('(' + str(self.id) + ') ' + text)
+ else:
+ self.AddText('(' + str(self.id) + ')')
+
+ def GetName(self):
+ """!Get name"""
+ return _("loop")
+
+ def SetItems(self, items):
+ """!Set items (id)"""
+ self.items = items
+
+class ModelLoopDialog(ModelItemDialog):
+ """!Loop properties dialog"""
+ def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Loop properties"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ ModelItemDialog.__init__(self, parent, shape, title,
+ style = style, **kwargs)
+
+ self.listBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("List of items in loop"))
+
+ self._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)
+
+ listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+ listSizer.Add(item = self.itemList, 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 = 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()
+
+class ItemPanel(wx.Panel):
+ def __init__(self, parent, id = wx.ID_ANY,
+ **kwargs):
+ """!Manage model items
+ """
+ self.parent = parent
+
+ wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
+
+ self.listBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label=" %s " % _("List of items - right-click to delete"))
+
+ self.list = ItemListCtrl(parent = self,
+ columns = [_("ID"), _("Name"), _("In block"),
+ _("Command / Condition")])
+
+ self._layout()
+
+ def _layout(self):
+ """!Layout dialog"""
+ listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
+ listSizer.Add(item = self.list, proportion = 1,
+ flag = wx.EXPAND)
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = listSizer, proportion = 1,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def Update(self):
+ """!Reload list of variables"""
+ self.list.OnReload(None)
+
+class ItemListCtrl(ModelListCtrl):
+ def __init__(self, parent, columns, disablePopup = False, **kwargs):
+ """!List of model actions"""
+ self.disablePopup = disablePopup
+
+ ModelListCtrl.__init__(self, parent, columns, **kwargs)
+ self.SetColumnWidth(1, 100)
+ self.SetColumnWidth(2, 65)
+
+ def GetListCtrl(self):
+ """!Used by ColumnSorterMixin"""
+ return self
+
+ def GetData(self):
+ """!Get list data"""
+ return self.itemDataMap
+
+ def Populate(self, data):
+ """!Populate the list"""
+ self.itemDataMap = dict()
+ if self.shape:
+ if isinstance(self.shape, ModelCondition):
+ if self.GetName() == 'ElseBlockList':
+ shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['else'])
+ else:
+ shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['if'])
+ else:
+ shapeItems = map(lambda x: x.GetId(), self.shape.GetItems())
+ else:
+ shapeItems = list()
+ i = 0
+ if len(self.columns) == 3: # ItemCheckList
+ checked = list()
+ for action in data:
+ if len(self.columns) == 3:
+ self.itemDataMap[i] = [str(action.GetId()),
+ action.GetName(),
+ action.GetLog()]
+ aId = action.GetBlockId()
+ if action.GetId() in shapeItems:
+ checked.append(aId)
+ else:
+ checked.append(None)
+ else:
+ bId = action.GetBlockId()
+ if not bId:
+ bId = ''
+ self.itemDataMap[i] = [str(action.GetId()),
+ action.GetName(),
+ ','.join(map(str, bId)),
+ action.GetLog()]
+
+ i += 1
+
+ self.itemCount = len(self.itemDataMap.keys())
+ self.DeleteAllItems()
+ i = 0
+ if len(self.columns) == 3:
+ for aid, name, desc in self.itemDataMap.itervalues():
+ index = self.InsertStringItem(sys.maxint, aid)
+ self.SetStringItem(index, 0, aid)
+ self.SetStringItem(index, 1, name)
+ self.SetStringItem(index, 2, desc)
+ self.SetItemData(index, i)
+ if checked[i]:
+ self.CheckItem(index, True)
+ i += 1
+ else:
+ for aid, name, inloop, desc in self.itemDataMap.itervalues():
+ index = self.InsertStringItem(sys.maxint, aid)
+ self.SetStringItem(index, 0, aid)
+ self.SetStringItem(index, 1, name)
+ self.SetStringItem(index, 2, inloop)
+ self.SetStringItem(index, 3, desc)
+ self.SetItemData(index, i)
+ i += 1
+
+ def OnRemove(self, event):
+ """!Remove selected action(s) from the model"""
+ model = self.frame.GetModel()
+ canvas = self.frame.GetCanvas()
+
+ item = self.GetFirstSelected()
+ while item != -1:
+ self.DeleteItem(item)
+ del self.itemDataMap[item]
+
+ aId = self.GetItem(item, 0).GetText()
+ action = model.GetItem(int(aId))
+ if not action:
+ item = self.GetFirstSelected()
+ continue
+
+ model.RemoveItem(action)
+ canvas.GetDiagram().RemoveShape(action)
+ self.frame.ModelChanged()
+
+ item = self.GetFirstSelected()
+
+ canvas.Refresh()
+
+ event.Skip()
+
+ def OnRemoveAll(self, event):
+ """!Remove all variable(s) from the model"""
+ deleteDialog = wx.MessageBox(parent=self,
+ message=_("Selected data records (%d) will permanently deleted "
+ "from table. Do you want to delete them?") % \
+ (len(self.listOfSQLStatements)),
+ caption=_("Delete records"),
+ style=wx.YES_NO | wx.CENTRE)
+ if deleteDialog != wx.YES:
+ return False
+
+ self.DeleteAllItems()
+ self.itemDataMap = dict()
+
+ self.parent.UpdateModelVariables()
+
+ def OnEndEdit(self, event):
+ """!Finish editing of item"""
+ itemIndex = event.GetIndex()
+ columnIndex = event.GetColumn()
+
+ self.itemDataMap[itemIndex][columnIndex] = event.GetText()
+
+ aId = int(self.GetItem(itemIndex, 0).GetText())
+ action = self.frame.GetModel().GetItem(aId)
+ if not action:
+ event.Veto()
+ if columnIndex == 0:
+ action.SetId(int(event.GetText()))
+
+ self.frame.ModelChanged()
+
+ def OnReload(self, event = None):
+ """!Reload list of actions"""
+ self.Populate(self.frame.GetModel().GetItems())
+
+ def OnRightUp(self, event):
+ """!Mouse right button up"""
+ if self.disablePopup:
+ return
+
+ if not hasattr(self, "popupID1"):
+ self.popupID1 = wx.NewId()
+ self.popupID2 = wx.NewId()
+ self.popupID3 = wx.NewId()
+ self.popupID4 = wx.NewId()
+ self.Bind(wx.EVT_MENU, self.OnRemove, id = self.popupID1)
+ self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
+ self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
+ self.Bind(wx.EVT_MENU, self.OnNormalize, id = self.popupID4)
+
+ # generate popup-menu
+ menu = wx.Menu()
+ menu.Append(self.popupID1, _("Delete selected"))
+ menu.Append(self.popupID2, _("Delete all"))
+ if self.GetFirstSelected() == -1:
+ menu.Enable(self.popupID1, False)
+ menu.Enable(self.popupID2, False)
+
+ menu.AppendSeparator()
+ menu.Append(self.popupID4, _("Normalize"))
+ menu.Append(self.popupID3, _("Reload"))
+
+ self.PopupMenu(menu)
+ menu.Destroy()
+
+ def OnNormalize(self, event):
+ """!Update id of actions"""
+ model = self.frame.GetModel()
+
+ aId = 1
+ for item in model.GetItems():
+ item.SetId(aId)
+ aId += 1
+
+ self.OnReload(None)
+ self.frame.GetCanvas().Refresh()
+ self.frame.ModelChanged()
+
+class ItemCheckListCtrl(ItemListCtrl, listmix.CheckListCtrlMixin):
+ def __init__(self, parent, shape, columns, window = None, **kwargs):
+ self.parent = parent
+ self.window = window
+
+ ItemListCtrl.__init__(self, parent, columns, disablePopup = True, **kwargs)
+ listmix.CheckListCtrlMixin.__init__(self)
+ self.SetColumnWidth(0, 50)
+
+ self.shape = shape
+
+ def OnBeginEdit(self, event):
+ """!Disable editing"""
+ event.Veto()
+
+ def OnCheckItem(self, index, flag):
+ """!Item checked/unchecked"""
+ name = self.GetName()
+ if name == 'IfBlockList' and self.window:
+ self.window.OnCheckItemIf(index, flag)
+ elif name == 'ElseBlockList' and self.window:
+ self.window.OnCheckItemElse(index, flag)
+
+ def GetItems(self):
+ """!Get list of selected actions"""
+ ids = { 'checked' : list(),
+ 'unchecked' : list() }
+ for i in range(self.GetItemCount()):
+ iId = int(self.GetItem(i, 0).GetText())
+ if self.IsChecked(i):
+ ids['checked'].append(iId)
+ else:
+ ids['unchecked'].append(iId)
+
+ return ids
+
+ def CheckItemById(self, aId, flag):
+ """!Check/uncheck given item by id"""
+ for i in range(self.GetItemCount()):
+ iId = int(self.GetItem(i, 0).GetText())
+ if iId == aId:
+ self.CheckItem(i, flag)
+ break
+
+class ModelCondition(ModelItem, ogl.PolygonShape):
+ def __init__(self, parent, x, y, id = -1, width = None, height = None, text = '',
+ items = { 'if' : [], 'else' : [] }):
+ """!Defines a if-else condition"""
+ ModelItem.__init__(self, parent, x, y, id, width, height, text, items)
+
+ if not width:
+ self.width = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'width'))
+ else:
+ self.width = width
+ if not height:
+ self.height = UserSettings.Get(group='modeler', key='if-else', subkey=('size', 'height'))
+ else:
+ self.height = height
+
+ if self.parent.GetCanvas():
+ ogl.PolygonShape.__init__(self)
+
+ points = [(0, - self.height / 2),
+ (self.width / 2, 0),
+ (0, self.height / 2),
+ (- self.width / 2, 0)]
+ self.Create(points)
+
+ self.SetCanvas(self.parent)
+ self.SetX(x)
+ self.SetY(y)
+ self.SetPen(wx.BLACK_PEN)
+ if text:
+ self.AddText('(' + str(self.id) + ') ' + text)
+ else:
+ self.AddText('(' + str(self.id) + ')')
+
+ def GetName(self):
+ """!Get name"""
+ return _("if-else")
+
+ def GetWidth(self):
+ """!Get object width"""
+ return self.width
+
+ def GetHeight(self):
+ """!Get object height"""
+ return self.height
+
+ def SetItems(self, items, branch = 'if'):
+ """!Set items (id)
+
+ @param items list of items
+ @param branch 'if' / 'else'
+ """
+ if branch in ['if', 'else']:
+ self.items[branch] = items
+
+class ModelConditionDialog(ModelItemDialog):
+ """!Condition properties dialog"""
+ def __init__(self, parent, shape, id = wx.ID_ANY, title = _("If-else properties"),
+ style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
+ ModelItemDialog.__init__(self, parent, shape, title,
+ style = style, **kwargs)
+
+ self.listBoxIf = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("List of items in 'if' block"))
+ self.itemListIf = self.itemList
+ self.itemListIf.SetName('IfBlockList')
+
+ self.listBoxElse = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
+ label=" %s " % _("List of items in 'else' block"))
+ self.itemListElse = ItemCheckListCtrl(parent = self.panel,
+ window = self,
+ columns = [_("ID"), _("Name"),
+ _("Command")],
+ shape = shape)
+ self.itemListElse.SetName('ElseBlockList')
+ self.itemListElse.Populate(self.parent.GetModel().GetItems())
+
+ self._layout()
+ self.SetMinSize(self.GetSize())
+ self.SetSize((500, 400))
+
+ def _layout(self):
+ """!Do layout"""
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ condSizer = wx.StaticBoxSizer(self.condBox, wx.VERTICAL)
+ condSizer.Add(item = self.condText, proportion = 1,
+ flag = wx.EXPAND)
+
+ listIfSizer = wx.StaticBoxSizer(self.listBoxIf, wx.VERTICAL)
+ listIfSizer.Add(item = self.itemListIf, proportion = 1,
+ flag = wx.EXPAND)
+ listElseSizer = wx.StaticBoxSizer(self.listBoxElse, wx.VERTICAL)
+ listElseSizer.Add(item = self.itemListElse, proportion = 1,
+ flag = wx.EXPAND)
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.btnCancel)
+ btnSizer.AddButton(self.btnOk)
+ btnSizer.Realize()
+
+ sizer.Add(item = condSizer, proportion = 0,
+ flag = wx.EXPAND | wx.ALL, border = 3)
+ sizer.Add(item = listIfSizer, proportion = 1,
+ flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+ sizer.Add(item = listElseSizer, proportion = 1,
+ flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
+ sizer.Add(item = btnSizer, proportion=0,
+ flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
+
+ self.panel.SetSizer(sizer)
+ sizer.Fit(self.panel)
+
+ self.Layout()
+
+ def OnCheckItemIf(self, index, flag):
+ """!Item in if-block checked/unchecked"""
+ if flag is False:
+ return
+
+ aId = int(self.itemListIf.GetItem(index, 0).GetText())
+ if aId in self.itemListElse.GetItems()['checked']:
+ self.itemListElse.CheckItemById(aId, False)
+
+ def OnCheckItemElse(self, index, flag):
+ """!Item in else-block checked/unchecked"""
+ if flag is False:
+ return
+
+ aId = int(self.itemListElse.GetItem(index, 0).GetText())
+ if aId in self.itemListIf.GetItems()['checked']:
+ self.itemListIf.CheckItemById(aId, False)
+
+ def GetItems(self):
+ """!Get items"""
+ return { 'if' : self.itemListIf.GetItems(),
+ 'else' : self.itemListElse.GetItems() }
+
+class WritePythonFile:
+ def __init__(self, fd, model):
+ """!Class for exporting model to Python script
+
+ @param fd file desciptor
+ """
+ self.fd = fd
+ self.model = model
+ self.indent = 4
+
+ self._writePython()
+
+ def _writePython(self):
+ """!Write model to file"""
+ properties = self.model.GetProperties()
+
+ self.fd.write(
+r"""#!/usr/bin/env python
+#
+############################################################################
+#
+# MODULE: %s
+#
+# AUTHOR(S): %s
+#
+# PURPOSE: %s
+#
+# DATE: %s
+#
+#############################################################################
+""" % (properties['name'],
+ properties['author'],
+ properties['description'],
+ time.asctime()))
+
+ self.fd.write(
+r"""
+import sys
+import os
+import atexit
+
+import grass.script as grass
+""")
+
+ # cleanup()
+ rast, vect, rast3d, msg = self.model.GetIntermediateData()
+ self.fd.write(
+r"""
+def cleanup():
+""")
+ if rast:
+ self.fd.write(
+r""" grass.run_command('g.remove',
+ rast=%s)
+""" % ','.join(map(lambda x: "'" + x + "'", rast)))
+ if vect:
+ self.fd.write(
+r""" grass.run_command('g.remove',
+ vect = %s)
+""" % ','.join(map(lambda x: "'" + x + "'", vect)))
+ if rast3d:
+ self.fd.write(
+r""" grass.run_command('g.remove',
+ rast3d = %s)
+""" % ','.join(map(lambda x: "'" + x + "'", rast3d)))
+ if not rast and not vect and not rast3d:
+ self.fd.write(' pass\n')
+
+ self.fd.write("\ndef main():\n")
+ for item in self.model.GetItems():
+ self._writePythonItem(item)
+
+ self.fd.write("\n return 0\n")
+
+ self.fd.write(
+r"""
+if __name__ == "__main__":
+ options, flags = grass.parser()
+ atexit.register(cleanup)
+ sys.exit(main())
+""")
+
+ def _writePythonItem(self, item, ignoreBlock = True):
+ """!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)
+ 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):
+ self.fd.write('%sfor %s:\n' % (' ' * self.indent, cond))
+ self.indent += 4
+ for action in item.GetItems():
+ self._writePythonItem(action, ignoreBlock = False)
+ 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):
+ """!Write model action to Python file"""
+ task = menuform.GUI().ParseCommand(cmd = item.GetLog(string = False),
+ show = None)
+ opts = task.get_options()
+ flags = ''
+ params = list()
+ strcmd = "%sgrass.run_command(" % (' ' * self.indent)
+ cmdIndent = len(strcmd)
+ for f in opts['flags']:
+ if f.get('value', False) == True:
+ 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 ptype == 'string':
+ params.append('%s = "%s"' % (name, value))
+ else:
+ params.append("%s = %s" % (name, value))
+
+ self.fd.write(strcmd + '"%s"' % task.get_name())
+ if flags:
+ self.fd.write(",\n%sflags = '%s'" % (' ' * cmdIndent, flags))
+ if len(params) > 0:
+ self.fd.write(",\n")
+ for opt in params[:-1]:
+ self.fd.write("%s%s,\n" % (' ' * cmdIndent, opt))
+ self.fd.write("%s%s)\n" % (' ' * cmdIndent, params[-1]))
+ else:
+ self.fd.write(")\n")
+
+
+def main():
+ 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/gui_modules/gmodeler.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/goutput.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,4 +1,4 @@
-"""
+"""!
@package goutput
@brief Command output log widget
@@ -9,7 +9,7 @@
- GMStdout
- GMStderr
-(C) 2007-2008 by the GRASS Development Team
+(C) 2007-2010 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
@@ -29,11 +29,18 @@
import wx.stc
from wx.lib.newevent import NewEvent
+import grass.script as grass
+
import globalvar
import gcmd
import utils
-from debug import Debug as Debug
+import preferences
+import menuform
+import prompt
+
+from debug import Debug
from preferences import globalSettings as UserSettings
+from ghelp import SearchModuleWindow
wxCmdOutput, EVT_CMD_OUTPUT = NewEvent()
wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
@@ -42,12 +49,12 @@
wxCmdAbort, EVT_CMD_ABORT = NewEvent()
def GrassCmd(cmd, stdout, stderr):
- """Return GRASS command thread"""
+ """!Return GRASS command thread"""
return gcmd.CommandThread(cmd,
stdout=stdout, stderr=stderr)
class CmdThread(threading.Thread):
- """Thread for GRASS commands"""
+ """!Thread for GRASS commands"""
requestId = 0
def __init__(self, parent, requestQ, resultQ, **kwds):
threading.Thread.__init__(self, **kwds)
@@ -55,6 +62,7 @@
self.setDaemon(True)
self.parent = parent # GMConsole
+ self._want_abort_all = False
self.requestQ = requestQ
self.resultQ = resultQ
@@ -69,7 +77,12 @@
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, callable, onDone, args, kwds = self.requestQ.get()
@@ -77,11 +90,15 @@
event = wxCmdRun(cmd=args[0],
pid=requestId)
wx.PostEvent(self.parent, event)
-
+
time.sleep(.1)
self.requestCmd = 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:
@@ -96,36 +113,60 @@
time.sleep(.1)
- event = wxCmdDone(aborted = aborted,
+ # set default color table for raster data
+ if UserSettings.Get(group='cmd', key='rasterColorTable', subkey='enabled') and \
+ args[0][0][:2] == 'r.':
+ moduleInterface = menuform.GUI().ParseCommand(args[0], show = None)
+ outputParam = moduleInterface.get_param(value = 'output', raiseError = False)
+ colorTable = UserSettings.Get(group='cmd', key='rasterColorTable', subkey='selection')
+ if outputParam and outputParam['prompt'] == 'raster':
+ argsColor = list(args)
+ argsColor[0] = [ 'r.colors',
+ 'map=%s' % outputParam['value'],
+ 'color=%s' % colorTable ]
+ self.requestCmdColor = callable(*argsColor, **kwds)
+ self.resultQ.put((requestId, self.requestCmdColor.run()))
+
+ event = wxCmdDone(cmd = args[0],
+ aborted = aborted,
returncode = returncode,
time = requestTime,
pid = requestId,
onDone = onDone)
-
+
+ # send event
wx.PostEvent(self.parent, event)
-
- def abort(self):
+
+ def abort(self, abortall = True):
+ """!Abort command(s)"""
+ if abortall:
+ self._want_abort_all = True
self.requestCmd.abort()
-
-class GMConsole(wx.Panel):
+ if self.requestQ.empty():
+ self._want_abort_all = False
+
+class GMConsole(wx.SplitterWindow):
+ """!Create and manage output console for commands run by GUI.
"""
- Create and manage output console for commands entered on the
- GIS Manager command line.
- """
def __init__(self, parent, id=wx.ID_ANY, margin=False, pageid=0,
notebook = None,
- pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE):
- wx.Panel.__init__(self, parent, id, pos, size, style)
+ 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.Map = None
- self.parent = parent # GMFrame | CmdPanel
+ self.parent = parent # GMFrame | CmdPanel | ?
if notebook:
- self.parent.notebook = notebook
+ self._notebook = notebook
+ else:
+ self._notebook = self.parent.notebook
self.lineWidth = 80
self.pageid = pageid
+
# remember position of line begining (used for '\r')
self.linePos = -1
@@ -134,11 +175,11 @@
#
self.requestQ = Queue.Queue()
self.resultQ = Queue.Queue()
-
+
#
# progress bar
#
- self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY,
+ self.console_progressbar = wx.Gauge(parent=self.panelOutput, id=wx.ID_ANY,
range=100, pos=(110, 50), size=(-1, 25),
style=wx.GA_HORIZONTAL)
self.console_progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
@@ -146,7 +187,7 @@
#
# text control for command output
#
- self.cmd_output = GMStc(parent=self, id=wx.ID_ANY, margin=margin,
+ self.cmd_output = GMStc(parent=self.panelOutput, id=wx.ID_ANY, margin=margin,
wrap=None)
self.cmd_output_timer = wx.Timer(self.cmd_output, id=wx.ID_ANY)
self.cmd_output.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
@@ -154,61 +195,152 @@
self.Bind(EVT_CMD_RUN, self.OnCmdRun)
self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+ # search & command prompt
+ self.cmd_prompt = prompt.GPromptSTC(parent = self)
+
+ if self.parent.GetName() != 'LayerManager':
+ self.search = None
+ self.cmd_prompt.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.cmd_stdout = GMStdout(self)
self.cmd_stderr = GMStderr(self)
-
+
#
# thread
#
self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
-
+
#
# buttons
#
- self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR)
- self.console_save = wx.Button(parent=self, id=wx.ID_SAVE)
- self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear)
- self.Bind(wx.EVT_BUTTON, self.SaveHistory, self.console_save)
-
- self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)
+ self.btn_console_clear = wx.Button(parent = self.panelPrompt, id = wx.ID_ANY,
+ label = _("C&lear output"), size=(125,-1))
+ self.btn_cmd_clear = wx.Button(parent = self.panelPrompt, id = wx.ID_ANY,
+ label = _("&Clear command"), size=(125,-1))
+ if self.parent.GetName() != 'LayerManager':
+ self.btn_cmd_clear.Hide()
+ self.btn_console_save = wx.Button(parent = self.panelPrompt, id = wx.ID_ANY,
+ label = _("&Save output"), size=(125,-1))
+ # abort
+ self.btn_abort = wx.Button(parent = self.panelPrompt, id = wx.ID_ANY, label = _("&Abort command"),
+ size=(125,-1))
+ self.btn_abort.SetToolTipString(_("Abort the running command"))
+ self.btn_abort.Enable(False)
+ self.btn_cmd_clear.Bind(wx.EVT_BUTTON, self.cmd_prompt.OnCmdErase)
+ self.btn_console_clear.Bind(wx.EVT_BUTTON, self.ClearHistory)
+ self.btn_console_save.Bind(wx.EVT_BUTTON, self.SaveHistory)
+ self.btn_abort.Bind(wx.EVT_BUTTON, self.OnCmdAbort)
+ self.btn_abort.Bind(EVT_CMD_ABORT, self.OnCmdAbort)
+
self.__layout()
-
+
def __layout(self):
- """Do layout"""
- boxsizer1 = wx.BoxSizer(wx.VERTICAL)
- gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0)
- boxsizer1.Add(item=self.cmd_output, proportion=1,
- flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0)
- gridsizer1.Add(item=self.console_clear, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
- gridsizer1.Add(item=self.console_save, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
+ """!Do layout"""
+ OutputSizer = wx.BoxSizer(wx.VERTICAL)
+ PromptSizer = wx.BoxSizer(wx.VERTICAL)
+ ButtonSizer = wx.BoxSizer(wx.HORIZONTAL)
+ 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.cmd_output, proportion=1,
+ flag=wx.EXPAND | wx.ALL, border=3)
+ OutputSizer.Add(item=self.console_progressbar, proportion=0,
+ flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=3)
+
+ PromptSizer.Add(item=self.cmd_prompt, proportion=1,
+ flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=3)
+
+ ButtonSizer.Add(item=self.btn_console_clear, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.ALL, border=5)
+ ButtonSizer.Add(item=self.btn_console_save, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.ALL, border=5)
+ ButtonSizer.Add(item=self.btn_cmd_clear, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.ALL, border=5)
+ ButtonSizer.Add(item=self.btn_abort, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.FIXED_MINSIZE | wx.ALL, border=5)
+ PromptSizer.Add(item=ButtonSizer, proportion=0,
+ flag=wx.ALIGN_CENTER)
+
+ OutputSizer.Fit(self)
+ OutputSizer.SetSizeHints(self)
+
+ PromptSizer.Fit(self)
+ PromptSizer.SetSizeHints(self)
+
+ self.panelOutput.SetSizer(OutputSizer)
+ self.panelPrompt.SetSizer(PromptSizer)
+
+ # split window
+ if self.parent.GetName() == 'LayerManager':
+ self.SplitHorizontally(self.panelOutput, self.panelPrompt, -50)
+ self.SetMinimumPaneSize(self.btn_cmd_clear.GetSize()[1] + 50)
+ else:
+ self.SplitHorizontally(self.panelOutput, self.panelPrompt, -45)
+ self.SetMinimumPaneSize(self.btn_cmd_clear.GetSize()[1] + 10)
+
+ self.SetSashGravity(1.0)
+
+ # layout
+ self.SetAutoLayout(True)
+ self.Layout()
- boxsizer1.Add(item=gridsizer1, proportion=0,
- flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM,
- border=5)
- boxsizer1.Add(item=self.console_progressbar, proportion=0,
- flag=wx.EXPAND | wx.ADJUST_MINSIZE | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
+ def MakeSearchPaneContent(self, pane):
+ """!Create search pane"""
+ border = wx.BoxSizer(wx.VERTICAL)
+
+ self.search = SearchModuleWindow(parent = pane, cmdPrompt = self.cmd_prompt)
+
+ 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
- boxsizer1.Fit(self)
- boxsizer1.SetSizeHints(self)
+ @param prompt get prompt / output panel
- # layout
- self.SetAutoLayout(True)
- self.SetSizer(boxsizer1)
+ @return wx.Panel reference
+ """
+ if prompt:
+ return self.panelPrompt
+ return self.panelOutput
+
def Redirect(self):
- """Redirect stderr
+ """!Redirect stderr
@return True redirected
@return False failed
"""
- if Debug.get_level() == 0:
+ if Debug.get_level() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
# don't redirect when debugging is enabled
sys.stdout = self.cmd_stdout
sys.stderr = self.cmd_stderr
@@ -219,23 +351,27 @@
def WriteLog(self, text, style = None, wrap = None,
switchPage = False):
- """Generic method for writing log message in
+ """!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.cmd_output.SetStyle()
+
if switchPage and \
- self.parent.notebook.GetSelection() != self.parent.goutput.pageid:
- self.parent.notebook.SetSelection(self.parent.goutput.pageid)
+ self._notebook.GetSelection() != self.parent.goutput.pageid:
+ self._notebook.SetSelection(self.parent.goutput.pageid)
if not style:
style = self.cmd_output.StyleDefault
# p1 = self.cmd_output.GetCurrentPos()
p1 = self.cmd_output.GetEndStyled()
- self.cmd_output.GotoPos(p1)
+# self.cmd_output.GotoPos(p1)
+ self.cmd_output.DocumentEnd()
for line in text.splitlines():
# fill space
@@ -253,52 +389,66 @@
self.cmd_output.EnsureCaretVisible()
def WriteCmdLog(self, line, pid=None):
- """Write message in selected style"""
+ """!Write message in selected style"""
if pid:
line = '(' + str(pid) + ') ' + line
- self.WriteLog(line, style=self.cmd_output.StyleCommand)
+ self.WriteLog(line, style=self.cmd_output.StyleCommand, switchPage = True)
def WriteWarning(self, line):
- """Write message in warning style"""
- self.WriteLog(line, style=self.cmd_output.StyleWarning)
+ """!Write message in warning style"""
+ self.WriteLog(line, style=self.cmd_output.StyleWarning, switchPage = True)
def WriteError(self, line):
- """Write message in error style"""
- self.WriteLog(line, style=self.cmd_output.StyleError)
+ """!Write message in error style"""
+ self.WriteLog(line, style=self.cmd_output.StyleError, switchPage = True)
- def RunCmd(self, command, compReg=True, switchPage=False,
+ def RunCmd(self, command, compReg = True, switchPage = False,
onDone = None):
- """
- Run in GUI GRASS (or other) commands typed into
- console command text widget, and send stdout output to output
- text widget.
+ """!Run in GUI GRASS (or other) commands typed into console
+ command text widget, and send stdout output to output text
+ widget.
Command is transformed into a list for processing.
- 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).
+ @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 (list)
@param compReg if true use computation region
@param switchPage switch to output page
@param onDone function to be called when command is finished
"""
-
- # map display window available ?
- try:
- curr_disp = self.parent.curr_page.maptree.mapdisplay
- self.Map = curr_disp.GetRender()
- except:
- curr_disp = None
-
# command given as a string ?
try:
cmdlist = command.strip().split(' ')
except:
cmdlist = command
+ # update history file
+ env = grass.gisenv()
+ try:
+ fileHistory = open(os.path.join(env['GISDBASE'], env['LOCATION_NAME'], env['MAPSET'],
+ '.bash_history'), 'a')
+ except IOError, e:
+ self.WriteError(str(e))
+ fileHistory = None
+
+ cmdString = ' '.join(cmdlist)
+ if fileHistory:
+ try:
+ fileHistory.write(cmdString + '\n')
+ finally:
+ fileHistory.close()
+
+ # update history items
+ if self.parent.GetName() == 'LayerManager':
+ try:
+ self.parent.cmdinput.SetHistoryItems()
+ except AttributeError:
+ pass
+
if cmdlist[0] in globalvar.grassCmd['all']:
# send GRASS command without arguments to GUI command interface
# except display commands (they are handled differently)
@@ -308,6 +458,7 @@
#
try:
layertype = {'d.rast' : 'raster',
+ 'd.rast3d' : '3d-raster',
'd.rgb' : 'rgb',
'd.his' : 'his',
'd.shaded' : 'shaded',
@@ -322,9 +473,9 @@
'd.rhumbline' : 'rhumb',
'd.labels' : 'labels'}[cmdlist[0]]
except KeyError:
- wx.MessageBox(caption = _("Message"),
- message=_("Command '%s' not yet implemented in the GUI. "
- "Try adding it as a command layer instead.") % cmdlist[0])
+ gcmd.GMessage(parent = self.parent,
+ message = _("Command '%s' not yet implemented in the WxGUI. "
+ "Try adding it as a command layer instead.") % cmdlist[0])
return None
# add layer into layer tree
@@ -336,9 +487,8 @@
layerType = 'vector')
else:
lname = None
-
- # add layer into layer tree
- if self.parent.GetName() == "LayerManager":
+
+ if self.parent.GetName() == "LayerManager":
self.parent.curr_page.maptree.AddLayer(ltype=layertype,
lname=lname,
lcmd=cmdlist)
@@ -349,8 +499,8 @@
# switch to 'Command output'
if switchPage:
- if self.parent.notebook.GetSelection() != self.parent.goutput.pageid:
- self.parent.notebook.SetSelection(self.parent.goutput.pageid)
+ if self._notebook.GetSelection() != self.parent.goutput.pageid:
+ self._notebook.SetSelection(self.parent.goutput.pageid)
self.parent.SetFocus() # -> set focus
self.parent.Raise()
@@ -361,20 +511,26 @@
tmpreg = os.getenv("GRASS_REGION")
if os.environ.has_key("GRASS_REGION"):
del os.environ["GRASS_REGION"]
-
+
if len(cmdlist) == 1:
import menuform
+ task = menuform.GUI().ParseInterface(cmdlist)
+ if not task.has_required():
+ task = None # run command
+ else:
+ task = None
+
+ if task and cmdlist[0] not in ('v.krige.py'):
# process GRASS command without argument
- menuform.GUI().ParseCommand(cmdlist, parentframe=self)
+ menuform.GUI().ParseCommand(cmdlist, parentframe = self)
else:
# process GRASS command with argument
self.cmdThread.RunCmd(GrassCmd,
onDone,
cmdlist,
self.cmd_stdout, self.cmd_stderr)
+ self.cmd_output_timer.Start(50)
- self.cmd_output_timer.Start(50)
-
return None
# deactivate computational region and return to display settings
@@ -383,24 +539,23 @@
else:
# Send any other command to the shell. Send output to
# console output window
-
- # if command is not a GRASS command, treat it like a shell command
- try:
- generalCmd = gcmd.Command(cmdlist,
- stdout=self.cmd_stdout,
- stderr=self.cmd_stderr)
- except gcmd.CmdError, e:
- print >> sys.stderr, e
-
+ self.cmdThread.RunCmd(GrassCmd,
+ onDone,
+ cmdlist,
+ self.cmd_stdout, self.cmd_stderr)
+ self.cmd_output_timer.Start(50)
+
return None
def ClearHistory(self, event):
- """Clear history of commands"""
+ """!Clear history of commands"""
+ self.cmd_output.SetReadOnly(False)
self.cmd_output.ClearAll()
+ self.cmd_output.SetReadOnly(True)
self.console_progressbar.SetValue(0)
def SaveHistory(self, event):
- """Save history of commands"""
+ """!Save history of commands"""
self.history = self.cmd_output.GetSelectedText()
if self.history == '':
self.history = self.cmd_output.GetText()
@@ -427,19 +582,29 @@
dlg.Destroy()
def GetCmd(self):
- """Get running command or None"""
+ """!Get running command or None"""
return self.requestQ.get()
+
+ def OnUpdateStatusBar(self, event):
+ """!Update statusbar text"""
+ if event.GetString():
+ nItems = len(self.cmd_prompt.GetCommandItems())
+ self.parent.SetStatusText(_('%d modules match') % nItems, 0)
+ else:
+ self.parent.SetStatusText('', 0)
+ event.Skip()
+
def OnCmdOutput(self, event):
- """Print command output"""
+ """!Print command output"""
message = event.text
type = event.type
- if self.parent.notebook.GetSelection() != self.parent.goutput.pageid:
- textP = self.parent.notebook.GetPageText(self.parent.goutput.pageid)
+ if self._notebook.GetSelection() != self.parent.goutput.pageid:
+ textP = self._notebook.GetPageText(self.parent.goutput.pageid)
if textP[-1] != ')':
textP += ' (...)'
- self.parent.notebook.SetPageText(self.parent.goutput.pageid,
- textP)
+ self._notebook.SetPageText(self.parent.goutput.pageid,
+ textP)
# message prefix
if type == 'warning':
@@ -476,7 +641,7 @@
self.cmd_output.AddTextWrapped(message, wrap=60)
else:
self.cmd_output.AddTextWrapped(message, wrap=None)
-
+
p2 = self.cmd_output.GetCurrentPos()
if p2 >= p1:
@@ -494,19 +659,26 @@
self.cmd_output.EnsureCaretVisible()
def OnCmdProgress(self, event):
- """Update progress message info"""
+ """!Update progress message info"""
self.console_progressbar.SetValue(event.value)
def OnCmdAbort(self, event):
- """Abort running command"""
+ """!Abort running command"""
self.cmdThread.abort()
-
+
def OnCmdRun(self, event):
- """Run command"""
+ """!Run command"""
+ if self.parent.GetName() == 'Modeler':
+ self.parent.OnCmdRun(event)
+
self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
+ self.btn_abort.Enable()
def OnCmdDone(self, event):
- """Command done (or aborted)"""
+ """!Command done (or aborted)"""
+ if self.parent.GetName() == 'Modeler':
+ self.parent.OnCmdDone(event)
+
if event.aborted:
# Thread aborted (using our convention of None return)
self.WriteLog(_('Please note that the data are left in inconsistent state '
@@ -515,78 +687,98 @@
_('Command aborted'),
(time.time() - event.time)))
# pid=self.cmdThread.requestId)
+ self.btn_abort.Enable(False)
else:
try:
# Process results here
self.WriteCmdLog('(%s) %s (%d sec)' % (str(time.ctime()),
_('Command finished'),
(time.time() - event.time)))
- # pid=event.pid)
except KeyError:
# stopped deamon
pass
+
+ self.btn_abort.Enable(False)
if event.onDone:
- event.onDone(returncode = event.returncode)
+ event.onDone(cmd = event.cmd, returncode = event.returncode)
self.console_progressbar.SetValue(0) # reset progress bar on '0%'
self.cmd_output_timer.Stop()
- # updated command dialog
- if hasattr(self.parent.parent, "btn_run"):
+ # set focus on prompt
+ if self.parent.GetName() == "LayerManager":
+ self.btn_abort.Enable(False)
+ if event.cmd[0] in globalvar.cmdAutoRender:
+ display = self.parent.GetLayerTree().GetMapDisplay()
+ if display and display.IsAutoRendered():
+ display.GetWindow().UpdateMap(render = True)
+
+ else:
+ # updated command dialog
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)
-
- dialog.btn_run.Enable(True)
-
- if event.returncode == 0 and \
- not event.aborted and hasattr(dialog, "addbox") and \
- dialog.addbox.IsChecked():
- # add new map into layer tree
- if dialog.outputType in ('raster', 'vector'):
- # add layer into layer tree
- cmd = dialog.notebookpanel.createCmd(ignoreErrors = True)
- name = utils.GetLayerNameFromCmd(cmd, fullyQualified=True, param='output')
- winName = self.parent.parent.parent.GetName()
- if winName == 'LayerManager':
- mapTree = self.parent.parent.parent.curr_page.maptree
- else: # GMConsole
- mapTree = self.parent.parent.parent.parent.curr_page.maptree
-
- if dialog.outputType == 'raster':
- lcmd = ['d.rast',
- 'map=%s' % name]
- else:
- lcmd = ['d.vect',
- 'map=%s' % name]
- mapTree.AddLayer(ltype=dialog.outputType,
- lcmd=lcmd,
- lname=name)
- if dialog.get_dcmd is None and \
- dialog.closebox.IsChecked():
+ if hasattr(self.parent.parent, "btn_run"):
+ dialog.btn_run.Enable(True)
+
+ if event.returncode == 0 and not event.aborted:
+ winName = self.parent.parent.parent.GetName()
+ if winName == 'LayerManager':
+ mapTree = self.parent.parent.parent.GetLayerTree()
+ elif winName == 'LayerTree':
+ mapTree = self.parent.parent.parent
+ else: # GMConsole
+ mapTree = self.parent.parent.parent.parent.GetLayerTree()
+
+ 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 = 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 \
+ dialog.closebox.IsChecked():
time.sleep(1)
dialog.Close()
-
+
event.Skip()
def OnProcessPendingOutputWindowEvents(self, event):
self.ProcessPendingEvents()
class GMStdout:
- """GMConsole standard output
+ """!GMConsole standard output
Based on FrameOutErr.py
@@ -612,7 +804,7 @@
wx.PostEvent(self.parent.cmd_output, evt)
class GMStderr:
- """GMConsole standard error output
+ """!GMConsole standard error output
Based on FrameOutErr.py
@@ -629,6 +821,9 @@
self.message = ''
self.printMessage = False
+ def flush(self):
+ pass
+
def write(self, s):
if "GtkPizza" in s:
return
@@ -639,7 +834,7 @@
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:
@@ -682,7 +877,7 @@
wx.PostEvent(self.parent.console_progressbar, evt)
class GMStc(wx.stc.StyledTextCtrl):
- """Styled GMConsole
+ """!Styled GMConsole
Based on FrameOutErr.py
@@ -695,39 +890,14 @@
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.StyleDefault = 0
- self.StyleDefaultSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF"
- self.StyleCommand = 1
- self.StyleCommandSpec = "face:Courier New,size:10,fore:#000000,back:#bcbcbc"
- self.StyleOutput = 2
- self.StyleOutputSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF"
- # fatal error
- self.StyleError = 3
- self.StyleErrorSpec = "face:Courier New,size:10,fore:#7F0000,back:#FFFFFF"
- # warning
- self.StyleWarning = 4
- self.StyleWarningSpec = "face:Courier New,size:10,fore:#0000FF,back:#FFFFFF"
- # message
- self.StyleMessage = 5
- self.StyleMessageSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF"
- # unknown
- self.StyleUnknown = 6
- self.StyleUnknownSpec = "face:Courier New,size:10,fore:#000000,back:#FFFFFF"
+ #
+ self.SetStyle()
- # 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)
-
#
# line margins
#
@@ -751,22 +921,67 @@
self.SetUseHorizontalScrollBar(True)
#
- # bindins
+ # bindings
#
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+ def SetStyle(self):
+ """!Set styles for styled text output windows with type face
+ and point size selected by user (Courier New 10 is default)"""
+ settings = preferences.Settings()
+
+ typeface = settings.Get(group='display', key='outputfont', subkey='type')
+ if typeface == "": typeface = "Courier New"
+
+ typesize = settings.Get(group='display', 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 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.
+ """!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:
@@ -795,5 +1010,8 @@
else:
txt = _('Unable to encode text. Please set encoding in GUI preferences.') + '\n'
- self.AddText(txt)
+ self.AddText(txt)
+
+ # reset output window to read only
+ self.SetReadOnly(True)
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gselect.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gselect.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/gselect.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,4 +1,4 @@
-"""
+"""!
@package gselect
@brief Custom control that selects elements
@@ -12,59 +12,81 @@
- DriverSelect
- DatabaseSelect
- ColumnSelect
+ - LocationSelect
+ - MapsetSelect
- SubGroupSelect
+ - FormatSelect
+ - GdalSelect
+
+(C) 2007-2010 by the GRASS Development Team This program is free
+software under the GNU General Public License (>=v2). Read the file
+COPYING that comes with GRASS for details.
-(C) 2007-2010 by the GRASS Development Team
-This program is free software under the GNU General Public License
-(>=v2). Read the file COPYING that comes with GRASS for details.
-
@author Michael Barton
@author Martin Landa <landa.martin gmail.com>
"""
import os
import sys
+import glob
import wx
import wx.combo
+import wx.lib.filebrowsebutton as filebrowse
+from wx.lib.newevent import NewEvent
+import globalvar
+
+sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
import grass.script as grass
-import globalvar
import gcmd
import utils
from preferences import globalSettings as UserSettings
+from debug import Debug
+wxGdalSelect, EVT_GDALSELECT = NewEvent()
+
class Select(wx.combo.ComboCtrl):
def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
- type = None, multiple = False, mapsets = None, exceptOf = [],
- updateOnPopup = True):
+ type = None, multiple = False, mapsets = None,
+ updateOnPopup = True, onPopup = None):
+ """!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
"""
- 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.
- """
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.GetElementList(type, mapsets, exceptOf)
self.tcp.SetData(type = type, mapsets = mapsets,
- exceptOf = exceptOf, multiple = multiple,
- updateOnPopup = updateOnPopup)
+ multiple = multiple,
+ updateOnPopup = updateOnPopup, onPopup = onPopup)
+
+ def SetElementList(self, type, mapsets = None):
+ """!Set element list
- def SetElementList(self, type, mapsets = None, exceptOf = []):
- self.tcp.seltree.DeleteAllItems()
- self.tcp.GetElementList(type)
- self.tcp.SetData(type = type, mapsets = mapsets,
- exceptOf = exceptOf)
+ @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()
+
class VectorSelect(Select):
def __init__(self, parent, ftype, **kwargs):
"""!Custom to create a ComboBox with a tree control to display and
@@ -92,21 +114,19 @@
return True
class TreeCtrlComboPopup(wx.combo.ComboPopup):
- """
- Create a tree ComboBox for selecting maps and other GIS elements
+ """!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.mapsets = []
- self.exceptOf = []
-
+ self.onPopup = None
+
self.SetFilter(None)
def Create(self, parent):
@@ -154,14 +174,27 @@
"""!Set filter for GIS elements, see e.g. VectorSelect"""
self.filterElements = filter
- def OnPopup(self):
- """Limited only for first selected"""
+ 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)
+
+ 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
- if not self.updateOnPopup:
- return
self.seltree.DeleteAllItems()
- self.GetElementList(self.type, self.mapsets, self.exceptOf)
-
+ self._getElementList(self.type, self.mapsets, elements, exclude)
+
if len(self.value) > 0:
root = self.seltree.GetRootItem()
if not root:
@@ -186,10 +219,14 @@
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
return wx.Size(minWidth, min(200, maxHeight))
- def GetElementList(self, element, mapsets=None, exceptOf=[]):
- """
- Get list of GIS elements in accessible mapsets and display as tree
+ 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']
@@ -197,7 +234,7 @@
# list of mapsets in current location
if mapsets is None:
mapsets = utils.ListOfMapsets(get = 'accessible')
-
+
# map element types to g.mlist types
elementdict = {'cell':'rast',
'raster':'rast',
@@ -243,11 +280,11 @@
'3dview':'3dview',
'3D viewing parameters':'3dview',
'3D view parameters':'3dview'}
-
+
if element not in elementdict:
self.AddItem(_('Not selectable element'))
return
-
+
# get directory tree nodes
# reorder mapsets based on search path (TODO)
for i in range(len(mapsets)):
@@ -273,9 +310,16 @@
for elem in elem_list:
if elem != '':
fullqElem = elem + '@' + dir
- if len(exceptOf) > 0 and fullqElem in exceptOf:
- continue
- self.AddItem(fullqElem, parent=dir_node)
+ if elements:
+ if (exclude and fullqElem in elements) or \
+ (not exclude and fullqElem not in elements):
+ continue
+
+ if self.filterElements:
+ if self.filterElements(fullqElem):
+ self.AddItem(fullqElem, parent=dir_node)
+ else:
+ self.AddItem(fullqElem, parent=dir_node)
except:
continue
@@ -357,20 +401,20 @@
evt.Skip()
def SetData(self, **kargs):
- """Set object properties"""
+ """!Set object properties"""
if kargs.has_key('type'):
self.type = kargs['type']
if kargs.has_key('mapsets'):
self.mapsets = kargs['mapsets']
- if kargs.has_key('exceptOf'):
- self.exceptOf = kargs['exceptOf']
if kargs.has_key('multiple'):
self.multiple = kargs['multiple']
if kargs.has_key('updateOnPopup'):
self.updateOnPopup = kargs['updateOnPopup']
+ if kargs.has_key('onPopup'):
+ self.onPopup = kargs['onPopup']
class VectorDBInfo:
- """Class providing information about attribute tables
+ """!Class providing information about attribute tables
linked to a vector map"""
def __init__(self, map):
self.map = map
@@ -380,13 +424,13 @@
# dictionary of table and associated columns (type, length, values, ids)
self.tables = {}
- if not self.__CheckDBConnection(): # -> self.layers
+ if not self._CheckDBConnection(): # -> self.layers
return
- self.__DescribeTables() # -> self.tables
+ self._DescribeTables() # -> self.tables
- def __CheckDBConnection(self):
- """Check DB connection"""
+ def _CheckDBConnection(self):
+ """!Check DB connection"""
nuldev = file(os.devnull, 'w+')
self.layers = grass.vector_db(map=self.map, stderr=nuldev)
nuldev.close()
@@ -395,45 +439,37 @@
return False
return True
-
- def __DescribeTables(self):
- """Describe linked tables"""
+
+ def _DescribeTables(self):
+ """!Describe linked tables"""
for layer in self.layers.keys():
# determine column names and types
table = self.layers[layer]["table"]
- columnsCommand = gcmd.Command (cmd=["db.describe",
- "-c", "--q",
- "table=%s" % self.layers[layer]["table"],
- "driver=%s" % self.layers[layer]["driver"],
- "database=%s" % self.layers[layer]["database"]],
- rerr = None)
-
-
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
- if columnsCommand.returncode == 0:
- # skip nrows and ncols
- i = 0
- for line in columnsCommand.ReadStdOutput()[2:]:
- num, name, type, length = line.strip().split(':')
- # 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
- else:
- return False
-
+ 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():
@@ -447,14 +483,14 @@
return True
def Reset(self):
- """Reset"""
+ """!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
@@ -464,7 +500,7 @@
@param layer vector layer number
"""
- return self.layers[layer]['key']
+ return str(self.layers[layer]['key'])
def GetTable(self, layer):
"""!Get table name of given layer
@@ -490,8 +526,7 @@
return self.tables[table]
class LayerSelect(wx.Choice):
- """
- Creates combo box for selecting data layers defined for vector.
+ """!Creates combo box for selecting data layers defined for vector.
The 'layer' terminology is likely to change for GRASS 7
"""
def __init__(self, parent,
@@ -522,13 +557,13 @@
self.SetStringSelection('1')
def InsertLayers(self, vector):
- """Insert layers for a vector into the layer combobox"""
+ """!Insert layers for a vector into the layer combobox"""
layerchoices = utils.GetVectorNumberOfLayers(vector)
for layer in self.initial:
if layer in layerchoices:
continue
layerchoices.append(layer)
-
+
# sort list of available layers
utils.ListSortLower(layerchoices)
@@ -543,9 +578,8 @@
self.SetStringSelection(str(self.default))
class DriverSelect(wx.ComboBox):
+ """!Creates combo box for selecting database driver.
"""
- 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):
@@ -558,9 +592,8 @@
self.SetStringSelection(value)
class DatabaseSelect(wx.TextCtrl):
+ """!Creates combo box for selecting database driver.
"""
- 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):
@@ -570,9 +603,8 @@
self.SetName("DatabaseSelect")
class TableSelect(wx.ComboBox):
+ """!Creates combo box for selecting attribute tables from the database
"""
- 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,
@@ -587,24 +619,23 @@
self.InsertTables()
def InsertTables(self, driver=None, database=None):
- """Insert attribute tables into combobox"""
+ """!Insert attribute tables into combobox"""
items = []
- cmd = ['db.tables',
- '-p']
- if driver:
- cmd.append('driver=%s' % driver)
- if database:
- cmd.append('database=%s' % database)
-
- try:
- tableCmd = gcmd.Command(cmd)
- except gcmd.CmdError:
- tableCmd = None
+ if not driver or not database:
+ connect = grass.db_connection()
+
+ driver = connect['driver']
+ database = connect['database']
- if tableCmd and \
- tableCmd.returncode == 0:
- for table in tableCmd.ReadStdOutput():
+ ret = gcmd.RunCommand('db.tables',
+ flags = 'p',
+ read = True,
+ driver = driver,
+ database = database)
+
+ if ret:
+ for table in ret.splitlines():
items.append(table)
self.SetItems(items)
@@ -620,46 +651,41 @@
@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, choices = [], readonly = False, param = None,
- **kwargs):
- if readonly:
- if kwargs.has_key('style'):
- style |= wx.CB_READONLY
- else:
- style = wx.CB_READONLY
-
+ 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 = value, choices = choices, size = size,
- **kwargs)
+ super(ColumnSelect, self).__init__(parent, id, value, size = size, **kwargs)
self.SetName("ColumnSelect")
if vector:
self.InsertColumns(vector, layer)
- def InsertColumns(self, vector, layer, type = None, dbInfo = None):
+ def InsertColumns(self, vector, layer, excludeKey = False, 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 type only columns of given type (given as list)
- @param dbInfo reference to VectorDbInfo instance or None
"""
if not dbInfo:
dbInfo = VectorDBInfo(vector)
try:
- table = dbInfo.layers[int(layer)]['table']
- columnchoices = dbInfo.tables[table]
+ 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 type: # only selected column types
for key, value in columnchoices.iteritems():
if value['type'] not in type:
@@ -697,45 +723,44 @@
if self.param:
self.param['value'] = ''
-class DbColumnSelect(wx.ComboBox):
- """
- Creates combo box for selecting columns from any table.
- """
- def __init__(self, parent,
- id=wx.ID_ANY, value='', pos=wx.DefaultPosition,
- size=wx.DefaultSize, choices=[''], **kargs):
+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")
- super(ColumnSelect, self).__init__(parent, id, value, pos, size, choices)
+ if not gisdbase:
+ self.gisdbase = grass.gisenv()['GISDBASE']
+ else:
+ self.gisdbase = gisdbase
- dbtable = kargs['table'] # table to check for columns
- dbdriver = kargs['driver'] # driver for table
- dbdatabase = kargs['database'] # database for table
+ self.SetItems(utils.GetListOfLocations(self.gisdbase))
- if dbtable == '':
- return
+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, **kwargs):
+ super(MapsetSelect, self).__init__(parent, id, size = size,
+ style = wx.CB_READONLY, **kwargs)
+
+ self.SetName("MapsetSelect")
+
+ if not gisdbase:
+ self.gisdbase = grass.gisenv()['GISDBASE']
else:
- self.InsertColumns(dbtable)
-
- def InsertColumns(self, table):
- """insert columns for a table into the columns combobox"""
- if table == '' : return
+ self.gisdbase = gisdbase
- cmd = ['db.columns',
- 'table=%s' % table]
+ if not location:
+ self.location = grass.gisenv()['LOCATION_NAME']
+ else:
+ self.location = location
- if dbdriver:
- cmd.append('driver=%s' % dbdriver)
- if dbdatabase:
- cmd.append('database=%s' % dbdatabase)
-
- try:
- columnchoices = gcmd.Command(cmd).ReadStdOutput()
- except gcmd.CmdError:
- columnchoices = []
+ if setItems:
+ self.SetItems(utils.GetListOfMapsets(self.gisdbase, self.location, selectable = True)) # selectable
- # columnchoices.sort()
- self.SetItems(columnchoices)
-
class SubGroupSelect(wx.ComboBox):
"""!Widget for selecting subgroups"""
def __init__(self, parent, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
@@ -762,4 +787,477 @@
except OSError:
self.SetItems([])
self.SetValue('')
+
+class FormatSelect(wx.Choice):
+ def __init__(self, parent, ogr = False,
+ sourceType = None, id = wx.ID_ANY, size = globalvar.DIALOG_COMBOBOX_SIZE,
+ **kwargs):
+ """!Widget for selecting external (GDAL/OGR) format
+
+ @param parent parent window
+ @param sourceType source type ('file', 'directory', 'database', 'protocol') or None
+ @param ogr True for OGR otherwise GDAL
+ """
+ super(FormatSelect, self).__init__(parent, id, size = size,
+ style = wx.CB_READONLY, **kwargs)
+ self.SetName("FormatSelect")
+ if ogr:
+ ftype = 'ogr'
+ else:
+ ftype = 'gdal'
+
+ formats = list()
+ for f in utils.GetFormats()[ftype].values():
+ formats += f
+ self.SetItems(formats)
+
+ def GetExtension(self, name):
+ """!Get file extension by format name"""
+ formatToExt = {
+ # raster
+ 'GeoTIFF' : 'tif',
+ 'Erdas Imagine Images (.img)' : 'img',
+ 'Ground-based SAR Applications Testbed File Format (.gff)' : 'gff',
+ 'Arc/Info Binary Grid' : 'adf',
+ 'Portable Network Graphics' : 'png',
+ 'JPEG JFIF' : 'jpg',
+ 'Japanese DEM (.mem)' : 'mem',
+ 'Graphics Interchange Format (.gif)' : 'gif',
+ 'X11 PixMap Format' : 'xpm',
+ 'MS Windows Device Independent Bitmap' : 'bmp',
+ 'SPOT DIMAP' : 'dim',
+ 'RadarSat 2 XML Product' : 'xml',
+ 'EarthWatch .TIL' : 'til',
+ 'ERMapper .ers Labelled' : 'ers',
+ 'ERMapper Compressed Wavelets' : 'ecw',
+ 'GRIdded Binary (.grb)' : 'grb',
+ 'EUMETSAT Archive native (.nat)' : 'nat',
+ 'Idrisi Raster A.1' : 'rst',
+ 'Golden Software ASCII Grid (.grd)' : 'grd',
+ 'Golden Software Binary Grid (.grd)' : 'grd',
+ 'Golden Software 7 Binary Grid (.grd)' : 'grd',
+ 'R Object Data Store' : 'r',
+ 'USGS DOQ (Old Style)' : 'doq',
+ 'USGS DOQ (New Style)' : 'doq',
+ 'ENVI .hdr Labelled' : 'hdr',
+ 'ESRI .hdr Labelled' : 'hdr',
+ 'Generic Binary (.hdr Labelled)' : 'hdr',
+ 'PCI .aux Labelled' : 'aux',
+ 'EOSAT FAST Format' : 'fst',
+ 'VTP .bt (Binary Terrain) 1.3 Format' : 'bt',
+ 'FARSITE v.4 Landscape File (.lcp)' : 'lcp',
+ 'Swedish Grid RIK (.rik)' : 'rik',
+ 'USGS Optional ASCII DEM (and CDED)' : 'dem',
+ 'Northwood Numeric Grid Format .grd/.tab' : '',
+ 'Northwood Classified Grid Format .grc/.tab' : '',
+ 'ARC Digitized Raster Graphics' : 'arc',
+ 'Magellan topo (.blx)' : 'blx',
+ 'SAGA GIS Binary Grid (.sdat)' : 'sdat',
+ # vector
+ 'ESRI Shapefile' : 'shp',
+ 'UK .NTF' : 'ntf',
+ 'SDTS' : 'ddf',
+ 'DGN' : 'dgn',
+ 'VRT' : 'vrt',
+ 'REC' : 'rec',
+ 'BNA' : 'bna',
+ 'CSV' : 'csv',
+ 'GML' : 'gml',
+ 'GPX' : 'gpx',
+ 'KML' : 'kml',
+ 'GMT' : 'gmt',
+ 'PGeo' : 'mdb',
+ 'XPlane' : 'dat',
+ 'AVCBin' : 'adf',
+ 'AVCE00' : 'e00',
+ 'DXF' : 'dxf',
+ 'Geoconcept' : 'gxt',
+ 'GeoRSS' : 'xml',
+ 'GPSTrackMaker' : 'gtm',
+ 'VFK' : 'vfk'
+ }
+
+ try:
+ return formatToExt[name]
+ except KeyError:
+ return ''
+
+class GdalSelect(wx.Panel):
+ def __init__(self, parent, panel, ogr = False,
+ default = 'file',
+ exclude = [],
+ envHandler = None):
+ """!Widget for selecting GDAL/OGR datasource, format
+
+ @param parent parent window
+ @param ogr use OGR selector instead of GDAL
+ """
+ self.parent = parent
+ self.ogr = ogr
+ wx.Panel.__init__(self, parent = panel, id = wx.ID_ANY)
+
+ self.inputBox = wx.StaticBox(parent = self, id=wx.ID_ANY,
+ label=" %s " % _("Source name"))
+
+ # 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
+
+ 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 (*.tif)|*.tif'
+ else:
+ filemask = 'ESRI Shapefile (*.shp)|*.shp'
+
+ dsnFile = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
+ size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+ dialogTitle=_('Choose input file'),
+ 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)
+
+ if ogr:
+ fType = 'ogr'
+ else:
+ fType = 'gdal'
+ self.input = { 'file' : [_("File:"),
+ dsnFile,
+ utils.GetFormats()[fType]['file']],
+ 'dir' : [_("Directory:"),
+ dsnDir,
+ utils.GetFormats()[fType]['file']],
+ 'db' : [_("Database:"),
+ dsnDbFile,
+ utils.GetFormats()[fType]['database']],
+ 'pro' : [_("Protocol:"),
+ dsnPro,
+ utils.GetFormats()[fType]['protocol']],
+ 'db-win' : { 'file' : dsnDbFile,
+ 'text' : dsnDbText,
+ 'choice' : dsnDbChoice },
+ }
+
+ self.dsnType = default
+ self.input[self.dsnType][1].Show()
+ self.format.SetItems(self.input[self.dsnType][2])
+
+ if not ogr:
+ self.format.SetStringSelection('GeoTIFF')
+ else:
+ self.format.SetStringSelection('ESRI Shapefile')
+
+ self.dsnText = wx.StaticText(parent = self, id = wx.ID_ANY,
+ label = self.input[self.dsnType][0],
+ size = (75, -1))
+ self.formatText = wx.StaticText(parent = self, id = wx.ID_ANY,
+ label = _("Format:"))
+ self._layout()
+
+ def _layout(self):
+ """!Layout"""
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ inputSizer = wx.StaticBoxSizer(self.inputBox, wx.HORIZONTAL)
+
+ self.dsnSizer = wx.GridBagSizer(vgap=3, hgap=3)
+ self.dsnSizer.AddGrowableRow(1)
+ self.dsnSizer.AddGrowableCol(1)
+
+ 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))
+
+ self.dsnSizer.Add(item=self.formatText,
+ flag=wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 0))
+ self.dsnSizer.Add(item=self.format,
+ flag = wx.ALIGN_CENTER_VERTICAL,
+ pos = (1, 1))
+
+ inputSizer.Add(item=self.dsnSizer, proportion=1,
+ flag=wx.EXPAND | wx.ALL)
+
+ mainSizer.Add(item=self.source, proportion=0,
+ flag=wx.ALL | wx.EXPAND, border=5)
+ mainSizer.Add(item=inputSizer, proportion=0,
+ flag=wx.ALL | wx.EXPAND, border=5)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def OnSetType(self, event):
+ """!Datasource type changed"""
+ sel = event.GetSelection()
+ 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' % (ext, ext)
+ except KeyError:
+ format += ' (*.*)|*.*'
+
+ win = filebrowse.FileBrowseButton(parent=self, id=wx.ID_ANY,
+ size=globalvar.DIALOG_GSELECT_SIZE, labelText='',
+ dialogTitle=_('Choose input file'),
+ 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.format.SetStringSelection('GeoTIFF')
+ else:
+ self.format.SetStringSelection('ESRI Shapefile')
+ elif 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()
+
+ self.dsnSizer.Layout()
+
+ def OnSetDsn(self, event):
+ """!Input DXF file/OGR dsn defined, update list of layer widget"""
+ path = event.GetString()
+ if not path:
+ return
+
+ data = list()
+
+ layerId = 1
+ if self.format.GetStringSelection() == 'PostgreSQL':
+ dsn = 'PG:dbname=%s' % self.input[self.dsnType][1].GetStringSelection()
+ else:
+ dsn = self.input[self.dsnType][1].GetValue()
+ if self.dsnType == 'file':
+ baseName = os.path.basename(dsn)
+ grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
+ data.append((layerId, baseName, grassName))
+ elif self.dsnType == 'dir':
+ try:
+ ext = self.format.GetExtension(self.format.GetStringSelection())
+ except KeyError:
+ ext = ''
+ for file in glob.glob(os.path.join(dsn, "*.%s") % ext):
+ baseName = os.path.basename(file)
+ grassName = utils.GetValidLayerName(baseName.split('.', -1)[0])
+ data.append((layerId, baseName, grassName))
+ layerId += 1
+ elif self.dsnType == 'db':
+ ret = gcmd.RunCommand('v.in.ogr',
+ quiet = True,
+ parent = self,
+ read = True,
+ flags = 'l',
+ dsn = dsn)
+ if not ret:
+ self.list.LoadData()
+ self.btn_run.Enable(False)
+ return
+ layerId = 1
+ for line in ret.splitlines():
+ layerName = line.strip()
+ grassName = utils.GetValidLayerName(layerName)
+ data.append((layerId, layerName.strip(), grassName.strip()))
+ layerId += 1
+
+ evt = wxGdalSelect(dsn = dsn + '@OGR')
+ evt.SetId(self.input[self.dsnType][1].GetId())
+ wx.PostEvent(self.parent, evt)
+
+ if self.parent.GetName() == 'MultiImportDialog':
+ self.parent.list.LoadData(data)
+ if len(data) > 0:
+ self.parent.btn_run.Enable(True)
+ else:
+ self.parent.btn_run.Enable(False)
+
+ event.Skip()
+
+ def OnSetFormat(self, event):
+ """!Format changed"""
+ if self.dsnType not in ['file', 'db']:
+ return
+
+ win = self.input[self.dsnType][1]
+ self.dsnSizer.Remove(win)
+
+ if self.dsnType == 'file':
+ win.Destroy()
+ else: # database
+ win.Hide()
+
+ format = event.GetString()
+
+ if self.dsnType == 'file':
+ try:
+ ext = self.format.GetExtension(format)
+ if not ext:
+ raise KeyError
+ format += ' (*.%s)|*.%s' % (ext, ext)
+ except KeyError:
+ format += ' (*.*)|*.*'
+
+ 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)
+ 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'):
+ 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))
+ self.dsnSizer.Layout()
+
+ 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())
+
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/histogram.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/histogram.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/histogram.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,73 +1,54 @@
-"""
-MODULE: histogram
+"""!
+ at package histogram.py
-CLASSES:
- * BufferedWindow
- * HistFrame
+Plotting histogram
-PURPOSE: Plotting histogram
+Classes:
+ - BufferedWindow
+ - HistFrame
-AUTHORS: The GRASS Development Team
- Michael Barton
+COPYRIGHT: (C) 2007, 2010 by the GRASS Development Team
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
-COPYRIGHT: (C) 2007 by the GRASS Development Team
- This program is free software under the GNU General Public
- License (>=v2). Read the file COPYING that comes with GRASS
- for details.
+ at author Michael Barton
+ at author Various updates by Martin Landa
"""
+import os
+import sys
+
import wx
-import wx.aui
-import os, sys, time, glob, math
-from threading import Thread
-import globalvar
-try:
- import subprocess
-except:
- CompatPath = os.path.join(globalvar.ETCWXDIR)
- sys.path.append(CompatPath)
- from compat import subprocess
-
-gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
-sys.path.append(gmpath)
-
import render
import menuform
import disp_print
import utils
-from gui_modules.preferences import DefaultFontDialog as DefaultFontDialog
-from debug import Debug as Debug
-from icon import Icons as Icons
+import gdialogs
+import globalvar
+from toolbars import HistogramToolbar
+from preferences import DefaultFontDialog
+from debug import Debug
+from icon import Icons
-import images
-imagepath = images.__path__[0]
-sys.path.append(imagepath)
-
-os.environ["GRASS_BACKGROUNDCOLOR"] = "blue"
-
class BufferedWindow(wx.Window):
- """
- A Buffered window class.
+ """!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,
- pos = wx.DefaultPosition,
- size = wx.DefaultSize,
- style=wx.NO_FULL_REPAINT_ON_RESIZE,
- Map=None):
-
- wx.Window.__init__(self, parent, id, pos, size, style)
-
+ 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
#
@@ -75,36 +56,34 @@
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
-
+ 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]):
+
+ def Draw(self, pdc, img = None, drawid = None, pdctype = 'image', coords = [0,0,0,0]):
+ """!Draws histogram or clears window
"""
- Draws histogram or clears window
- """
-
if drawid == None:
if pdctype == 'image' :
drawid = imagedict[img]
@@ -114,11 +93,11 @@
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)
@@ -126,7 +105,7 @@
self.Refresh()
pdc.EndDrawing()
return
-
+
if pdctype == 'image':
bg = wx.TRANSPARENT_BRUSH
pdc.SetBackground(bg)
@@ -134,17 +113,15 @@
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
"""
- Draw psuedo DC to buffer
- """
-
- dc = wx.BufferedPaintDC(self, self._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
@@ -157,80 +134,83 @@
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
"""
- Init image size to match window size
- """
-
- # set size of the input image
+ # 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)
-
+ 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.
"""
- 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):
+
+ 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
"""
- This will save the contents of the buffer
- to the specified file. See the wx.Windows docs for
- wx.Bitmap::SaveFile for the details
- """
- dc = wx.BufferedPaintDC(self, self._Buffer)
+ 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)
- self._Buffer.SaveFile(FileName, FileType)
-
+ ibuffer.SaveFile(FileName, FileType)
+
+ busy.Destroy()
+
def GetImage(self):
+ """!Converts files to wx.Image
"""
- 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):
+
+ def UpdateHist(self, img = None):
+ """!Update canvas if histogram options changes or window
+ changes geometry
"""
- 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"]
@@ -241,297 +221,230 @@
os.environ[GRASS_ENCODING] = self.parent.encoding
# using active comp region
- self.Map.GetRegion(update=True)
+ self.Map.GetRegion(update = True)
self.Map.width, self.Map.height = self.GetClientSize()
- self.mapfile = self.Map.Render(force=self.render)
+ 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.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("Raster/Image map layer <%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
"""
- Erase the map display
- """
- self.Draw(self.pdc, pdctype='clear')
-
+ self.Draw(self.pdc, pdctype = 'clear')
+
class HistFrame(wx.Frame):
+ """!Main frame for hisgram display window. Uses d.histogram
+ rendered onto canvas
"""
- Main frame for hisgram display window.
- Uses d.histogram rendered onto canvas
- """
-
- def __init__(self, parent=None, id = wx.ID_ANY,
- title= _("GRASS GIS Histogram of image or raster map"),
- pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.DEFAULT_FRAME_STYLE):
-
- wx.Frame.__init__(self, parent, id, title, pos, size, style)
+ def __init__(self, parent = None, id = wx.ID_ANY,
+ title = _("GRASS GIS Histogram of image or raster map"),
+ style = wx.DEFAULT_FRAME_STYLE, **kwargs):
+ wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
- toolbar = self.__createToolBar()
-
self.Map = render.Map() # instance of render.Map to be associated with display
self.layer = None # reference to layer with histogram
- #
- # Set the size & cursor
- #
- self.SetClientSize(size)
# 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 = 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
-
- #
+ self.HistWindow = BufferedWindow(self, id = wx.ID_ANY, Map = self.Map) # initialize buffered DC
+
# Bind various events
- #
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
-
- #
+
# Init print module and classes
- #
self.printopt = disp_print.PrintOptions(self, self.HistWindow)
-
- #
+
# Add layer to the map
- #
- self.layer = self.Map.AddLayer(type="command", name='histogram', command=['d.histogram'],
- l_active=False, l_hidden=False, l_opacity=1, l_render=False)
-
-
- def __createToolBar(self):
- """Creates toolbar"""
- toolbar = self.CreateToolBar()
- toolbar.SetToolBitmapSize(globalvar.toolbarSize)
- for each in self.toolbarData():
- self.AddToolbarButton(toolbar, *each)
- toolbar.Realize()
+ self.layer = self.Map.AddLayer(type = "command", name = 'histogram', command = ['d.histogram'],
+ l_active = False, l_hidden = False, l_opacity = 1, l_render = False)
- return toolbar
-
- def AddToolbarButton(self, toolbar, label, icon, help, handler):
- """Adds buttons to the toolbar"""
-
- if not label:
- toolbar.AddSeparator()
- return
- tool = toolbar.AddLabelTool(id=wx.ID_ANY, label=label, bitmap=icon, shortHelp=help)
- self.Bind(wx.EVT_TOOL, handler, tool)
-
- def toolbarData(self):
-
- return (
- ('histogram',
- Icons["histogram"].GetBitmap(),
- Icons["histogram"].GetLabel(),
- self.OnOptions),
- ('rendermap',
- Icons["displaymap"].GetBitmap(),
- Icons["displaymap"].GetLabel(),
- self.OnRender),
- ('erase',
- Icons["erase"].GetBitmap(),
- Icons["erase"].GetLabel(),
- self.OnErase),
- ('font',
- Icons["font"].GetBitmap(),
- Icons["font"].GetLabel(),
- self.SetHistFont),
- ('', '', '', ''),
- ('save',
- Icons["savefile"].GetBitmap(),
- Icons["savefile"].GetLabel(),
- self.SaveToFile),
- ('print',
- Icons["printmap"].GetBitmap(),
- Icons["printmap"].GetLabel(),
- self.PrintMenu),
- ('quit',
- Icons["quit"].GetBitmap(),
- Icons["quit"].GetLabel(),
- self.OnQuit))
-
def InitDisplay(self):
+ """!Initialize histogram display, set dimensions and region
"""
- 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"""
-
+ """!Change histogram settings"""
cmd = ['d.histogram']
if self.mapname != '':
cmd.append('map=%s' % self.mapname)
-
+
menuform.GUI().ParseCommand(cmd,
- completed=(self.GetOptData, None, self.params),
- parentframe=self)
+ completed = (self.GetOptData, None, self.params),
+ parentframe = self)
def GetOptData(self, dcmd, layer, params, propwin):
+ """!Callback method for histogram command generated by dialog
+ created in menuform.py
"""
- Callback method for histogram command generated by
- dialog created in menuform.py
- """
if dcmd:
- name = utils.GetLayerNameFromCmd(dcmd, fullyQualified=True)
+ name = utils.GetLayerNameFromCmd(dcmd, fullyQualified = True)
self.SetHistLayer(name)
self.params = params
self.propwin = propwin
-
+
self.HistWindow.UpdateHist()
-
+
def SetHistLayer(self, name):
+ """!Set histogram layer
"""
- Set histogram layer
- """
self.mapname = name
-
- self.layer = self.Map.ChangeLayer(layer=self.layer,
- command=[['d.histogram', 'map=%s' % self.mapname],],
- active=True)
-
+
+ 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.
"""
- 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 = 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
"""
- Erase the histogram display
- """
- self.HistWindow.Draw(self.HistWindow.pdc, pdctype='clear')
-
+ self.HistWindow.Draw(self.HistWindow.pdc, pdctype = 'clear')
+
def OnRender(self, event):
+ """!Re-render histogram
"""
- Re-render histogram
- """
self.HistWindow.UpdateHist()
-
+
+ def GetWindow(self):
+ """!Get buffered window"""
+ return self.HistWindow
+
def SaveToFile(self, event):
+ """!Save to file
"""
- Save to file
- """
- filetype = "PNG file (*.png)|*.png|"\
- "TIF file (*.tif)|*.tif|"\
- "GIF file (*.gif)|*.gif"
-
- dlg = wx.FileDialog(self, "Choose a file name to save the image as a PNG to",
- defaultDir = "",
- defaultFile = "",
- wildcard = filetype,
- style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
+ filetype, ltype = gdialogs.GetImageHandlers(self.HistWindow.img)
+
+ # get size
+ dlg = gdialogs.ImageSizeDialog(self)
+ dlg.CentreOnParent()
+ if dlg.ShowModal() != wx.ID_OK:
+ dlg.Destroy()
+ return
+ width, height = dlg.GetValues()
+ dlg.Destroy()
+
+ # get filename
+ dlg = wx.FileDialog(parent = self,
+ message = _("Choose a file name to save the image "
+ "(no need to add extension)"),
+ wildcard = filetype,
+ style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
+
if dlg.ShowModal() == wx.ID_OK:
- base = os.path.splitext(dlg.GetPath())[0]
- ext = os.path.splitext(dlg.GetPath())[1]
- if dlg.GetFilterIndex() == 0:
- type = wx.BITMAP_TYPE_PNG
- path = dlg.GetPath()
- if ext != '.png': path = base+'.png'
- elif dlg.GetFilterIndex() == 1:
- type = wx.BITMAP_TYPE_TIF
- if ext != '.tif': path = base+'.tif'
- elif dlg.GetFilterIndex() == 2:
- type = wx.BITMAP_TYPE_TIF
- if ext != '.gif': path = base+'.gif'
- self.HistWindow.SaveToFile(path, type)
+ 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
"""
- Print options and output menu
- """
point = wx.GetMousePosition()
printmenu = wx.Menu()
# Add items to the menu
- setup = wx.MenuItem(printmenu, -1,'Page setup')
+ 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, -1,'Print preview')
+
+ 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, -1,'Print display')
+
+ 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
+ """!Window closed
Also remove associated rendered images
"""
try:
@@ -540,5 +453,4 @@
pass
self.Map.Clean()
self.Destroy()
-
-
+
Added: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/layertree.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/layertree.py (rev 0)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/layertree.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -0,0 +1,1505 @@
+"""!
+ at package layertree.py
+
+ at brief Utility classes for map layer management.
+
+Classes:
+ - AbstractLayer
+ - Layer
+ - LayerTree
+
+(C) 2007-2010 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Jachym Cepicky (Mendel University of Agriculture)
+ at author Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import sys
+import string
+
+import wx
+try:
+ import wx.lib.agw.customtreectrl as CT
+except ImportError:
+ import wx.lib.customtreectrl as CT
+import wx.combo
+import wx.lib.newevent
+import wx.lib.buttons as buttons
+
+import globalvar
+
+from grass.script import core as grass
+
+import gdialogs
+import menuform
+import toolbars
+import mapdisp
+import render
+import histogram
+import utils
+import profile
+from debug import Debug as Debug
+from icon import Icons as Icons
+from preferences import globalSettings as UserSettings
+from vdigit import haveVDigit
+from gcmd import GError
+try:
+ import subprocess
+except:
+ from compat import subprocess
+
+try:
+ import treemixin
+except ImportError:
+ from wx.lib.mixins import treemixin
+
+TREE_ITEM_HEIGHT = 25
+
+class LayerTree(treemixin.DragAndDrop, CT.CustomTreeCtrl):
+ """
+ Creates layer tree structure
+ """
+ def __init__(self, parent,
+ id = wx.ID_ANY, style=wx.SUNKEN_BORDER,
+ ctstyle=CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT |
+ CT.TR_HIDE_ROOT | CT.TR_ROW_LINES | CT.TR_FULL_ROW_HIGHLIGHT |
+ CT.TR_MULTIPLE, **kwargs):
+
+ if 'style' in kwargs:
+ ctstyle |= kwargs['style']
+ del kwargs['style']
+ self.disp_idx = kwargs['idx']
+ del kwargs['idx']
+ self.lmgr = kwargs['lmgr']
+ del kwargs['lmgr']
+ self.notebook = kwargs['notebook'] # GIS Manager notebook for layer tree
+ del kwargs['notebook']
+ self.auimgr = kwargs['auimgr'] # aui manager
+ del kwargs['auimgr']
+ showMapDisplay = kwargs['showMapDisplay']
+ del kwargs['showMapDisplay']
+ self.treepg = parent # notebook page holding layer tree
+ self.Map = render.Map() # instance of render.Map to be associated with display
+ self.root = None # ID of layer tree root node
+ self.groupnode = 0 # index value for layers
+ self.optpage = {} # dictionary of notebook option pages for each map layer
+ self.layer_selected = None # ID of currently selected layer
+ self.saveitem = {} # dictionary to preserve layer attributes for drag and drop
+ self.first = True # indicates if a layer is just added or not
+ self.flag = '' # flag for drag and drop hittest
+ self.rerender = False # layer change requires a rerendering if auto render
+ self.reorder = False # layer change requires a reordering
+
+ 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.SetFirstGradientColour(wx.Colour(100, 100, 100))
+ self.SetSecondGradientColour(wx.Colour(150, 150, 150))
+
+ # init associated map display
+ pos = wx.Point((self.disp_idx + 1) * 25, (self.disp_idx + 1) * 25)
+ self.mapdisplay = mapdisp.MapFrame(self,
+ id=wx.ID_ANY, pos=pos,
+ size=globalvar.MAP_WINDOW_SIZE,
+ style=wx.DEFAULT_FRAME_STYLE,
+ tree=self, notebook=self.notebook,
+ lmgr=self.lmgr, page=self.treepg,
+ Map=self.Map, auimgr=self.auimgr)
+
+ # title
+ self.mapdisplay.SetTitle(_("GRASS GIS Map Display: %(id)d - Location: %(loc)s") % \
+ { 'id' : self.disp_idx + 1,
+ 'loc' : grass.gisenv()["LOCATION_NAME"] })
+
+ # show new display
+ if showMapDisplay is True:
+ self.mapdisplay.Show()
+ self.mapdisplay.Refresh()
+ self.mapdisplay.Update()
+
+ self.root = self.AddRoot(_("Map Layers"))
+ self.SetPyData(self.root, (None, None))
+
+ #create image list to use with layer tree
+ il = wx.ImageList(16, 16, mask=False)
+
+ trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, (16, 16))
+ self.folder_open = il.Add(trart)
+ trart = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))
+ self.folder = il.Add(trart)
+
+ bmpsize = (16, 16)
+ trgif = Icons["addrast"].GetBitmap(bmpsize)
+ self.rast_icon = il.Add(trgif)
+
+ trgif = Icons["addrast3d"].GetBitmap(bmpsize)
+ self.rast3d_icon = il.Add(trgif)
+
+ trgif = Icons["addrgb"].GetBitmap(bmpsize)
+ self.rgb_icon = il.Add(trgif)
+
+ trgif = Icons["addhis"].GetBitmap(bmpsize)
+ self.his_icon = il.Add(trgif)
+
+ trgif = Icons["addshaded"].GetBitmap(bmpsize)
+ self.shaded_icon = il.Add(trgif)
+
+ trgif = Icons["addrarrow"].GetBitmap(bmpsize)
+ self.rarrow_icon = il.Add(trgif)
+
+ trgif = Icons["addrnum"].GetBitmap(bmpsize)
+ self.rnum_icon = il.Add(trgif)
+
+ trgif = Icons["addvect"].GetBitmap(bmpsize)
+ self.vect_icon = il.Add(trgif)
+
+ trgif = Icons["addthematic"].GetBitmap(bmpsize)
+ self.theme_icon = il.Add(trgif)
+
+ trgif = Icons["addchart"].GetBitmap(bmpsize)
+ self.chart_icon = il.Add(trgif)
+
+ trgif = Icons["addgrid"].GetBitmap(bmpsize)
+ self.grid_icon = il.Add(trgif)
+
+ trgif = Icons["addgeodesic"].GetBitmap(bmpsize)
+ self.geodesic_icon = il.Add(trgif)
+
+ trgif = Icons["addrhumb"].GetBitmap(bmpsize)
+ self.rhumb_icon = il.Add(trgif)
+
+ trgif = Icons["addlabels"].GetBitmap(bmpsize)
+ self.labels_icon = il.Add(trgif)
+
+ trgif = Icons["addcmd"].GetBitmap(bmpsize)
+ self.cmd_icon = il.Add(trgif)
+
+ self.AssignImageList(il)
+
+ self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnExpandNode)
+ self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnCollapseNode)
+ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivateLayer)
+ self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnChangeSel)
+ self.Bind(CT.EVT_TREE_ITEM_CHECKED, self.OnLayerChecked)
+ self.Bind(wx.EVT_TREE_DELETE_ITEM, self.OnDeleteLayer)
+ self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnLayerContextMenu)
+ self.Bind(wx.EVT_TREE_END_DRAG, self.OnEndDrag)
+ self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
+ self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+ 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.statusbarWin['render'].GetValue():
+ self.mapdisplay.MapWindow.UpdateMap(render=True)
+
+ event.Skip()
+
+ def OnKeyUp(self, event):
+ """!Key pressed"""
+ key = event.GetKeyCode()
+
+ if key == wx.WXK_DELETE and self.lmgr:
+ 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']
+
+ Debug.msg (4, "LayerTree.OnContextMenu: layertype=%s" % \
+ ltype)
+
+ 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() # nviz
+ self.popupID12 = wx.NewId()
+ self.popupID13 = wx.NewId()
+ self.popupID14 = wx.NewId()
+ self.popupID15 = wx.NewId()
+ self.popupID16 = wx.NewId()
+
+ self.popupMenu = wx.Menu()
+
+ numSelected = len(self.GetSelections())
+
+ # general item
+ self.popupMenu.Append(self.popupID1, text=_("Remove"))
+ self.Bind(wx.EVT_MENU, self.lmgr.OnDeleteLayer, id=self.popupID1)
+
+ if ltype != "command": # rename
+ self.popupMenu.Append(self.popupID2, text=_("Rename"))
+ self.Bind(wx.EVT_MENU, self.RenameLayer, id=self.popupID2)
+ if numSelected > 1:
+ self.popupMenu.Enable(self.popupID2, False)
+
+ # map layer items
+ if ltype != "group" and \
+ ltype != "command":
+ self.popupMenu.AppendSeparator()
+ self.popupMenu.Append(self.popupID8, text=_("Change opacity level"))
+ self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=self.popupID8)
+ self.popupMenu.Append(self.popupID3, text=_("Properties"))
+ self.Bind(wx.EVT_MENU, self.OnPopupProperties, id=self.popupID3)
+
+ if ltype in ('raster', 'vector', '3d-raster') and self.mapdisplay.toolbars['nviz']:
+ self.popupMenu.Append(self.popupID11, _("3D view properties"))
+ self.Bind (wx.EVT_MENU, self.OnNvizProperties, id=self.popupID11)
+
+ if ltype in ('raster', 'vector', 'rgb'):
+ self.popupMenu.Append(self.popupID9, text=_("Zoom to selected map(s)"))
+ self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToMap, id=self.popupID9)
+ self.popupMenu.Append(self.popupID10, text=_("Set computational region from selected map(s)"))
+ self.Bind(wx.EVT_MENU, self.OnSetCompRegFromMap, id=self.popupID10)
+ if numSelected > 1:
+ self.popupMenu.Enable(self.popupID8, False)
+ self.popupMenu.Enable(self.popupID3, False)
+
+ # 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.popupID4, text=_("Show attribute data"))
+ self.Bind (wx.EVT_MENU, self.lmgr.OnShowAttributeTable, id=self.popupID4)
+
+ self.popupMenu.Append(self.popupID5, text=_("Start editing"))
+ self.popupMenu.Append(self.popupID6, text=_("Stop editing"))
+ self.popupMenu.Enable(self.popupID6, False)
+ self.Bind (wx.EVT_MENU, self.OnStartEditing, id=self.popupID5)
+ self.Bind (wx.EVT_MENU, self.OnStopEditing, id=self.popupID6)
+
+ layer = self.GetPyData(self.layer_selected)[0]['maplayer']
+ # enable editing only for vector map layers available in the current mapset
+ digitToolbar = self.mapdisplay.toolbars['vdigit']
+ if digitToolbar:
+ # background vector map
+ self.popupMenu.Append(self.popupID14,
+ text=_("Use as background vector map"),
+ kind=wx.ITEM_CHECK)
+ self.Bind(wx.EVT_MENU, self.OnSetBgMap, id=self.popupID14)
+ if UserSettings.Get(group='vdigit', key='bgmap', subkey='value',
+ internal=True) == layer.GetName():
+ self.popupMenu.Check(self.popupID14, True)
+
+ self.popupMenu.Append(self.popupID16, text=_("Rebuild topology"))
+ self.Bind(wx.EVT_MENU, self.OnTopology, id=self.popupID16)
+
+ if layer.GetMapset() != grass.gisenv()['MAPSET']:
+ # only vector map in current mapset can be edited
+ self.popupMenu.Enable (self.popupID5, False)
+ self.popupMenu.Enable (self.popupID6, False)
+ self.popupMenu.Enable (self.popupID16, False)
+ elif digitToolbar and digitToolbar.GetLayer():
+ # vector map already edited
+ vdigitLayer = digitToolbar.GetLayer()
+ if vdigitLayer is layer:
+ # disable 'start editing'
+ self.popupMenu.Enable (self.popupID5, False)
+ # enable 'stop editing'
+ self.popupMenu.Enable(self.popupID6, True)
+ # disable 'remove'
+ self.popupMenu.Enable(self.popupID1, False)
+ # disable 'bgmap'
+ self.popupMenu.Enable(self.popupID14, False)
+ # disable 'topology'
+ self.popupMenu.Enable (self.popupID16, False)
+ else:
+ # disable 'start editing'
+ self.popupMenu.Enable(self.popupID5, False)
+ # disable 'stop editing'
+ self.popupMenu.Enable(self.popupID6, False)
+ # enable 'bgmap'
+ self.popupMenu.Enable(self.popupID14, True)
+
+ self.popupMenu.Append(self.popupID7, _("Metadata"))
+ self.Bind (wx.EVT_MENU, self.OnMetadata, id=self.popupID7)
+ if numSelected > 1:
+ self.popupMenu.Enable(self.popupID4, False)
+ self.popupMenu.Enable(self.popupID5, False)
+ self.popupMenu.Enable(self.popupID6, False)
+ self.popupMenu.Enable(self.popupID7, False)
+ self.popupMenu.Enable(self.popupID14, False)
+
+ #
+ # raster layers (specific items)
+ #
+ elif mltype and mltype == "raster":
+ self.popupMenu.Append(self.popupID12, text=_("Zoom to selected map(s) (ignore NULLs)"))
+ self.Bind(wx.EVT_MENU, self.mapdisplay.OnZoomToRaster, id=self.popupID12)
+ self.popupMenu.Append(self.popupID13, text=_("Set computational region from selected map(s) (ignore NULLs)"))
+ self.Bind(wx.EVT_MENU, self.OnSetCompRegFromRaster, id=self.popupID13)
+ self.popupMenu.AppendSeparator()
+ self.popupMenu.Append(self.popupID15, _("Set color table"))
+ self.Bind (wx.EVT_MENU, self.OnColorTable, id=self.popupID15)
+ self.popupMenu.Append(self.popupID4, _("Histogram"))
+ self.Bind (wx.EVT_MENU, self.OnHistogram, id=self.popupID4)
+ self.popupMenu.Append(self.popupID5, _("Profile"))
+ self.Bind (wx.EVT_MENU, self.OnProfile, id=self.popupID5)
+ self.popupMenu.Append(self.popupID6, _("Metadata"))
+ self.Bind (wx.EVT_MENU, self.OnMetadata, id=self.popupID6)
+
+ if numSelected > 1:
+ self.popupMenu.Enable(self.popupID12, False)
+ self.popupMenu.Enable(self.popupID13, False)
+ self.popupMenu.Enable(self.popupID15, False)
+ self.popupMenu.Enable(self.popupID4, False)
+ self.popupMenu.Enable(self.popupID5, False)
+ self.popupMenu.Enable(self.popupID6, False)
+ self.popupMenu.Enable(self.popupID11, False)
+
+ ## self.PopupMenu(self.popupMenu, pos)
+ 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())
+
+ cmd = ['g.region']
+ if rast:
+ cmd.append('rast=%s' % ','.join(rast))
+ if vect:
+ cmd.append('vect=%s' % ','.join(vect))
+ if rast3d:
+ cmd.append('rast3d=%s' % ','.join(rast3d))
+
+ # print output to command log area
+ if len(cmd) > 1:
+ cmd.append('-p')
+ self.lmgr.goutput.RunCmd(cmd)
+
+ def OnProfile(self, event):
+ """!Plot profile of given raster map layer"""
+ mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+ if not mapLayer.GetName():
+ wx.MessageBox(parent=self,
+ message=_("Unable to create profile of "
+ "raster map."),
+ caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ return False
+
+ if not hasattr (self, "profileFrame"):
+ self.profileFrame = None
+
+ if hasattr (self.mapdisplay, "profile") and self.mapdisplay.profile:
+ self.profileFrame = self.mapdisplay.profile
+
+ if not self.profileFrame:
+ self.profileFrame = profile.ProfileFrame(self.mapdisplay,
+ id=wx.ID_ANY, pos=wx.DefaultPosition, size=(700,300),
+ style=wx.DEFAULT_FRAME_STYLE, rasterList=[mapLayer.GetName()])
+ # show new display
+ self.profileFrame.Show()
+
+ def OnColorTable(self, event):
+ """!Set color table for raster map"""
+ name = self.GetPyData(self.layer_selected)[0]['maplayer'].GetName()
+ menuform.GUI().ParseCommand(['r.colors',
+ 'map=%s' % name],
+ parentframe=self)
+
+ def OnHistogram(self, event):
+ """
+ Plot histogram for given raster map layer
+ """
+ mapLayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+ if not mapLayer.GetName():
+ wx.MessageBox(parent=self,
+ message=_("Unable to display histogram of "
+ "raster map."),
+ caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ return False
+
+ if not hasattr (self, "histogramFrame"):
+ self.histogramFrame = None
+
+ if hasattr (self.mapdisplay, "histogram") and self.mapdisplay.histogram:
+ self.histogramFrame = self.mapdisplay.histogram
+
+ if not self.histogramFrame:
+ self.histogramFrame = histogram.HistFrame(self,
+ id=wx.ID_ANY,
+ pos=wx.DefaultPosition, size=globalvar.HIST_WINDOW_SIZE,
+ style=wx.DEFAULT_FRAME_STYLE)
+ # show new display
+ self.histogramFrame.Show()
+
+ self.histogramFrame.SetHistLayer(mapLayer.GetName())
+ self.histogramFrame.HistWindow.UpdateHist()
+ self.histogramFrame.Refresh()
+ self.histogramFrame.Update()
+
+ return 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.toolbars['vdigit']: # enable tool
+ self.mapdisplay.AddToolbar('vdigit')
+ else: # tool already enabled
+ pass
+
+ # mark layer as 'edited'
+
+ if not self.mapdisplay.toolbars['vdigit'].StartEditing(maplayer) or \
+ not haveVDigit:
+ if not haveVDigit:
+ from vdigit import errorMsg
+ else:
+ errorMsg = _("Unable to initialize display driver of vector "
+ "digitizer")
+ msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
+ "TCL/TK digitizer (v.digit) instead?\n\n"
+ "Details: %s" % errorMsg)
+
+ self.mapdisplay.toolbars['map'].combo.SetValue (_("2D view"))
+ dlg = wx.MessageDialog(parent = self.mapdisplay,
+ message = msg,
+ caption=_("Vector digitizer failed"),
+ style = wx.YES_NO | wx.CENTRE)
+ if dlg.ShowModal() == wx.ID_YES:
+ self.lmgr.goutput.RunCmd(['v.digit', 'map=%s' % maplayer.GetName()],
+ switchPage=False)
+
+ dlg.Destroy()
+
+ def OnStopEditing(self, event):
+ """
+ Stop editing the current vector map layer
+ """
+ maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+
+ self.mapdisplay.toolbars['vdigit'].OnExit()
+ self.mapdisplay.imgVectorMap = None
+
+ def OnSetBgMap(self, event):
+ """!Set background vector map for editing sesstion"""
+ 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)
+ else:
+ UserSettings.Set(group='vdigit', key='bgmap', subkey='value',
+ value='', internal=True)
+
+ 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
+
+ #win = self.FindWindowById(self.GetPyData(self.layer_selected)[0]['ctrl'])
+ #type = win.GetName()
+ #
+ #self.layer_selected.DeleteWindow()
+
+ maplayer = self.GetPyData(self.layer_selected)[0]['maplayer']
+ current_opacity = maplayer.GetOpacity()
+
+ dlg = gdialogs.SetOpacityDialog(self, opacity=current_opacity,
+ title=_("Set opacity <%s>") % maplayer.GetName())
+ dlg.CentreOnParent()
+
+ if dlg.ShowModal() == wx.ID_OK:
+ new_opacity = dlg.GetOpacity() # string
+ self.Map.ChangeOpacity(maplayer, new_opacity)
+ maplayer.SetOpacity(new_opacity)
+ opacity_pct = int(new_opacity * 100)
+ layername = self.GetItemText(self.layer_selected)
+ layerbase = layername.split('(')[0].strip()
+ self.SetItemText(self.layer_selected,
+ layerbase + ' (opacity: ' + str(opacity_pct) + '%)')
+
+ # vector layer currently edited
+ if self.mapdisplay.toolbars['vdigit'] and \
+ self.mapdisplay.toolbars['vdigit'].GetLayer() == maplayer:
+ alpha = int(new_opacity * 255)
+ self.mapdisplay.digit.driver.UpdateSettings(alpha)
+
+ # redraw map if auto-rendering is enabled
+ self.rerender = True
+ self.reorder = True
+ #if self.mapdisplay.statusbarWin['render'].GetValue():
+ # print "*** Opacity OnRender *****"
+ # self.mapdisplay.OnRender(None)
+
+ def OnNvizProperties(self, event):
+ """!Nviz-related properties (raster/vector/volume)
+
+ @todo vector/volume
+ """
+ self.lmgr.notebook.SetSelection(3)
+ 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 RenameLayer (self, event):
+ """!Rename layer"""
+ self.EditLabel(self.layer_selected)
+
+ def AddLayer(self, ltype, lname=None, lchecked=None,
+ lopacity=1.0, lcmd=None, lgroup=None, lvdigit=None, lnviz=None):
+ """!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
+ """
+ self.first = True
+ params = {} # no initial options parameters
+
+ # deselect active item
+ if self.layer_selected:
+ self.SelectItem(self.layer_selected, select=False)
+
+ Debug.msg (3, "LayerTree().AddLayer(): ltype=%s" % (ltype))
+
+ if ltype == 'command':
+ # generic command item
+ ctrl = wx.TextCtrl(self, id=wx.ID_ANY, value='',
+ pos=wx.DefaultPosition, size=(self.GetSize()[0]-100,25),
+ # style=wx.TE_MULTILINE|wx.TE_WORDWRAP)
+ style=wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
+ ctrl.Bind(wx.EVT_TEXT_ENTER, self.OnCmdChanged)
+ # ctrl.Bind(wx.EVT_TEXT, self.OnCmdChanged)
+ elif ltype == 'group':
+ # group item
+ ctrl = None
+ grouptext = _('Layer group:') + str(self.groupnode)
+ self.groupnode += 1
+ else:
+ btnbmp = Icons["layeropts"].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)
+
+ # select new item
+ self.SelectItem(layer, select=True)
+ self.layer_selected = layer
+
+ # add text and icons for each layer ltype
+ if ltype == 'raster':
+ self.SetItemImage(layer, self.rast_icon)
+ self.SetItemText(layer, '%s %s' % (_('raster'), _('(double click to set properties)')))
+ elif ltype == '3d-raster':
+ self.SetItemImage(layer, self.rast3d_icon)
+ self.SetItemText(layer, '%s %s' % (_('3d raster'), _('(double click to set properties)')))
+ elif ltype == 'rgb':
+ self.SetItemImage(layer, self.rgb_icon)
+ self.SetItemText(layer, '%s %s' % (_('RGB'), _('(double click to set properties)')))
+ elif ltype == 'his':
+ self.SetItemImage(layer, self.his_icon)
+ self.SetItemText(layer, '%s %s' % (_('HIS'), _('(double click to set properties)')))
+ elif ltype == 'shaded':
+ self.SetItemImage(layer, self.shaded_icon)
+ self.SetItemText(layer, '%s %s' % (_('Shaded relief'), _('(double click to set properties)')))
+ elif ltype == 'rastnum':
+ self.SetItemImage(layer, self.rnum_icon)
+ self.SetItemText(layer, '%s %s' % (_('raster cell numbers'), _('(double click to set properties)')))
+ elif ltype == 'rastarrow':
+ self.SetItemImage(layer, self.rarrow_icon)
+ self.SetItemText(layer, '%s %s' % (_('raster flow arrows'), _('(double click to set properties)')))
+ elif ltype == 'vector':
+ self.SetItemImage(layer, self.vect_icon)
+ self.SetItemText(layer, '%s %s' % (_('vector'), _('(double click to set properties)')))
+ elif ltype == 'thememap':
+ self.SetItemImage(layer, self.theme_icon)
+ self.SetItemText(layer, '%s %s' % (_('thematic map'), _('(double click to set properties)')))
+ elif ltype == 'themechart':
+ self.SetItemImage(layer, self.chart_icon)
+ self.SetItemText(layer, '%s %s' % (_('thematic charts'), _('(double click to set properties)')))
+ elif ltype == 'grid':
+ self.SetItemImage(layer, self.grid_icon)
+ self.SetItemText(layer, '%s %s' % (_('grid'), _('(double click to set properties)')))
+ elif ltype == 'geodesic':
+ self.SetItemImage(layer, self.geodesic_icon)
+ self.SetItemText(layer, '%s %s' % (_('geodesic line'), _('(double click to set properties)')))
+ elif ltype == 'rhumb':
+ self.SetItemImage(layer, self.rhumb_icon)
+ self.SetItemText(layer, '%s %s' % (_('rhumbline'), _('(double click to set properties)')))
+ elif ltype == 'labels':
+ self.SetItemImage(layer, self.labels_icon)
+ self.SetItemText(layer, '%s %s' % (_('vector labels'), _('(double click to set properties)')))
+ 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 = utils.GetLayerNameFromCmd(lcmd)
+ else:
+ cmd = []
+ if ltype == 'command' and lname:
+ for c in lname.split(';'):
+ cmd.append(c.split(' '))
+
+ render = False
+ name = None
+
+ if ctrl:
+ ctrlId = ctrl.GetId()
+ else:
+ ctrlId = None
+
+ # add a data object to hold the layer's command (does not apply to generic command layers)
+ self.SetPyData(layer, ({'cmd' : cmd,
+ 'type' : ltype,
+ 'ctrl' : ctrlId,
+ '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,
+ 'maplayer' : None,
+ 'propwin' : None},
+ None))
+
+ # use predefined layer name if given
+ if lname:
+ if ltype == 'group':
+ self.SetItemText(layer, lname)
+ elif ltype == 'command':
+ ctrl.SetValue(lname)
+ else:
+ name = lname + ' (opacity: ' + \
+ str(self.GetPyData(layer)[0]['maplayer'].GetOpacity()) + '%)'
+ self.SetItemText(layer, name)
+
+ # updated progress bar range (mapwindow statusbar)
+ if checked is True:
+ self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active=True)))
+
+ # layer.SetHeight(TREE_ITEM_HEIGHT)
+
+ return layer
+
+ def PropertiesDialog (self, layer, show=True):
+ """!Launch the properties dialog"""
+ if self.GetPyData(layer)[0].has_key('propwin') and \
+ self.GetPyData(layer)[0]['propwin'] is not None:
+ # recycle GUI dialogs
+ win = self.GetPyData(layer)[0]['propwin']
+ # update properties (columns, layers)
+ win.notebookpanel.OnUpdateSelection(None)
+ if win.IsShown():
+ win.SetFocus()
+ else:
+ win.Show()
+
+ return
+
+ completed = ''
+ params = self.GetPyData(layer)[1]
+ ltype = self.GetPyData(layer)[0]['type']
+
+ Debug.msg (3, "LayerTree.PropertiesDialog(): ltype=%s" % \
+ ltype)
+
+ if self.GetPyData(layer)[0]['cmd']:
+ module = menuform.GUI()
+ module.ParseCommand(self.GetPyData(layer)[0]['cmd'],
+ completed=(self.GetOptData,layer,params),
+ parentframe=self, show=show)
+
+ 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')
+ menuform.GUI().ParseCommand(cmd, completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == '3d-raster':
+ cmd = ['d.rast3d']
+ menuform.GUI().ParseCommand(cmd, completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'rgb':
+ menuform.GUI().ParseCommand(['d.rgb'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'his':
+ menuform.GUI().ParseCommand(['d.his'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'shaded':
+ menuform.GUI().ParseCommand(['d.shadedmap'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'rastarrow':
+ menuform.GUI().ParseCommand(['d.rast.arrow'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'rastnum':
+ menuform.GUI().ParseCommand(['d.rast.num'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'vector':
+ types = ''
+ for type in UserSettings.Get(group='cmd', key='showType').keys():
+ if UserSettings.Get(group='cmd', key='showType', subkey=[type, 'enabled']):
+ types += type + ','
+ types = types.rstrip(',')
+
+ menuform.GUI().ParseCommand(['d.vect', 'type=%s' % types],
+ completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'thememap':
+ # -s flag requested, otherwise only first thematic category is displayed
+ # should be fixed by C-based d.thematic.* modules
+ menuform.GUI().ParseCommand(['d.vect.thematic', '-s'],
+ completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'themechart':
+ menuform.GUI().ParseCommand(['d.vect.chart'],
+ completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'grid':
+ menuform.GUI().ParseCommand(['d.grid'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'geodesic':
+ menuform.GUI().ParseCommand(['d.geodesic'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'rhumb':
+ menuform.GUI().ParseCommand(['d.rhumbline'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'labels':
+ menuform.GUI().ParseCommand(['d.labels'], completed=(self.GetOptData,layer,params),
+ parentframe=self)
+ elif ltype == 'cmdlayer':
+ pass
+ elif ltype == 'group':
+ pass
+
+ def OnActivateLayer(self, event):
+ """!Double click on the layer item.
+ Launch property dialog, or expand/collapse group of items, etc.
+ """
+ self.lmgr.WorkspaceChanged()
+ layer = event.GetItem()
+ self.layer_selected = layer
+
+ self.PropertiesDialog (layer)
+
+ if self.GetPyData(layer)[0]['type'] == 'group':
+ if self.IsExpanded(layer):
+ self.Collapse(layer)
+ else:
+ self.Expand(layer)
+
+ def OnDeleteLayer(self, event):
+ """!Remove selected layer item from the layer tree"""
+ self.lmgr.WorkspaceChanged()
+ item = event.GetItem()
+
+ try:
+ item.properties.Close(True)
+ except:
+ pass
+
+ if item != self.root:
+ Debug.msg (3, "LayerTree.OnDeleteLayer(): name=%s" % \
+ (self.GetItemText(item)))
+ else:
+ self.root = None
+
+ # unselect item
+ self.Unselect()
+ self.layer_selected = None
+
+ try:
+ if self.GetPyData(item)[0]['type'] != 'group':
+ self.Map.DeleteLayer( self.GetPyData(item)[0]['maplayer'])
+ except:
+ pass
+
+ # redraw map if auto-rendering is enabled
+ self.rerender = True
+ self.reorder = True
+ #if self.mapdisplay.statusbarWin['render'].GetValue():
+ # print "*** Delete OnRender *****"
+ # self.mapdisplay.OnRender(None)
+
+ if self.mapdisplay.toolbars['vdigit']:
+ self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers (updateTool=True)
+
+ # update progress bar range (mapwindow statusbar)
+ self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active=True)))
+
+ event.Skip()
+
+ def OnLayerChecked(self, event):
+ """!Enable/disable data layer"""
+ self.lmgr.WorkspaceChanged()
+
+ item = event.GetItem()
+ checked = item.IsChecked()
+
+ digitToolbar = self.mapdisplay.toolbars['vdigit']
+ if self.first == False:
+ # 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)
+
+ #
+ # update progress bar range (mapwindow statusbar)
+ #
+ self.mapdisplay.statusbarWin['progress'].SetRange(len(self.Map.GetListOfLayers(l_active=True)))
+
+ #
+ # nviz
+ #
+ if self.mapdisplay.toolbars['nviz'] 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':
+ self.mapdisplay.MapWindow.LoadVector(item)
+
+ else: # disable
+ data = self.GetPyData(item)[0]['nviz']
+
+ 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
+
+ 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.statusbarWin['render'].IsChecked()
+ self.mapdisplay.MapWindow.ZoomToMap(layers = [mapLayer,],
+ render = render)
+
+ #
+ # update nviz tools
+ #
+ if self.mapdisplay.toolbars['nviz'] 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]
+ #self.Expand(newItem)
+
+ # delete layer at original position
+ try:
+ self.Delete(old) # entry in render.Map layers list automatically deleted by OnDeleteLayer handler
+ except AttributeError:
+ # FIXME being ugly (item.SetWindow(None))
+ pass
+
+ # reorder layers in render.Map to match new order after drag and drop
+ #self.ReorderLayers()
+
+ # redraw map if auto-rendering is enabled
+ self.rerender = True
+ self.reorder = True
+ #if self.mapdisplay.statusbarWin['render'].GetValue():
+ # print "*** Drop OnRender *****"
+ # self.mapdisplay.OnRender(None)
+
+ # select new item
+ self.SelectItem(newItem)
+
+ def RecreateItem (self, dragItem, dropTarget, parent=None):
+ """
+ Recreate item (needed for OnEndDrag())
+ """
+ Debug.msg (4, "LayerTree.RecreateItem(): layer=%s" % \
+ self.GetItemText(dragItem))
+
+ # fetch data (dragItem)
+ checked = self.IsItemChecked(dragItem)
+ image = self.GetItemImage(dragItem, 0)
+ text = self.GetItemText(dragItem)
+ if self.GetPyData(dragItem)[0]['ctrl']:
+ # recreate data layer
+ btnbmp = Icons["layeropts"].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
+
+ # newItem.SetHeight(TREE_ITEM_HEIGHT)
+
+ return newItem
+
+ def GetOptData(self, dcmd, layer, params, propwin):
+ """!Process layer data"""
+ # set layer text to map name
+ if dcmd:
+ mapLayer = self.GetPyData(layer)[0]['maplayer']
+ opacity = int(mapLayer.GetOpacity(float=True) * 100)
+ mapname = utils.GetLayerNameFromCmd(dcmd, layerType=mapLayer.type,
+ fullyQualified=True)
+ if not mapname:
+ GError(parent=self,
+ message=_("Map <%s> not found.") % utils.GetLayerNameFromCmd(dcmd))
+ return
+
+ self.SetItemText(layer, mapname + ' (opacity: ' + str(opacity) + '%)')
+
+ # update layer data
+ if params:
+ self.SetPyData(layer, (self.GetPyData(layer)[0], params))
+ if dcmd:
+ self.GetPyData(layer)[0]['cmd'] = dcmd
+ 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)
+
+ if self.mapdisplay.toolbars['nviz'] and dcmd:
+ # update nviz session
+ mapLayer = self.GetPyData(layer)[0]['maplayer']
+ mapWin = self.mapdisplay.MapWindow
+ if len(mapLayer.GetCmd()) > 0:
+ id = -1
+ if mapLayer.type == 'raster':
+ if mapWin.IsLoaded(layer):
+ mapWin.UnloadRaster(layer)
+
+ mapWin.LoadRaster(layer)
+
+ elif mapLayer.type == '3d-raster':
+ if mapWin.IsLoaded(layer):
+ mapWin.UnloadRaster3d(layer)
+
+ mapWin.LoadRaster3d(layer)
+
+ elif mapLayer.type == 'vector':
+ if mapWin.IsLoaded(layer):
+ mapWin.UnloadVector(layer)
+
+ mapWin.LoadVector(layer)
+
+ # reset view when first layer loaded
+ nlayers = len(mapWin.Map.GetListOfLayers(l_type=('raster', 'vector'),
+ l_active=True))
+ if nlayers < 2:
+ mapWin.ResetView()
+
+ def ReorderLayers(self):
+ """!Add commands from data associated with
+ any valid layers (checked or not) to layer list in order to
+ match layers in layer tree."""
+
+ # make a list of visible layers
+ treelayers = []
+
+ vislayer = self.GetFirstVisibleItem()
+
+ if not vislayer or self.GetPyData(vislayer) is None:
+ return
+
+ itemList = ""
+
+ for item in range(self.GetCount()):
+ itemList += self.GetItemText(vislayer) + ','
+ if self.GetPyData(vislayer)[0]['type'] != 'group':
+ treelayers.append(self.GetPyData(vislayer)[0]['maplayer'])
+
+ if not self.GetNextVisible(vislayer):
+ break
+ else:
+ vislayer = self.GetNextVisible(vislayer)
+
+ Debug.msg (4, "LayerTree.ReorderLayers(): items=%s" % \
+ (itemList))
+
+ # reorder map layers
+ treelayers.reverse()
+ self.Map.ReorderLayers(treelayers)
+ self.reorder = False
+
+ def ChangeLayer(self, item):
+ """!Change layer"""
+ type = self.GetPyData(item)[0]['type']
+ layerName = None
+
+ if type == 'command':
+ win = self.FindWindowById(self.GetPyData(item)[0]['ctrl'])
+ if win.GetValue() != None:
+ cmd = win.GetValue().split(';')
+ cmdlist = []
+ for c in cmd:
+ cmdlist.append(c.split(' '))
+ opac = 1.0
+ chk = self.IsItemChecked(item)
+ hidden = not self.IsVisible(item)
+ elif type != 'group':
+ if self.GetPyData(item)[0] is not None:
+ cmdlist = self.GetPyData(item)[0]['cmd']
+ opac = self.GetPyData(item)[0]['maplayer'].GetOpacity(float=True)
+ chk = self.IsItemChecked(item)
+ hidden = not self.IsVisible(item)
+ # determine layer name
+ layerName = utils.GetLayerNameFromCmd(cmdlist, fullyQualified=True)
+ if not layerName:
+ 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.toolbars['vdigit']:
+ self.mapdisplay.toolbars['vdigit'].UpdateListOfLayers(updateTool=True)
+
+ # redraw map if auto-rendering is enabled
+ self.rerender = True
+ self.reorder = True
+ #if self.mapdisplay.statusbarWin['render'].GetValue():
+ # print "*** Change OnRender *****"
+ # self.mapdisplay.OnRender(None)
+
+ 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/gui_modules/layertree.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/location_wizard.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/location_wizard.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/location_wizard.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -22,7 +22,7 @@
- LocationWizard
- SelectTransformDialog
-COPYRIGHT: (C) 2007-2010 by the GRASS Development Team
+(C) 2007-2010 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@@ -33,7 +33,6 @@
"""
import os
import shutil
-import re
import string
import sys
import locale
@@ -126,9 +125,8 @@
self.Layout()
class DatabasePage(TitledPage):
+ """!Wizard page for setting GIS data directory and location name
"""
- 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"))
@@ -234,7 +232,7 @@
event.Skip()
class CoordinateSystemPage(TitledPage):
- """!
+ """
Wizard page for choosing method for location creation
"""
def __init__(self, wizard, parent):
@@ -345,7 +343,7 @@
self.parent.sumpage.SetPrev(self.parent.csystemspage)
class ProjectionsPage(TitledPage):
- """!
+ """
Wizard page for selecting projection (select coordinate system option)
"""
def __init__(self, wizard, parent):
@@ -484,9 +482,10 @@
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:
@@ -663,192 +662,184 @@
def __init__(self, wizard, parent):
TitledPage.__init__(self, wizard, _("Choose projection parameters"))
global coordsys
-
- self.utmzoneNum = 0
- self.hemischoices = ["north","south"]
+
self.parent = parent
self.panel = None
- self.prjparamsizer = ''
- self.pentry = {}
- self.pdesc = {}
- self.ptype = {}
- self.pval = {}
- self.proj4param = {}
- self.pcount = 0
- self.paramlist = []
+ self.prjParamSizer = None
+
+ self.pparam = dict()
+
self.p4projparams = ''
self.projdesc = ''
- self.paramSBox = None
- radioSBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
- label=" %s " % _("Select datum or ellipsoid (next page)"))
+ radioSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label = " %s " % _("Select datum or ellipsoid (next page)"))
radioSBSizer = wx.StaticBoxSizer(radioSBox)
- self.sizer.AddGrowableCol(1)
- self.sizer.Add(item = radioSBSizer, pos = (0, 1),
- flag=wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border=10)
+ 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)
+ label=_("Datum with associated ellipsoid"),
+ style = wx.RB_GROUP)
self.radio2 = wx.RadioButton(parent=self, id=wx.ID_ANY,
- label=_("Ellipsoid only"))
+ 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)
-
+ # 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(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"""
- num = 0
- if event.GetId() >= 2000:
- num = event.GetId() - 2000
- else:
- pass
-
+ id = event.GetId()
val = event.GetString()
- if self.ptype[num] == 'zone':
- try:
- intval = int(val)
- if intval < 1:
- self.pentry[num].SetValue('1')
- val = 1
- if intval > 60:
- self.pentry[num].SetValue('60')
- val = 60
- except:
- pass
+ if not self.pparam.has_key(id):
+ event.Skip()
+ return
- self.pval[num] = val
+ 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):
+
+ def OnPageChange(self,event=None):
"""!Go to next page"""
if event.GetDirection():
self.p4projparams = ''
- for num in range(self.pcount + 1):
- if self.ptype[num] == 'bool':
- if self.pval[num] == 'No':
+ for id, param in self.pparam.iteritems():
+ if param['type'] == 'bool':
+ if param['value'] == False:
continue
else:
- self.p4projparams += (' +' + self.proj4param[num])
+ self.p4projparams += (' +' + param['proj4'])
else:
- if self.pval[num] == '':
+ if param['value'] is None:
wx.MessageBox(parent = self,
- message = _('You must enter a value for %s') % self.pdesc[num],
- caption = _('Error'), style= wx.ICON_ERROR | wx.CENTRE)
+ message = _('You must enter a value for %s') % param['desc'],
+ caption = _('Error'), style = wx.ICON_ERROR | wx.CENTRE)
event.Veto()
else:
- self.pval[num] = str(self.pval[num])
- self.p4projparams += (' +' + self.proj4param[num] + '=' + self.pval[num])
+ self.p4projparams += (' +' + param['proj4'] + '=' + str(param['value']))
- def OnEnterPage(self, event):
+ def OnEnterPage(self,event):
"""!Page entered"""
self.projdesc = self.parent.projections[self.parent.projpage.proj][0]
- try:
- # page already formatted
- if self.pagesizer.GetItem(self.panel):
- self.paramSBox.SetLabel(_(" Enter parameters for %s projection ") % self.projdesc)
- except:
+ 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(self, wx.ID_ANY)
- self.prjparamsizer = wx.GridBagSizer(vgap=0, hgap=0)
-
+ paramSBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
+ label=_(" Enter parameters for %s projection ") % self.projdesc)
+ paramSBSizer = wx.StaticBoxSizer(paramSBox)
+
+ self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
self.panel.SetupScrolling()
- self.pagesizer.Add(paramSBSizer, proportion=1,
- flag=wx.EXPAND | wx.ALIGN_TOP | wx.ALL, border=10)
- paramSBSizer.Add(self.panel, proportion=1,
- flag=wx.ALIGN_CENTER|wx.EXPAND)
-
+ self.prjParamSizer = wx.GridBagSizer(vgap=0, hgap=0)
+
+ self.pagesizer.Add(item = paramSBSizer, proportion = 1,
+ flag = wx.EXPAND | wx.ALIGN_TOP | wx.ALL, border = 10)
+ paramSBSizer.Add(item = self.panel, proportion = 1,
+ flag = wx.ALIGN_CENTER | wx.EXPAND)
+
paramSBSizer.Fit(self.panel)
- self.panel.SetSizer(self.prjparamsizer)
+ self.panel.SetSizer(self.prjParamSizer)
if event.GetDirection():
- self.pcount = 0
- self.prjparamsizer.Clear(True)
- num = 0
-
+ self.prjParamSizer.Clear(True)
+
+ self.pparam = dict()
+ row = 0
for paramgrp in self.parent.projections[self.parent.projpage.proj][1]:
# get parameters
- self.pcount = num
- self.ptype[num] = self.parent.paramdesc[paramgrp[0]][0]
- self.proj4param[num] = self.parent.paramdesc[paramgrp[0]][1]
- self.pdesc[num] = self.parent.paramdesc[paramgrp[0]][2]
-
+ 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 self.ptype[num] == 'bool':
- self.pval[num] = 'No'
- elif self.ptype[num] == 'zone':
- self.pdesc[num] += ' (1-60)'
- self.pval[num] = ''
+ if param['type'] == 'bool':
+ param['value'] = 0
+ elif param['type'] == 'zone':
+ param['value'] = 30
+ param['desc'] += ' (1-60)'
else:
- self.pval[num] = paramgrp[2]
+ param['value'] = paramgrp[2]
- label = wx.StaticText(self.panel, id=1000+num, label=self.pdesc[num],
- style=wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE)
- if self.ptype[num] == 'bool':
- self.pentry[num] = wx.Choice(self.panel, id=2000+num, size=(100,-1),
- choices = ['No','Yes'])
- self.pentry[num].SetStringSelection(self.pval[num])
- self.Bind(wx.EVT_CHOICE, self.OnParamEntry)
+ 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:
- self.pentry[num] = wx.TextCtrl(self.panel, id=2000+num,
- value=self.pval[num],
- size=(100, -1))
- self.Bind(wx.EVT_TEXT, self.OnParamEntry)
+ 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':
- self.pentry[num].SetEditable(False)
- self.pentry[num].SetBackgroundColour(wx.LIGHT_GREY)
- self.pval[num] = paramgrp[2]
-
- self.prjparamsizer.Add(item=label, pos=(num, 1),
- flag=wx.ALIGN_RIGHT |
+ 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=self.pentry[num], pos=(num, 2),
- flag=wx.ALIGN_LEFT |
+ wx.RIGHT, border = 5)
+ self.prjParamSizer.Add(item = win, pos = (row, 2),
+ flag = wx.ALIGN_LEFT |
wx.ALIGN_CENTER_VERTICAL |
- wx.LEFT, border=5)
- num += 1
-
+ 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)
@@ -926,7 +917,8 @@
if self.datum not in self.parent.datums:
event.Veto()
else:
- # check for datum tranforms
+ # check for datum tranforms
+# proj4string = self.parent.CreateProj4String() + ' +datum=%s' % self.datum
ret = gcmd.RunCommand('g.proj',
read = True,
proj4 = '%s +datum=%s' % (proj, self.datum),
@@ -1380,8 +1372,9 @@
# check for datum transforms
ret = gcmd.RunCommand('g.proj',
read = True,
- epsg = '%s' % self.epsgcode,
+ epsg = self.epsgcode,
datumtrans = '-1')
+
if ret != '':
dtrans = ''
# open a dialog to select datum transform number
@@ -1473,53 +1466,20 @@
def OnBrowseCodes(self, event, search=None):
"""!Browse EPSG codes"""
- if True:
- data = []
- self.epsgCodeDict = {}
- try:
- f = open(self.tfile.GetValue(), "r")
- except IOError:
- wx.MessageBox(parent=self,
- message=_("Unable to read EPGS file: '%s'") % self.tfile.GetValue(),
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
- self.epsglist.Populate([], update=True)
- return
-
- 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:
- code = None
-
- if code is not None:
- data.append((code, descr, params))
- self.epsgCodeDict[code] = (descr, params)
- code = None
- i += 1
- f.close()
-
- if type(self.epsgCodeDict) == type(''):
+ 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([], update=True)
+ self.epsglist.Populate(list(), update=True)
return
-
- data = []
+
+ 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):
@@ -1566,30 +1526,39 @@
def OnPageChanging(self, event):
if event.GetDirection() and not self.customstring:
event.Veto()
- else:
- # check for datum tranforms
- ret = gcmd.RunCommand('g.proj',
- read = True,
- proj4 = '%s' % self.customstring,
- datumtrans = '-1')
- if ret != '':
+ elif not event.GetDirection() and not self.customstring:
+ return
+ else: # check for datum tranforms
+ ret, out, err = gcmd.RunCommand('g.proj',
+ read = True, getErrorMsg = True,
+ proj4 = self.customstring,
+ datumtrans = '-1')
+ if ret != 0:
+ wx.MessageBox(parent = self,
+ message = err,
+ caption = _("Error"),
+ style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ event.Veto()
+ return
+
+ if out:
dtrans = ''
# open a dialog to select datum transform number
dlg = SelectTransformDialog(self.parent.parent, transforms=out)
if dlg.ShowModal() == wx.ID_OK:
dtrans = dlg.GetTransform()
- if dtrans == '':
+ if len(dtrans) == 0:
dlg.Destroy()
event.Veto()
- return 'Datum transform is required.'
+ return _('Datum transform is required.')
else:
dlg.Destroy()
event.Veto()
- return 'Datum transform is required.'
+ return _('Datum transform is required.')
self.parent.datumtrans = dtrans
-
+
self.GetNext().SetPrev(self)
def GetProjstring(self, event):
@@ -1605,15 +1574,13 @@
nextButton.Enable()
class SummaryPage(TitledPage):
- """
- Shows summary result of choosing coordinate system parameters
+ """!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
-
+
# labels
self.ldatabase = self.MakeLabel("")
self.llocation = self.MakeLabel("")
@@ -1621,11 +1588,8 @@
self.lproj4string = self.MakeLabel("")
self.lproj4stringLabel = self.MakeLabel("")
- self.lprojection.Wrap(400)
-
self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnEnterPage)
- # self.Bind(wx.EVT_BUTTON, self.OnFinish, wx.ID_FINISH)
-
+
# do sub-page layout
self.__DoLayout()
@@ -1661,10 +1625,9 @@
border=5, pos=(5, 0), span=(1, 2))
def OnEnterPage(self,event):
+ """!Insert values into text controls for summary of location
+ creation options
"""
- 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()
@@ -1681,61 +1644,54 @@
self.lproj4string.Show()
self.lproj4stringLabel.SetLabel(_("PROJ.4 definition:"))
if coordsys == 'proj':
- p = gcmd.Command(['g.proj', '-j',
- 'proj4=%s' % proj4string,
- 'datumtrans=%s' % dtrans,
- 'location=%s' % location])
-
+ ret, projlabel, err = gcmd.RunCommand('g.proj',
+ flags = 'jf',
+ proj4 = proj4string,
+ datumtrans = dtrans,
+ location = location,
+ getErrorMsg = True,
+ read = True)
elif coordsys == 'epsg':
- p = gcmd.Command(['g.proj', '-j',
- 'epsg=%s' % epsgcode,
- 'datumtrans=%s' % dtrans,
- 'location=%s' % location])
-
- if p.returncode == 0:
- projlabel = ''
- msg = p.ReadStdOutput()
- for line in msg:
- projlabel = projlabel + '%s ' % line
- self.lproj4string.SetLabel(projlabel)
- else:
- err = p.ReadErrOutput()
- wx.MessageBox(err, 'Error', wx.ICON_ERROR)
-
- self.lproj4string.Wrap(400)
+ ret, projlabel, err = gcmd.RunCommand('g.proj',
+ flags = 'jf',
+ epsg = epsgcode,
+ datumtrans = dtrans,
+ location = location,
+ getErrorMsg = True,
+ read = True)
+ if ret == 0:
+ self.lproj4string.SetLabel(projlabel.replace(' ', os.linesep))
+ else:
+ gcmd.GError(err, parent = self)
+
projdesc = self.parent.projpage.projdesc
ellipsedesc = self.parent.ellipsepage.ellipsedesc
datumdesc = self.parent.datumpage.datumdesc
self.ldatabase.SetLabel(database)
self.llocation.SetLabel(location)
- label = ''
+ label = ''
if coordsys == 'epsg':
label = 'EPSG code %s (%s)' % (self.parent.epsgpage.epsgcode, self.parent.epsgpage.epsgdesc)
- self.lprojection.SetLabel(label)
elif coordsys == 'file':
label = 'matches file %s' % self.parent.filepage.georeffile
- self.lprojection.SetLabel(label)
elif coordsys == 'wkt':
label = 'matches file %s' % self.parent.wktpage.wktfile
- self.lprojection.SetLabel(label)
elif coordsys == 'proj':
label = ('%s, %s %s' % (projdesc, datumdesc, ellipsedesc))
- self.lprojection.SetLabel(label)
elif coordsys == 'xy':
label = ('XY coordinate system (not projected).')
- self.lprojection.SetLabel(label)
elif coordsys == 'custom':
- label = ('%s' % self.parent.custompage.customstring)
- self.lprojection.SetLabel(label)
-
+ label = ('%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()
@@ -1744,15 +1700,14 @@
event.Skip()
class LocationWizard(wx.Object):
- """!
- Start wizard here and finish wizard here
+ """!Start wizard here and finish wizard here
"""
def __init__(self, parent, grassdatabase):
self.__cleanUp()
global coordsys
self.parent = parent
-
+
#
# define wizard image
#
@@ -1770,7 +1725,7 @@
#
self.datumtrans = 0
self.proj4string = ''
-
+
#
# define wizard pages
#
@@ -1822,7 +1777,7 @@
self.custompage.SetNext(self.sumpage)
self.sumpage.SetPrev(self.csystemspage)
-
+
#
# do pages layout
#
@@ -1838,7 +1793,9 @@
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
@@ -1899,13 +1856,13 @@
global wizerror
global translist
- coordsys = ''
- north = ''
- south = ''
- east = ''
- west = ''
- resolution = ''
- transformlist = []
+ 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"""
@@ -2120,7 +2077,8 @@
proj4string = '%s %s' % (proj4string, item)
# set datum and transform parameters if relevant
- if datum != '': proj4string = '%s +datum=%s' % (proj4string, datum)
+ if datum != '':
+ proj4string = '%s +datum=%s' % (proj4string, datum)
if datumparams:
for item in datumparams:
proj4string = '%s +%s' % (proj4string,item)
@@ -2134,16 +2092,17 @@
@return error message (empty string on success)
"""
- p = gcmd.Command(['g.proj', '-c',
- 'proj4=%s' % proj4string,
- 'location=%s' % self.startpage.location,
- 'datumtrans=%s' % self.datumtrans])
-
- if p.returncode == 0:
+ ret, msg = gcmd.RunCommand('g.proj',
+ flags = 'c',
+ proj4 = proj4string,
+ location = self.startpage.location,
+ datumtrans = self.datumtrans,
+ getErrorMsg = True)
+
+ if ret == 0:
return ''
- err = p.ReadErrOutput()
- return err
+ return msg
def CustomCreate(self):
@@ -2153,18 +2112,18 @@
"""
proj4string = self.custompage.customstring
location = self.startpage.location
-
- p = gcmd.Command(['g.proj', '-c',
- 'proj4=%s' % proj4string,
- 'location=%s' % self.startpage.location,
- 'datumtrans=%s' % self.datumtrans])
-
- if p.returncode == 0:
+
+ ret, msg = gcmd.RunCommand('g.proj',
+ flags = 'c',
+ proj4 = proj4string,
+ location = location,
+ getErrorMsg = True)
+
+ if ret == 0:
return ''
+
+ return msg
- err = p.ReadErrOutput()
- return err
-
def EPSGCreate(self):
"""!Create a new location from an EPSG code.
@@ -2178,17 +2137,18 @@
if epsgcode == '':
return _('EPSG code missing.')
- p = gcmd.Command(['g.proj', '-c',
- 'epsg=%s' % epsgcode,
- 'location=%s' % self.startpage.location,
- 'datumtrans=%s' % self.datumtrans])
+ ret, msg = gcmd.RunCommand('g.proj',
+ flags = 'c',
+ epsg = epsgcode,
+ location = location,
+ datumtrans = self.datumtrans,
+ getErrorMsg = True)
- if p.returncode == 0:
+ if ret == 0:
return ''
-
- err = p.ReadErrOutput()
- return err
-
+
+ return msg
+
def FileCreate(self):
"""!Create a new location from a georeferenced file
@@ -2202,16 +2162,17 @@
return _("File not found.")
# creating location
- p = gcmd.Command(['g.proj', '-c',
- 'georef=%s' % georeffile,
- 'location=%s' % self.startpage.location])
-
- if p.returncode == 0:
+ ret, msg = gcmd.RunCommand('g.proj',
+ flags = 'c',
+ georef = georeffile,
+ location = location,
+ getErrorMsg = True)
+
+ if ret == 0:
return ''
+
+ return msg
- err = p.ReadErrOutput()
- return err
-
def WKTCreate(self):
"""!Create a new location from a WKT file
@@ -2224,17 +2185,16 @@
if not wktfile or not os.path.isfile(wktfile):
return _("File not found.")
- # creating location
- p = gcmd.Command(['g.proj', '-c',
- 'wkt=%s' % wktfile,
- 'location=%s' % self.startpage.location])
-
- out = p.ReadStdOutput()
- msg = p.ReadErrOutput()
+ # creating location
+ ret, msg = gcmd.RunCommand('g.proj',
+ flags = 'c',
+ wkt = wktfile,
+ location = location,
+ getErrorMsg = True)
- if p.returncode == 0:
+ if ret == 0:
return ''
-
+
return msg
class RegionDef(BaseClass, wx.Frame):
@@ -2663,23 +2623,11 @@
def __UpdateInfo(self):
"""!Update number of rows/cols/cells"""
- try:
- self.rows = abs(int((self.north - self.south) / self.nsres))
- except:
- self.rows = 0
-
- try:
- self.cols = abs(int((self.east - self.west) / self.ewres))
- except:
- self.rows = 0
-
+ self.rows = int((self.north - self.south) / self.nsres)
+ self.cols = int((self.east - self.west) / self.ewres)
self.cells = self.rows * self.cols
- try:
- self.depth = abs(int((self.top - self.bottom) / self.tbres))
- except:
- self.depth = 0
-
+ self.depth = int((self.top - self.bottom) / self.tbres)
self.cells3 = self.rows * self.cols * self.depth
# 2D
@@ -2692,26 +2640,20 @@
def OnSetButton(self, event=None):
"""!Set default region"""
+ ret = gcmd.RunCommand('g.region',
+ flags = 'sgpa',
+ n = self.north,
+ s = self.south,
+ e = self.east,
+ w = self.west,
+ nsres = self.nsres,
+ ewres = self.ewres,
+ t = self.top,
+ b = self.bottom,
+ tbres = self.tbres)
+ if ret == 0:
+ self.Destroy()
- if self.cells <= 0 or self.cells3 <= 0:
- dlg = wx.MessageBox(message = _("Resolution cannot be 0"),
- caption = _("Extents set incorrectly"),
- style = wx.OK)
- else:
- ret = gcmd.RunCommand('g.region',
- flags = 'sgpa',
- n = self.north,
- s = self.south,
- e = self.east,
- w = self.west,
- nsres = self.nsres,
- ewres = self.ewres,
- t = self.top,
- b = self.bottom,
- tbres = self.tbres)
- if ret == 0:
- self.Destroy()
-
def OnCancel(self, event):
self.Destroy()
Modified: grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp.py 2010-10-14 15:24:19 UTC (rev 43910)
+++ grass/branches/releasebranch_6_4/gui/wxpython/gui_modules/mapdisp.py 2010-10-14 15:39:14 UTC (rev 43911)
@@ -1,23 +1,20 @@
-"""
+"""!
@package mapdisp.py
@brief GIS map display canvas, with toolbar for various display
-management functions, and second toolbar for vector
-digitizing.
+management functions, and additional toolbars (vector digitizer, 3d
+view).
-Can be used either from GIS Manager or as p.mon backend.
+Can be used either from Layer Manager or as p.mon backend.
Classes:
- - Command
- - MapWindow
- - BufferedWindow
- - MapFrame
- - MapApp
+- MapFrame
+- MapApp
Usage:
- python mapdisp.py monitor-identifier /path/to/command/file
+python mapdisp.py monitor-identifier /path/to/command/file
-(C) 2006-2008 by the GRASS Development Team
+(C) 2006-2010 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
@@ -29,7 +26,6 @@
import os
import sys
-import time
import glob
import math
import tempfile
@@ -41,7 +37,6 @@
import wx
import wx.aui
-from threading import Thread
try:
import subprocess
except:
@@ -52,28 +47,30 @@
gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
sys.path.append(gmpath)
+grassPath = os.path.join(globalvar.ETCDIR, "python")
+sys.path.append(grassPath)
+
import render
import toolbars
-import track
import menuform
import gselect
import disp_print
import gcmd
import dbm
+import dbm_dialogs
import histogram
import profile
import globalvar
import utils
import gdialogs
from grass.script import core as grass
-from vdigit import VDigitCategoryDialog as VDigitCategoryDialog
-from vdigit import VDigitZBulkDialog as VDigitZBulkDialog
-from vdigit import VDigitDuplicatesDialog as VDigitDuplicatesDialog
-from vdigit import GV_LINES as VDigit_Lines_Type
-from debug import Debug as Debug
-from icon import Icons as Icons
+from debug import Debug
+from icon import Icons
from preferences import globalSettings as UserSettings
+from mapdisp_command import Command
+from mapdisp_window import BufferedWindow
+
import images
imagepath = images.__path__[0]
sys.path.append(imagepath)
@@ -84,2545 +81,38 @@
# for standalone app
cmdfilename = None
-class Command(Thread):
- """
- Creates thread which will observe the command file and see, if
- there is new command to be executed
- """
- def __init__ (self, parent, Map):
- Thread.__init__(self)
-
- global cmdfilename
-
- self.parent = parent
- self.map = Map
- self.cmdfile = open(cmdfilename, "r")
-
- def run(self):
- """
- Run this in thread
- """
- dispcmd = []
- while 1:
- self.parent.redraw = False
- line = self.cmdfile.readline().strip()
- if line == "quit":
- break
-
- if line:
- try:
- Debug.msg (3, "Command.run(): cmd=%s" % (line))
-
- self.map.AddLayer(item=None, type="raster",
- name='',
- command=line,
- l_opacity=1)
-
- self.parent.redraw =True
-
- except Exception, e:
- print "Command Thread: ",e
-
- time.sleep(0.1)
-
- sys.exit()
-
-class MapWindow(object):
- """
- Abstract map window class
-
- Parent for BufferedWindow class (2D display mode) and
- GLWindow (3D display mode)
- """
- def __init__(self, parent, id=wx.ID_ANY,
- pos=wx.DefaultPosition,
- size=wx.DefaultSize,
- style=wx.NO_FULL_REPAINT_ON_RESIZE,
- Map=None, tree=None, gismgr=None):
- self.parent = parent # MapFrame
-
- #
- # mouse attributes like currently pressed buttons, position on
- # the screen, begin and end of dragging, and type of drawing
- #
- self.mouse = {
- 'l' : False,
- 'r' : False,
- 'm' : False,
- 'begin': [0, 0], # screen coordinates
- 'end' : [0, 0],
- 'use' : "pointer",
- 'box' : "point"
- }
-
- def EraseMap(self):
- """
- Erase the canvas (virtual method)
- """
- pass
-
- def UpdateMap(self):
- """
- Updates the canvas anytime there is a change to the
- underlaying images or to the geometry of the canvas.
- """
- pass
-
- def OnLeftDown(self, event):
- pass
-
- def OnLeftUp(self, event):
- pass
-
- def OnMouseMotion(self, event):
- pass
-
- def OnZoomToMap(self, event):
- pass
-
- def OnZoomToRaster(self, event):
- pass
-
- def GetSelectedLayer(self, type = 'layer', multi = False):
- """
- Get selected layer from layer tree
-
- @param type 'item' / 'layer' / 'nviz'
- @param multi return first selected layer or all
-
- @return layer / map layer properties / nviz properties
- @return None / [] on failure
- """
- ret = []
- if not self.tree or \
- not self.tree.GetSelection():
- if multi:
- return []
- else:
- return None
-
- if multi and \
- type == 'item':
- return self.tree.GetSelections()
-
- for item in self.tree.GetSelections():
- if not item.IsChecked():
- if multi:
- continue
- else:
- return None
-
- if type == 'item': # -> multi = False
- return item
-
- try:
- if type == 'nviz':
- layer = self.tree.GetPyData(item)[0]['nviz']
- else:
- layer = self.tree.GetPyData(item)[0]['maplayer']
- except:
- layer = None
-
- if multi:
- ret.append(layer)
- else:
- return layer
-
- return ret
-
-class BufferedWindow(MapWindow, wx.Window):
- """
- A Buffered window class.
-
- 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(self,file_name,file_type) method.
- """
-
- def __init__(self, parent, id,
- pos = wx.DefaultPosition,
- size = wx.DefaultSize,
- style=wx.NO_FULL_REPAINT_ON_RESIZE,
- Map=None, tree=None, gismgr=None):
-
- MapWindow.__init__(self, parent, id, pos, size, style,
- Map, tree, gismgr)
- wx.Window.__init__(self, parent, id, pos, size, style)
-
- self.Map = Map
- self.tree = tree
- self.gismanager = gismgr
-
- #
- # Flags
- #
- self.resize = False # indicates whether or not a resize event has taken place
- self.dragimg = None # initialize variable for map panning
-
- #
- # Variable 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.Bind(wx.EVT_MOTION, self.MouseActions)
- self.Bind(wx.EVT_MOUSE_EVENTS, self.MouseActions)
- self.processMouse = True
-
- #
- # Render output objects
- #
- self.mapfile = None # image file to be rendered
- self.img = "" # wx.Image object (self.mapfile)
- # used in digitization tool (do not redraw vector map)
- self.imgVectorMap = None
- # 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)
-
- # 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()
- # 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 = ''
-
- self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None)
-
- # vars for handling mouse clicks
- self.dragid = -1
- self.lastpos = (0, 0)
-
- 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)
- ### pdc.Clear()
-
- 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, (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)
- # self.ovlcoords[drawid] = coords
-
- 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.DrawLine(coords[0], coords[1], coords[2], coords[3])
- pdc.SetIdBounds(drawid,(coords[0], coords[1], coords[2], coords[3]))
- # self.ovlcoords[drawid] = coords
-
- 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)
- pdc.DrawLines(coords)
-
- # 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,(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, coordsBound)
- # self.ovlcoords[drawid] = coords
-
- elif pdctype == 'text': # draw text on top of map
- if not img['active']:
- return #only draw active text
- if img.has_key('rotation'):
- 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, w, h = 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, (coords[0], coords[1], w, h))
-
- pdc.EndDrawing()
-
- self.Refresh()
-
- return drawid
-
- def TextBounds(self, textinfo):
- """
- Return text boundary data
-
- @param textinfo text metadata (text, font, color, rotation)
- @param coords reference point
- """
- if textinfo.has_key('rotation'):
- rotation = float(textinfo['rotation'])
- else:
- rotation = 0.0
-
- coords = textinfo['coords']
-
- Debug.msg (4, "BufferedWindow.TextBounds(): text=%s, rotation=%f" % \
- (textinfo['text'], rotation))
-
- self.Update()
- ### self.Refresh()
-
- self.SetFont(textinfo['font'])
-
- w, h = self.GetTextExtent(textinfo['text'])
-
- if rotation == 0:
- coords[2], coords[3] = coords[0] + w, coords[1] + h
- return coords, w, h
-
- boxh = math.fabs(math.sin(math.radians(rotation)) * w) + h
- boxw = math.fabs(math.cos(math.radians(rotation)) * w) + h
- coords[2] = coords[0] + boxw
- coords[3] = coords[1] + boxh
-
- return coords, boxw, boxh
-
- def OnPaint(self, event):
- """
- Draw PseudoDC's to buffered paint DC
-
- self.pdc for background and decorations
- self.pdcVector for vector map which is edited
- self.pdcTmp for temporaly drawn objects (self.polycoords)
-
- 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.SetBackground(wx.Brush("White"))
- 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 self.pdcVector:
- # 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 self.pdcVector:
- # 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))
-
- pdcLast = wx.PseudoDC()
- pdcLast.DrawBitmap(bmp=self.bufferLast, x=0, y=0)
- pdcLast.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):
- """
- This draws the psuedo DC to a buffer that
- can be saved to a file.
- """
- dc = wx.BufferedPaintDC(self, self.buffer)
- self.pdc.DrawToDC(dc)
- if self.pdcVector:
- self.pdcVector.DrawToDC(dc)
- self.buffer.SaveFile(FileName, FileType)
-
- 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 len(self.Map.GetListOfLayers()) == 0:
- # return False
-
- if self.img is None:
- render = True
-
- #
- # initialize process bar (only on 'render')
- #
- if render is True or renderVector is True:
- self.parent.onRenderGauge.Show()
- if self.parent.onRenderGauge.GetRange() > 0:
- self.parent.onRenderGauge.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 == True:
- self.tree.ReorderLayers()
-
- # reset flag for auto-rendering
- if self.tree:
- self.tree.rerender = False
-
- if render:
- # update display size
- self.Map.ChangeMapSize(self.GetClientSize())
- if self.parent.compResolution.IsChecked():
- # 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)
-
- 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
- #
- digitToolbar = self.parent.toolbars['vdigit']
- if renderVector and digitToolbar and \
- digitToolbar.GetLayer():
- # set region
- self.parent.digit.driver.UpdateRegion()
- # re-calculate threshold for digitization tool
- self.parent.digit.driver.GetThreshold()
- # draw map
- self.pdcVector.Clear()
- self.pdcVector.RemoveAll()
- try:
- item = self.tree.FindItemByData('maplayer', digitToolbar.GetLayer())
- except TypeError:
- item = None
-
- if item and self.tree.IsItemChecked(item):
- self.parent.digit.driver.DrawMap()
-
- # translate tmp objects (pointer position)
- if digitToolbar.GetAction() == 'moveLine':
- if hasattr(self, "vdigitMove") and \
- self.vdigitMove.has_key('beginDiff'):
- # move line
- for id in self.vdigitMove['id']:
- # print self.pdcTmp.GetIdBounds(id)
- self.pdcTmp.TranslateId(id,
- self.vdigitMove['beginDiff'][0],
- self.vdigitMove['beginDiff'][1])
- del self.vdigitMove['beginDiff']
-
- #
- # 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 self.parent.gismanager.gcpmanagement:
- # -> GCP Manager (redraw GCPs)
- if self.parent.toolbars['gcpdisp']:
- if self == self.parent.TgtMapWindow:
- coordtype = 'target'
- else:
- coordtype = 'source'
- self.parent.gismanager.gcpmanagement.DrawGCP(coordtype)
-
- if self.parent.gismanager.georectifying:
- # -> georectifier (redraw GCPs)
- if self.parent.toolbars['georect']:
- coordtype = 'gcpcoord'
- else:
- coordtype = 'mapcoord'
- self.parent.gismanager.georectifying.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.onRenderGauge.Hide()
-
- #
- # update statusbar
- #
- ### self.Map.SetRegion()
- self.parent.StatusbarUpdate()
- if grass.find_file(name = 'MASK', element = 'cell')['name']:
- # mask found
- self.parent.maskInfo.SetLabel(_('MASK'))
- else:
- self.parent.maskInfo.SetLabel('')
-
- Debug.msg (2, "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 the canvas
- """
- self.Draw(self.pdc, pdctype='clear')
-
- if self.pdcVector:
- 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.
- """
-
- 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()
-
- return True
-
- 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 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 id > 100: # text
- self.textdict[id]['coords'] = r2
- 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'].
-
- """
-# self.redrawAll = False
-
- 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)
- r.Inflate(4,4)
- pdc.ClearId(boxid)
- self.RefreshRect(r, False)
- pdc.SetId(boxid)
- self.Draw(pdc, drawid=boxid, pdctype='box', coords=mousecoords)
- elif self.mouse['box'] == "line" or self.mouse['box'] == 'point':
- 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
-
- ### if self.redrawAll is False:
- ### self.redrawAll = True
-
- # 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)
-
- # 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)
-
-# event.Skip()
-
- def OnMouseWheel(self, event):
- """
- Mouse wheel moved
- """
- self.processMouse = False
- current = event.GetPositionTuple()[:]
- wheel = event.GetWheelRotation()
- Debug.msg (5, "BufferedWindow.MouseAction(): wheel=%d" % wheel)
- # zoom 1/2 of the screen, centered to current mouse position (TODO: settings)
- begin = (current[0] - self.Map.width / 4,
- current[1] - self.Map.height / 4)
- end = (current[0] + self.Map.width / 4,
- current[1] + self.Map.height / 4)
-
- if wheel > 0:
- zoomtype = 1
- else:
- zoomtype = -1
-
- # zoom
- self.Zoom(begin, end, zoomtype)
-
- # redraw map
- self.UpdateMap()
-
- ### self.OnPaint(None)
-
- # update statusbar
- self.parent.StatusbarUpdate()
-
- self.Refresh()
- self.processMouse = True
-# event.Skip()
-
- def OnDragging(self, event):
- """
- Mouse dragging with left button down
- """
- Debug.msg (5, "BufferedWindow.MouseAction(): Dragging")
- current = event.GetPositionTuple()[:]
- previous = self.mouse['begin']
- move = (current[0] - previous[0],
- current[1] - previous[1])
-
- digitToolbar = self.parent.toolbars['vdigit']
-
- # dragging or drawing box with left button
- if self.mouse['use'] == 'pan':
- 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()[:]
- digitClass = self.parent.digit
- if (event.LeftIsDown() and
- not (digitToolbar and
- digitToolbar.GetAction() in ("moveLine",) and
- digitClass.driver.GetSelected() > 0)):
- # draw box only when left mouse button is pressed
- self.MouseDraw(pdc=self.pdcTmp)
-
-# event.Skip()
-
- 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'] == 'zoom':
- pass
- elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
- # digitization
- digitToolbar = self.parent.toolbars['vdigit']
- digitClass = self.parent.digit
- east, north = self.Pixel2Cell(self.mouse['begin'])
-
- try:
- map = digitToolbar.GetLayer().GetName()
- except:
- map = None
- wx.MessageBox(parent=self,
- message=_("No vector map selected for editing."),
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
- event.Skip()
- return
-
- # calculate position of 'update record' dialog
- position = self.mouse['begin']
- posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
- position[1] + self.dialogOffset))
-
- if digitToolbar.GetAction() 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 digitToolbar.GetAction() in ("addVertex", "removeVertex"):
- # unselect
- digitClass.driver.SetSelected([])
-
- if digitToolbar.GetAction() == "addLine":
- if digitToolbar.GetAction('type') in ["point", "centroid"]:
- # add new point
- if digitToolbar.GetAction('type') == 'point':
- point = True
- else:
- point = False
-
- fid = digitClass.AddPoint(map, point, east, north)
- if fid < 0:
- return
-
- self.UpdateMap(render=False) # redraw map
-
- # add new record into atribute table
- if UserSettings.Get(group='vdigit', key="addRecord", subkey='enabled') is True:
- # select attributes based on layer and category
- cats = { fid : {
- UserSettings.Get(group='vdigit', key="layer", subkey='value') :
- (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
- }}
- addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
- cats=cats,
- pos=posWindow,
- action="add")
- 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()
- executeCommand = gcmd.Command(cmd=["db.execute",
- "--q",
- "input=%s" % sqlfile.name])
-
- elif digitToolbar.GetAction('type') in ["line", "boundary"]:
- # add new point to the line
- self.polycoords.append(self.Pixel2Cell(event.GetPositionTuple()[:]))
- self.DrawLines(pdc=self.pdcTmp)
-
- elif digitToolbar.GetAction() == "editLine" and hasattr(self, "vdigitMove"):
- self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
- self.vdigitMove['id'].append(wx.NewId())
- self.DrawLines(pdc=self.pdcTmp)
-
- elif digitToolbar.GetAction() == "deleteLine":
- pass
-
- elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
- not hasattr(self, "vdigitMove"):
- self.vdigitMove = {}
- # geographic coordinates of initial position (left-down)
- self.vdigitMove['begin'] = None
- # list of ids to modify
- self.vdigitMove['id'] = []
- # ids geographic coordinates
- self.vdigitMove['coord'] = {}
-
- if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
- # set pen
- 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)
-
- elif digitToolbar.GetAction() == "splitLine":
- # unselect
- digitClass.driver.SetSelected([])
-
- elif digitToolbar.GetAction() in ["displayAttrs", "displayCats"]:
- qdist = digitClass.driver.GetThreshold(type='selectThresh')
- coords = (east, north)
- if digitClass.type == 'vdigit':
- # unselect
- digitClass.driver.SetSelected([])
-
- # select feature by point
- cats = {}
- if digitClass.driver.SelectLineByPoint(coords,
- digitClass.GetSelectType()) is not None:
- if UserSettings.Get(group='vdigit', key='checkForDupl',
- subkey='enabled'):
- lines = digitClass.driver.GetSelected()
- else:
- lines = (digitClass.driver.GetSelected()[0],) # only first found
-
- for line in lines:
- cats[line] = digitClass.GetLineCats(line)
-
- if digitToolbar.GetAction() == "displayAttrs":
- # select attributes based on coordinates (all layers)
- if self.parent.dialogs['attributes'] is None:
- if digitClass.type == 'vedit':
- self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
- query=(coords, qdist),
- pos=posWindow,
- action="update")
- else:
- self.parent.dialogs['attributes'] = dbm.DisplayAttributesDialog(parent=self, map=map,
- cats=cats,
- action="update")
- else:
- # update currently open dialog
- if digitClass.type == 'vedit':
- self.parent.dialogs['attributes'].UpdateDialog(query=(coords, qdist))
- else:
- # upgrade dialog
- self.parent.dialogs['attributes'].UpdateDialog(cats=cats)
-
- if self.parent.dialogs['attributes']:
- 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
- if digitClass.type == 'vedit':
- dlg = VDigitCategoryDialog(parent=self,
- map=map,
- query=(coords, qdist),
- pos=posWindow,
- title=_("Update categories"))
- self.parent.dialogs['category'] = dlg
- else:
- dlg = VDigitCategoryDialog(parent=self,
- map=map,
- cats=cats,
- pos=posWindow,
- title=_("Update categories"))
- self.parent.dialogs['category'] = dlg
- else:
- # update currently open dialog
- if digitClass.type == 'vedit':
- self.parent.dialogs['category'].UpdateDialog(query=(coords, qdist))
- else:
- # upgrade dialog
- self.parent.dialogs['category'].UpdateDialog(cats=cats)
-
- if self.parent.dialogs['category']:
- if len(cats.keys()) > 0:
- # highlight feature & re-draw map
- ### digitClass.driver.SetSelected(line)
- 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)
-
- elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
- if not hasattr(self, "copyCatsList"):
- self.copyCatsList = []
- else:
- self.copyCatsIds = []
- self.mouse['box'] = 'box'
-
- elif digitToolbar.GetAction() == "copyLine":
- self.copyIds = []
- self.layerTmp = None
-
- elif digitToolbar.GetAction() == "zbulkLine":
- 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])
- elif self.mouse['use'] == 'pointer':
- # get decoration or text id
- self.idlist = []
- self.dragid = ''
- self.lastpos = self.mouse['begin']
- idlist = self.pdc.FindObjects(x=self.lastpos[0], y=self.lastpos[1],
- radius=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
- self.parent.QueryMap(self.mouse['begin'][0],self.mouse['begin'][1])
-
- 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.gismanager.gcpmanagement:
- # -> GCP Manager
- coord = self.Pixel2Cell(self.mouse['end'])
- if self.parent.toolbars['gcpdisp']:
- if self.parent.MapWindow == self.parent.SrcMapWindow:
- coordtype = 'source'
- else:
- coordtype = 'target'
-
- self.parent.gismanager.gcpmanagement.SetGCPData(coordtype, coord, self, confirm=True)
- self.UpdateMap(render = False, renderVector = False)
-
- elif self.mouse["use"] == "pointer" and self.parent.gismanager.georectifying:
- # -> georectifying
- coord = self.Pixel2Cell(self.mouse['end'])
- if self.parent.toolbars['georect']:
- coordtype = 'gcpcoord'
- else:
- coordtype = 'mapcoord'
-
- self.parent.gismanager.georectifying.SetGCPData(coordtype, coord, self)
- self.UpdateMap(render=False, renderVector=False)
-
- elif self.mouse["use"] == "pointer" and self.parent.toolbars['vdigit']:
- # digitization tool active
- digitToolbar = self.parent.toolbars['vdigit']
- digitClass = self.parent.digit
-
- pos1 = self.Pixel2Cell(self.mouse['begin'])
- pos2 = self.Pixel2Cell(self.mouse['end'])
-
- if hasattr(self, "vdigitMove"):
- if len(digitClass.driver.GetSelected()) == 0:
- self.vdigitMove['begin'] = pos1 # left down
- ### else:
- ### dx = pos2[0] - pos1[0] ### ???
- ### dy = pos2[1] - pos1[1]
- ### self.vdigitMove = (self.vdigitMove['begin'][0] + dx,
- ### self.vdigitMove['begin'][1] + dy)
-
- # eliminate initial mouse moving efect
- self.mouse['begin'] = self.mouse['end']
-
- if digitToolbar.GetAction() in ["deleteLine", "moveLine", "moveVertex",
- "copyCats", "copyAttrs", "editLine", "flipLine",
- "mergeLine", "snapLine",
- "queryLine", "breakLine", "typeConv", "connectLine"]:
- nselected = 0
- # -> delete line || move line || move vertex
- if digitToolbar.GetAction() in ["moveVertex", "editLine"]:
- if len(digitClass.driver.GetSelected()) == 0:
- nselected = digitClass.driver.SelectLineByPoint(pos1, type=VDigit_Lines_Type)
- if digitToolbar.GetAction() == "editLine":
- try:
- selVertex = digitClass.driver.GetSelectedVertex(pos1)[0]
- except IndexError:
- selVertex = None
-
- if selVertex:
- # self.UpdateMap(render=False)
- ids = digitClass.driver.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.pdcVector.RemoveId(id)
- digitClass.driver.DrawSelected(False)
-
- if selVertex < ids[-1] / 2:
- # choose first or last node of line
- self.vdigitMove['id'].reverse()
- self.polycoords.reverse()
- else:
- # unselect
- digitClass.driver.SetSelected([])
- del self.vdigitMove
-
- self.UpdateMap(render=False)
-
-
- elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
- if not hasattr(self, "copyCatsIds"):
- # 'from' -> select by point
- nselected = digitClass.driver.SelectLineByPoint(pos1, digitClass.GetSelectType())
- if nselected:
- self.copyCatsList = digitClass.driver.GetSelected()
- else:
- # -> 'to' -> select by bbox
- digitClass.driver.SetSelected([])
- # return number of selected features (by box/point)
- nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
- digitClass.GetSelectType())
- if nselected == 0:
- if digitClass.driver.SelectLineByPoint(pos1,
- digitClass.GetSelectType()) is not None:
- nselected = 1
-
- if nselected > 0:
- self.copyCatsIds = digitClass.driver.GetSelected()
-
- elif digitToolbar.GetAction() == "queryLine":
- selected = digitClass.SelectLinesByQuery(pos1, pos2)
- nselected = len(selected)
- if nselected > 0:
- digitClass.driver.SetSelected(selected)
-
- else:
- # -> moveLine || deleteLine, etc. (select by point/box)
- if digitToolbar.GetAction() == 'moveLine' and \
- len(digitClass.driver.GetSelected()) > 0:
- nselected = 0
- else:
- if digitToolbar.GetAction() == 'moveLine':
- drawSeg = True
- else:
- drawSeg = False
- nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
- digitClass.GetSelectType(),
- drawSeg)
-
- if nselected == 0:
- if digitClass.driver.SelectLineByPoint(pos1,
- digitClass.GetSelectType()) is not None:
- nselected = 1
-
- if nselected > 0:
- if digitToolbar.GetAction() in ["moveLine", "moveVertex"]:
- # get pseudoDC id of objects which should be redrawn
- if digitToolbar.GetAction() == "moveLine":
- # -> move line
- self.vdigitMove['id'] = digitClass.driver.GetSelected(grassId=False)
- self.vdigitMove['coord'] = digitClass.driver.GetSelectedCoord()
- elif digitToolbar.GetAction() == "moveVertex":
- # -> move vertex
- self.vdigitMove['id'] = digitClass.driver.GetSelectedVertex(pos1)
- if len(self.vdigitMove['id']) == 0: # no vertex found
- digitClass.driver.SetSelected([])
-
-
- #
- # check for duplicates
- #
- if UserSettings.Get(group='vdigit', key='checkForDupl', subkey='enabled') is True:
- dupl = digitClass.driver.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:
- digitClass.driver.UnSelect(dlg.GetUnSelected())
- # update selected
- self.UpdateMap(render=False)
-
- if digitToolbar.GetAction() != "editLine":
- # -> move line || move vertex
- self.UpdateMap(render=False)
-
- else: # no vector object found
- if not (digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
- len(self.vdigitMove['id']) > 0):
- # avoid left-click when features are already selected
- self.UpdateMap(render=False, renderVector=False)
-
- elif digitToolbar.GetAction() in ["splitLine", "addVertex", "removeVertex"]:
- pointOnLine = digitClass.driver.SelectLineByPoint(pos1,
- type=VDigit_Lines_Type)
- if pointOnLine:
- if digitToolbar.GetAction() in ["splitLine", "addVertex"]:
- self.UpdateMap(render=False) # highlight object
- self.DrawCross(pdc=self.pdcTmp, coords=self.Cell2Pixel(pointOnLine),
- size=5)
- elif digitToolbar.GetAction() == "removeVertex":
- # get only id of vertex
- try:
- id = digitClass.driver.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
- digitClass.driver.SetSelected([])
- self.UpdateMap(render=False)
-
- elif digitToolbar.GetAction() == "copyLine":
- if UserSettings.Get(group='vdigit', key='bgmap',
- subkey='value', internal=True) == '':
- # no background map -> copy from current vector map layer
- nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
- digitClass.GetSelectType())
-
- 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 = digitClass.SelectLinesFromBackgroundMap(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' % utils.ListOfCatsToRange(self.copyIds),
- '-i',
- 'color=%s' % colorStr,
- 'fcolor=%s' % colorStr,
- 'type=point,line,boundary,centroid',
- 'width=2']
-
- self.layerTmp = self.Map.AddLayer(type='vector',
- name=globalvar.QUERYLAYER,
- command=dVectTmp)
- self.UpdateMap(render=True, renderVector=False)
- else:
- self.UpdateMap(render=False, renderVector=False)
- self.redrawAll = None
-
- elif digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
- # select lines to be labeled
- pos1 = self.polycoords[0]
- pos2 = self.polycoords[1]
- nselected = digitClass.driver.SelectLinesByBox(pos1, pos2,
- digitClass.GetSelectType())
-
- 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)
-
- elif digitToolbar.GetAction() == "connectLine":
- if len(digitClass.driver.GetSelected()) > 0:
- self.UpdateMap(render=False)
-
- if len(digitClass.driver.GetSelected()) > 0:
- self.redrawAll = None
- ### self.OnPaint(None)
-
- elif (self.mouse['use'] == 'pointer' and
- self.dragid >= 0):
- # end drag of overlay decoration
-
- if self.dragid < 99 and self.overlays.has_key(self.dragid):
- self.overlays[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
- elif self.dragid > 100 and self.textdict.has_key(self.dragid):
- self.textdict[self.dragid]['coords'] = self.pdc.GetIdBounds(self.dragid)
- else:
- pass
- self.dragid = None
- self.currtxtid = None
-# self.UpdateMap(render=True)
-
- else:
- pass
-
-# event.Skip()
-
- 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":
- # profile
- pass
- # self.pdc.ClearId(self.lineid)
- # self.pdc.ClearId(self.plineid)
- # print 'coordinates: ',self.polycoords
- # self.polycoords = []
- # self.mouse['begin'] = self.mouse['end'] = [0, 0]
- # self.Refresh()
- elif self.mouse['use'] == 'pointer' and self.parent.toolbars['vdigit']:
- # digitization tool
- pass
- else:
- # 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)
-
-# event.Skip()
-
- def OnRightDown(self, event):
- """
- Right mouse button pressed
- """
- Debug.msg (5, "BufferedWindow.OnRightDown(): use=%s" % \
- self.mouse["use"])
-
- digitToolbar = self.parent.toolbars['vdigit']
- if digitToolbar:
- digitClass = self.parent.digit
- # digitization tool (confirm action)
- if digitToolbar.GetAction() in ["moveLine", "moveVertex"] and \
- hasattr(self, "vdigitMove"):
-
- pFrom = self.vdigitMove['begin']
- pTo = self.Pixel2Cell(event.GetPositionTuple())
-
- move = (pTo[0] - pFrom[0],
- pTo[1] - pFrom[1])
-
- if digitToolbar.GetAction() == "moveLine":
- # move line
- if digitClass.MoveSelectedLines(move) < 0:
- return
- elif digitToolbar.GetAction() == "moveVertex":
- # move vertex
- if digitClass.MoveSelectedVertex(pFrom, move) < 0:
- return
-
- del self.vdigitMove
-
- event.Skip()
-
- def OnRightUp(self, event):
- """
- Right mouse button released
- """
- Debug.msg (5, "BufferedWindow.OnRightUp(): use=%s" % \
- self.mouse["use"])
-
- digitToolbar = self.parent.toolbars['vdigit']
- if digitToolbar:
- digitClass = self.parent.digit
- # digitization tool (confirm action)
- if digitToolbar.GetAction() == "addLine" and \
- digitToolbar.GetAction('type') in ["line", "boundary"]:
- # -> add new line / boundary
- try:
- map = digitToolbar.GetLayer().GetName()
- except:
- map = None
- wx.MessageBox(parent=self,
- message=_("No vector map selected for editing."),
- caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
-
- if map:
- # mapcoords = []
- # xy -> EN
- # for coord in self.polycoords:
- # mapcoords.append(self.Pixel2Cell(coord))
- if digitToolbar.GetAction('type') == 'line':
- line = True
- else:
- line = False
-
- if len(self.polycoords) < 2: # ignore 'one-point' lines
- return
-
- fid = digitClass.AddLine(map, line, self.polycoords)
- if fid < 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') is True:
- posWindow = self.ClientToScreen((position[0] + self.dialogOffset,
- position[1] + self.dialogOffset))
-
- # select attributes based on layer and category
- cats = { fid : {
- UserSettings.Get(group='vdigit', key="layer", subkey='value') :
- (UserSettings.Get(group='vdigit', key="category", subkey='value'), )
- }}
-
- addRecordDlg = dbm.DisplayAttributesDialog(parent=self, map=map,
- cats=cats,
- pos=posWindow,
- action="add")
- 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()
- executeCommand = gcmd.Command(cmd=["db.execute",
- "--q",
- "input=%s" % sqlfile.name])
- elif digitToolbar.GetAction() == "deleteLine":
- # -> delete selected vector features
- if digitClass.DeleteSelectedLines() < 0:
- return
- elif digitToolbar.GetAction() == "splitLine":
- # split line
- if digitClass.SplitLine(self.Pixel2Cell(self.mouse['begin'])) < 0:
- return
- elif digitToolbar.GetAction() == "addVertex":
- # add vertex
- if digitClass.AddVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
- return
- elif digitToolbar.GetAction() == "removeVertex":
- # remove vertex
- if digitClass.RemoveVertex(self.Pixel2Cell(self.mouse['begin'])) < 0:
- return
- elif digitToolbar.GetAction() in ("copyCats", "copyAttrs"):
- try:
- if digitToolbar.GetAction() == 'copyCats':
- if digitClass.CopyCats(self.copyCatsList,
- self.copyCatsIds, copyAttrb=False) < 0:
- return
- else:
- if digitClass.CopyCats(self.copyCatsList,
- self.copyCatsIds, copyAttrb=True) < 0:
- return
-
- del self.copyCatsList
- del self.copyCatsIds
- except AttributeError:
- pass
- elif digitToolbar.GetAction() == "editLine" and \
- hasattr(self, "vdigitMove"):
- line = digitClass.driver.GetSelected()
- if digitClass.EditLine(line, self.polycoords) < 0:
- return
-
- del self.vdigitMove
-
- elif digitToolbar.GetAction() == "flipLine":
- if digitClass.FlipLine() < 0:
- return
- elif digitToolbar.GetAction() == "mergeLine":
- if digitClass.MergeLine() < 0:
- return
- elif digitToolbar.GetAction() == "breakLine":
- if digitClass.BreakLine() < 0:
- return
- elif digitToolbar.GetAction() == "snapLine":
- if digitClass.SnapLine() < 0:
- return
- elif digitToolbar.GetAction() == "connectLine":
- if len(digitClass.driver.GetSelected()) > 1:
- if digitClass.ConnectLine() < 0:
- return
- elif digitToolbar.GetAction() == "copyLine":
- if digitClass.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 digitToolbar.GetAction() == "zbulkLine" and len(self.polycoords) == 2:
- pos1 = self.polycoords[0]
- pos2 = self.polycoords[1]
-
- selected = digitClass.driver.GetSelected()
- dlg = VDigitZBulkDialog(parent=self, title=_("Z bulk-labeling dialog"),
- nselected=len(selected))
- if dlg.ShowModal() == wx.ID_OK:
- if digitClass.ZBulkLines(pos1, pos2, dlg.value.GetValue(),
- dlg.step.GetValue()) < 0:
- return
- self.UpdateMap(render=False, renderVector=True)
- elif digitToolbar.GetAction() == "typeConv":
- # -> feature type conversion
- # - point <-> centroid
- # - line <-> boundary
- if digitClass.TypeConvForSelectedLines() < 0:
- return
-
- if digitToolbar.GetAction() != "addLine":
- # unselect and re-render
- digitClass.driver.SetSelected([])
- self.polycoords = []
- self.UpdateMap(render=False)
-
- self.redrawAll = True
- self.Refresh()
-
- event.Skip()
-
- def OnMiddleDown(self, event):
- """
- Middle mouse button pressed
- """
- digitToolbar = self.parent.toolbars['vdigit']
- # digitization tool
- if self.mouse["use"] == "pointer" and digitToolbar:
- digitClass = self.parent.digit
- if (digitToolbar.GetAction() == "addLine" and \
- digitToolbar.GetAction('type') in ["line", "boundary"]) or \
- digitToolbar.GetAction() == "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 digitToolbar.GetAction() == "editLine":
- # remove last vertex & line
- if len(self.vdigitMove['id']) > 1:
- self.vdigitMove['id'].pop()
-
- self.UpdateMap(render=False, renderVector=False)
-
- elif digitToolbar.GetAction() in ["deleteLine", "moveLine", "splitLine",
- "addVertex", "removeVertex", "moveVertex",
- "copyCats", "flipLine", "mergeLine",
- "snapLine", "connectLine", "copyLine",
- "queryLine", "breakLine", "typeConv"]:
- # varios tools -> unselected selected features
- digitClass.driver.SetSelected([])
- if digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] and \
- hasattr(self, "vdigitMove"):
-
- del self.vdigitMove
-
- elif digitToolbar.GetAction() == "copyCats":
- try:
- del self.copyCatsList
- del self.copyCatsIds
- except AttributeError:
- pass
-
- elif digitToolbar.GetAction() == "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 digitToolbar.GetAction() == "zbulkLine":
- # reset polyline
- self.polycoords = []
- digitClass.driver.SetSelected([])
- self.UpdateMap(render=False)
-
- self.redrawAll = True
-
- def OnMouseEnter(self, event):
- """!
- Mouse entered window and no mouse buttons were pressed
- """
- if self.parent.gismanager.gcpmanagement:
- if self.parent.toolbars['gcpdisp']:
- if not self.parent.MapWindow == self:
- self.parent.MapWindow = self
- self.parent.Map = self.Map
- self.parent.UpdateActive(self)
- self.SetFocus()
- else:
- event.Skip()
-
- def OnMouseMoving(self, event):
- """
- Motion event and no mouse buttons were pressed
- """
- digitToolbar = self.parent.toolbars['vdigit']
- if self.mouse["use"] == "pointer" and digitToolbar:
- digitClass = self.parent.digit
- self.mouse['end'] = event.GetPositionTuple()[:]
- Debug.msg (5, "BufferedWindow.OnMouseMoving(): coords=%f,%f" % \
- (self.mouse['end'][0], self.mouse['end'][1]))
- if digitToolbar.GetAction() == "addLine" and digitToolbar.GetAction('type') in ["line", "boundary"]:
- if len(self.polycoords) > 0:
- self.MouseDraw(pdc=self.pdcTmp, begin=self.Cell2Pixel(self.polycoords[-1]))
- elif digitToolbar.GetAction() in ["moveLine", "moveVertex", "editLine"] \
- and hasattr(self, "vdigitMove"):
- dx = self.mouse['end'][0] - self.mouse['begin'][0]
- dy = self.mouse['end'][1] - self.mouse['begin'][1]
-
- if len(self.vdigitMove['id']) > 0:
- # draw lines on new position
- if digitToolbar.GetAction() == "moveLine":
- # move line
- for id in self.vdigitMove['id']:
- self.pdcTmp.TranslateId(id, dx, dy)
- elif digitToolbar.GetAction() in ["moveVertex", "editLine"]:
- # move vertex ->
- # (vertex, left vertex, left line,
- # right vertex, right line)
-
- # do not draw static lines
- if digitToolbar.GetAction() == "moveVertex":
- self.polycoords = []
- ### self.pdcTmp.TranslateId(self.vdigitMove['id'][0], dx, dy)
- self.pdcTmp.RemoveId(self.vdigitMove['id'][0])
- if self.vdigitMove['id'][1] > 0: # previous vertex
- x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][1])[0:2])
- self.pdcTmp.RemoveId(self.vdigitMove['id'][1]+1)
- self.polycoords.append((x, y))
- ### x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][0])[0:2])
- self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
- if self.vdigitMove['id'][2] > 0: # next vertex
- x, y = self.Pixel2Cell(self.pdcTmp.GetIdBounds(self.vdigitMove['id'][2])[0:2])
- self.pdcTmp.RemoveId(self.vdigitMove['id'][2]-1)
- self.polycoords.append((x, y))
-
- self.ClearLines(pdc=self.pdcTmp)
- self.DrawLines(pdc=self.pdcTmp)
-
- else: # edit line
- try:
- if self.vdigitMove['id'][-1] > 0: # previous vertex
- self.MouseDraw(pdc=self.pdcTmp,
- begin=self.Cell2Pixel(self.polycoords[-1]))
- except: # no line
- self.vdigitMove['id'] = []
- self.polycoords = []
-
- self.Refresh() # TODO: use RefreshRect()
- self.mouse['begin'] = self.mouse['end']
-
- elif digitToolbar.GetAction() == "zbulkLine":
- if len(self.polycoords) == 1:
- # draw mouse moving
- self.MouseDraw(self.pdcTmp)
-
- 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))
-
- ### self.Refresh()
-
- return True
-
- def Pixel2Cell(self, (x, y)):
- """
- Convert image coordinates to real word coordinates
-
- Input : int x, int y
- Output: float x, float y
- """
-
- 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
-
- # extent does not correspond with whole map canvas area...
- # east = self.Map.region['w'] + x * self.Map.region["ewres"]
- # north = self.Map.region['n'] - y * self.Map.region["nsres"]
-
- 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 = int((east - w) / res)
- # y = int((n - north) / res)
-
- x = (east - w) / res
- y = (n - north) / res
-
- return (x, y)
-
- 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.parent.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
-
- if hasattr(self, "vdigitMove"):
- # xo = self.Cell2Pixel((self.Map.region['center_easting'], self.Map.region['center_northing']))
- # xn = self.Cell2Pixel(ce, cn))
- tmp = self.Pixel2Cell(self.mouse['end'])
-
- # 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()
-
- if hasattr(self, "vdigitMove"):
- tmp1 = self.mouse['end']
- tmp2 = self.Cell2Pixel(self.vdigitMove['begin'])
- dx = tmp1[0] - tmp2[0]
- dy = tmp1[1] - tmp2[1]
- self.vdigitMove['beginDiff'] = (dx, dy)
- for id in self.vdigitMove['id']:
- self.pdcTmp.RemoveId(id)
-
- 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 = []
- if len(self.zoomhistory) > 1:
- self.zoomhistory.pop()
- zoom = self.zoomhistory[len(self.zoomhistory)-1]
- # (n, s, e, w)
- if zoom:
- # zoom to selected region
- self.Map.region['center_easting'] = zoom[3] + \
- (zoom[2] - zoom[3]) / 2
- self.Map.region['center_northing'] = zoom[1] + \
- (zoom[0] - zoom[1]) / 2
- self.Map.region["ewres"] = (zoom[2] - zoom[3]) / self.Map.width
- self.Map.region["nsres"] = (zoom[0] - zoom[1]) / self.Map.height
- self.Map.AlignExtentFromDisplay()
-
- # update map
- self.UpdateMap()
-
- # update statusbar
- self.parent.StatusbarUpdate()
-
- def ZoomHistory(self, n, s, e, w):
- """
- Manages a list of last 10 zoom extents
-
- Return removed history item if exists
- """
- 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))
-
- return removed
-
- def OnZoomToMap(self, event):
- """
- Set display extents to match selected raster (including NULLs)
- or vector map.
- """
- self.ZoomToMap()
-
- def OnZoomToRaster(self, event):
- """
- Set display extents to match selected raster map (ignore NULLs)
- """
- self.ZoomToMap(zoom=True)
-
- def ZoomToMap(self, layer = None, zoom = False):
- """
- Set display extents to match selected raster
- or vector map.
- """
- zoomreg = {}
-
- if not layer:
- layer = self.GetSelectedLayer(multi = True)
-
- if not layer:
- return
-
- rast = []
- vect = []
- updated = False
- for l in layer:
- # only raster/vector layers are currently supported
- if l.type == 'raster':
- rast.append(l.name)
- elif l.type == 'vector':
- if self.parent.digit and l.name == self.parent.digit.map and \
- self.parent.digit.type == 'vdigit':
- w, s, b, e, n, t = self.parent.digit.driver.GetMapBoundingBox()
- self.Map.GetRegion(n=n, s=s, w=w, e=e,
- update=True)
- updated = True
- else:
- vect.append(l.name)
-
- 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'])
-
- self.UpdateMap()
-
- self.parent.StatusbarUpdate()
-
- def ZoomToWind(self, event):
- """
- Set display geometry to match computational
- region settings (set with g.region)
- """
- self.Map.region = self.Map.GetRegion()
- ### self.Map.SetRegion(windres=True)
-
- 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, event):
- """
- 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 DisplayToWind(self, event):
- """
- 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()
-
- cmdRegion = ["g.region", "--o",
- "n=%f" % new['n'],
- "s=%f" % new['s'],
- "e=%f" % new['e'],
- "w=%f" % new['w'],
- "rows=%d" % int(new['rows']),
- "cols=%d" % int(new['cols'])]
-
- p = gcmd.Command(cmdRegion)
-
- if tmpreg:
- os.environ["GRASS_REGION"] = tmpreg
-
- def ZoomToSaved(self, event):
- """!Set display geometry to match extents in
- saved region file
- """
- dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
- title = _("Zoom to saved region extents"),
- pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.DEFAULT_DIALOG_STYLE,
- loadsave='load')
-
- if dlg.ShowModal() == wx.ID_CANCEL:
- dlg.Destroy()
- return
-
- wind = dlg.wind
-
- self.Map.GetRegion(regionName = 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, event):
- """
- Save display extents to named region file.
- """
-
- dlg = gdialogs.SavedRegion(parent = self, id = wx.ID_ANY,
- title = _("Save display extents to region file"),
- pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.DEFAULT_DIALOG_STYLE,
- loadsave='save')
- if dlg.ShowModal() == wx.ID_CANCEL:
- dlg.Destroy()
- return
-
- wind = dlg.wind
-
- # test to see if it already exists and ask permission to overwrite
- windpath = os.path.join(self.Map.env["GISDBASE"], self.Map.env["LOCATION_NAME"],
- self.Map.env["MAPSET"], "windows", wind)
-
- if windpath and not os.path.exists(windpath):
- self.SaveRegion(wind)
- elif windpath and os.path.exists(windpath):
- overwrite = wx.MessageBox(_("Region file <%s> already exists. "
- "Do you want to overwrite it?") % (wind),
- _("Warning"), wx.YES_NO | wx.CENTRE)
- if (overwrite == wx.YES):
- self.SaveRegion(wind)
- else:
- pass
-
- dlg.Destroy()
-
- def SaveRegion(self, wind):
- """
- Save region settings
- """
- ### new = self.Map.AlignResolution()
- new = self.Map.GetCurrentRegion()
-
- cmdRegion = ["g.region",
- "-u",
- "n=%f" % new['n'],
- "s=%f" % new['s'],
- "e=%f" % new['e'],
- "w=%f" % new['w'],
- "rows=%d" % new['rows'],
- "cols=%d" % new['cols'],
- "save=%s" % wind,
- "--o"]
-
- tmpreg = os.getenv("GRASS_REGION")
- if tmpreg:
- del os.environ["GRASS_REGION"]
-
- p = gcmd.Command(cmdRegion)
-
- if tmpreg:
- os.environ["GRASS_REGION"] = tmpreg
-
- def Distance(self, beginpt, endpt, screen=True):
- """Calculete distance
-
- LL-locations not supported
-
- @todo Use m.distance
-
- @param beginpt first point
- @param endpt second point
- @param screen True for screen coordinates otherwise EN
- """
- x1, y1 = beginpt
- x2, y2 = endpt
- if screen:
- dEast = (x2 - x1) * self.Map.region["ewres"]
- dNorth = (y2 - y1) * self.Map.region["nsres"]
- else:
- dEast = (x2 - x1)
- dNorth = (y2 - y1)
-
-
- return (math.sqrt(math.pow((dEast),2) + math.pow((dNorth),2)), (dEast, dNorth))
-
class MapFrame(wx.Frame):
+ """!Main frame for map display window. Drawing takes place in
+ child double buffered drawing window.
"""
- Main frame for map display window. Drawing takes place in child double buffered
- drawing window.
- """
-
def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS - Map display"),
- pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, toolbars=["map"],
- tree=None, notebook=None, gismgr=None, page=None,
- Map=None, auimgr=None):
- """
- Main map display window with toolbars, statusbar and
+ tree=None, notebook=None, lmgr=None, page=None,
+ Map=None, auimgr=None, **kwargs):
+ """!Main map display window with toolbars, statusbar and
DrawWindow
@param toolbars array of activated toolbars, e.g. ['map', 'digit']
@param tree reference to layer tree
@param notebook control book ID in Layer Manager
- @param gismgr Layer Manager panel
+ @param lmgr Layer Manager
@param page notebook page with layer tree
@param Map instance of render.Map
+ @param auimgs AUI manager
+ @param kwargs wx.Frame attribures
"""
- self.gismanager = gismgr # GIS Manager object
+ self._layerManager = lmgr # Layer Manager object
self.Map = Map # instance of render.Map
- self.tree = tree # GIS Manager layer tree object
+ self.tree = tree # Layer Manager layer tree object
self.page = page # Notebook page holding the layer tree
- self.layerbook = notebook # GIS Manager layer tree notebook
+ self.layerbook = notebook # Layer Manager layer tree notebook
self.parent = parent
-
- #
+
+ if not kwargs.has_key('name'):
+ kwargs['name'] = 'MapWindow'
+ wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
+
# available cursors
- #
self.cursors = {
# default: cross
# "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
@@ -2632,14 +122,11 @@
"pencil" : wx.StockCursor(wx.CURSOR_PENCIL),
"sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
}
-
- wx.Frame.__init__(self, parent, id, title, pos, size, style)
- self.SetName("MapWindow")
-
+
#
# set the size & system icon
#
- self.SetClientSize(size)
+ self.SetClientSize(self.GetSize())
self.iconsize = (16, 16)
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
@@ -2655,8 +142,8 @@
#
self.toolbars = { 'map' : None,
'vdigit' : None,
- 'gcpdisp' : None,
'georect' : None,
+ 'gcpdisp' : None,
'nviz' : None }
for toolb in toolbars:
self.AddToolbar(toolb)
@@ -2666,56 +153,87 @@
#
self.statusbar = self.CreateStatusBar(number=4, style=0)
self.statusbar.SetStatusWidths([-5, -2, -1, -1])
- self.toggleStatus = wx.Choice(self.statusbar, wx.ID_ANY,
- choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
- self.toggleStatus.SetSelection(UserSettings.Get(group='display', key='statusbarMode', subkey='selection'))
- self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.toggleStatus)
+ self.statusbarWin = dict()
+ self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
+ choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
+ self.statusbarWin['toggle'].SetSelection(UserSettings.Get(group='display',
+ key='statusbarMode',
+ subkey='selection'))
+ self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
# auto-rendering checkbox
- self.autoRender = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
- label=_("Render"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.autoRender)
- self.autoRender.SetValue(UserSettings.Get(group='display', key='autoRendering', subkey='enabled'))
- self.autoRender.SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
+ self.statusbarWin['render'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ label=_("Render"))
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
+ self.statusbarWin['render'].SetValue(UserSettings.Get(group='display',
+ key='autoRendering',
+ subkey='enabled'))
+ self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
# show region
- self.showRegion = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
- label=_("Show computational extent"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.showRegion)
+ self.statusbarWin['region'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ label=_("Show computational extent"))
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
- self.showRegion.SetValue(False)
- self.showRegion.Hide()
- self.showRegion.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.statusbarWin['region'].SetValue(False)
+ self.statusbarWin['region'].Hide()
+ self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
+ "region extent (set with g.region). "
+ "Display region drawn as a blue box inside the "
+ "computational region, "
+ "computational region inside a display region "
+ "as a red box).")))
# set resolution
- self.compResolution = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
- label=_("Constrain display resolution to computational settings"))
- self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.compResolution)
- self.compResolution.SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
- self.compResolution.Hide()
- self.compResolution.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.statusbarWin['resolution'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ label=_("Constrain display resolution to computational settings"))
+ self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
+ self.statusbarWin['resolution'].SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
+ self.statusbarWin['resolution'].Hide()
+ self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
+ "to computational region settings. "
+ "Default value for new map displays can "
+ "be set up in 'User GUI settings' dialog.")))
# map scale
- self.mapScale = wx.TextCtrl(parent=self.statusbar, id=wx.ID_ANY,
- value="", style=wx.TE_PROCESS_ENTER,
- size=(150, -1))
- self.mapScale.Hide()
- self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.mapScale)
+ self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
+ style = wx.TE_PROCESS_ENTER,
+ size=(150, -1))
+ self.statusbarWin['mapscale'].SetItems(['1:1000',
+ '1:5000',
+ '1:10000',
+ '1:25000',
+ '1:50000',
+ '1:100000',
+ '1:1000000'])
+ self.statusbarWin['mapscale'].Hide()
+ self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
+ self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
+ # go to
+ self.statusbarWin['goto'] = wx.TextCtrl(parent=self.statusbar, id=wx.ID_ANY,
+ value="", style=wx.TE_PROCESS_ENTER,
+ size=(300, -1))
+ self.statusbarWin['goto'].Hide()
+ self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
+
+ # projection
+ self.statusbarWin['projection'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
+ label=_("Use defined projection"))
+ self.statusbarWin['projection'].SetValue(False)
+ size = self.statusbarWin['projection'].GetSize()
+ self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
+ self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
+ "in the statusbar. Projection can be "
+ "defined in GUI preferences dialog "
+ "(tab 'Display')")))
+ self.statusbarWin['projection'].Hide()
+
# mask
- self.maskInfo = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
+ self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
label = '')
- self.maskInfo.SetForegroundColour(wx.Colour(255, 0, 0))
+ self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
-
# on-render gauge
- self.onRenderGauge = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
+ self.statusbarWin['progress'] = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
range=0, style=wx.GA_HORIZONTAL)
- self.onRenderGauge.Hide()
+ self.statusbarWin['progress'].Hide()
self.StatusbarReposition() # reposition statusbar
@@ -2723,10 +241,9 @@
# Init map display (buffered DC & set default cursor)
#
self.MapWindow2D = BufferedWindow(self, id=wx.ID_ANY,
- Map=self.Map, tree=self.tree, gismgr=self.gismanager)
+ Map=self.Map, tree=self.tree, lmgr=self._layerManager)
# default is 2D display mode
self.MapWindow = self.MapWindow2D
- self.MapWindow.Bind(wx.EVT_MOTION, self.OnMotion)
self.MapWindow.SetCursor(self.cursors["default"])
# used by Nviz (3D display mode)
self.MapWindow3D = None
@@ -2747,9 +264,9 @@
# Update fancy gui style
#
self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
- Dockable(False).BestSize((-1,-1)).
- CloseButton(False).DestroyOnClose(True).
- Layer(0))
+ Dockable(False).BestSize((-1,-1)).
+ CloseButton(False).DestroyOnClose(True).
+ Layer(0))
self._mgr.Update()
#
@@ -2782,26 +299,27 @@
self.decorationDialog = None # decoration/overlays
def AddToolbar(self, name):
- """
- Add defined toolbar to the window
-
+ """!Add defined toolbar to the window
+
Currently known toolbars are:
- - map basic map toolbar
- - digit vector digitizer
- - georect georectifier
+ - 'map' - basic map toolbar
+ - 'vdigit' - vector digitizer
+ - 'gcpdisp' - GCP Manager Display
+ - 'georect' - georectifier
+ - 'nviz' - 3D view mode
"""
# default toolbar
if name == "map":
self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
- self._mgr.AddPane(self.toolbars['map'].toolbar,
+ self._mgr.AddPane(self.toolbars['map'],
wx.aui.AuiPaneInfo().
- Name("maptoolbar").Caption(_("Map Toolbar")).
+ Name("maptoolbar").Caption(_("Map toolbar")).
ToolbarPane().Top().
LeftDockable(False).RightDockable(False).
BottomDockable(False).TopDockable(True).
CloseButton(False).Layer(2).
- BestSize((self.toolbars['map'].GetToolbar().GetSize())))
+ BestSize((self.toolbars['map'].GetSize())))
# vector digitizer
elif name == "vdigit":
@@ -2812,43 +330,46 @@
"TCL/TK digitizer (v.digit) instead?\n\n"
"Details: %s" % errorMsg)
- self.toolbars['map'].combo.SetValue (_("2D view"))
- dlg = wx.MessageDialog(parent = self,
+ self.mapdisplay.toolbars['map'].combo.SetValue (_("2D view"))
+ dlg = wx.MessageDialog(parent = self.mapdisplay,
message = msg,
caption=_("Vector digitizer failed"),
style = wx.YES_NO | wx.CENTRE)
if dlg.ShowModal() == wx.ID_YES:
- mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
- self.gismanager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
- switchPage=False)
+ self.lmgr.goutput.RunCmd(['v.digit', 'map=%s' % maplayer.GetName()],
+ switchPage=False)
dlg.Destroy()
+
+ self.toolbars['map'].combo.SetValue (_("2D view"))
return
- self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent=self, map=self.Map,
+ if self._layerManager:
+ log = self._layerManager.goutput
+ else:
+ log = None
+ self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent=self, mapcontent=self.Map,
layerTree=self.tree,
- log=self.gismanager.goutput)
+ log=log)
- for toolRow in range(0, self.toolbars['vdigit'].numOfRows):
- self._mgr.AddPane(self.toolbars['vdigit'].toolbar[toolRow],
- wx.aui.AuiPaneInfo().
- Name("vdigittoolbar" + str(toolRow)).Caption(_("Vector digitizer toolbar")).
- ToolbarPane().Top().Row(toolRow + 1).
- LeftDockable(False).RightDockable(False).
- BottomDockable(False).TopDockable(True).
- CloseButton(False).Layer(2).
- BestSize((self.toolbars['vdigit'].GetToolbar().GetSize())))
+ 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'].GetSize())))
# 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)
-
# georectifier
elif name == "georect":
self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
- self._mgr.AddPane(self.toolbars['georect'].toolbar,
+ self._mgr.AddPane(self.toolbars['georect'],
wx.aui.AuiPaneInfo().
Name("georecttoolbar").Caption(_("Georectification toolbar")).
ToolbarPane().Top().
@@ -2861,105 +382,87 @@
# check for GLCanvas and OpenGL
if not nviz.haveNviz:
- wx.MessageBox(parent=self,
+ self.toolbars['map'].combo.SetValue (_("2D view"))
+ wx.MessageBox(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),
- caption=_("Error"),
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
- self.toolbars['map'].combo.SetValue (_("2D view"))
+ caption = _("Error"),
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
return
- #
# add Nviz toolbar and disable 2D display mode tools
- #
self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
self.toolbars['map'].Enable2D(False)
-
- #
- # update layer tree (-> enable 3d-rasters)
- #
- self.tree.EnableItemType(type='3d-raster', enable=True)
- #
# update status bar
- #
- self.toggleStatus.Enable(False)
+ self.statusbarWin['toggle'].Enable(False)
- #
# erase map window
- #
self.MapWindow.EraseMap()
-
- busy = wx.BusyInfo(message=_("Please wait, loading data..."),
- parent=self)
- wx.Yield()
-
- #
+
+ self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."))
+ self.statusbar.SetStatusText(_("Please wait, loading data..."), 0)
+
# create GL window & NVIZ toolbar
- #
if not self.MapWindow3D:
self.MapWindow3D = nviz.GLWindow(self, id=wx.ID_ANY,
- Map=self.Map, tree=self.tree, gismgr=self.gismanager)
- self.nvizToolWin = nviz.NvizToolWindow(self, id=wx.ID_ANY,
- mapWindow=self.MapWindow3D)
+ Map=self.Map, tree=self.tree, lmgr=self._layerManager)
+ self.MapWindow = self.MapWindow3D
+ self.MapWindow.SetCursor(self.cursors["default"])
+
+ # add Nviz notebookpage
+ self._layerManager.AddNviz()
+
self.MapWindow3D.OnPaint(None) # -> LoadData
self.MapWindow3D.Show()
self.MapWindow3D.UpdateView(None)
-
- busy.Destroy()
-
- self.nvizToolWin.Show()
-
- #
+ else:
+ self.MapWindow = self.MapWindow3D
+ # add Nviz notebookpage
+ self._layerManager.AddNviz()
+
# switch from MapWindow to MapWindowGL
# add nviz toolbar
- #
self._mgr.DetachPane(self.MapWindow2D)
self.MapWindow2D.Hide()
self._mgr.AddPane(self.MapWindow3D, w