[GRASS-SVN] r30584 - in grass/trunk/gui/wxpython: . gui_modules

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Mar 16 11:45:31 EDT 2008


Author: martinl
Date: 2008-03-16 11:45:31 -0400 (Sun, 16 Mar 2008)
New Revision: 30584

Added:
   grass/trunk/gui/wxpython/gui_modules/goutput.py
Modified:
   grass/trunk/gui/wxpython/gui_modules/__init__.py
   grass/trunk/gui/wxpython/gui_modules/menuform.py
   grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
   grass/trunk/gui/wxpython/wxgui.py
Log:
wxGUI: building GUI dialog for modules is too slow now. First attempt to speed up the things.
GMConsole, GMStc, etc. moved to separate module called 'goutput'.
FIXME: calling wxHtmlWindow.LoadPage() is strangely slow.


Modified: grass/trunk/gui/wxpython/gui_modules/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/__init__.py	2008-03-16 15:29:33 UTC (rev 30583)
+++ grass/trunk/gui/wxpython/gui_modules/__init__.py	2008-03-16 15:45:31 UTC (rev 30584)
@@ -7,6 +7,7 @@
         "globalvar",
         "grassenv",
         "gselect",
+        "goutput",
         "histogram",
         "location_wizard",
         "mapdisp",

Added: grass/trunk/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/goutput.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/gui_modules/goutput.py	2008-03-16 15:45:31 UTC (rev 30584)
@@ -0,0 +1,461 @@
+"""
+ at package goutput
+
+ at brief Command output log widget
+
+Classes:
+ - GMConsole
+ - GMStc
+ - GMStdout
+ - GMStderr
+
+(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 Michael Barton (Arizona State University)
+Martin Landa <landa.martin gmail.com>
+"""
+
+import os
+import textwrap
+import time
+
+import wx
+import wx.stc
+
+import globalvar
+import gcmd
+from debug import Debug as Debug
+
+class GMConsole(wx.Panel):
+    """
+    Create and manage output console for commands entered on the
+    GIS Manager command line.
+    """
+    def __init__(self, parent, id=wx.ID_ANY, margin=False,
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE):
+        wx.Panel.__init__(self, parent, id, pos, size, style)
+
+        # initialize variables
+        self.Map             = None
+        self.parent          = parent # GMFrame
+        self.cmdThreads      = []     # list of running commands (alive or dead)
+
+        # progress bar
+        self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY,
+                                            range=100, pos=(110, 50), size=(-1, 25),
+                                            style=wx.GA_HORIZONTAL)
+
+        # text control for command output
+        self.cmd_output = GMStc(parent=self, id=wx.ID_ANY, margin=margin)
+        # redirect
+        self.cmd_stdout = GMStdout(self.cmd_output)
+        self.cmd_stderr = GMStderr(self.cmd_output,
+                                   self.console_progressbar)
+
+        # 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)
+
+        # output control 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)
+
+
+        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, border=0)
+
+        boxsizer1.Fit(self)
+        boxsizer1.SetSizeHints(self)
+
+        # set up event handler for any command thread results
+        gcmd.EVT_RESULT(self, self.OnResult)
+
+        # layout
+        self.SetAutoLayout(True)
+        self.SetSizer(boxsizer1)
+
+    def WriteCmdLog(self, line, pid=None):
+        """Write out line in selected style"""
+        self.cmd_output.GotoPos(self.cmd_output.GetEndStyled())
+        p1 = self.cmd_output.GetCurrentPos()
+        if pid:
+            line = '(' + str(pid) + ') ' + line
+        if len(line) < 80:
+            diff = 80 - len(line)
+            line += diff * ' '
+            line += '%s' % os.linesep
+            self.cmd_output.AddText(line)
+            self.cmd_output.EnsureCaretVisible()
+            p2 = self.cmd_output.GetCurrentPos()
+            self.cmd_output.StartStyling(p1, 0xff)
+            self.cmd_output.SetStyling(p2 - p1, self.cmd_output.StyleCommand)
+        
+    def RunCmd(self, command):
+        """
+        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).
+        """
+        
+        # map display window available ?
+        try:
+            curr_disp = self.parent.curr_page.maptree.mapdisplay
+            self.Map = curr_disp.GetRender()
+        except:
+            curr_disp = None
+
+        if len(self.GetListOfCmdThreads()) > 0:
+            # only one running command enabled (per GMConsole instance)
+            busy = wx.BusyInfo(message=_("Unable to run the command, another command is running..."),
+                               parent=self)
+            wx.Yield()
+            time.sleep(3)
+            busy.Destroy()
+            return 
+
+        # command given as a string ?
+        try:
+            cmdlist = command.strip().split(' ')
+        except:
+            cmdlist = command
+
+        if cmdlist[0] in globalvar.grassCmd['all']:
+            # send GRASS command without arguments to GUI command interface
+            # except display commands (they are handled differently)
+            if cmdlist[0][0:2] == "d.": # display GRASS commands
+                try:
+                    layertype = {'d.rast'         : 'raster',
+                                 'd.rgb'          : 'rgb',
+                                 'd.his'          : 'his',
+                                 'd.shaded'       : 'shaded',
+                                 'd.legend'       : 'rastleg',
+                                 'd.rast.arrow'   : 'rastarrow',
+                                 'd.rast.num'     : 'rastnum',
+                                 'd.vect'         : 'vector',
+                                 'd.vect.thematic': 'thememap',
+                                 'd.vect.chart'   : 'themechart',
+                                 'd.grid'         : 'grid',
+                                 'd.geodesic'     : 'geodesic',
+                                 'd.rhumbline'    : 'rhumb',
+                                 'd.labels'       : 'labels'}[cmdlist[0]]
+                except KeyError:
+                    wx.MessageBox(message=_("Command '%s' not yet implemented.") % cmdlist[0])
+                    return False
+
+                # add layer into layer tree
+                self.parent.curr_page.maptree.AddLayer(ltype=layertype,
+                                                       lcmd=cmdlist)
+
+            else: # other GRASS commands (r|v|g|...)
+                if self.parent.notebook.GetSelection() != 1:
+                    # select 'Command output' tab
+                    self.parent.notebook.SetSelection(1)
+                
+                # activate computational region (set with g.region)
+                # for all non-display commands.
+                tmpreg = os.getenv("GRASS_REGION")
+                os.unsetenv("GRASS_REGION")
+                if len(cmdlist) == 1:
+                    import menuform
+                    # process GRASS command without argument
+                    menuform.GUI().ParseCommand(cmdlist, parentframe=self)
+                else:
+                    # process GRASS command with argument
+                    self.cmdPID = len(self.cmdThreads)+1
+                    self.WriteCmdLog('%s' % ' '.join(cmdlist), pid=self.cmdPID)
+                    
+                    grassCmd = gcmd.Command(cmdlist, wait=False,
+                                            stdout=self.cmd_stdout,
+                                            stderr=self.cmd_stderr)
+                    
+                    self.cmdThreads.append(grassCmd.cmdThread)
+                    
+                    return grassCmd
+                # deactivate computational region and return to display settings
+                if tmpreg:
+                    os.environ["GRASS_REGION"] = tmpreg
+        else:
+            # Send any other command to the shell. Send output to
+            # console output window
+            if self.parent.notebook.GetSelection() != 1:
+                # select 'Command output' tab
+                self.parent.notebook.SetSelection(1)
+
+            print "$ " + ' '.join(cmdlist)
+            
+            # if command is not a GRASS command, treat it like a shell command
+            generalCmd = subprocess.Popen(cmdlist,
+                                          stdout=subprocess.PIPE,
+                                          stderr=subprocess.PIPE)
+            
+            for outline in generalCmd.stdout:
+                print outline
+                   
+            return None
+
+    def ClearHistory(self, event):
+        """Clear history of commands"""
+        self.cmd_output.ClearAll()
+        self.console_progressbar.SetValue(0)
+
+    def SaveHistory(self, event):
+        """Save history of commands"""
+        self.history = self.cmd_output.GetSelectedText()
+        if self.history == '':
+            self.history = self.cmd_output.GetText()
+
+        # add newline if needed
+        if len(self.history) > 0 and self.history[-1] != os.linesep:
+            self.history += os.linesep
+
+        wildcard = "Text file (*.txt)|*.txt"
+        dlg = wx.FileDialog(
+            self, message=_("Save file as..."), defaultDir=os.getcwd(),
+            defaultFile="grass_cmd_history.txt", wildcard=wildcard,
+            style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
+
+        # Show the dialog and retrieve the user response. If it is the OK response,
+        # process the data.
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+
+            output = open(path, "w")
+            output.write(self.history)
+            output.close()
+
+        dlg.Destroy()
+
+    def GetListOfCmdThreads(self, onlyAlive=True):
+        """Return list of command threads)"""
+        list = []
+        for t in self.cmdThreads:
+            Debug.msg (4, "GMConsole.GetListOfCmdThreads(): name=%s, alive=%s" %
+                       (t.getName(), t.isAlive()))
+            if onlyAlive and not t.isAlive():
+                continue
+            list.append(t)
+
+        return list
+
+    def OnResult(self, event):
+        """Show result status"""
+        if event.cmdThread is None:
+            # Thread aborted (using our convention of None return)
+            self.WriteCmdLog(_('Command aborted'),
+                             pid=self.cmdPID)
+        else:
+            # Process results here
+            self.WriteCmdLog(_('Command finished (%d sec)') % (time.time() - event.cmdThread.startTime),
+                             pid=self.cmdPID)
+
+        self.console_progressbar.SetValue(0) # reset progress bar on '0%'
+        if hasattr(self.parent.parent, "btn_run"): # menuform.mainFrame
+            dialog = self.parent.parent
+            dialog.btn_run.Enable(True)
+            if dialog.get_dcmd is None and \
+                   dialog.closebox.IsChecked():
+                time.sleep(1)
+                dialog.Close()
+
+class GMStdout:
+    """GMConsole standard output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, gmstc):
+        self.gmstc  = gmstc
+
+    def write(self, s):
+        if len(s) == 0:
+            return
+        s = s.replace('\n', os.linesep)
+        for line in s.split(os.linesep):
+            p1 = self.gmstc.GetCurrentPos() # get caret position
+            self.gmstc.AddTextWrapped(line)
+            self.gmstc.EnsureCaretVisible()
+            p2 = self.gmstc.GetCurrentPos()
+            self.gmstc.StartStyling(p1, 0xff)
+            self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleOutput)
+
+class GMStderr:
+    """GMConsole standard error output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, gmstc, gmgauge):
+        self.gmstc   = gmstc
+        self.gmgauge = gmgauge
+
+    def write(self, s):
+        s = s.replace('\n', os.linesep)
+        message = ''
+        for line in s.split(os.linesep):
+            if len(line) == 0:
+                continue
+
+            if 'GRASS_INFO_PERCENT' in line:
+                # 'GRASS_INFO_PERCENT: 10' -> value=10
+                value = int(line.split(':')[1].strip())
+                if value < 100:
+                    self.gmgauge.SetValue(value)
+                else:
+                    self.gmgauge.SetValue(0) # reset progress bar on '0%'
+            elif 'GRASS_INFO_MESSAGE' in line:
+                type = 'message'
+                message += line.split(':')[1].strip()
+            elif 'GRASS_INFO_WARNING' in line:
+                type = 'warning'
+                message += line.split(':')[1].strip()
+            elif 'GRASS_INFO_ERROR' in line:
+                type = 'error'
+                message += line.split(':')[1].strip()
+            elif 'GRASS_INFO_END' in line:
+                message = ''
+            else:
+                if len(line) > 0:
+                    p1 = self.gmstc.GetCurrentPos()
+                    self.gmstc.AddTextWrapped(line)
+                    self.gmstc.EnsureCaretVisible()
+                    p2 = self.gmstc.GetCurrentPos()
+                    self.gmstc.StartStyling(p1, 0xff)
+                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleUnknown)
+
+            if len(message) > 0:
+                p1 = self.gmstc.GetCurrentPos()
+                if type == 'warning':
+                    message = 'WARNING: ' + message
+                elif type == 'error':
+                    message = 'ERROR: ' + message
+                self.gmstc.AddTextWrapped(message)
+                self.gmstc.EnsureCaretVisible()
+                p2 = self.gmstc.GetCurrentPos()
+                self.gmstc.StartStyling(p1, 0xff)
+                if type == 'error':
+                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError)
+                elif type == 'warning':
+                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleWarning)
+                elif type == 'message':
+                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleMessage)
+
+class GMStc(wx.stc.StyledTextCtrl):
+    """Styled GMConsole
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """    
+    def __init__(self, parent, id, margin=False):
+        wx.stc.StyledTextCtrl.__init__(self, parent, id)
+        self.parent = parent
+        
+        #
+        # 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:#7F0000,back:#FFFFFF"
+        
+        # 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
+        #
+        # TODO print number only from cmdlog
+        self.SetMarginWidth(1, 0)
+        self.SetMarginWidth(2, 0)
+        if margin:
+            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+            self.SetMarginWidth(0, 30)
+        else:
+            self.SetMarginWidth(0, 0)
+
+        #
+        # miscellaneous
+        #
+        self.SetViewWhiteSpace(False)
+        self.SetTabWidth(4)
+        self.SetUseTabs(False)
+        self.UsePopUp(True)
+        self.SetSelBackground(True, "#FFFF00")
+        self.SetUseHorizontalScrollBar(True)
+
+        #
+        # bindins
+        #
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+
+    def OnDestroy(self, evt):
+        """The clipboard contents can be preserved after
+        the app has exited"""
+        
+        wx.TheClipboard.Flush()
+        evt.Skip()
+
+    def AddTextWrapped(self, str, wrap=80):
+        """Add string to text area.
+
+        String is wrapped and linesep is also added to the end
+        of the string"""
+        str = textwrap.fill(str, wrap) + os.linesep
+        self.AddText(str)

Modified: grass/trunk/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menuform.py	2008-03-16 15:29:33 UTC (rev 30583)
+++ grass/trunk/gui/wxpython/gui_modules/menuform.py	2008-03-16 15:45:31 UTC (rev 30584)
@@ -88,21 +88,16 @@
 import grassenv
 import gselect
 import gcmd
-import wxgui_utils
+import goutput
+import utils
 from preferences import globalSettings as UserSettings
 try:
     import subprocess
 except:
     from compat import subprocess
 
-def reexec_with_pythonw():
-    if sys.platform == 'darwin' and\
-        not sys.executable.endswith('MacOS/Python'):
-        print >>sys.stderr,'re-executing using pythonw'
-        os.execvp('pythonw',['pythonw',__file__] + sys.argv[1:])
+utils.reexec_with_pythonw()
 
-reexec_with_pythonw()
-
 ID_ABOUT_COMMAND = 102
 
 #
@@ -479,6 +474,7 @@
 
         If 'text' is given, it must be the HTML text to be presented in the Panel.
         """
+
         wx.html.HtmlWindow.__init__(self, *args, **kwargs)
         self.fspath = gisbase + "/docs/html/"
         self.SetStandardFonts ( size = 10 )
@@ -490,6 +486,7 @@
                 self.fillContentsFromFile ( self.fspath + grass_command + ".html",
                                             skip_description=skip_description )
             else:
+                ### FIXME: calling self.LoadPage is too time costly (why?)
                 self.LoadPage(self.fspath + grass_command + ".html")
                 self.Ok = True
         else:
@@ -879,7 +876,7 @@
         # are we running from command line?
         ### add 'command output' tab regardless standalone dialog
         #        if standalone:
-        self.goutput = wxgui_utils.GMConsole(parent=self, margin=False)
+        self.goutput = goutput.GMConsole(parent=self, margin=False)
         self.outpage = self.notebook.AddPage(self.goutput, text=_("Command output") )
         self.outpageid = self.notebook.GetPageCount() - 1
 

Modified: grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py	2008-03-16 15:29:33 UTC (rev 30583)
+++ grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py	2008-03-16 15:45:31 UTC (rev 30584)
@@ -28,13 +28,10 @@
 import os
 import sys
 import string
-import time
-import textwrap
 
 import wx
 import wx.lib.customtreectrl as CT
 import wx.combo
-import wx.stc
 import wx.lib.newevent
 
 import globalvar
@@ -1017,436 +1014,6 @@
 
         return None
 
-class GMConsole(wx.Panel):
-    """
-    Create and manage output console for commands entered on the
-    GIS Manager command line.
-    """
-    def __init__(self, parent, id=wx.ID_ANY, margin=False,
-                 pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE):
-        wx.Panel.__init__(self, parent, id, pos, size, style)
-
-        # initialize variables
-        self.Map             = None
-        self.parent          = parent # GMFrame
-        self.cmdThreads      = []     # list of running commands (alive or dead)
-
-        # progress bar
-        self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY,
-                                            range=100, pos=(110, 50), size=(-1, 25),
-                                            style=wx.GA_HORIZONTAL)
-
-        # text control for command output
-        self.cmd_output = GMStc(parent=self, id=wx.ID_ANY, margin=margin)
-        # redirect
-        self.cmd_stdout = GMStdout(self.cmd_output)
-        self.cmd_stderr = GMStderr(self.cmd_output,
-                                   self.console_progressbar)
-
-        # 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)
-
-        # output control 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)
-
-
-        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, border=0)
-
-        boxsizer1.Fit(self)
-        boxsizer1.SetSizeHints(self)
-
-        # set up event handler for any command thread results
-        gcmd.EVT_RESULT(self, self.OnResult)
-
-        # layout
-        self.SetAutoLayout(True)
-        self.SetSizer(boxsizer1)
-
-    def WriteCmdLog(self, line, pid=None):
-        """Write out line in selected style"""
-        self.cmd_output.GotoPos(self.cmd_output.GetEndStyled())
-        p1 = self.cmd_output.GetCurrentPos()
-        if pid:
-            line = '(' + str(pid) + ') ' + line
-        if len(line) < 80:
-            diff = 80 - len(line)
-            line += diff * ' '
-            line += '%s' % os.linesep
-            self.cmd_output.AddText(line)
-            self.cmd_output.EnsureCaretVisible()
-            p2 = self.cmd_output.GetCurrentPos()
-            self.cmd_output.StartStyling(p1, 0xff)
-            self.cmd_output.SetStyling(p2 - p1, self.cmd_output.StyleCommand)
-        
-    def RunCmd(self, command):
-        """
-        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).
-        """
-        
-        # map display window available ?
-        try:
-            curr_disp = self.parent.curr_page.maptree.mapdisplay
-            self.Map = curr_disp.GetRender()
-        except:
-            curr_disp = None
-
-        if len(self.GetListOfCmdThreads()) > 0:
-            # only one running command enabled (per GMConsole instance)
-            busy = wx.BusyInfo(message=_("Unable to run the command, another command is running..."),
-                               parent=self)
-            wx.Yield()
-            time.sleep(3)
-            busy.Destroy()
-            return 
-
-        # command given as a string ?
-        try:
-            cmdlist = command.strip().split(' ')
-        except:
-            cmdlist = command
-
-        if cmdlist[0] in globalvar.grassCmd['all']:
-            # send GRASS command without arguments to GUI command interface
-            # except display commands (they are handled differently)
-            if cmdlist[0][0:2] == "d.": # display GRASS commands
-                try:
-                    layertype = {'d.rast'         : 'raster',
-                                 'd.rgb'          : 'rgb',
-                                 'd.his'          : 'his',
-                                 'd.shaded'       : 'shaded',
-                                 'd.legend'       : 'rastleg',
-                                 'd.rast.arrow'   : 'rastarrow',
-                                 'd.rast.num'     : 'rastnum',
-                                 'd.vect'         : 'vector',
-                                 'd.vect.thematic': 'thememap',
-                                 'd.vect.chart'   : 'themechart',
-                                 'd.grid'         : 'grid',
-                                 'd.geodesic'     : 'geodesic',
-                                 'd.rhumbline'    : 'rhumb',
-                                 'd.labels'       : 'labels'}[cmdlist[0]]
-                except KeyError:
-                    wx.MessageBox(message=_("Command '%s' not yet implemented.") % cmdlist[0])
-                    return False
-
-                # add layer into layer tree
-                self.parent.curr_page.maptree.AddLayer(ltype=layertype,
-                                                       lcmd=cmdlist)
-
-            else: # other GRASS commands (r|v|g|...)
-                if self.parent.notebook.GetSelection() != 1:
-                    # select 'Command output' tab
-                    self.parent.notebook.SetSelection(1)
-                
-                # activate computational region (set with g.region)
-                # for all non-display commands.
-                tmpreg = os.getenv("GRASS_REGION")
-                os.unsetenv("GRASS_REGION")
-                if len(cmdlist) == 1:
-                    # process GRASS command without argument
-                    menuform.GUI().ParseCommand(cmdlist, parentframe=self)
-                else:
-                    # process GRASS command with argument
-                    self.cmdPID = len(self.cmdThreads)+1
-                    self.WriteCmdLog('%s' % ' '.join(cmdlist), pid=self.cmdPID)
-                    
-                    grassCmd = gcmd.Command(cmdlist, wait=False,
-                                            stdout=self.cmd_stdout,
-                                            stderr=self.cmd_stderr)
-                    
-                    self.cmdThreads.append(grassCmd.cmdThread)
-                    
-                    return grassCmd
-                # deactivate computational region and return to display settings
-                if tmpreg:
-                    os.environ["GRASS_REGION"] = tmpreg
-        else:
-            # Send any other command to the shell. Send output to
-            # console output window
-            if self.parent.notebook.GetSelection() != 1:
-                # select 'Command output' tab
-                self.parent.notebook.SetSelection(1)
-
-            print "$ " + ' '.join(cmdlist)
-            
-            # if command is not a GRASS command, treat it like a shell command
-            generalCmd = subprocess.Popen(cmdlist,
-                                          stdout=subprocess.PIPE,
-                                          stderr=subprocess.PIPE)
-            
-            for outline in generalCmd.stdout:
-                print outline
-                   
-            return None
-
-    def ClearHistory(self, event):
-        """Clear history of commands"""
-        self.cmd_output.ClearAll()
-        self.console_progressbar.SetValue(0)
-
-    def SaveHistory(self, event):
-        """Save history of commands"""
-        self.history = self.cmd_output.GetSelectedText()
-        if self.history == '':
-            self.history = self.cmd_output.GetText()
-
-        # add newline if needed
-        if len(self.history) > 0 and self.history[-1] != os.linesep:
-            self.history += os.linesep
-
-        wildcard = "Text file (*.txt)|*.txt"
-        dlg = wx.FileDialog(
-            self, message=_("Save file as..."), defaultDir=os.getcwd(),
-            defaultFile="grass_cmd_history.txt", wildcard=wildcard,
-            style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
-
-        # Show the dialog and retrieve the user response. If it is the OK response,
-        # process the data.
-        if dlg.ShowModal() == wx.ID_OK:
-            path = dlg.GetPath()
-
-            output = open(path, "w")
-            output.write(self.history)
-            output.close()
-
-        dlg.Destroy()
-
-    def GetListOfCmdThreads(self, onlyAlive=True):
-        """Return list of command threads)"""
-        list = []
-        for t in self.cmdThreads:
-            Debug.msg (4, "GMConsole.GetListOfCmdThreads(): name=%s, alive=%s" %
-                       (t.getName(), t.isAlive()))
-            if onlyAlive and not t.isAlive():
-                continue
-            list.append(t)
-
-        return list
-
-    def OnResult(self, event):
-        """Show result status"""
-        if event.cmdThread is None:
-            # Thread aborted (using our convention of None return)
-            self.WriteCmdLog(_('Command aborted'),
-                             pid=self.cmdPID)
-        else:
-            # Process results here
-            self.WriteCmdLog(_('Command finished (%d sec)') % (time.time() - event.cmdThread.startTime),
-                             pid=self.cmdPID)
-
-        self.console_progressbar.SetValue(0) # reset progress bar on '0%'
-        if hasattr(self.parent.parent, "btn_run"): # menuform.mainFrame
-            dialog = self.parent.parent
-            dialog.btn_run.Enable(True)
-            if dialog.get_dcmd is None and \
-                   dialog.closebox.IsChecked():
-                time.sleep(1)
-                dialog.Close()
-
-class GMStdout:
-    """GMConsole standard output
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, gmstc):
-        self.gmstc  = gmstc
-
-    def write(self, s):
-        if len(s) == 0:
-            return
-        s = s.replace('\n', os.linesep)
-        for line in s.split(os.linesep):
-            p1 = self.gmstc.GetCurrentPos() # get caret position
-            self.gmstc.AddTextWrapped(line)
-            self.gmstc.EnsureCaretVisible()
-            p2 = self.gmstc.GetCurrentPos()
-            self.gmstc.StartStyling(p1, 0xff)
-            self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleOutput)
-
-class GMStderr:
-    """GMConsole standard error output
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, gmstc, gmgauge):
-        self.gmstc   = gmstc
-        self.gmgauge = gmgauge
-
-    def write(self, s):
-        s = s.replace('\n', os.linesep)
-        message = ''
-        for line in s.split(os.linesep):
-            if len(line) == 0:
-                continue
-
-            if 'GRASS_INFO_PERCENT' in line:
-                # 'GRASS_INFO_PERCENT: 10' -> value=10
-                value = int(line.split(':')[1].strip())
-                if value < 100:
-                    self.gmgauge.SetValue(value)
-                else:
-                    self.gmgauge.SetValue(0) # reset progress bar on '0%'
-            elif 'GRASS_INFO_MESSAGE' in line:
-                type = 'message'
-                message += line.split(':')[1].strip()
-            elif 'GRASS_INFO_WARNING' in line:
-                type = 'warning'
-                message += line.split(':')[1].strip()
-            elif 'GRASS_INFO_ERROR' in line:
-                type = 'error'
-                message += line.split(':')[1].strip()
-            elif 'GRASS_INFO_END' in line:
-                message = ''
-            else:
-                if len(line) > 0:
-                    p1 = self.gmstc.GetCurrentPos()
-                    self.gmstc.AddTextWrapped(line)
-                    self.gmstc.EnsureCaretVisible()
-                    p2 = self.gmstc.GetCurrentPos()
-                    self.gmstc.StartStyling(p1, 0xff)
-                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleUnknown)
-
-            if len(message) > 0:
-                p1 = self.gmstc.GetCurrentPos()
-                if type == 'warning':
-                    message = 'WARNING: ' + message
-                elif type == 'error':
-                    message = 'ERROR: ' + message
-                self.gmstc.AddTextWrapped(message)
-                self.gmstc.EnsureCaretVisible()
-                p2 = self.gmstc.GetCurrentPos()
-                self.gmstc.StartStyling(p1, 0xff)
-                if type == 'error':
-                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleError)
-                elif type == 'warning':
-                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleWarning)
-                elif type == 'message':
-                    self.gmstc.SetStyling(p2 - p1 + 1, self.gmstc.StyleMessage)
-
-class GMStc(wx.stc.StyledTextCtrl):
-    """Styled GMConsole
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """    
-    def __init__(self, parent, id, margin=False):
-        wx.stc.StyledTextCtrl.__init__(self, parent, id)
-        self.parent = parent
-        
-        #
-        # 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:#7F0000,back:#FFFFFF"
-        
-        # 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
-        #
-        # TODO print number only from cmdlog
-        self.SetMarginWidth(1, 0)
-        self.SetMarginWidth(2, 0)
-        if margin:
-            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
-            self.SetMarginWidth(0, 30)
-        else:
-            self.SetMarginWidth(0, 0)
-
-        #
-        # miscellaneous
-        #
-        self.SetViewWhiteSpace(False)
-        self.SetTabWidth(4)
-        self.SetUseTabs(False)
-        self.UsePopUp(True)
-        self.SetSelBackground(True, "#FFFF00")
-        self.SetUseHorizontalScrollBar(True)
-
-        #
-        # bindins
-        #
-        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
-
-    def OnDestroy(self, evt):
-        """The clipboard contents can be preserved after
-        the app has exited"""
-        
-        wx.TheClipboard.Flush()
-        evt.Skip()
-
-    def AddTextWrapped(self, str, wrap=80):
-        """Add string to text area.
-
-        String is wrapped and linesep is also added to the end
-        of the string"""
-        str = textwrap.fill(str, wrap) + os.linesep
-        self.AddText(str)
-
 class LoadMapLayersDialog(wx.Dialog):
     """Load selected map layers (raster, vector) into layer tree"""
     def __init__(self, parent, title, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):

Modified: grass/trunk/gui/wxpython/wxgui.py
===================================================================
--- grass/trunk/gui/wxpython/wxgui.py	2008-03-16 15:29:33 UTC (rev 30583)
+++ grass/trunk/gui/wxpython/wxgui.py	2008-03-16 15:45:31 UTC (rev 30584)
@@ -82,6 +82,7 @@
 import gui_modules.dbm as dbm
 import gui_modules.globalvar as globalvar
 import gui_modules.workspace as workspace
+import gui_modules.goutput as goutput
 from   gui_modules.debug import Debug as Debug
 from   icons.icon import Icons as Icons
 
@@ -281,7 +282,7 @@
         self.notebook.AddPage(self.gm_cb, text=_("Map layers for each display"))
 
         # create command output text area and add it to main notebook page
-        self.goutput = wxgui_utils.GMConsole(self)
+        self.goutput = goutput.GMConsole(self)
         self.outpage = self.notebook.AddPage(self.goutput, text=_("Command output"))
 
         # bingings



More information about the grass-commit mailing list