[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