|
@@ -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 @@ This program is free software under the GNU General Public License
|
|
|
|
|
|
@author Michael Barton (Arizona State University)
|
|
|
@author Martin Landa <landa.martin gmail.com>
|
|
|
-@author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
|
|
|
+@author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
|
|
|
+@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 @@ class GConsole(wx.SplitterWindow):
|
|
|
|
|
|
# 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 @@ class GConsole(wx.SplitterWindow):
|
|
|
# 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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
|
|
|
# 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 @@ class GConsole(wx.SplitterWindow):
|
|
|
"""!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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
|
|
|
# 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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsole(wx.SplitterWindow):
|
|
|
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 @@ class GConsoleFrame(wx.Frame):
|
|
|
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)
|