Selaa lähdekoodia

wxGUI: major update for d.mon

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@46998 15284696-431f-4ddb-bdfa-cd5b030d7da7
Martin Landa 14 vuotta sitten
vanhempi
commit
619a74945c

+ 86 - 82
gui/wxpython/gui_modules/mapdisp.py

@@ -1,20 +1,19 @@
 """!
 """!
 @package mapdisp.py
 @package mapdisp.py
 
 
-@brief GIS map display canvas, with toolbar for various display
-management functions, and additional toolbars (vector digitizer, 3d
-view).
+@brief Map display with toolbar for various display management
+functions, and additional toolbars (vector digitizer, 3d view).
 
 
-Can be used either from Layer Manager or as p.mon backend.
+Can be used either from Layer Manager or as d.mon backend.
 
 
 Classes:
 Classes:
 - MapFrame
 - MapFrame
 - MapApp
 - MapApp
 
 
 Usage:
 Usage:
-python mapdisp.py monitor-identifier /path/to/command/file
+python mapdisp.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
 
 
-(C) 2006-2010 by the GRASS Development Team
+(C) 2006-2011 by the GRASS Development Team
 This program is free software under the GNU General Public
 This program is free software under the GNU General Public
 License (>=v2). Read the file COPYING that comes with GRASS
 License (>=v2). Read the file COPYING that comes with GRASS
 for details.
 for details.
@@ -35,18 +34,8 @@ import globalvar
 import wx
 import wx
 import wx.aui
 import wx.aui
 
 
-try:
-    import subprocess
-except:
-    CompatPath = os.path.join(globalvar.ETCWXDIR)
-    sys.path.append(CompatPath)
-    from compat import subprocess
-
-gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
-sys.path.append(gmpath)
-
-grassPath = os.path.join(globalvar.ETCDIR, "python")
-sys.path.append(grassPath)
+sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
+sys.path.append(os.path.join(globalvar.ETCDIR,   "python"))
 
 
 import render
 import render
 import toolbars
 import toolbars
@@ -61,16 +50,21 @@ import profile
 import globalvar
 import globalvar
 import utils
 import utils
 import gdialogs
 import gdialogs
-from grass.script import core as grass
-from debug import Debug
-from icon  import Icons
+from debug       import Debug
+from icon        import Icons
 from preferences import globalSettings as UserSettings
 from preferences import globalSettings as UserSettings
 
 
 from mapdisp_command import Command
 from mapdisp_command import Command
-from mapdisp_window import BufferedWindow
+from mapdisp_window  import BufferedWindow
+
+from grass.script import core as grass
 
 
 # for standalone app
 # for standalone app
-cmdfilename = None
+monFile = { 'cmd' : None,
+            'map' : None,
+            'env' : None,
+            }
+monName = None
 
 
 haveCtypes = False
 haveCtypes = False
 
 
@@ -83,8 +77,8 @@ class MapFrame(wx.Frame):
                  tree = None, notebook = None, lmgr = None, page = None,
                  tree = None, notebook = None, lmgr = None, page = None,
                  Map = None, auimgr = None, **kwargs):
                  Map = None, auimgr = None, **kwargs):
         """!Main map display window with toolbars, statusbar and
         """!Main map display window with toolbars, statusbar and
-        DrawWindow
-
+        BufferedWindow (map canvas)
+        
         @param toolbars array of activated toolbars, e.g. ['map', 'digit']
         @param toolbars array of activated toolbars, e.g. ['map', 'digit']
         @param tree reference to layer tree
         @param tree reference to layer tree
         @param notebook control book ID in Layer Manager
         @param notebook control book ID in Layer Manager
@@ -427,7 +421,7 @@ class MapFrame(wx.Frame):
         
         
         self.SetStatusText("", 0)
         self.SetStatusText("", 0)
         Debug.msg(5, "MapFrame._addToolbarNviz(): end")
         Debug.msg(5, "MapFrame._addToolbarNviz(): end")
-        
+
     def AddToolbar(self, name):
     def AddToolbar(self, name):
         """!Add defined toolbar to the window
         """!Add defined toolbar to the window
         
         
@@ -533,7 +527,7 @@ class MapFrame(wx.Frame):
         self.Map.ChangeMapSize(self.GetClientSize())
         self.Map.ChangeMapSize(self.GetClientSize())
         self.Map.region = self.Map.GetRegion() # g.region -upgc
         self.Map.region = self.Map.GetRegion() # g.region -upgc
         # self.Map.SetRegion() # adjust region to match display window
         # self.Map.SetRegion() # adjust region to match display window
-
+        
     def OnUpdateProgress(self, event):
     def OnUpdateProgress(self, event):
         """!Update progress bar info
         """!Update progress bar info
         """
         """
@@ -627,8 +621,7 @@ class MapFrame(wx.Frame):
             self.MapWindow.SetCursor(self.cursors["default"])
             self.MapWindow.SetCursor(self.cursors["default"])
 
 
     def OnZoomIn(self, event):
     def OnZoomIn(self, event):
-        """
-        Zoom in the map.
+        """!Zoom in the map.
         Set mouse cursor, zoombox attributes, and zoom direction
         Set mouse cursor, zoombox attributes, and zoom direction
         """
         """
         if self.toolbars['map']:
         if self.toolbars['map']:
@@ -644,8 +637,7 @@ class MapFrame(wx.Frame):
         self.MapWindow.SetCursor(self.cursors["cross"])
         self.MapWindow.SetCursor(self.cursors["cross"])
 
 
     def OnZoomOut(self, event):
     def OnZoomOut(self, event):
-        """
-        Zoom out the map.
+        """!Zoom out the map.
         Set mouse cursor, zoombox attributes, and zoom direction
         Set mouse cursor, zoombox attributes, and zoom direction
         """
         """
         if self.toolbars['map']:
         if self.toolbars['map']:
@@ -661,14 +653,12 @@ class MapFrame(wx.Frame):
         self.MapWindow.SetCursor(self.cursors["cross"])
         self.MapWindow.SetCursor(self.cursors["cross"])
 
 
     def OnZoomBack(self, event):
     def OnZoomBack(self, event):
-        """
-        Zoom last (previously stored position)
+        """!Zoom last (previously stored position)
         """
         """
         self.MapWindow.ZoomBack()
         self.MapWindow.ZoomBack()
 
 
     def OnPan(self, event):
     def OnPan(self, event):
-        """
-        Panning, set mouse to drag
+        """!Panning, set mouse to drag
         """
         """
         if self.toolbars['map']:
         if self.toolbars['map']:
             self.toolbars['map'].OnTool(event)
             self.toolbars['map'].OnTool(event)
@@ -682,14 +672,12 @@ class MapFrame(wx.Frame):
         self.MapWindow.SetCursor(self.cursors["hand"])
         self.MapWindow.SetCursor(self.cursors["hand"])
 
 
     def OnErase(self, event):
     def OnErase(self, event):
-        """
-        Erase the canvas
+        """!Erase the canvas
         """
         """
         self.MapWindow.EraseMap()
         self.MapWindow.EraseMap()
 
 
     def OnZoomRegion(self, event):
     def OnZoomRegion(self, event):
-        """
-        Zoom to region
+        """!Zoom to region
         """
         """
         self.Map.getRegion()
         self.Map.getRegion()
         self.Map.getResolution()
         self.Map.getResolution()
@@ -697,8 +685,7 @@ class MapFrame(wx.Frame):
         # event.Skip()
         # event.Skip()
 
 
     def OnAlignRegion(self, event):
     def OnAlignRegion(self, event):
-        """
-        Align region
+        """!Align region
         """
         """
         if not self.Map.alignRegion:
         if not self.Map.alignRegion:
             self.Map.alignRegion = True
             self.Map.alignRegion = True
@@ -2025,73 +2012,90 @@ class MapFrame(wx.Frame):
         """
         """
         return self._layerManager
         return self._layerManager
     
     
-# end of class MapFrame
-
 class MapApp(wx.App):
 class MapApp(wx.App):
     def OnInit(self):
     def OnInit(self):
         wx.InitAllImageHandlers()
         wx.InitAllImageHandlers()
         if __name__ == "__main__":
         if __name__ == "__main__":
-            Map = render.Map() # instance of Map class to render GRASS display output to PPM file
+            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
+            Map = render.Map(cmdfile = monFile['cmd'], mapfile = monFile['map'],
+                             envfile = monFile['env'], monitor = monName)
         else:
         else:
             Map = None
             Map = None
-
+        
         self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
         self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
                                size = globalvar.MAP_WINDOW_SIZE)
                                size = globalvar.MAP_WINDOW_SIZE)
-        #self.SetTopWindow(Map)
+        # self.SetTopWindow(Map)
         self.mapFrm.Show()
         self.mapFrm.Show()
-
+        
         if __name__ == "__main__":
         if __name__ == "__main__":
-            # redraw map, if new command appears
-            self.redraw = False
-            status = Command(self, Map, cmdfilename)
-            status.start()
+            #status = Command(self, Map, cmdfile)
+            # status.start()
             self.timer = wx.PyTimer(self.watcher)
             self.timer = wx.PyTimer(self.watcher)
-            # check each 0.1s
-            self.timer.Start(100)
-
-        return 1
-
+            #check each 0.5s
+            global mtime
+            mtime = 500
+            self.timer.Start(mtime)
+            
+        return True
+    
     def OnExit(self):
     def OnExit(self):
         if __name__ == "__main__":
         if __name__ == "__main__":
             # stop the timer
             # stop the timer
-            self.timer.Stop()
-            # terminate thread (a bit ugly)
-            os.system("""!echo "quit" >> %s""" % (cmdfilename))
-
+            # self.timer.Stop()
+            # terminate thread
+            for f in monFile.itervalues():
+                grass.try_remove(f)
+            
     def watcher(self):
     def watcher(self):
-        """!Redraw, if new layer appears"""
-        if self.redraw:
+        """!Redraw, if new layer appears (check's timestamp of
+        cmdfile)
+        """
+        # todo: events
+        if os.path.getmtime(monFile['cmd']) > self.cmdTimeStamp:
+            self.timer.Stop()
+            self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
             self.mapFrm.OnDraw(None)
             self.mapFrm.OnDraw(None)
-        self.redraw = False
-        return
-# end of class MapApp
-
+            self.timer.Start(mtime)
+        
 if __name__ == "__main__":
 if __name__ == "__main__":
-
-    ###### SET command variable
-    if len(sys.argv) != 3:
+    # set command variable
+    if len(sys.argv) != 5:
         print __doc__
         print __doc__
-        sys.exit()
-
-    title = sys.argv[1]
-    cmdfilename = sys.argv[2]
-
+        sys.exit(1)
+    
+    monName = sys.argv[1]
+    monFile = { 'map' : sys.argv[2],
+                'cmd' : sys.argv[3],
+                'env' : sys.argv[4],
+                }
+    
     import gettext
     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)
+    
+    grass.verbose(_("Starting map display <%s>...") % (monName))
 
 
-    print >> sys.stderr, "\nStarting monitor <%s>...\n" % (title)
-
+    gcmd.RunCommand('g.gisenv',
+                    set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
+    
     gm_map = MapApp(0)
     gm_map = MapApp(0)
     # set title
     # set title
     gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
     gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
-                             title + 
+                             monName + 
                              " - Location: " + grass.gisenv()["LOCATION_NAME"]))
                              " - Location: " + grass.gisenv()["LOCATION_NAME"]))
     
     
     gm_map.MainLoop()
     gm_map.MainLoop()
     
     
-    os.remove(cmdfilename)
-    os.system("""!g.gisenv set="GRASS_PYCMDFILE" """)
-
-    print >> sys.stderr, "\nStopping monitor <%s>...\n" % (title)
-
+    grass.verbose(_("Stopping map display <%s>...") % (monName))
+
+    # clean up GRASS env variables
+    env = grass.gisenv()
+    env_name = 'MONITOR_%s' % monName
+    for key in env.keys():
+        if key.find(env_name) == 0:
+            gcmd.RunCommand('g.gisenv',
+                              set = '%s=' % key)
+        if key == 'MONITOR' and env[key] == monName:
+            gcmd.RunCommand('g.gisenv',
+                            set = '%s=' % key)
+    
     sys.exit(0)
     sys.exit(0)

+ 9 - 5
gui/wxpython/gui_modules/mapdisp_window.py

@@ -444,7 +444,6 @@ class BufferedWindow(MapWindow, wx.Window):
         If self.redrawAll is False on self.pdcTmp content is re-drawn
         If self.redrawAll is False on self.pdcTmp content is re-drawn
         """
         """
         Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
         Debug.msg(4, "BufferedWindow.OnPaint(): redrawAll=%s" % self.redrawAll)
-        
         dc = wx.BufferedPaintDC(self, self.buffer)
         dc = wx.BufferedPaintDC(self, self.buffer)
         dc.Clear()
         dc.Clear()
         
         
@@ -632,7 +631,7 @@ class BufferedWindow(MapWindow, wx.Window):
         
         
         self.resize = False
         self.resize = False
         
         
-        if self.img is None:
+        if not self.Map.cmdfile and self.img is None:
             render = True
             render = True
         
         
         #
         #
@@ -663,10 +662,12 @@ class BufferedWindow(MapWindow, wx.Window):
                     windres = True
                     windres = True
                 else:
                 else:
                     windres = False
                     windres = False
+                
                 self.mapfile = self.Map.Render(force = True, mapWindow = self.parent,
                 self.mapfile = self.Map.Render(force = True, mapWindow = self.parent,
                                                windres = windres)
                                                windres = windres)
             else:
             else:
                 self.mapfile = self.Map.Render(force = False, mapWindow = self.parent)
                 self.mapfile = self.Map.Render(force = False, mapWindow = self.parent)
+            
         except gcmd.GException, e:
         except gcmd.GException, e:
             gcmd.GError(message = e.value)
             gcmd.GError(message = e.value)
             self.mapfile = None
             self.mapfile = None
@@ -772,6 +773,7 @@ class BufferedWindow(MapWindow, wx.Window):
         else:
         else:
             self.parent.statusbarWin['mask'].SetLabel('')
             self.parent.statusbarWin['mask'].SetLabel('')
         
         
+        
         Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
         Debug.msg (1, "BufferedWindow.UpdateMap(): render=%s, renderVector=%s -> time=%g" % \
                    (render, renderVector, (stop-start)))
                    (render, renderVector, (stop-start)))
         
         
@@ -1211,6 +1213,7 @@ class BufferedWindow(MapWindow, wx.Window):
             self.DrawLines(pdc = self.pdcTmp)
             self.DrawLines(pdc = self.pdcTmp)
         
         
         elif self.mouse["use"] == "pointer" and \
         elif self.mouse["use"] == "pointer" and \
+                not self.parent.IsStandalone() and \
                 self.parent.GetLayerManager().gcpmanagement:
                 self.parent.GetLayerManager().gcpmanagement:
             # -> GCP manager
             # -> GCP manager
             if self.parent.toolbars['gcpdisp']:
             if self.parent.toolbars['gcpdisp']:
@@ -1224,6 +1227,7 @@ class BufferedWindow(MapWindow, wx.Window):
                 self.UpdateMap(render = False, renderVector = False)
                 self.UpdateMap(render = False, renderVector = False)
         
         
         elif self.mouse["use"] == "pointer" and \
         elif self.mouse["use"] == "pointer" and \
+                not self.parent.IsStandalone() and \
                 self.parent.GetLayerManager().georectifying:
                 self.parent.GetLayerManager().georectifying:
             # -> georectifying
             # -> georectifying
             coord = self.Pixel2Cell(self.mouse['end'])
             coord = self.Pixel2Cell(self.mouse['end'])
@@ -1340,7 +1344,8 @@ class BufferedWindow(MapWindow, wx.Window):
     def OnMouseEnter(self, event):
     def OnMouseEnter(self, event):
         """!Mouse entered window and no mouse buttons were pressed
         """!Mouse entered window and no mouse buttons were pressed
         """
         """
-        if self.parent.GetLayerManager().gcpmanagement:
+        if not self.parent.IsStandalone() and \
+                self.parent.GetLayerManager().gcpmanagement:
             if self.parent.toolbars['gcpdisp']:
             if self.parent.toolbars['gcpdisp']:
                 if not self.parent.MapWindow == self:
                 if not self.parent.MapWindow == self:
                     self.parent.MapWindow = self
                     self.parent.MapWindow = self
@@ -1432,8 +1437,7 @@ class BufferedWindow(MapWindow, wx.Window):
         return (x, y)
         return (x, y)
     
     
     def Zoom(self, begin, end, zoomtype):
     def Zoom(self, begin, end, zoomtype):
-        """!
-        Calculates new region while (un)zoom/pan-ing
+        """!Calculates new region while (un)zoom/pan-ing
         """
         """
         x1, y1 = begin
         x1, y1 = begin
         x2, y2 = end
         x2, y2 = end

+ 163 - 131
gui/wxpython/gui_modules/render.py

@@ -24,13 +24,6 @@ import sys
 import glob
 import glob
 import math
 import math
 import copy
 import copy
-
-try:
-    import subprocess
-except:
-    compatPath = os.path.join(globalvar.ETCWXDIR, "compat")
-    sys.path.append(compatPath)
-    import subprocess
 import tempfile
 import tempfile
 
 
 import wx
 import wx
@@ -46,22 +39,19 @@ from preferences import globalSettings as UserSettings
 
 
 wxUpdateProgressBar, EVT_UPDATE_PRGBAR = NewEvent()
 wxUpdateProgressBar, EVT_UPDATE_PRGBAR = NewEvent()
 
 
-#
-# use g.pnmcomp for creating image composition or
-# wxPython functionality
-#
 USE_GPNMCOMP = True
 USE_GPNMCOMP = True
 
 
 class Layer(object):
 class Layer(object):
     """!Virtual class which stores information about layers (map layers and
     """!Virtual class which stores information about layers (map layers and
     overlays) of the map composition.
     overlays) of the map composition.
     
     
-    For map layer use MapLayer class.
-    For overlays use Overlay class.
+    - For map layer use MapLayer class.
+    - For overlays use Overlay class.
     """
     """
     def __init__(self, type, cmd, name = None,
     def __init__(self, type, cmd, name = None,
                  active = True, hidden = False, opacity = 1.0):
                  active = True, hidden = False, opacity = 1.0):
-        """!
+        """!Create new instance
+        
         @todo pass cmd as tuple instead of list
         @todo pass cmd as tuple instead of list
         
         
         @param type layer type ('raster', 'vector', 'overlay', 'command', etc.)
         @param type layer type ('raster', 'vector', 'overlay', 'command', etc.)
@@ -94,22 +84,26 @@ class Layer(object):
                         self.opacity, self.hidden))
                         self.opacity, self.hidden))
         
         
         # generated file for each layer
         # generated file for each layer
-        self.gtemp = tempfile.mkstemp()[1]
-        self.maskfile = self.gtemp + ".pgm"
-        if self.type == 'overlay':
-            self.mapfile  = self.gtemp + ".png"
+        if USE_GPNMCOMP or self.type == 'overlay':
+            tmpfile = tempfile.mkstemp()[1]
+            self.maskfile = tmpfile + '.pgm'
+            if self.type == 'overlay':
+                self.mapfile  = tmpfile + '.png'
+            else:
+                self.mapfile  = tmpfile + '.ppm'
+            grass.try_remove(tmpfile)
         else:
         else:
-            self.mapfile  = self.gtemp + ".ppm"
+            self.mapfile = self.maskfile = None
         
         
     def __del__(self):
     def __del__(self):
         Debug.msg (3, "Layer.__del__(): layer=%s, cmd='%s'" %
         Debug.msg (3, "Layer.__del__(): layer=%s, cmd='%s'" %
                    (self.name, self.GetCmd(string = True)))
                    (self.name, self.GetCmd(string = True)))
-
+        
     def Render(self):
     def Render(self):
         """!Render layer to image
         """!Render layer to image
         
         
         @return rendered image filename
         @return rendered image filename
-        @return None on error
+        @return None on error or if cmdfile is defined
         """
         """
         if not self.cmd:
         if not self.cmd:
             return None
             return None
@@ -135,7 +129,7 @@ class Layer(object):
         # start monitor
         # start monitor
 	if self.mapfile:
 	if self.mapfile:
 	    os.environ["GRASS_PNGFILE"] = self.mapfile
 	    os.environ["GRASS_PNGFILE"] = self.mapfile
-                
+        
         # execute command
         # execute command
         try:
         try:
             if self.type == 'command':
             if self.type == 'command':
@@ -154,37 +148,24 @@ class Layer(object):
             else:
             else:
                 ret, msg = gcmd.RunCommand(self.cmd[0],
                 ret, msg = gcmd.RunCommand(self.cmd[0],
                                            getErrorMsg = True,
                                            getErrorMsg = True,
-                                           quiet = True,
+                                           # quiet = True,
+                                           verbose = True,
                                            **self.cmd[1])
                                            **self.cmd[1])
-            # if len(msg):
-            # sys.stderr.write(_("Running") + " '" + utils.GetCmdString(self.cmd) + "'")
-            # sys.stderr.write(msg)
             
             
             if ret != 0:
             if ret != 0:
-                # clean up after problem
-                try:
-                    os.remove(self.mapfile)
-                    os.remove(self.maskfile)
-                    os.remove(self.gtemp)
-                except (OSError, TypeError):
-                    pass
-                self.mapfile = None
-                self.maskfile = None
-        
+                raise gcmd.GException(value = _("%s failed") % self.cmd[0])
+            
         except gcmd.GException, e:
         except gcmd.GException, e:
             # sys.stderr.write(e.value)
             # sys.stderr.write(e.value)
             # clean up after problems
             # clean up after problems
-            try:
-                os.remove(self.mapfile)
-                os.remove(self.maskfile)
-                os.remove(self.gtemp)
-            except (OSError, TypeError):
-                pass
-            self.mapfile = None
-            self.maskfile = None
+            for f in [self.mapfile, self.maskfile]:
+                if not f:
+                    continue
+                grass.try_remove(f)
+                f = None
         
         
         # stop monitor
         # stop monitor
-        if "GRASS_PNGFILE" in os.environ:
+        if self.mapfile and "GRASS_PNGFILE" in os.environ:
             del os.environ["GRASS_PNGFILE"]
             del os.environ["GRASS_PNGFILE"]
         
         
         self.force_render = False
         self.force_render = False
@@ -350,9 +331,15 @@ class Overlay(Layer):
         self.id = id
         self.id = id
         
         
 class Map(object):
 class Map(object):
-    """!Map composition (stack of map layers and overlays)
-    """
-    def __init__(self, gisrc = None):
+    def __init__(self, gisrc = None, cmdfile = None, mapfile = None, envfile = None, monitor = None):
+        """!Map composition (stack of map layers and overlays)
+
+        @param gisrc alternative gisrc (used eg. by georectifier)
+        @param cmdline full path to the cmd file (defined by d.mon)
+        @param mapfile full path to the map file (defined by d.mon)
+        @param envfile full path to the env file (defined by d.mon)
+        @param monitor name of monitor (defined by d.mon)
+        """
         # region/extent settigns
         # region/extent settigns
         self.wind      = dict() # WIND settings (wind file)
         self.wind      = dict() # WIND settings (wind file)
         self.region    = dict() # region settings (g.region)
         self.region    = dict() # region settings (g.region)
@@ -366,20 +353,37 @@ class Map(object):
         self.ovlookup  = dict()  # lookup dictionary for overlay items and overlays
         self.ovlookup  = dict()  # lookup dictionary for overlay items and overlays
         
         
         # environment settings
         # environment settings
-        # environment variables, like MAPSET, LOCATION_NAME, etc.
         self.env   = dict()
         self.env   = dict()
         # path to external gisrc
         # path to external gisrc
         self.gisrc = gisrc
         self.gisrc = gisrc
         
         
-        # generated file for g.pnmcomp output for rendering the map
-        self.mapfile = tempfile.mkstemp(suffix = '.ppm')[1]
+        self.cmdfile = cmdfile
+        self.envfile = envfile
+        self.monitor = monitor
+        
+        if mapfile:
+            self.mapfile = mapfile
+        else:
+            # generated file for g.pnmcomp output for rendering the map
+            self.mapfile = grass.tempfile(create = False) + '.ppm'
         
         
         # setting some initial env. variables
         # setting some initial env. variables
         self._initGisEnv() # g.gisenv
         self._initGisEnv() # g.gisenv
         self.GetWindow()
         self.GetWindow()
         # GRASS environment variable (for rendering)
         # GRASS environment variable (for rendering)
-        os.environ["GRASS_TRANSPARENT"] = "TRUE"
-        os.environ["GRASS_BACKGROUNDCOLOR"] = "ffffff"
+        env = {"GRASS_TRANSPARENT"     : "TRUE",
+               "GRASS_BACKGROUNDCOLOR" : "FFFFFF",
+               # "GRASS_PNG_AUTO_WRITE"  : "TRUE",
+               "GRASS_COMPRESSION"     : "0",
+               "GRASS_TRUECOLOR"       : "TRUE" }
+        if self.cmdfile:
+            env["GRASS_PNG_READ"] = "TRUE"
+        else:
+            env["GRASS_PNG_READ"] = "FALSE"
+        
+        self._writeEnvFile(env)
+        for k, v in env.iteritems():
+            os.environ[k] = v
         
         
         # projection info
         # projection info
         self.projinfo = self._projInfo()
         self.projinfo = self._projInfo()
@@ -540,24 +544,47 @@ class Map(object):
             if self.region['s'] < -90.0:
             if self.region['s'] < -90.0:
                 self.region['s'] = -90.0
                 self.region['s'] = -90.0
         
         
+    def _writeEnvFile(self, data):
+        """!Write display-related variable to the file (used for
+        standalone app)
+        """
+        if not self.envfile:
+            return
+        
+        try:
+            fd = open(self.envfile, "r")
+            for line in fd.readlines():
+                key, value = line.split('=')
+                if key not in data.keys():
+                    data[key] = value
+            fd.close()
+            
+            fd = open(self.envfile, "w")
+            for k, v in data.iteritems():
+                fd.write('%s=%s\n' % (k.strip(), str(v).strip()))
+        except IOError, e:
+            grass.warning(_("Unable to open file '%s' for writting. Details: %s") % \
+                              (self.envfile, e))
+            return
+        
+        fd.close()
+        
     def ChangeMapSize(self, (width, height)):
     def ChangeMapSize(self, (width, height)):
         """!Change size of rendered map.
         """!Change size of rendered map.
         
         
         @param width,height map size
         @param width,height map size
-
-        @return True on success
-        @return False on failure
         """
         """
         try:
         try:
             self.width  = int(width)
             self.width  = int(width)
             self.height = int(height)
             self.height = int(height)
-            Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
-                          (self.width, self.height))
-            return True
         except:
         except:
             self.width  = 640
             self.width  = 640
             self.height = 480
             self.height = 480
-            return False
+
+        Debug.msg(2, "Map.ChangeMapSize(): width=%d, height=%d" % \
+                      (self.width, self.height))
+        self._writeEnvFile({'GRASS_WIDTH' : self.width,
+                            'GRASS_HEIGHT' : self.height})
         
         
     def GetRegion(self, rast = [], zoom = False, vect = [], regionName = None,
     def GetRegion(self, rast = [], zoom = False, vect = [], regionName = None,
                   n = None, s = None, e = None, w = None, default = False,
                   n = None, s = None, e = None, w = None, default = False,
@@ -800,15 +827,12 @@ class Map(object):
         # render map layers
         # render map layers
         ilayer = 1
         ilayer = 1
         for layer in self.layers + self.overlays:
         for layer in self.layers + self.overlays:
-            # skip dead or disabled map layers
-            if layer == None or layer.active == False:
+            # skip non-active map layers
+            if not layer or not layer.active:
                 continue
                 continue
             
             
-            # render if there is no mapfile
-            if force or \
-               layer.force_render or \
-               layer.mapfile == None or \
-               (not os.path.isfile(layer.mapfile) or not os.path.getsize(layer.mapfile)):
+            # render
+            if force or layer.force_render:
                 if not layer.Render():
                 if not layer.Render():
                     continue
                     continue
             
             
@@ -823,10 +847,49 @@ class Map(object):
                 maps.append(layer.mapfile)
                 maps.append(layer.mapfile)
                 masks.append(layer.maskfile)
                 masks.append(layer.maskfile)
                 opacities.append(str(layer.opacity))
                 opacities.append(str(layer.opacity))
-                
-            Debug.msg (3, "Map.Render() type=%s, layer=%s " % (layer.type, layer.name))
+            
+            Debug.msg(3, "Map.Render() type=%s, layer=%s " % (layer.type, layer.name))
             ilayer += 1
             ilayer += 1
         
         
+    def _parseCmdFile(self):
+        """!Parse cmd file for standalone application
+        """
+        try:
+            fd = open(self.cmdfile, 'r')
+            grass.try_remove(self.mapfile)
+            for cmd in fd.readlines():
+                cmdStr = cmd.strip().split(' ')
+                cmd = utils.CmdToTuple(cmdStr)
+                
+                gcmd.RunCommand(cmd[0], **cmd[1])
+        except IOError, e:
+            grass.warning(_("Unable to read cmdfile '%s'. Details: %s") % \
+                              (self.cmdfile, e))
+            return
+        
+        Debug.msg(1, "Map.__parseCmdFile(): cmdfile=%s" % self.cmdfile)
+        Debug.msg(1, "                      nlayers=%d" % len(self.layers))
+        
+        fd.close()
+        
+    def _renderCmdFile(self, force, windres):
+        if not force:
+            return self.mapfile
+        
+        os.environ["GRASS_REGION"] = self.SetRegion(windres)
+        currMon = grass.gisenv()['MONITOR']
+        if currMon != self.monitor:
+            gcmd.RunCommand('g.gisenv',
+                            set = 'MONITOR=%s' % self.monitor)
+                
+        self._parseCmdFile()
+        
+        if currMon != self.monitor:
+            gcmd.RunCommand('g.gisenv',
+                            set = 'MONITOR=%s' % currMon)
+            
+        return self.mapfile
+
     def Render(self, force = False, mapWindow = None, windres = False):
     def Render(self, force = False, mapWindow = None, windres = False):
         """!Creates final image composite
         """!Creates final image composite
         
         
@@ -839,9 +902,12 @@ class Map(object):
         
         
         @return name of file with rendered image or None
         @return name of file with rendered image or None
         """
         """
-        maps = []
-        masks = []
-        opacities = []
+        if self.cmdfile:
+            return self._renderCmdFile(force, windres)
+        
+        maps      = list()
+        masks     = list()
+        opacities = list()
         
         
         # use external gisrc if defined
         # use external gisrc if defined
         gisrc_orig = os.getenv("GISRC")
         gisrc_orig = os.getenv("GISRC")
@@ -852,9 +918,6 @@ class Map(object):
         os.environ["GRASS_REGION"] = self.SetRegion(windres)
         os.environ["GRASS_REGION"] = self.SetRegion(windres)
         os.environ["GRASS_WIDTH"]  = str(self.width)
         os.environ["GRASS_WIDTH"]  = str(self.width)
         os.environ["GRASS_HEIGHT"] = str(self.height)
         os.environ["GRASS_HEIGHT"] = str(self.height)
-	os.environ["GRASS_PNG_AUTO_WRITE"] = "TRUE"
-	os.environ["GRASS_COMPRESSION"] = "0"
-	os.environ["GRASS_TRUECOLOR"] = "TRUE"
         driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
         driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
         if driver == 'cairo':
         if driver == 'cairo':
             os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
             os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
@@ -863,12 +926,10 @@ class Map(object):
         else:
         else:
             os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
             os.environ["GRASS_RENDER_IMMEDIATE"] = "TRUE"
         
         
-        os.environ["GRASS_PNG_READ"] = "FALSE"
-        
         self._renderLayers(force, mapWindow, maps, masks, opacities)
         self._renderLayers(force, mapWindow, maps, masks, opacities)
-        
+
         # ugly hack for MSYS
         # ugly hack for MSYS
-        if not subprocess.mswindows:
+        if sys.platform != 'win32':
             mapstr = ",".join(maps)
             mapstr = ",".join(maps)
             maskstr = ",".join(masks)
             maskstr = ",".join(masks)
             mapoutstr = self.mapfile
             mapoutstr = self.mapfile
@@ -882,33 +943,18 @@ class Map(object):
                 maskstr += item.replace('\\', '/')
                 maskstr += item.replace('\\', '/')
             maskstr = maskstr.rstrip(',')
             maskstr = maskstr.rstrip(',')
             mapoutstr = self.mapfile.replace('\\', '/')
             mapoutstr = self.mapfile.replace('\\', '/')
-        
-        # compose command
+            
+        # run g.pngcomp to get composite image
         bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
         bgcolor = ':'.join(map(str, UserSettings.Get(group = 'display', key = 'bgcolor',
                                                      subkey = 'color')))
                                                      subkey = 'color')))
         
         
-        complist = ["g.pnmcomp",
-                    "in=%s" % ",".join(maps),
-                    "mask=%s" % ",".join(masks),
-                    "opacity=%s" % ",".join(opacities),
-                    "background=%s" % bgcolor,
-                    "width=%s" % str(self.width),
-                    "height=%s" % str(self.height),
-                    "output=%s" % self.mapfile]
-        
-        # render overlays
-        if tmp_region:
-            os.environ["GRASS_REGION"] = tmp_region
-        else:
-            del os.environ["GRASS_REGION"]
-        
         if maps:
         if maps:
-            # run g.pngcomp to get composite image
             ret = gcmd.RunCommand('g.pnmcomp',
             ret = gcmd.RunCommand('g.pnmcomp',
+                                  overwrite = True,
                                   input = '%s' % ",".join(maps),
                                   input = '%s' % ",".join(maps),
                                   mask = '%s' % ",".join(masks),
                                   mask = '%s' % ",".join(masks),
                                   opacity = '%s' % ",".join(opacities),
                                   opacity = '%s' % ",".join(opacities),
-                                  background = bgcolor,
+                                  bgcolor = bgcolor,
                                   width = self.width,
                                   width = self.width,
                                   height = self.height,
                                   height = self.height,
                                   output = self.mapfile)
                                   output = self.mapfile)
@@ -916,8 +962,14 @@ class Map(object):
             if ret != 0:
             if ret != 0:
                 print >> sys.stderr, _("ERROR: Rendering failed")
                 print >> sys.stderr, _("ERROR: Rendering failed")
                 return None
                 return None
-            
-            Debug.msg (3, "Map.Render() force=%s file=%s" % (force, self.mapfile))
+        
+        Debug.msg (3, "Map.Render() force=%s file=%s" % (force, self.mapfile))
+        
+        # back to original region
+        if tmp_region:
+            os.environ["GRASS_REGION"] = tmp_region
+        else:
+            del os.environ["GRASS_REGION"]
         
         
         # back to original gisrc
         # back to original gisrc
         if self.gisrc:
         if self.gisrc:
@@ -1228,43 +1280,23 @@ class Map(object):
         """
         """
         return self.DeleteLayer(overlay, overlay = True)
         return self.DeleteLayer(overlay, overlay = True)
 
 
+    def _clean(self, llist):
+        for layer in llist:
+            if layer.maskfile:
+                grass.try_remove(layer.maskfile)
+            if layer.mapfile:
+                grass.try_remove(layer.mapfile)
+            llist.remove(layer)
+        
     def Clean(self):
     def Clean(self):
         """!Clean layer stack - go trough all layers and remove them
         """!Clean layer stack - go trough all layers and remove them
         from layer list.
         from layer list.
 
 
-        Removes also l_mapfile and l_maskfile
-        
-        @return False on failure
-        @return True on success
+        Removes also mapfile and maskfile.
         """
         """
-        try:
-            dir = os.path.dirname(self.mapfile)
-            base = os.path.basename(self.mapfile).split('.')[0]
-            removepath = os.path.join(dir,base)+r'*'
-            for f in glob.glob(removepath):
-                os.remove(f)
-            for layer in self.layers:
-                if layer.mapfile:
-                    dir = os.path.dirname(layer.mapfile)
-                    base = os.path.basename(layer.mapfile).split('.')[0]
-                    removepath = os.path.join(dir,base)+r'*'
-                    for f in glob.glob(removepath):
-                        os.remove(f)
-                self.layers.remove(layer)
-            
-            for overlay in self.overlays:
-                if overlay.mapfile:
-                    dir = os.path.dirname(overlay.mapfile)
-                    base = os.path.basename(overlay.mapfile).split('.')[0]
-                    removepath = os.path.join(dir,base)+r'*'
-                    for f in glob.glob(removepath):
-                        os.remove(f)
-                self.overlays.remove(overlay)
-        except:
-            return False
+        self._clean(self.layers)
+        self._clean(self.overlays)
         
         
-        return True
-    
     def ReverseListOfLayers(self):
     def ReverseListOfLayers(self):
         """!Reverse list of layers"""
         """!Reverse list of layers"""
         return self.layers.reverse()
         return self.layers.reverse()

+ 2 - 1
gui/wxpython/gui_modules/toolbars.py

@@ -208,7 +208,8 @@ class MapToolbar(AbstractToolbar):
             log = self.parent.GetLayerManager().GetLogWindow()
             log = self.parent.GetLayerManager().GetLogWindow()
         
         
         if haveNviz:
         if haveNviz:
-            if not self.parent.GetLayerManager().existNviz:
+            if self.parent.GetLayerManager() and \
+                    not self.parent.GetLayerManager().existNviz:
                 choices.append(_('3D view'))
                 choices.append(_('3D view'))
                 self.toolId['3d'] = 1
                 self.toolId['3d'] = 1
             else:
             else:

+ 1 - 1
gui/wxpython/gui_modules/utils.py

@@ -480,7 +480,7 @@ def CmdToTuple(cmd):
     for item in cmd[1:]:
     for item in cmd[1:]:
         if '=' in item: # params
         if '=' in item: # params
             key, value = item.split('=', 1)
             key, value = item.split('=', 1)
-            dcmd[str(key)] = str(value)
+            dcmd[str(key)] = str(value).replace('"', '')
         elif item[:2] == '--': # long flags
         elif item[:2] == '--': # long flags
             flag = item[2:]
             flag = item[2:]
             if flag in ('verbose', 'quiet', 'overwrite'):
             if flag in ('verbose', 'quiet', 'overwrite'):

+ 1 - 3
gui/wxpython/wxgui.py

@@ -1687,14 +1687,12 @@ def main(argv = None):
 
 
     workspaceFile = process_opt(opts, args)[0]
     workspaceFile = process_opt(opts, args)[0]
 
 
-    #
     # run application
     # run application
-    #
     app = GMApp(workspaceFile)
     app = GMApp(workspaceFile)
     # suppress wxPython logs
     # suppress wxPython logs
     q = wx.LogNull()
     q = wx.LogNull()
 
 
     app.MainLoop()
     app.MainLoop()
-
+    
 if __name__ == "__main__":
 if __name__ == "__main__":
     sys.exit(main())
     sys.exit(main())