[GRASS-SVN] r53989 - in grass/trunk/gui/wxpython: . core gmodeler gui_core lmgr psmap scripts
svn_grass at osgeo.org
svn_grass at osgeo.org
Fri Nov 23 06:54:53 PST 2012
Author: wenzeslaus
Date: 2012-11-23 06:54:53 -0800 (Fri, 23 Nov 2012)
New Revision: 53989
Added:
grass/trunk/gui/wxpython/core/gconsole.py
Modified:
grass/trunk/gui/wxpython/gmodeler/frame.py
grass/trunk/gui/wxpython/gui_core/forms.py
grass/trunk/gui/wxpython/gui_core/goutput.py
grass/trunk/gui/wxpython/lmgr/frame.py
grass/trunk/gui/wxpython/lmgr/giface.py
grass/trunk/gui/wxpython/psmap/frame.py
grass/trunk/gui/wxpython/scripts/vkrige.py
grass/trunk/gui/wxpython/wxpythonlib.dox
Log:
wxGUI/GConsole: splitted into two classes GConsole (logic) and GConsoleWindow (GUI) (co-author: annakrat)
Added: grass/trunk/gui/wxpython/core/gconsole.py
===================================================================
--- grass/trunk/gui/wxpython/core/gconsole.py (rev 0)
+++ grass/trunk/gui/wxpython/core/gconsole.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -0,0 +1,640 @@
+"""!
+ at package core.gconsole
+
+ at brief Command output widgets
+
+Classes:
+ - goutput::CmdThread
+ - goutput::GStdout
+ - goutput::GStderr
+ - goutput::GConsole
+
+(C) 2007-2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (refactoring)
+"""
+
+import os
+import sys
+import re
+import time
+import threading
+import Queue
+import codecs
+import locale
+
+import wx
+from wx.lib.newevent import NewEvent
+
+import grass.script as grass
+from grass.script import task as gtask
+
+from core import globalvar
+from core.gcmd import CommandThread, GError, GException
+from core.events import gMapCreated
+from gui_core.forms import GUI
+from core.debug import Debug
+from core.settings import UserSettings
+
+
+wxCmdOutput, EVT_CMD_OUTPUT = NewEvent()
+wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
+wxCmdRun, EVT_CMD_RUN = NewEvent()
+wxCmdDone, EVT_CMD_DONE = NewEvent()
+wxCmdAbort, EVT_CMD_ABORT = NewEvent()
+wxCmdPrepare, EVT_CMD_PREPARE = NewEvent()
+
+
+def GrassCmd(cmd, env=None, stdout=None, stderr=None):
+ """!Return GRASS command thread"""
+ return CommandThread(cmd, env=env,
+ stdout=stdout, stderr=stderr)
+
+
+class CmdThread(threading.Thread):
+ """!Thread for GRASS commands"""
+ requestId = 0
+
+ def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
+ """!
+ @param receiver event receiver (used in PostEvent)
+ """
+ threading.Thread.__init__(self, **kwds)
+
+ if requestQ is None:
+ self.requestQ = Queue.Queue()
+ else:
+ self.requestQ = requestQ
+
+ if resultQ is None:
+ self.resultQ = Queue.Queue()
+ else:
+ self.resultQ = resultQ
+
+ self.setDaemon(True)
+
+ self.receiver = receiver
+ self._want_abort_all = False
+
+ self.start()
+
+ def RunCmd(self, *args, **kwds):
+ """!Run command in queue
+
+ @param args unnamed command arguments
+ @param kwds named command arguments
+
+ @return request id in queue
+ """
+ CmdThread.requestId += 1
+
+ self.requestCmd = None
+ self.requestQ.put((CmdThread.requestId, args, kwds))
+
+ return CmdThread.requestId
+
+ def SetId(self, id):
+ """!Set starting id"""
+ CmdThread.requestId = id
+
+ def run(self):
+ os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
+ while True:
+ requestId, args, kwds = self.requestQ.get()
+ for key in ('callable', 'onDone', 'onPrepare', 'userData'):
+ if key in kwds:
+ vars()[key] = kwds[key]
+ del kwds[key]
+ else:
+ vars()[key] = None
+
+ if not vars()['callable']:
+ vars()['callable'] = GrassCmd
+
+ requestTime = time.time()
+
+ # prepare
+ event = wxCmdPrepare(cmd=args[0],
+ time=requestTime,
+ pid=requestId,
+ onPrepare=vars()['onPrepare'],
+ userData=vars()['userData'])
+ wx.PostEvent(self.receiver, event)
+
+ # run command
+ event = wxCmdRun(cmd=args[0],
+ pid=requestId)
+
+ wx.PostEvent(self.receiver, event)
+
+ time.sleep(.1)
+ self.requestCmd = vars()['callable'](*args, **kwds)
+ if self._want_abort_all:
+ self.requestCmd.abort()
+ if self.requestQ.empty():
+ self._want_abort_all = False
+
+ self.resultQ.put((requestId, self.requestCmd.run()))
+
+ try:
+ returncode = self.requestCmd.module.returncode
+ except AttributeError:
+ returncode = 0 # being optimistic
+
+ try:
+ aborted = self.requestCmd.aborted
+ except AttributeError:
+ aborted = False
+
+ time.sleep(.1)
+
+ # set default color table for raster data
+ if UserSettings.Get(group='rasterLayer',
+ key='colorTable', subkey='enabled') and \
+ args[0][0][:2] == 'r.':
+ colorTable = UserSettings.Get(group='rasterLayer',
+ key='colorTable',
+ subkey='selection')
+ mapName = None
+ if args[0][0] == 'r.mapcalc':
+ try:
+ mapName = args[0][1].split('=', 1)[0].strip()
+ except KeyError:
+ pass
+ else:
+ moduleInterface = GUI(show=None).ParseCommand(args[0])
+ outputParam = moduleInterface.get_param(value='output',
+ raiseError=False)
+ if outputParam and outputParam['prompt'] == 'raster':
+ mapName = outputParam['value']
+
+ if mapName:
+ argsColor = list(args)
+ argsColor[0] = ['r.colors',
+ 'map=%s' % mapName,
+ 'color=%s' % colorTable]
+ self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
+ self.resultQ.put((requestId, self.requestCmdColor.run()))
+
+ event = wxCmdDone(cmd=args[0],
+ aborted=aborted,
+ returncode=returncode,
+ time=requestTime,
+ pid=requestId,
+ onDone=vars()['onDone'],
+ userData=vars()['userData'])
+
+ # send event
+ wx.PostEvent(self.receiver, event)
+
+ def abort(self, abortall=True):
+ """!Abort command(s)"""
+ if abortall:
+ self._want_abort_all = True
+ self.requestCmd.abort()
+ if self.requestQ.empty():
+ self._want_abort_all = False
+
+
+class GStdout:
+ """!GConsole 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, receiver):
+ """!
+ @param receiver event receiver (used in PostEvent)
+ """
+ self.receiver = receiver
+
+ def write(self, s):
+ if len(s) == 0 or s == '\n':
+ return
+
+ for line in s.splitlines():
+ if len(line) == 0:
+ continue
+
+ evt = wxCmdOutput(text=line + '\n',
+ type='')
+ wx.PostEvent(self.receiver, evt)
+
+
+class GStderr:
+ """!GConsole 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, receiver):
+ """!
+ @param receiver event receiver (used in PostEvent)
+ """
+ self.receiver = receiver
+ self.type = ''
+ self.message = ''
+ self.printMessage = False
+
+ def flush(self):
+ pass
+
+ def write(self, s):
+ if "GtkPizza" in s:
+ return
+
+ # remove/replace escape sequences '\b' or '\r' from stream
+ progressValue = -1
+
+ for line in s.splitlines():
+ if len(line) == 0:
+ continue
+
+ if 'GRASS_INFO_PERCENT' in line:
+ value = int(line.rsplit(':', 1)[1].strip())
+ if value >= 0 and value < 100:
+ progressValue = value
+ else:
+ progressValue = 0
+ elif 'GRASS_INFO_MESSAGE' in line:
+ self.type = 'message'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_WARNING' in line:
+ self.type = 'warning'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_ERROR' in line:
+ self.type = 'error'
+ self.message += line.split(':', 1)[1].strip() + '\n'
+ elif 'GRASS_INFO_END' in line:
+ self.printMessage = True
+ elif self.type == '':
+ if len(line) == 0:
+ continue
+ evt = wxCmdOutput(text=line,
+ type='')
+ wx.PostEvent(self.receiver, evt)
+ elif len(line) > 0:
+ self.message += line.strip() + '\n'
+
+ if self.printMessage and len(self.message) > 0:
+ evt = wxCmdOutput(text=self.message,
+ type=self.type)
+ wx.PostEvent(self.receiver, evt)
+
+ self.type = ''
+ self.message = ''
+ self.printMessage = False
+
+ # update progress message
+ if progressValue > -1:
+ # self.gmgauge.SetValue(progressValue)
+ evt = wxCmdProgress(value=progressValue)
+ wx.PostEvent(self.receiver, evt)
+
+
+# events related to messages
+# TODO: create separete class for handling messages?
+gWriteLog, EVT_WRITE_LOG = NewEvent()
+gWriteCmdLog, EVT_WRITE_CMD_LOG = NewEvent()
+gWriteWarning, EVT_WRITE_WARNING = NewEvent()
+gWriteError, EVT_WRITE_ERROR = NewEvent()
+
+# Occurs when ignored command is called.
+# Attribute cmd contains command (as a list).
+gIgnoredCmdRun, EVT_IGNORED_CMD_RUN = NewEvent()
+
+
+class GConsole(wx.EvtHandler):
+ """!
+ """
+ def __init__(self, guiparent=None, lmgr=None, ignoredCmdPattern=None):
+ """!
+ @param guiparent parent window for created GUI objects
+ @param lmgr layer manager window (TODO: replace by giface)
+ @param ignoredCmdPattern regular expression specifying commads
+ to be ignored (e.g. @c '^d\..*' for display commands)
+ """
+ wx.EvtHandler.__init__(self)
+
+ self._guiparent = guiparent
+ self._lmgr = lmgr
+ self._ignoredCmdPattern = ignoredCmdPattern
+
+ # create queues
+ self.requestQ = Queue.Queue()
+ self.resultQ = Queue.Queue()
+
+ self.cmdOutputTimer = wx.Timer(self)
+ self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
+ self.Bind(EVT_CMD_RUN, self.OnCmdRun)
+ self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+ self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)
+
+ # stream redirection
+ self.cmdStdOut = GStdout(receiver=self)
+ self.cmdStdErr = GStderr(receiver=self)
+
+ # thread
+ self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
+
+ def Redirect(self):
+ """!Redirect stdout/stderr
+ """
+ if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
+ # don't redirect when debugging is enabled
+ sys.stdout = self.cmdStdOut
+ sys.stderr = self.cmdStdErr
+ else:
+ enc = locale.getdefaultlocale()[1]
+ if enc:
+ sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
+ sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
+ else:
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+
+ def WriteLog(self, text, style=None, wrap=None,
+ switchPage=False, priority=1):
+ """!Generic method for writing log message in
+ given style
+
+ @param line text line
+ @param switchPage for backward compatibility
+ (replace by priority: False=1, True=2)
+ @param priority priority of this message
+ (0=no priority, 1=normal, 2=medium, 3=high)
+ """
+ event = gWriteLog(text=text, wrap=wrap,
+ switchPage=switchPage, priority=priority)
+ wx.PostEvent(self, event)
+
+ def WriteCmdLog(self, line, pid=None, switchPage=True):
+ """!Write message in selected style
+
+ @param line message to be printed
+ @param pid process pid or None
+ @param switchPage True to switch page
+ """
+ event = gWriteCmdLog(line=line, pid=pid,
+ switchPage=switchPage)
+ wx.PostEvent(self, event)
+
+ def WriteWarning(self, line):
+ """!Write message in warning style"""
+ event = gWriteWarning(line=line)
+ wx.PostEvent(self, event)
+
+ def WriteError(self, line):
+ """!Write message in error style"""
+ event = gWriteError(line=line)
+ wx.PostEvent(self, event)
+
+ def RunCmd(self, command, compReg=True, switchPage=False, skipInterface=False,
+ onDone=None, onPrepare=None, userData=None):
+ """!Run command typed into console command prompt (GPrompt).
+
+ @todo Document the other event.
+ @todo Solve problem with the other event
+ (now uses gOutputText event but there is no text,
+ use onPrepare handler instead?)
+
+ Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
+ (according to ignoredCmdPattern) is run.
+ For example, see layer manager which handles d.* on its own.
+
+ @todo all switchPage and priority params are currently broken in this class)
+
+ @param command command given as a list (produced e.g. by utils.split())
+ @param compReg True use computation region
+ @param switchPage switch to output page
+ @param skipInterface True to do not launch GRASS interface
+ parser when command has no arguments given
+ @param onDone function to be called when command is finished
+ @param onPrepare function to be called before command is launched
+ @param userData data defined for the command
+ """
+ if len(command) == 0:
+ Debug.msg(2, "GPrompt:RunCmd(): empty command")
+ return
+
+ # update history file
+ env = grass.gisenv()
+ try:
+ filePath = os.path.join(env['GISDBASE'],
+ env['LOCATION_NAME'],
+ env['MAPSET'],
+ '.bash_history')
+ fileHistory = codecs.open(filePath, encoding='utf-8', mode='a')
+ except IOError, e:
+ GError(_("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") %
+ {'filePath': filePath, 'error': e},
+ parent=self._guiparent)
+ fileHistory = None
+
+ if fileHistory:
+ try:
+ fileHistory.write(' '.join(command) + os.linesep)
+ finally:
+ fileHistory.close()
+
+ if command[0] in globalvar.grassCmd:
+ # send GRASS command without arguments to GUI command interface
+ # except ignored commands (event is emitted)
+
+ if self._ignoredCmdPattern and \
+ re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
+ '--help' not in command:
+ event = gIgnoredCmdRun(cmd=command)
+ wx.PostEvent(self, event)
+ return
+
+ else:
+ # other GRASS commands (r|v|g|...)
+ try:
+ task = GUI(show=None).ParseCommand(command)
+ except GException, e:
+ GError(parent=self._guiparent,
+ message=unicode(e),
+ showTraceback=False)
+ return
+
+ hasParams = False
+ if task:
+ options = task.get_options()
+ hasParams = options['params'] and options['flags']
+ # check for <input>=-
+ for p in options['params']:
+ if p.get('prompt', '') == 'input' and \
+ p.get('element', '') == 'file' and \
+ p.get('age', 'new') == 'old' and \
+ p.get('value', '') == '-':
+ GError(parent=self._guiparent,
+ message=_("Unable to run command:\n%(cmd)s\n\n"
+ "Option <%(opt)s>: read from standard input is not "
+ "supported by wxGUI") % {'cmd': ' '.join(command),
+ 'opt': p.get('name', '')})
+ return
+
+ if len(command) == 1 and hasParams and \
+ command[0] != 'v.krige':
+ # no arguments given
+ try:
+ GUI(parent = self._guiparent, lmgr = self._lmgr).ParseCommand(command)
+ except GException, e:
+ print >> sys.stderr, e
+ return
+
+ # documenting old behavior/implementation:
+ # switch and focus if required
+ # TODO: this probably should be run command event
+ # TODO: this should be solved by the user using userData and onDone
+
+ # activate computational region (set with g.region)
+ # for all non-display commands.
+ if compReg:
+ tmpreg = os.getenv("GRASS_REGION")
+ if "GRASS_REGION" in os.environ:
+ del os.environ["GRASS_REGION"]
+
+ # process GRASS command with argument
+ self.cmdThread.RunCmd(command,
+ stdout=self.cmdStdOut,
+ stderr=self.cmdStdErr,
+ onDone=onDone, onPrepare=onPrepare,
+ userData=userData,
+ env=os.environ.copy())
+ self.cmdOutputTimer.Start(50)
+
+ # deactivate computational region and return to display settings
+ if compReg and tmpreg:
+ os.environ["GRASS_REGION"] = tmpreg
+ else:
+ # Send any other command to the shell. Send output to
+ # console output window
+ if len(command) == 1 and not skipInterface:
+ try:
+ task = gtask.parse_interface(command[0])
+ except:
+ task = None
+ else:
+ task = None
+
+ if task:
+ # process GRASS command without argument
+ GUI(parent=self._guiparent, lmgr=self._lmgr).ParseCommand(command)
+ else:
+ self.cmdThread.RunCmd(command,
+ stdout=self.cmdStdOut,
+ stderr=self.cmdStdErr,
+ onDone=onDone, onPrepare=onPrepare,
+ userData=userData)
+ self.cmdOutputTimer.Start(50)
+
+ def GetLog(self, err=False):
+ """!Get widget used for logging
+
+ @todo what's this?
+
+ @param err True to get stderr widget
+ """
+ if err:
+ return self.cmdStdErr
+
+ return self.cmdStdOut
+
+ def GetCmd(self):
+ """!Get running command or None"""
+ return self.requestQ.get()
+
+ def OnCmdAbort(self, event):
+ """!Abort running command"""
+ self.cmdThread.abort()
+ event.Skip()
+
+ def OnCmdRun(self, event):
+ """!Run command"""
+ self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
+ event.Skip()
+
+ def OnCmdDone(self, event):
+ """!Command done (or aborted)
+
+ Posts event EVT_MAP_CREATED.
+ """
+ # Process results here
+ try:
+ ctime = time.time() - event.time
+ if ctime < 60:
+ stime = _("%d sec") % int(ctime)
+ else:
+ mtime = int(ctime / 60)
+ stime = _("%(min)d min %(sec)d sec") % {'min': mtime,
+ 'sec': int(ctime - (mtime * 60))}
+ except KeyError:
+ # stopped deamon
+ stime = _("unknown")
+
+ if event.aborted:
+ # Thread aborted (using our convention of None return)
+ self.WriteWarning(_('Please note that the data are left in'
+ ' inconsistent state and may be corrupted'))
+ msg = _('Command aborted')
+ else:
+ msg = _('Command finished')
+
+ self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime))
+
+ if event.onDone:
+ event.onDone(cmd=event.cmd, returncode=event.returncode)
+
+ self.cmdOutputTimer.Stop()
+
+ if event.cmd[0] == 'g.gisenv':
+ Debug.SetLevel()
+ self.Redirect()
+
+ # do nothing when no map added
+ if event.returncode != 0 or event.aborted:
+ event.Skip()
+ return
+
+ # find which maps were created
+ try:
+ task = GUI(show=None).ParseCommand(event.cmd)
+ except GException, e:
+ print >> sys.stderr, e
+ task = None
+ return
+
+ for p in task.get_options()['params']:
+ prompt = p.get('prompt', '')
+ if prompt in ('raster', 'vector', '3d-raster') and \
+ p.get('age', 'old') == 'new' and \
+ p.get('value', None):
+ name = p.get('value')
+ if '@' not in name:
+ name = name + '@' + grass.gisenv()['MAPSET']
+ mapEvent = gMapCreated(wx.ID_ANY,
+ name=name, ltype=prompt, add=None)
+ wx.PostEvent(self, mapEvent)
+
+ event.Skip()
+
+ def OnProcessPendingOutputWindowEvents(self, event):
+ wx.GetApp().ProcessPendingEvents()
\ No newline at end of file
Modified: grass/trunk/gui/wxpython/gmodeler/frame.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/frame.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gmodeler/frame.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -34,8 +34,9 @@
from core import globalvar
from gui_core.widgets import GNotebook
-from gui_core.goutput import GConsole, \
- EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE, EVT_OUTPUT_TEXT
+from core.gconsole import GConsole, \
+ EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE, EVT_CMD_RUN, EVT_CMD_DONE
+from gui_core.goutput import GConsoleWindow
from core.events import EVT_MAP_CREATED, EVT_SHOW_NOTIFICATION
from core.debug import Debug
from core.gcmd import GMessage, GException, GWarning, GError, RunCommand
@@ -107,8 +108,15 @@
self.pythonPanel = PythonPanel(parent = self)
- self.goutput = GConsole(parent = self)
- self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+ self._gconsole = GConsole(guiparent = self)
+ self.goutput = GConsoleWindow(parent = self, gconsole = self._gconsole)
+ # here events are binded twice
+ self._gconsole.Bind(EVT_CMD_RUN,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 2))
+ self._gconsole.Bind(EVT_CMD_DONE,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 3))
self.Bind(EVT_CMD_RUN, self.OnCmdRun)
self.Bind(EVT_CMD_DONE, self.OnCmdDone)
self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
@@ -481,7 +489,7 @@
def OnRunModel(self, event):
"""!Run entire model"""
- self.model.Run(self.goutput, self.OnDone, parent = self)
+ self.model.Run(self._gconsole, self.OnDone, parent = self)
def OnDone(self, cmd, returncode):
"""!Computation finished"""
@@ -699,13 +707,17 @@
self.canvas.Refresh()
- def OnOutputText(self, event):
+ def _switchPageHandler(self, event, priority):
+ self._switchPage(priority = priority)
+ event.Skip()
+
+ def _switchPage(self, priority):
"""!Manages @c 'output' notebook page according to event priority."""
- if event.priority == 1:
+ if priority == 1:
self.notebook.HighlightPageByName('output')
- if event.priority >= 2:
+ if priority >= 2:
self.notebook.SetSelectionByName('output')
- if event.priority >= 3:
+ if priority >= 3:
self.SetFocus()
self.Raise()
Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gui_core/forms.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -434,6 +434,7 @@
# notebooks
self.notebookpanel = CmdPanel(parent = self.panel, task = self.task,
frame = self, lmgr = self.lmgr)
+ self._gconsole = self.notebookpanel._gconsole
self.goutput = self.notebookpanel.goutput
self.notebookpanel.OnUpdateValues = self.updateValuesHook
guisizer.Add(item = self.notebookpanel, proportion = 1, flag = wx.EXPAND)
@@ -676,7 +677,7 @@
if self.task.path:
cmd[0] = self.task.path # full path
- ret = self.goutput.RunCmd(cmd, onDone = self.OnDone)
+ ret = self._gconsole.RunCmd(cmd, onDone = self.OnDone)
except AttributeError, e:
print >> sys.stderr, "%s: Probably not running in wxgui.py session?" % (e)
print >> sys.stderr, "parent window is: %s" % (str(self.parent))
@@ -1619,16 +1620,24 @@
# are we running from command line?
### add 'command output' tab regardless standalone dialog
if self.parent.GetName() == "MainFrame" and self.parent.get_dcmd is None:
- from gui_core.goutput import GConsole, EVT_OUTPUT_TEXT
- self.goutput = GConsole(parent = self.notebook, margin = False)
- self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+ from core.gconsole import GConsole, EVT_CMD_RUN, EVT_CMD_DONE
+ from gui_core.goutput import GConsoleWindow
+ self._gconsole = GConsole(guiparent = self.notebook)
+ self.goutput = GConsoleWindow(parent = self.notebook, gconsole = self._gconsole, margin = False)
+ self._gconsole.Bind(EVT_CMD_RUN,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 2))
+ self._gconsole.Bind(EVT_CMD_DONE,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 3))
self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
index = self.AddBitmapToImageList(section = 'output', imageList = imageList)
if index >= 0:
self.notebook.SetPageImage('output', index)
else:
self.goutput = None
-
+ self._gconsole = None
+
self.manualTab = HelpPanel(parent = self.notebook, command = self.task.name)
if not self.manualTab.GetFile():
self.manualTab.Hide()
@@ -1848,13 +1857,17 @@
# event is somehow propagated?
event.StopPropagation()
- def OnOutputText(self, event):
+ def _switchPageHandler(self, event, priority):
+ self._switchPage(priority = priority)
+ event.Skip()
+
+ def _switchPage(self, priority):
"""!Manages @c 'output' notebook page according to event priority."""
- if event.priority == 1:
+ if priority == 1:
self.notebook.HighlightPageByName('output')
- if event.priority >= 2:
+ if priority >= 2:
self.notebook.SetSelectionByName('output')
- if event.priority >= 3:
+ if priority >= 3:
self.SetFocus()
self.Raise()
Modified: grass/trunk/gui/wxpython/gui_core/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/goutput.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gui_core/goutput.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -4,11 +4,9 @@
@brief Command output widgets
Classes:
- - goutput::CmdThread
- - goutput::GConsole
- - goutput::GStdout
- - goutput::GStderr
+ - goutput::GConsoleWindow
- goutput::GStc
+ - goutput::GConsoleFrame
(C) 2007-2012 by the GRASS Development Team
@@ -17,218 +15,41 @@
@author Michael Barton (Arizona State University)
@author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
+ at author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (refactoring)
"""
import os
import sys
-import re
import textwrap
-import time
-import threading
-import Queue
-import codecs
-import locale
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
import wx
from wx import stc
-from wx.lib.newevent import NewEvent
-import grass.script as grass
-from grass.script import task as gtask
-
-from core import globalvar
-from core import utils
-from core.gcmd import CommandThread, GMessage, GError, GException, EncodeString
-from core.events import gShowNotification, gMapCreated
-from gui_core.forms import GUI
+from core.gcmd import GError, EncodeString
+from core.events import gShowNotification
+from core.gconsole import GConsole, \
+ EVT_CMD_OUTPUT, EVT_CMD_PROGRESS, EVT_CMD_RUN, EVT_CMD_DONE, \
+ EVT_WRITE_LOG, EVT_WRITE_CMD_LOG, EVT_WRITE_WARNING, EVT_WRITE_ERROR
from gui_core.prompt import GPromptSTC, EVT_GPROMPT_RUN_CMD
-from core.debug import Debug
from core.settings import UserSettings
from gui_core.widgets import SearchModuleWidget, EVT_MODULE_SELECTED
from core.modulesdata import ModulesData
-wxCmdOutput, EVT_CMD_OUTPUT = NewEvent()
-wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
-wxCmdRun, EVT_CMD_RUN = NewEvent()
-wxCmdDone, EVT_CMD_DONE = NewEvent()
-wxCmdAbort, EVT_CMD_ABORT = NewEvent()
-wxCmdPrepare, EVT_CMD_PREPARE = NewEvent()
-
GC_EMPTY = 0
GC_SEARCH = 1
GC_PROMPT = 2
-def GrassCmd(cmd, env = None, stdout = None, stderr = None):
- """!Return GRASS command thread"""
- return CommandThread(cmd, env = env,
- stdout = stdout, stderr = stderr)
-
-class CmdThread(threading.Thread):
- """!Thread for GRASS commands"""
- requestId = 0
- def __init__(self, receiver, requestQ = None, resultQ = None, **kwds):
- """!
- @param receiver event receiver (used in PostEvent)
- """
- threading.Thread.__init__(self, **kwds)
-
- if requestQ is None:
- self.requestQ = Queue.Queue()
- else:
- self.requestQ = requestQ
-
- if resultQ is None:
- self.resultQ = Queue.Queue()
- else:
- self.resultQ = resultQ
-
- self.setDaemon(True)
-
- self.receiver = receiver
- self._want_abort_all = False
-
- self.start()
-
- def RunCmd(self, *args, **kwds):
- """!Run command in queue
-
- @param args unnamed command arguments
- @param kwds named command arguments
-
- @return request id in queue
- """
- CmdThread.requestId += 1
-
- self.requestCmd = None
- self.requestQ.put((CmdThread.requestId, args, kwds))
-
- return CmdThread.requestId
-
- def SetId(self, id):
- """!Set starting id"""
- CmdThread.requestId = id
-
- def run(self):
- os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
- while True:
- requestId, args, kwds = self.requestQ.get()
- for key in ('callable', 'onDone', 'onPrepare', 'userData'):
- if key in kwds:
- vars()[key] = kwds[key]
- del kwds[key]
- else:
- vars()[key] = None
-
- if not vars()['callable']:
- vars()['callable'] = GrassCmd
-
- requestTime = time.time()
-
- # prepare
- event = wxCmdPrepare(cmd = args[0],
- time = requestTime,
- pid = requestId,
- onPrepare = vars()['onPrepare'],
- userData = vars()['userData'])
- wx.PostEvent(self.receiver, event)
-
- # run command
- event = wxCmdRun(cmd = args[0],
- pid = requestId)
-
- wx.PostEvent(self.receiver, event)
-
- time.sleep(.1)
- self.requestCmd = vars()['callable'](*args, **kwds)
- if self._want_abort_all:
- self.requestCmd.abort()
- if self.requestQ.empty():
- self._want_abort_all = False
-
- self.resultQ.put((requestId, self.requestCmd.run()))
-
- try:
- returncode = self.requestCmd.module.returncode
- except AttributeError:
- returncode = 0 # being optimistic
-
- try:
- aborted = self.requestCmd.aborted
- except AttributeError:
- aborted = False
-
- time.sleep(.1)
-
- # set default color table for raster data
- if UserSettings.Get(group = 'rasterLayer', key = 'colorTable', subkey = 'enabled') and \
- args[0][0][:2] == 'r.':
- colorTable = UserSettings.Get(group = 'rasterLayer', key = 'colorTable', subkey = 'selection')
- mapName = None
- if args[0][0] == 'r.mapcalc':
- try:
- mapName = args[0][1].split('=', 1)[0].strip()
- except KeyError:
- pass
- else:
- moduleInterface = GUI(show = None).ParseCommand(args[0])
- outputParam = moduleInterface.get_param(value = 'output', raiseError = False)
- if outputParam and outputParam['prompt'] == 'raster':
- mapName = outputParam['value']
-
- if mapName:
- argsColor = list(args)
- argsColor[0] = [ 'r.colors',
- 'map=%s' % mapName,
- 'color=%s' % colorTable ]
- self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
- self.resultQ.put((requestId, self.requestCmdColor.run()))
-
- event = wxCmdDone(cmd = args[0],
- aborted = aborted,
- returncode = returncode,
- time = requestTime,
- pid = requestId,
- onDone = vars()['onDone'],
- userData = vars()['userData'])
-
- # send event
- wx.PostEvent(self.receiver, event)
-
- def abort(self, abortall = True):
- """!Abort command(s)"""
- if abortall:
- self._want_abort_all = True
- self.requestCmd.abort()
- if self.requestQ.empty():
- self._want_abort_all = False
-
-
-# Occurs when some new text appears.
-# Text priority is specified by priority attribute.
-# Priority is 1 (lowest), 2, 3 (highest);
-# value 0 is currently not used and probably will not be used.
-# In theory, it can be used when text is completely uninteresting.
-# It is similar to wx.EVT_TEXT.
-# However, the new text or the whole text are not event attributes.
-gOutputText, EVT_OUTPUT_TEXT = NewEvent()
-
-# Occurs when ignored command is called.
-# Attribute cmd contains command (as a list).
-gIgnoredCmdRun, EVT_IGNORED_CMD_RUN = NewEvent()
-
-
-class GConsole(wx.SplitterWindow):
+class GConsoleWindow(wx.SplitterWindow):
"""!Create and manage output console for commands run by GUI.
"""
- def __init__(self, parent, margin = False,
+ def __init__(self, parent, gconsole, margin = False,
style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
gcstyle = GC_EMPTY,
- ignoredCmdPattern = None,
**kwargs):
"""!
@param parent gui parent
@@ -248,28 +69,40 @@
# initialize variables
self.parent = parent # GMFrame | CmdPanel | ?
+ self._gconsole = gconsole
self._gcstyle = gcstyle
self.lineWidth = 80
- self._ignoredCmdPattern = ignoredCmdPattern
- # create queues
- self.requestQ = Queue.Queue()
- self.resultQ = Queue.Queue()
-
+
# progress bar
self.progressbar = wx.Gauge(parent = self.panelOutput, id = wx.ID_ANY,
range = 100, pos = (110, 50), size = (-1, 25),
style = wx.GA_HORIZONTAL)
- self.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
-
+ self._gconsole.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
+ self._gconsole.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
+ self._gconsole.Bind(EVT_CMD_RUN, self.OnCmdRun)
+ self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone)
+ self._gconsole.Bind(EVT_WRITE_LOG,
+ lambda event:
+ self.WriteLog(text = event.text,
+ wrap = event.wrap,
+ switchPage = event.switchPage,
+ priority = event.priority))
+ self._gconsole.Bind(EVT_WRITE_CMD_LOG,
+ lambda event:
+ self.WriteCmdLog(line = event.line,
+ pid = event.pid,
+ switchPage = event.switchPage))
+ self._gconsole.Bind(EVT_WRITE_WARNING,
+ lambda event:
+ self.WriteWarning(line = event.line))
+ self._gconsole.Bind(EVT_WRITE_ERROR,
+ lambda event:
+ self.WriteError(line = event.line))
+
# text control for command output
self.cmdOutput = GStc(parent = self.panelOutput, id = wx.ID_ANY, margin = margin,
- wrap = None)
- self.cmdOutputTimer = wx.Timer(self.cmdOutput, id = wx.ID_ANY)
- self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
- self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
- self.Bind(EVT_CMD_RUN, self.OnCmdRun)
- self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+ wrap = None)
# information about available modules
modulesData = ModulesData()
@@ -279,7 +112,8 @@
# search depends on cmd prompt
self.cmdPrompt = GPromptSTC(parent = self, modulesData = modulesData)
self.cmdPrompt.Bind(EVT_GPROMPT_RUN_CMD,
- lambda event: self.RunCmd(command = event.cmd))
+ lambda event:
+ self._gconsole.RunCmd(command = event.cmd))
if not self._gcstyle & GC_PROMPT:
self.cmdPrompt.Hide()
@@ -301,13 +135,6 @@
else:
self.search = None
- # stream redirection
- self.cmdStdOut = GStdout(self)
- self.cmdStdErr = GStderr(self)
-
- # thread
- self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
-
self.outputBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
label = " %s " % _("Output window"))
@@ -341,8 +168,7 @@
self.btnCmdClear.Bind(wx.EVT_BUTTON, self.cmdPrompt.OnCmdErase)
self.btnOutputClear.Bind(wx.EVT_BUTTON, self.OnOutputClear)
self.btnOutputSave.Bind(wx.EVT_BUTTON, self.OnOutputSave)
- self.btnCmdAbort.Bind(wx.EVT_BUTTON, self.OnCmdAbort)
- self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)
+ self.btnCmdAbort.Bind(wx.EVT_BUTTON, self._gconsole.OnCmdAbort)
self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.OnCmdProtocol)
self._layout()
@@ -449,23 +275,7 @@
return self.panelPrompt
return self.panelOutput
-
- def Redirect(self):
- """!Redirect stdout/stderr
- """
- if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
- # don't redirect when debugging is enabled
- sys.stdout = self.cmdStdOut
- sys.stderr = self.cmdStdErr
- else:
- enc = locale.getdefaultlocale()[1]
- if enc:
- sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
- sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
- else:
- sys.stdout = sys.__stdout__
- sys.stderr = sys.__stderr__
-
+
def WriteLog(self, text, style = None, wrap = None,
switchPage = False, priority = 1):
"""!Generic method for writing log message in
@@ -484,12 +294,8 @@
# documenting old behavior/implementation:
# switch notebook if required
- if priority == 1:
- if switchPage:
- priority = 2
- event = gOutputText(priority = priority)
- wx.PostEvent(self, event)
-
+ # now, let user to bind to the old event
+
if not style:
style = self.cmdOutput.StyleDefault
@@ -532,142 +338,6 @@
"""!Write message in error style"""
self.WriteLog(line, style = self.cmdOutput.StyleError, switchPage = True)
- def RunCmd(self, command, compReg = True, switchPage = False, skipInterface = False,
- onDone = None, onPrepare = None, userData = None):
- """!Run command typed into console command prompt (GPrompt).
-
- @todo Document the other event.
- @todo Solve problem with the other event
- (now uses gOutputText event but there is no text,
- use onPrepare handler instead?)
-
- Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
- (according to ignoredCmdPattern) is run.
- For example, see layer manager which handles d.* on its own.
-
- @param command command given as a list (produced e.g. by utils.split())
- @param compReg True use computation region
- @param switchPage switch to output page
- @param skipInterface True to do not launch GRASS interface
- parser when command has no arguments given
- @param onDone function to be called when command is finished
- @param onPrepare function to be called before command is launched
- @param userData data defined for the command
- """
- if len(command) == 0:
- Debug.msg(2, "GPrompt:RunCmd(): empty command")
- return
-
- # update history file
- env = grass.gisenv()
- try:
- filePath = os.path.join(env['GISDBASE'],
- env['LOCATION_NAME'],
- env['MAPSET'],
- '.bash_history')
- fileHistory = codecs.open(filePath, encoding = 'utf-8', mode = 'a')
- except IOError, e:
- GError(_("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") %
- {'filePath': filePath, 'error' : e },
- parent = self)
- fileHistory = None
-
- if fileHistory:
- try:
- fileHistory.write(' '.join(command) + os.linesep)
- finally:
- fileHistory.close()
-
- if command[0] in globalvar.grassCmd:
- # send GRASS command without arguments to GUI command interface
- # except ignored commands (event is emitted)
-
- if self._ignoredCmdPattern and \
- re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
- '--help' not in command:
- event = gIgnoredCmdRun(cmd = command)
- wx.PostEvent(self, event)
- return
-
- else:
- # other GRASS commands (r|v|g|...)
- try:
- task = GUI(show = None).ParseCommand(command)
- except GException, e:
- GError(parent = self,
- message = unicode(e),
- showTraceback = False)
- return
-
- hasParams = False
- if task:
- options = task.get_options()
- hasParams = options['params'] and options['flags']
- # check for <input>=-
- for p in options['params']:
- if p.get('prompt', '') == 'input' and \
- p.get('element', '') == 'file' and \
- p.get('age', 'new') == 'old' and \
- p.get('value', '') == '-':
- GError(parent = self,
- message = _("Unable to run command:\n%(cmd)s\n\n"
- "Option <%(opt)s>: read from standard input is not "
- "supported by wxGUI") % { 'cmd': ' '.join(command),
- 'opt': p.get('name', '') })
- return
-
- if len(command) == 1 and hasParams and \
- command[0] != 'v.krige':
- # no arguments given
- try:
- GUI(parent = self, lmgr = self.parent).ParseCommand(command)
- except GException, e:
- print >> sys.stderr, e
- return
-
- # documenting old behavior/implementation:
- # switch and focus if required
- # TODO: this probably should be run command event
- if switchPage:
- priority = 3
- event = gOutputText(priority = priority)
- wx.PostEvent(self, event)
-
- # activate computational region (set with g.region)
- # for all non-display commands.
- if compReg:
- tmpreg = os.getenv("GRASS_REGION")
- if "GRASS_REGION" in os.environ:
- del os.environ["GRASS_REGION"]
-
- # process GRASS command with argument
- self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
- onDone = onDone, onPrepare = onPrepare, userData = userData,
- env = os.environ.copy())
- self.cmdOutputTimer.Start(50)
-
- # deactivate computational region and return to display settings
- if compReg and tmpreg:
- os.environ["GRASS_REGION"] = tmpreg
- else:
- # Send any other command to the shell. Send output to
- # console output window
- if len(command) == 1 and not skipInterface:
- try:
- task = gtask.parse_interface(command[0])
- except:
- task = None
- else:
- task = None
-
- if task:
- # process GRASS command without argument
- GUI(parent = self, lmgr = self.parent).ParseCommand(command)
- else:
- self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
- onDone = onDone, onPrepare = onPrepare, userData = userData)
- self.cmdOutputTimer.Start(50)
-
def OnOutputClear(self, event):
"""!Clear content of output window"""
self.cmdOutput.SetReadOnly(False)
@@ -678,17 +348,7 @@
def GetProgressBar(self):
"""!Return progress bar widget"""
return self.progressbar
-
- def GetLog(self, err = False):
- """!Get widget used for logging
- @param err True to get stderr widget
- """
- if err:
- return self.cmdStdErr
-
- return self.cmdStdOut
-
def OnOutputSave(self, event):
"""!Save (selected) text from output window to the file"""
text = self.cmdOutput.GetSelectedText()
@@ -722,10 +382,6 @@
dlg.Destroy()
- def GetCmd(self):
- """!Get running command or None"""
- return self.requestQ.get()
-
def SetCopyingOfSelectedText(self, copy):
"""!Enable or disable copying of selected text in to clipboard.
Effects prompt and output.
@@ -751,8 +407,6 @@
# documenting old behavior/implementation:
# add elipses if not active
- event = gOutputText(priority = 1)
- wx.PostEvent(self, event)
def OnCmdProgress(self, event):
"""!Update progress message info"""
@@ -803,90 +457,21 @@
dlg.Destroy()
event.Skip()
-
- def OnCmdAbort(self, event):
- """!Abort running command"""
- self.cmdThread.abort()
- event.Skip()
-
+
def OnCmdRun(self, event):
"""!Run command"""
- self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
self.btnCmdAbort.Enable()
event.Skip()
def OnCmdDone(self, event):
"""!Command done (or aborted)
-
- Posts event EVT_MAP_CREATED.
"""
-
- # Process results here
- try:
- ctime = time.time() - event.time
- if ctime < 60:
- stime = _("%d sec") % int(ctime)
- else:
- mtime = int(ctime / 60)
- stime = _("%(min)d min %(sec)d sec") % { 'min' : mtime,
- 'sec' : int(ctime - (mtime * 60)) }
- except KeyError:
- # stopped deamon
- stime = _("unknown")
-
- if event.aborted:
- # Thread aborted (using our convention of None return)
- self.WriteLog(_('Please note that the data are left in inconsistent state '
- 'and may be corrupted'), self.cmdOutput.StyleWarning)
- msg = _('Command aborted')
- else:
- msg = _('Command finished')
-
- self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime))
self.btnCmdAbort.Enable(False)
-
- if event.onDone:
- event.onDone(cmd = event.cmd, returncode = event.returncode)
-
- self.progressbar.SetValue(0) # reset progress bar on '0%'
- self.cmdOutputTimer.Stop()
-
- if event.cmd[0] == 'g.gisenv':
- Debug.SetLevel()
- self.Redirect()
-
- # do nothing when no map added
- if event.returncode != 0 or event.aborted:
- event.Skip()
- return
-
- # find which maps were created
- try:
- task = GUI(show = None).ParseCommand(event.cmd)
- except GException, e:
- print >> sys.stderr, e
- task = None
- return
-
- for p in task.get_options()['params']:
- prompt = p.get('prompt', '')
- if prompt in ('raster', 'vector', '3d-raster') and \
- p.get('age', 'old') == 'new' and \
- p.get('value', None):
- name = p.get('value')
- if '@' not in name:
- name = name + '@' + grass.gisenv()['MAPSET']
- mapEvent = gMapCreated(self.GetId(),
- name = name, ltype = prompt, add = None)
- wx.PostEvent(self, mapEvent)
-
+ self.progressbar.SetValue(0) # reset progress bar on '0%'
event.Skip()
- def OnProcessPendingOutputWindowEvents(self, event):
- wx.GetApp().ProcessPendingEvents()
-
def ResetFocus(self):
"""!Reset focus"""
self.cmdPrompt.SetFocus()
@@ -894,112 +479,8 @@
def GetPrompt(self):
"""!Get prompt"""
return self.cmdPrompt
-
-class GStdout:
- """!GConsole 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, receiver):
- """!
- @param receiver event receiver (used in PostEvent)
- """
- self.receiver = receiver
-
- def write(self, s):
- if len(s) == 0 or s == '\n':
- return
-
- for line in s.splitlines():
- if len(line) == 0:
- continue
-
- evt = wxCmdOutput(text = line + '\n',
- type = '')
- wx.PostEvent(self.receiver, evt)
-
-class GStderr:
- """!GConsole 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, receiver):
- """!
- @param receiver event receiver (used in PostEvent)
- """
- self.receiver = receiver
-
- self.type = ''
- self.message = ''
- self.printMessage = False
-
- def flush(self):
- pass
-
- def write(self, s):
- if "GtkPizza" in s:
- return
-
- # remove/replace escape sequences '\b' or '\r' from stream
- progressValue = -1
-
- for line in s.splitlines():
- if len(line) == 0:
- continue
-
- if 'GRASS_INFO_PERCENT' in line:
- value = int(line.rsplit(':', 1)[1].strip())
- if value >= 0 and value < 100:
- progressValue = value
- else:
- progressValue = 0
- elif 'GRASS_INFO_MESSAGE' in line:
- self.type = 'message'
- self.message += line.split(':', 1)[1].strip() + '\n'
- elif 'GRASS_INFO_WARNING' in line:
- self.type = 'warning'
- self.message += line.split(':', 1)[1].strip() + '\n'
- elif 'GRASS_INFO_ERROR' in line:
- self.type = 'error'
- self.message += line.split(':', 1)[1].strip() + '\n'
- elif 'GRASS_INFO_END' in line:
- self.printMessage = True
- elif self.type == '':
- if len(line) == 0:
- continue
- evt = wxCmdOutput(text = line,
- type = '')
- wx.PostEvent(self.receiver, evt)
- elif len(line) > 0:
- self.message += line.strip() + '\n'
-
- if self.printMessage and len(self.message) > 0:
- evt = wxCmdOutput(text = self.message,
- type = self.type)
- wx.PostEvent(self.receiver, evt)
-
- self.type = ''
- self.message = ''
- self.printMessage = False
-
- # update progress message
- if progressValue > -1:
- # self.gmgauge.SetValue(progressValue)
- evt = wxCmdProgress(value = progressValue)
- wx.PostEvent(self.receiver, evt)
-
class GStc(stc.StyledTextCtrl):
"""!Styled text control for GRASS stdout and stderr.
@@ -1218,7 +699,10 @@
wx.Frame.__init__(self, parent = parent, id = id, title = title)
panel = wx.Panel(self, id = wx.ID_ANY)
- self.goutput = GConsole(parent = panel, gcstyle = GC_SEARCH | GC_PROMPT)
+
+ self.gconsole = GConsole(guiparent=self)
+ self.goutput = GConsoleWindow(parent = panel, gconsole = self.gconsole,
+ gcstyle = GC_SEARCH | GC_PROMPT)
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(item = self.goutput, proportion = 1, flag = wx.EXPAND, border = 0)
Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/lmgr/frame.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -51,7 +51,9 @@
from modules.mcalc_builder import MapCalcFrame
from dbmgr.manager import AttributeManager
from core.workspace import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
-from gui_core.goutput import GConsole, GC_SEARCH, GC_PROMPT, EVT_OUTPUT_TEXT, EVT_IGNORED_CMD_RUN
+from core.gconsole import GConsole, \
+ EVT_CMD_OUTPUT, EVT_CMD_RUN, EVT_CMD_DONE, EVT_IGNORED_CMD_RUN
+from gui_core.goutput import GConsoleWindow, GC_SEARCH, GC_PROMPT
from gui_core.dialogs import GdalOutputDialog, DxfImportDialog, GdalImportDialog, MapLayersDialog
from gui_core.dialogs import EVT_APPLY_MAP_LAYERS
from gui_core.dialogs import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog
@@ -208,7 +210,7 @@
mapdisp.Show()
# redirect stderr to log area
- self.goutput.Redirect()
+ self._gconsole.Redirect()
# fix goutput's pane size (required for Mac OSX)`
self.goutput.SetSashPosition(int(self.GetSize()[1] * .8))
@@ -263,11 +265,20 @@
self.notebook.AddPage(page = self.notebookLayers, text = _("Map layers"), name = 'layers')
# create 'command output' text area
- self.goutput = GConsole(self,
- gcstyle = GC_SEARCH | GC_PROMPT,
- ignoredCmdPattern = '^d\..*|^r[3]?\.mapcalc$')
+ self._gconsole = GConsole(guiparent = self, lmgr = self,
+ ignoredCmdPattern = '^d\..*|^r[3]?\.mapcalc$')
+ self.goutput = GConsoleWindow(parent = self, gconsole = self._gconsole,
+ gcstyle = GC_SEARCH | GC_PROMPT)
self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
- self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+ self._gconsole.Bind(EVT_CMD_OUTPUT,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 1))
+ self._gconsole.Bind(EVT_CMD_RUN,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 2))
+ self._gconsole.Bind(EVT_CMD_DONE,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 3))
self.goutput.Bind(EVT_IGNORED_CMD_RUN,
lambda event: self.RunSpecialCmd(event.cmd))
self._setCopyingOfSelectedText()
@@ -530,13 +541,17 @@
event.Skip()
- def OnOutputText(self, event):
+ def _switchPageHandler(self, event, priority):
+ self._switchPage(priority = priority)
+ event.Skip()
+
+ def _switchPage(self, priority):
"""!Manages @c 'output' notebook page according to event priority."""
- if event.priority == 1:
+ if priority == 1:
self.notebook.HighlightPageByName('output')
- if event.priority >= 2:
+ if priority >= 2:
self.notebook.SetSelectionByName('output')
- if event.priority >= 3:
+ if priority >= 3:
self.SetFocus()
self.Raise()
Modified: grass/trunk/gui/wxpython/lmgr/giface.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/giface.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/lmgr/giface.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -19,7 +19,7 @@
self.lmgr = lmgr
def RunCmd(self, *args, **kwargs):
- self.lmgr.goutput.RunCmd(*args, **kwargs)
+ self.lmgr._gconsole.RunCmd(*args, **kwargs)
def Help(self, entry):
cmdlist = ['g.manual', 'entry=%s' % entry]
@@ -27,17 +27,17 @@
def WriteLog(self, text, wrap = None,
switchPage = False, priority = 1):
- self.lmgr.goutput.WriteLog(text = text, wrap = wrap, switchPage = switchPage,
+ self.lmgr._gconsole.WriteLog(text = text, wrap = wrap, switchPage = switchPage,
priority = priority)
def WriteCmdLog(self, line, pid = None, switchPage = True):
- self.lmgr.goutput.WriteCmdLog(line = line, pid = pid, switchPage = switchPage)
+ self.lmgr._gconsole.WriteCmdLog(line = line, pid = pid, switchPage = switchPage)
def WriteWarning(self, line):
- self.lmgr.goutput.WriteWarning(line = line)
+ self.lmgr._gconsole.WriteWarning(line = line)
def WriteError(self, line):
- self.lmgr.goutput.WriteError(line = line)
+ self.lmgr._gconsole.WriteError(line = line)
def GetLayerTree(self):
return self.lmgr.GetLayerTree()
Modified: grass/trunk/gui/wxpython/psmap/frame.py
===================================================================
--- grass/trunk/gui/wxpython/psmap/frame.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/psmap/frame.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -34,7 +34,7 @@
import grass.script as grass
from gui_core.menu import Menu
-from gui_core.goutput import CmdThread, EVT_CMD_DONE
+from core.gconsole import CmdThread, EVT_CMD_DONE
from psmap.toolbars import PsMapToolbar
from core.gcmd import RunCommand, GError, GMessage
from core.settings import UserSettings
Modified: grass/trunk/gui/wxpython/scripts/vkrige.py
===================================================================
--- grass/trunk/gui/wxpython/scripts/vkrige.py 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/scripts/vkrige.py 2012-11-23 14:54:53 UTC (rev 53989)
@@ -38,6 +38,7 @@
from core import globalvar
from gui_core import gselect
+from core import gconsole
from gui_core import goutput
from core.settings import UserSettings
from gui_core.widgets import GNotebook
@@ -101,8 +102,12 @@
self.goutput = goutput.GConsole(parent = self, margin = False)
self.goutputId = self.RPackagesBook.GetPageCount()
self.outpage = self.RPackagesBook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
- self.goutput.Bind(goutput.EVT_OUTPUT_TEXT, self.OnOutputText)
-
+ self._gconsole.Bind(gconsole.EVT_CMD_RUN,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 2))
+ self._gconsole.Bind(gconsole.EVT_CMD_DONE,
+ lambda event:
+ self._switchPageHandler(event = event, priority = 3))
self.RPackagesBook.SetSelection(0)
KrigingSizer.Add(self.RPackagesBook, proportion = 1, flag = wx.EXPAND)
@@ -255,13 +260,17 @@
def OnVarianceCBChecked(self, event):
self.OutputVarianceMapName.Enable(event.IsChecked())
- def OnOutputText(self, event):
- """!Manages @c 'output' notebook page according to event priority."""
- if event.priority == 1:
- self.RPackagesBook.HighlightPageByName('output')
- if event.priority >= 2:
- self.RPackagesBook.SetSelectionByName('output')
- if event.priority >= 3:
+ def _switchPageHandler(self, event, priority):
+ self._switchPage(priority = priority)
+ event.Skip()
+
+ def _switchPage(self, priority):
+ """!Manages @c 'output' notebook page according to priority."""
+ if priority == 1:
+ self.notebook.HighlightPageByName('output')
+ if priority >= 2:
+ self.notebook.SetSelectionByName('output')
+ if priority >= 3:
self.SetFocus()
self.Raise()
Modified: grass/trunk/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/trunk/gui/wxpython/wxpythonlib.dox 2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/wxpythonlib.dox 2012-11-23 14:54:53 UTC (rev 53989)
@@ -66,6 +66,11 @@
- gcmd::Popen
- gcmd::Command
- gcmd::CommandThread
+- core::gconsole
+ - goutput::CmdThread
+ - goutput::GStdout
+ - goutput::GStderr
+ - goutput::GConsole
- core::menudata
- menudata::MenuData
- core::modulesdata
@@ -118,11 +123,8 @@
- ghelp::HelpWindow
- ghelp::HelpPanel
- gui_core::goutput
- - goutput::CmdThread
- - goutput::GConsole
+ - goutput::GConsoleWindow
- goutput::GStc
- - goutput::GStdout
- - goutput::GStderr
- gui_core::gselect
- gselect::Select
- gselect::VectorSelect
More information about the grass-commit
mailing list