2 @package gui_core.goutput 
    4 @brief Command output widgets 
   14 (C) 2007-2012 by the GRASS Development Team 
   16 This program is free software under the GNU General Public License 
   17 (>=v2). Read the file COPYING that comes with GRASS for details. 
   19 @author Michael Barton (Arizona State University) 
   20 @author Martin Landa <landa.martin gmail.com> 
   21 @author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization) 
   36 from wx.lib.newevent 
import NewEvent
 
   41 from core            
import globalvar
 
   42 from core            
import utils
 
   43 from core.gcmd       import CommandThread, GMessage, GError, GException, EncodeString
 
   44 from gui_core.forms  
import GUI
 
   50 wxCmdOutput,   EVT_CMD_OUTPUT   = NewEvent()
 
   51 wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
 
   52 wxCmdRun,      EVT_CMD_RUN      = NewEvent()
 
   53 wxCmdDone,     EVT_CMD_DONE     = NewEvent()
 
   54 wxCmdAbort,    EVT_CMD_ABORT    = NewEvent()
 
   55 wxCmdPrepare,  EVT_CMD_PREPARE  = NewEvent()
 
   57 def GrassCmd(cmd, env = None, stdout = None, stderr = None):
 
   58     """!Return GRASS command thread""" 
   59     return CommandThread(cmd, env = env,
 
   60                          stdout = stdout, stderr = stderr)
 
   63     """!Thread for GRASS commands""" 
   65     def __init__(self, parent, requestQ, resultQ, **kwds):
 
   66         threading.Thread.__init__(self, **kwds)
 
   79         CmdThread.requestId += 1
 
   82         self.requestQ.put((CmdThread.requestId, args, kwds))
 
   84         return CmdThread.requestId
 
   87         """!Set starting id""" 
   88         CmdThread.requestId = id
 
   91         os.environ[
'GRASS_MESSAGE_FORMAT'] = 
'gui' 
   93             requestId, args, kwds = self.requestQ.get()
 
   94             for key 
in (
'callable', 
'onDone', 
'onPrepare', 
'userData'):
 
   96                     vars()[key] = kwds[key]
 
  101             if not vars()[
'callable']:
 
  102                 vars()[
'callable'] = GrassCmd
 
  104             requestTime = time.time()
 
  107             event = wxCmdPrepare(cmd = args[0],
 
  110                                  onPrepare = vars()[
'onPrepare'],
 
  111                                  userData = vars()[
'userData'])
 
  112             wx.PostEvent(self.
parent, event)
 
  115             event = wxCmdRun(cmd = args[0],
 
  117             wx.PostEvent(self.
parent, event)
 
  120             self.
requestCmd = vars()[
'callable'](*args, **kwds)
 
  122                 self.requestCmd.abort()
 
  123                 if self.requestQ.empty():
 
  126             self.resultQ.put((requestId, self.requestCmd.run()))
 
  129                 returncode = self.requestCmd.module.returncode
 
  130             except AttributeError:
 
  134                 aborted = self.requestCmd.aborted
 
  135             except AttributeError:
 
  141             if UserSettings.Get(group = 
'cmd', key = 
'rasterColorTable', subkey = 
'enabled') 
and \
 
  142                     args[0][0][:2] == 
'r.':
 
  143                 colorTable = UserSettings.Get(group = 
'cmd', key = 
'rasterColorTable', subkey = 
'selection')
 
  145                 if args[0][0] == 
'r.mapcalc':
 
  147                         mapName = args[0][1].
split(
'=', 1)[0].strip()
 
  151                     moduleInterface = GUI(show = 
None).ParseCommand(args[0])
 
  152                     outputParam = moduleInterface.get_param(value = 
'output', raiseError = 
False)
 
  153                     if outputParam 
and outputParam[
'prompt'] == 
'raster':
 
  154                         mapName = outputParam[
'value']
 
  157                     argsColor = list(args)
 
  158                     argsColor[0] = [ 
'r.colors',
 
  160                                      'color=%s' % colorTable ]
 
  162                     self.resultQ.put((requestId, self.requestCmdColor.run()))
 
  164             event = wxCmdDone(cmd = args[0],
 
  166                               returncode = returncode,
 
  169                               onDone = vars()[
'onDone'],
 
  170                               userData = vars()[
'userData'])
 
  173             wx.PostEvent(self.
parent, event)
 
  176         """!Abort command(s)""" 
  179         self.requestCmd.abort()
 
  180         if self.requestQ.empty():
 
  184     """!Create and manage output console for commands run by GUI. 
  186     def __init__(self, parent, id = wx.ID_ANY, margin = False,
 
  188                  style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
 
  190         wx.SplitterWindow.__init__(self, parent, id, style = style, *kwargs)
 
  191         self.SetName(
"GMConsole")
 
  213                                     range = 100, pos = (110, 50), size = (-1, 25),
 
  214                                     style = wx.GA_HORIZONTAL)
 
  221         self.cmdOutput.Bind(EVT_CMD_OUTPUT, self.
OnCmdOutput)
 
  223         self.Bind(EVT_CMD_RUN,     self.
OnCmdRun)
 
  230         if self.parent.GetName() != 
'LayerManager':
 
  232             self.cmdPrompt.Hide()
 
  238                                                  style = wx.CP_DEFAULT_STYLE |
 
  239                                                  wx.CP_NO_TLW_RESIZE | wx.EXPAND)
 
  241             self.searchPane.Collapse(
True)
 
  253                                       label = 
" %s " % _(
"Output window"))
 
  255                                    label = 
" %s " % _(
"Command prompt"))
 
  259         self.btnOutputClear.SetToolTipString(_(
"Clear output window content"))
 
  261         self.btnCmdClear.SetToolTipString(_(
"Clear command prompt content"))
 
  263         self.btnOutputSave.SetToolTipString(_(
"Save output window content to the file"))
 
  265         self.btnCmdAbort.SetToolTipString(_(
"Abort running command"))
 
  266         self.btnCmdAbort.Enable(
False)
 
  268                                               label = _(
"&Log file"),
 
  269                                               size = self.btnCmdClear.GetSize())
 
  270         self.btnCmdProtocol.SetToolTipString(_(
"Toggle to save list of executed commands into " 
  271                                                "a file; content saved when switching off."))
 
  273         if self.parent.GetName() != 
'LayerManager':
 
  274             self.btnCmdClear.Hide()
 
  275             self.btnCmdProtocol.Hide()
 
  277         self.btnCmdClear.Bind(wx.EVT_BUTTON,     self.cmdPrompt.OnCmdErase)
 
  279         self.btnOutputSave.Bind(wx.EVT_BUTTON,   self.
OnOutputSave)
 
  280         self.btnCmdAbort.Bind(wx.EVT_BUTTON,     self.
OnCmdAbort)
 
  282         self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.
OnCmdProtocol)
 
  288         outputSizer = wx.BoxSizer(wx.VERTICAL)
 
  289         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 
  290         outBtnSizer = wx.StaticBoxSizer(self.
outputBox, wx.HORIZONTAL)
 
  291         cmdBtnSizer = wx.StaticBoxSizer(self.
cmdBox, wx.HORIZONTAL)
 
  293         if self.cmdPrompt.IsShown():
 
  294             promptSizer = wx.BoxSizer(wx.VERTICAL)
 
  295             promptSizer.Add(item = self.
cmdPrompt, proportion = 1,
 
  296                         flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
 
  298         if self.
search and self.search.IsShown():
 
  299             outputSizer.Add(item = self.
searchPane, proportion = 0,
 
  300                             flag = wx.EXPAND | wx.ALL, border = 3)
 
  301         outputSizer.Add(item = self.
cmdOutput, proportion = 1,
 
  302                         flag = wx.EXPAND | wx.ALL, border = 3)
 
  303         outputSizer.Add(item = self.
progressbar, proportion = 0,
 
  304                         flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
 
  306                         flag = wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, border = 5)
 
  308                         flag = wx.ALIGN_RIGHT | wx.RIGHT, border = 5)
 
  311                         flag = wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, border = 5)
 
  312         cmdBtnSizer.Add(item = self.
btnCmdClear, proportion = 1,
 
  313                         flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
 
  314         cmdBtnSizer.Add(item = self.
btnCmdAbort, proportion = 1,
 
  315                         flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
 
  317         if self.parent.GetName() != 
'LayerManager':
 
  322         btnSizer.Add(item = outBtnSizer, proportion = proportion[0],
 
  323                      flag = wx.ALL | wx.ALIGN_CENTER, border = 5)
 
  324         btnSizer.Add(item = cmdBtnSizer, proportion = proportion[1],
 
  325                      flag = wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM | wx.RIGHT, border = 5)
 
  326         outputSizer.Add(item = btnSizer, proportion = 0,
 
  329         outputSizer.Fit(self)
 
  330         outputSizer.SetSizeHints(self)
 
  331         self.panelOutput.SetSizer(outputSizer)
 
  335         if self.cmdPrompt.IsShown():
 
  336             promptSizer.Fit(self)
 
  337             promptSizer.SetSizeHints(self)
 
  338             self.panelPrompt.SetSizer(promptSizer)
 
  341         if self.cmdPrompt.IsShown():
 
  346         self.SetMinimumPaneSize(self.btnCmdClear.GetSize()[1] + 25)
 
  348         self.SetSashGravity(1.0)
 
  351         self.SetAutoLayout(
True)
 
  355         """!Create search pane""" 
  356         border = wx.BoxSizer(wx.VERTICAL)
 
  358         self.
search = SearchModuleWindow(parent = pane, cmdPrompt = self.
cmdPrompt)
 
  360         border.Add(item = self.
search, proportion = 0,
 
  361                    flag = wx.EXPAND | wx.ALL, border = 1)
 
  363         pane.SetSizer(border)
 
  367         """!Collapse search module box""" 
  368         if self.searchPane.IsExpanded():
 
  373         self.panelOutput.Layout()
 
  374         self.panelOutput.SendSizeEvent()
 
  379         @param prompt get prompt / output panel 
  381         @return wx.Panel reference 
  389         """!Redirect stdout/stderr 
  391         if Debug.GetLevel() == 0 
and int(grass.gisenv().get(
'DEBUG', 0)) == 0:
 
  396             enc = locale.getdefaultlocale()[1]
 
  398                 sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
 
  399                 sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
 
  401                 sys.stdout = sys.__stdout__
 
  402                 sys.stderr = sys.__stderr__
 
  404     def WriteLog(self, text, style = None, wrap = None,
 
  406         """!Generic method for writing log message in  
  409         @param line text line 
  410         @param style text style (see GMStc) 
  411         @param stdout write to stdout or stderr 
  414         self.cmdOutput.SetStyle()
 
  417             self._notebook.SetSelectionByName(
'output')
 
  420             style = self.cmdOutput.StyleDefault
 
  423         p1 = self.cmdOutput.GetEndStyled()
 
  425         self.cmdOutput.DocumentEnd()
 
  427         for line 
in text.splitlines():
 
  433             self.cmdOutput.AddTextWrapped(line, wrap = wrap) 
 
  435             p2 = self.cmdOutput.GetCurrentPos()
 
  437             self.cmdOutput.StartStyling(p1, 0xff)
 
  438             self.cmdOutput.SetStyling(p2 - p1, style)
 
  440         self.cmdOutput.EnsureCaretVisible()
 
  443         """!Write message in selected style""" 
  445             line = 
'(' + str(pid) + 
') ' + line
 
  447         self.
WriteLog(line, style = self.cmdOutput.StyleCommand, switchPage = switchPage)
 
  450         """!Write message in warning style""" 
  451         self.
WriteLog(line, style = self.cmdOutput.StyleWarning, switchPage = 
True)
 
  454         """!Write message in error style""" 
  455         self.
WriteLog(line, style = self.cmdOutput.StyleError, switchPage = 
True)
 
  457     def RunCmd(self, command, compReg = True, switchPage = False, skipInterface = False,
 
  458                onDone = 
None, onPrepare = 
None, userData = 
None):
 
  459         """!Run command typed into console command prompt (GPrompt). 
  461         @todo Display commands (*.d) are captured and processed 
  462         separately by mapdisp.py. Display commands are rendered in map 
  463         display widget that currently has the focus (as indicted by 
  466         @param command command given as a list (produced e.g. by utils.split()) 
  467         @param compReg True use computation region 
  468         @param switchPage switch to output page 
  469         @param skipInterface True to do not launch GRASS interface 
  470         parser when command has no arguments given 
  471         @param onDone function to be called when command is finished 
  472         @param onPrepare function to be called before command is launched 
  473         @param userData data defined for the command 
  475         if len(command) == 0:
 
  476             Debug.msg(2, 
"GPrompt:RunCmd(): empty command")
 
  482             filePath = os.path.join(env[
'GISDBASE'],
 
  483                                     env[
'LOCATION_NAME'],
 
  486             fileHistory = codecs.open(filePath, encoding = 
'utf-8', mode = 
'a')
 
  488             GError(_(
"Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") % 
 
  489                     {
'filePath': filePath, 
'error' : e },
 
  495                 fileHistory.write(
' '.join(command) + os.linesep)
 
  499         if command[0] 
in globalvar.grassCmd:
 
  502             if self.parent.GetName() == 
"LayerManager" and \
 
  503                     command[0][0:2] == 
"d." and \
 
  504                     'help' not in ' '.join(command[1:]):
 
  507                     layertype = {
'd.rast'         : 
'raster',
 
  508                                  'd.rast3d'       : 
'3d-raster',
 
  511                                  'd.shadedmap'    : 
'shaded',
 
  512                                  'd.legend'       : 
'rastleg',
 
  513                                  'd.rast.arrow'   : 
'rastarrow',
 
  514                                  'd.rast.num'     : 
'rastnum',
 
  516                                  'd.vect.thematic': 
'thememap',
 
  517                                  'd.vect.chart'   : 
'themechart',
 
  519                                  'd.geodesic'     : 
'geodesic',
 
  520                                  'd.rhumbline'    : 
'rhumb',
 
  521                                  'd.labels'       : 
'labels',
 
  522                                  'd.barscale'     : 
'barscale',
 
  523                                  'd.redraw'       : 
'redraw'}[command[0]]
 
  525                     GMessage(parent = self.
parent,
 
  526                              message = _(
"Command '%s' not yet implemented in the WxGUI. " 
  527                                          "Try adding it as a command layer instead.") % command[0])
 
  530                 mapdisp = self.parent.GetMapDisplay()
 
  531                 if layertype == 
'barscale':
 
  532                     mapdisp.OnAddBarscale(
None)
 
  533                 elif layertype == 
'rastleg':
 
  534                     mapdisp.OnAddLegend(
None)
 
  535                 elif layertype == 
'redraw':
 
  536                     mapdisp.OnRender(
None)
 
  540                                                              layerType = layertype)
 
  541                     if self.parent.GetName() == 
"LayerManager":
 
  542                         self.parent.GetLayerTree().AddLayer(ltype = layertype,
 
  549                 if command[0] 
not in (
'r.mapcalc', 
'r3.mapcalc'):
 
  551                         task = GUI(show = 
None).ParseCommand(command)
 
  552                     except GException, e:
 
  553                         GError(parent = self,
 
  554                                message = unicode(e),
 
  555                                showTraceback = 
False)
 
  559                         options = task.get_options()
 
  560                         hasParams = options[
'params'] 
and options[
'flags']
 
  562                         for p 
in options[
'params']:
 
  563                             if p.get(
'prompt', 
'') == 
'input' and \
 
  564                                     p.get(
'element', 
'') == 
'file' and \
 
  565                                     p.get(
'age', 
'new') == 
'old' and \
 
  566                                     p.get(
'value', 
'') == 
'-':
 
  567                                 GError(parent = self,
 
  568                                        message = _(
"Unable to run command:\n%(cmd)s\n\n" 
  569                                                    "Option <%(opt)s>: read from standard input is not " 
  570                                                    "supported by wxGUI") % { 
'cmd': 
' '.join(command),
 
  571                                                                              'opt': p.get(
'name', 
'') })
 
  576                 if len(command) == 1 
and hasParams 
and \
 
  577                         command[0] != 
'v.krige.py':
 
  580                         GUI(parent = self).ParseCommand(command)
 
  581                     except GException, e:
 
  582                         print >> sys.stderr, e
 
  587                     self._notebook.SetSelectionByName(
'output')
 
  589                     self.parent.SetFocus()
 
  595                     tmpreg = os.getenv(
"GRASS_REGION")
 
  596                     if "GRASS_REGION" in os.environ:
 
  597                         del os.environ[
"GRASS_REGION"]
 
  601                                       onDone = onDone, onPrepare = onPrepare, userData = userData,
 
  602                                       env = os.environ.copy())
 
  603                 self.cmdOutputTimer.Start(50)
 
  606                 if compReg 
and tmpreg:
 
  607                     os.environ[
"GRASS_REGION"] = tmpreg
 
  611             if len(command) == 1 
and not skipInterface:
 
  613                     task = gtask.parse_interface(command[0])
 
  621                 GUI(parent = self).ParseCommand(command)
 
  624                                       onDone = onDone, onPrepare = onPrepare, userData = userData)
 
  625             self.cmdOutputTimer.Start(50)
 
  628         """!Clear content of output window""" 
  629         self.cmdOutput.SetReadOnly(
False)
 
  630         self.cmdOutput.ClearAll()
 
  631         self.cmdOutput.SetReadOnly(
True)
 
  632         self.progressbar.SetValue(0)
 
  635         """!Return progress bar widget""" 
  639         """!Get widget used for logging 
  641         @param err True to get stderr widget 
  649         """!Save (selected) text from output window to the file""" 
  650         text = self.cmdOutput.GetSelectedText()
 
  652             text = self.cmdOutput.GetText()
 
  655         if len(text) > 0 
and text[-1] != 
'\n':
 
  658         dlg = wx.FileDialog(self, message = _(
"Save file as..."),
 
  659                             defaultFile = 
"grass_cmd_output.txt",
 
  660                             wildcard = _(
"%(txt)s (*.txt)|*.txt|%(files)s (*)|*") % 
 
  661                             {
'txt': _(
"Text files"), 
'files': _(
"Files")},
 
  662                             style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
 
  666         if dlg.ShowModal() == wx.ID_OK:
 
  670                 output = open(path, 
"w")
 
  673                 GError(_(
"Unable to write file '%(path)s'.\n\nDetails: %(error)s") % {
'path': path, 
'error': e})
 
  676             message = _(
"Command output saved into '%s'") % path
 
  677             if hasattr(self.
parent, 
'SetStatusText'):
 
  678                 self.parent.SetStatusText(message)
 
  680                 self.parent.parent.SetStatusText(message)
 
  685         """!Get running command or None""" 
  686         return self.requestQ.get()
 
  689         """!Enable or disable copying of selected text in to clipboard. 
  690         Effects prompt and output. 
  692         @param copy True for enable, False for disable 
  695             self.cmdPrompt.Bind(stc.EVT_STC_PAINTED, self.cmdPrompt.OnTextSelectionChanged)
 
  696             self.cmdOutput.Bind(stc.EVT_STC_PAINTED, self.cmdOutput.OnTextSelectionChanged)
 
  698             self.cmdPrompt.Unbind(stc.EVT_STC_PAINTED)
 
  699             self.cmdOutput.Unbind(stc.EVT_STC_PAINTED)
 
  702         """!Update statusbar text""" 
  703         if event.GetString():
 
  704             nItems = len(self.cmdPrompt.GetCommandItems())
 
  705             self.parent.SetStatusText(_(
'%d modules match') % nItems, 0)
 
  707             self.parent.SetStatusText(
'', 0)
 
  712         """!Print command output""" 
  715         if self._notebook.GetSelection() != self._notebook.GetPageIndexByName(
'output'):
 
  716             page = self._notebook.GetPageIndexByName(
'output')
 
  717             textP = self._notebook.GetPageText(page)
 
  720             self._notebook.SetPageText(page, textP)
 
  723         if type == 
'warning':
 
  724             message = 
'WARNING: ' + message
 
  725         elif type == 
'error':
 
  726             message = 
'ERROR: ' + message
 
  728         p1 = self.cmdOutput.GetEndStyled()
 
  729         self.cmdOutput.GotoPos(p1)
 
  740                         pos = self.cmdOutput.GetCurLine()[1]
 
  743                         self.cmdOutput.SetCurrentPos(self.
linePos)
 
  744                     self.cmdOutput.ReplaceSelection(c)
 
  745                     self.
linePos = self.cmdOutput.GetCurrentPos()
 
  748             if last_c 
not in (
'0123456789'):
 
  749                 self.cmdOutput.AddTextWrapped(
'\n', wrap = 
None)
 
  753             if '\n' not in message:
 
  754                 self.cmdOutput.AddTextWrapped(message, wrap = 60)
 
  756                 self.cmdOutput.AddTextWrapped(message, wrap = 
None)
 
  758         p2 = self.cmdOutput.GetCurrentPos()
 
  761             self.cmdOutput.StartStyling(p1, 0xff)
 
  764                 self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleError)
 
  765             elif type == 
'warning':
 
  766                 self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleWarning)
 
  767             elif type == 
'message':
 
  768                 self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleMessage)
 
  770                 self.cmdOutput.SetStyling(p2 - p1, self.cmdOutput.StyleUnknown)
 
  772         self.cmdOutput.EnsureCaretVisible()
 
  775         """!Update progress message info""" 
  776         self.progressbar.SetValue(event.value)
 
  779         """Save list of manually entered commands into a text log file""" 
  780         if not hasattr(self, 
'cmdFileProtocol'):
 
  785             cmds = self.cmdPrompt.GetCommands()
 
  786             output.write(
'\n'.join(cmds))
 
  790             GError(_(
"Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") % 
 
  795         self.parent.SetStatusText(_(
"Command log saved to '%s'") % self.
cmdFileProtocol)
 
  799         """!Save commands into file""" 
  800         if not event.IsChecked():
 
  806             self.cmdPrompt.ClearCommands()
 
  808             dlg = wx.FileDialog(self, message = _(
"Save file as..."),
 
  809                                 defaultFile = 
"grass_cmd_log.txt",
 
  810                                 wildcard = _(
"%(txt)s (*.txt)|*.txt|%(files)s (*)|*") % 
 
  811                                             {
'txt': _(
"Text files"), 
'files': _(
"Files")},
 
  813             if dlg.ShowModal() == wx.ID_OK:
 
  816                 wx.CallAfter(self.btnCmdProtocol.SetValue, 
False)
 
  823         """!Abort running command""" 
  824         self.cmdThread.abort()
 
  828         if self.parent.GetName() == 
'Modeler':
 
  829             self.parent.OnCmdRun(event)
 
  831         self.
WriteCmdLog(
'(%s)\n%s' % (str(time.ctime()), 
' '.join(event.cmd)))
 
  832         self.btnCmdAbort.Enable()
 
  835         """!Prepare for running command""" 
  836         if self.parent.GetName() == 
'Modeler':
 
  837             self.parent.OnCmdPrepare(event)
 
  842         """!Command done (or aborted)""" 
  843         if self.parent.GetName() == 
'Modeler':
 
  844             self.parent.OnCmdDone(event)
 
  848             ctime = time.time() - event.time
 
  850                 stime = _(
"%d sec") % int(ctime)
 
  852                 mtime = int(ctime / 60)
 
  853                 stime = _(
"%(min)d min %(sec)d sec") %  { 
'min' : mtime, 
 
  854                                                           'sec' : int(ctime - (mtime * 60)) }
 
  861             self.
WriteLog(_(
'Please note that the data are left in inconsistent state ' 
  862                             'and may be corrupted'), self.cmdOutput.StyleWarning)
 
  863             msg = _(
'Command aborted')
 
  865             msg = _(
'Command finished')
 
  867         self.
WriteCmdLog(
'(%s) %s (%s)' % (str(time.ctime()), msg, stime))
 
  868         self.btnCmdAbort.Enable(
False)
 
  871             event.onDone(cmd = event.cmd, returncode = event.returncode)
 
  873         self.progressbar.SetValue(0) 
 
  875         self.cmdOutputTimer.Stop()
 
  877         if event.cmd[0] == 
'g.gisenv':
 
  881         if self.parent.GetName() == 
"LayerManager":
 
  882             self.btnCmdAbort.Enable(
False)
 
  883             if event.cmd[0] 
not in globalvar.grassCmd 
or \
 
  884                     event.cmd[0] 
in (
'r.mapcalc', 
'r3.mapcalc'):
 
  887             tree = self.parent.GetLayerTree()
 
  890                 display = tree.GetMapDisplay()
 
  891             if not display 
or not display.IsAutoRendered():
 
  893             mapLayers = map(
lambda x: x.GetName(),
 
  894                             display.GetMap().GetListOfLayers(l_type = 
'raster') +
 
  895                             display.GetMap().GetListOfLayers(l_type = 
'vector'))
 
  898                 task = GUI(show = 
None).ParseCommand(event.cmd)
 
  899             except GException, e:
 
  900                 print >> sys.stderr, e
 
  904             for p 
in task.get_options()[
'params']:
 
  905                 if p.get(
'prompt', 
'') 
not in (
'raster', 
'vector'):
 
  907                 mapName = p.get(
'value', 
'')
 
  908                 if '@' not in mapName:
 
  909                     mapName = mapName + 
'@' + grass.gisenv()[
'MAPSET']
 
  910                 if mapName 
in mapLayers:
 
  911                     display.GetWindow().UpdateMap(render = 
True)
 
  913         elif self.parent.GetName() == 
'Modeler':
 
  916             dialog = self.parent.parent
 
  917             if hasattr(self.parent.parent, 
"btn_abort"):
 
  918                 dialog.btn_abort.Enable(
False)
 
  920             if hasattr(self.parent.parent, 
"btn_cancel"):
 
  921                 dialog.btn_cancel.Enable(
True)
 
  923             if hasattr(self.parent.parent, 
"btn_clipboard"):
 
  924                 dialog.btn_clipboard.Enable(
True)
 
  926             if hasattr(self.parent.parent, 
"btn_help"):
 
  927                 dialog.btn_help.Enable(
True)
 
  929             if hasattr(self.parent.parent, 
"btn_run"):
 
  930                 dialog.btn_run.Enable(
True)
 
  932             if event.returncode == 0 
and not event.aborted:
 
  934                     winName = self.parent.parent.parent.GetName()
 
  935                 except AttributeError:
 
  938                 if winName == 
'LayerManager':
 
  939                     mapTree = self.parent.parent.parent.GetLayerTree()
 
  940                 elif winName == 
'LayerTree':
 
  941                     mapTree = self.parent.parent.parent
 
  943                     mapTree = self.parent.parent.parent.parent.GetLayerTree()
 
  947                 cmd = dialog.notebookpanel.createCmd(ignoreErrors = 
True)
 
  948                 if mapTree 
and hasattr(dialog, 
"addbox") 
and dialog.addbox.IsChecked():
 
  950                     for p 
in dialog.task.get_options()[
'params']:
 
  951                         prompt = p.get(
'prompt', 
'')
 
  952                         if prompt 
in (
'raster', 
'vector', 
'3d-raster') 
and \
 
  953                                 p.get(
'age', 
'old') == 
'new' and \
 
  954                                 p.get(
'value', 
None):
 
  956                                                                     param = p.get(
'name', 
''))
 
  958                             if mapTree.GetMap().GetListOfLayers(l_name = name):
 
  959                                 display = mapTree.GetMapDisplay()
 
  960                                 if display 
and display.IsAutoRendered():
 
  961                                     display.GetWindow().UpdateMap(render = 
True)
 
  964                             if prompt == 
'raster':
 
  967                             elif prompt == 
'3d-raster':
 
  973                             mapTree.AddLayer(ltype = prompt,
 
  977             if hasattr(dialog, 
"get_dcmd") 
and \
 
  978                     dialog.get_dcmd 
is None and \
 
  979                     hasattr(dialog, 
"closebox") 
and \
 
  980                     dialog.closebox.IsChecked() 
and \
 
  981                     (event.returncode == 0 
or event.aborted):
 
  982                 self.cmdOutput.Update()
 
  987         wx.GetApp().ProcessPendingEvents()
 
  991         self.cmdPrompt.SetFocus()
 
  998     """!GMConsole standard output 
 1000     Based on FrameOutErr.py 
 1002     Name:      FrameOutErr.py 
 1003     Purpose:   Redirecting stdout / stderr 
 1004     Author:    Jean-Michel Fauth, Switzerland 
 1005     Copyright: (c) 2005-2007 Jean-Michel Fauth 
 1012         if len(s) == 0 
or s == 
'\n':
 
 1015         for line 
in s.splitlines():
 
 1019             evt = wxCmdOutput(text = line + 
'\n',
 
 1021             wx.PostEvent(self.parent.cmdOutput, evt)
 
 1024     """!GMConsole standard error output 
 1026     Based on FrameOutErr.py 
 1028     Name:      FrameOutErr.py 
 1029     Purpose:   Redirecting stdout / stderr 
 1030     Author:    Jean-Michel Fauth, Switzerland 
 1031     Copyright: (c) 2005-2007 Jean-Michel Fauth 
 1051         for line 
in s.splitlines():
 
 1055             if 'GRASS_INFO_PERCENT' in line:
 
 1056                 value = int(line.rsplit(
':', 1)[1].strip())
 
 1057                 if value >= 0 
and value < 100:
 
 1058                     progressValue = value
 
 1061             elif 'GRASS_INFO_MESSAGE' in line:
 
 1062                 self.type = 
'message' 
 1063                 self.message += line.split(
':', 1)[1].strip() + 
'\n' 
 1064             elif 'GRASS_INFO_WARNING' in line:
 
 1065                 self.type = 
'warning' 
 1066                 self.message += line.split(
':', 1)[1].strip() + 
'\n' 
 1067             elif 'GRASS_INFO_ERROR' in line:
 
 1069                 self.message += line.split(
':', 1)[1].strip() + 
'\n' 
 1070             elif 'GRASS_INFO_END' in line:
 
 1071                 self.printMessage = 
True 
 1072             elif self.type == 
'':
 
 1075                 evt = wxCmdOutput(text = line,
 
 1077                 wx.PostEvent(self.parent.cmdOutput, evt)
 
 1079                 self.message += line.strip() + 
'\n' 
 1081             if self.printMessage 
and len(self.message) > 0:
 
 1082                 evt = wxCmdOutput(text = self.message,
 
 1084                 wx.PostEvent(self.parent.cmdOutput, evt)
 
 1088                 self.printMessage = 
False 
 1091         if progressValue > -1:
 
 1093             evt = wxCmdProgress(value = progressValue)
 
 1094             wx.PostEvent(self.parent.progressbar, evt)
 
 1097     """!Styled GMConsole 
 1099     Based on FrameOutErr.py 
 1101     Name:      FrameOutErr.py 
 1102     Purpose:   Redirecting stdout / stderr 
 1103     Author:    Jean-Michel Fauth, Switzerland 
 1104     Copyright: (c) 2005-2007 Jean-Michel Fauth 
 1107     def __init__(self, parent, id, margin = False, wrap = None):
 
 1108         stc.StyledTextCtrl.__init__(self, parent, id)
 
 1110         self.SetUndoCollection(
True)
 
 1111         self.SetReadOnly(
True)
 
 1122         self.SetMarginWidth(1, 0)
 
 1123         self.SetMarginWidth(2, 0)
 
 1125             self.SetMarginType(0, stc.STC_MARGIN_NUMBER)
 
 1126             self.SetMarginWidth(0, 30)
 
 1128             self.SetMarginWidth(0, 0)
 
 1133         self.SetViewWhiteSpace(
False)
 
 1135         self.SetUseTabs(
False)
 
 1137         self.SetSelBackground(
True, 
"#FFFF00")
 
 1138         self.SetUseHorizontalScrollBar(
True)
 
 1143         self.Bind(wx.EVT_WINDOW_DESTROY, self.
OnDestroy)
 
 1146         """!Copy selected text to clipboard and skip event. 
 1147         The same function is in TextCtrlAutoComplete class (prompt.py). 
 1153         """!Set styles for styled text output windows with type face  
 1154         and point size selected by user (Courier New 10 is default)""" 
 1156         typeface = UserSettings.Get(group = 
'appearance', key = 
'outputfont', subkey = 
'type')   
 
 1158             typeface = 
"Courier New" 
 1160         typesize = UserSettings.Get(group = 
'appearance', key = 
'outputfont', subkey = 
'size')
 
 1161         if typesize == 
None or typesize <= 0:
 
 1163         typesize = float(typesize)
 
 1170         self.
StyleOutputSpec  = 
"face:%s,size:%d,,fore:#000000,back:#FFFFFF" % (typeface, typesize)
 
 1173         self.
StyleErrorSpec   = 
"face:%s,size:%d,,fore:#7F0000,back:#FFFFFF" % (typeface, typesize)
 
 1186         self.StyleClearAll()
 
 1195         """!The clipboard contents can be preserved after 
 1196         the app has exited""" 
 1198         wx.TheClipboard.Flush()
 
 1202         """!Add string to text area. 
 1204         String is wrapped and linesep is also added to the end 
 1207         self.SetReadOnly(
False)
 
 1210             txt = textwrap.fill(txt, wrap) + 
'\n' 
 1216             self.parent.linePos = -1
 
 1217             for seg 
in txt.split(
'\r'):
 
 1218                 if self.parent.linePos > -1:
 
 1219                     self.SetCurrentPos(self.parent.linePos)
 
 1220                     self.ReplaceSelection(seg)
 
 1222                     self.parent.linePos = self.GetCurrentPos()
 
 1225             self.parent.linePos = self.GetCurrentPos()
 
 1228             except UnicodeDecodeError:
 
 1229                 enc = UserSettings.Get(group = 
'atm', key = 
'encoding', subkey = 
'value')
 
 1231                     txt = unicode(txt, enc)
 
 1232                 elif 'GRASS_DB_ENCODING' in os.environ:
 
 1233                     txt = unicode(txt, os.environ[
'GRASS_DB_ENCODING'])
 
 1240         self.SetReadOnly(
True)
 
 1243     """!Styled Python output (see gmodeler::frame::PythonPanel for 
 1246     Based on StyledTextCtrl_2 from wxPython demo 
 1248     def __init__(self, parent, id = wx.ID_ANY, statusbar = None):
 
 1249         stc.StyledTextCtrl.__init__(self, parent, id)
 
 1256         self.
faces = { 
'times': 
'Times New Roman',
 
 1257                        'mono' : 
'Courier New',
 
 1259                        'other': 
'Comic Sans MS',
 
 1264         self.CmdKeyAssign(ord(
'B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
 
 1265         self.CmdKeyAssign(ord(
'N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
 
 1267         self.SetLexer(stc.STC_LEX_PYTHON)
 
 1268         self.SetKeyWords(0, 
" ".join(keyword.kwlist))
 
 1270         self.SetProperty(
"fold", 
"1")
 
 1271         self.SetProperty(
"tab.timmy.whinge.level", 
"1")
 
 1272         self.SetMargins(0, 0)
 
 1274         self.SetUseTabs(
False)
 
 1276         self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
 
 1277         self.SetEdgeColumn(78)
 
 1280         self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
 
 1281         self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
 
 1282         self.SetMarginSensitive(2, 
True)
 
 1283         self.SetMarginWidth(2, 12)
 
 1286         self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN,    stc.STC_MARK_BOXMINUS,          
"white", 
"#808080")
 
 1287         self.MarkerDefine(stc.STC_MARKNUM_FOLDER,        stc.STC_MARK_BOXPLUS,           
"white", 
"#808080")
 
 1288         self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB,     stc.STC_MARK_VLINE,             
"white", 
"#808080")
 
 1289         self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL,    stc.STC_MARK_LCORNER,           
"white", 
"#808080")
 
 1290         self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND,     stc.STC_MARK_BOXPLUSCONNECTED,  
"white", 
"#808080")
 
 1291         self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, 
"white", 
"#808080")
 
 1292         self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER,           
"white", 
"#808080")
 
 1294         self.Bind(stc.EVT_STC_UPDATEUI, self.
OnUpdateUI)
 
 1303         self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     
"face:%(helv)s,size:%(size)d" % self.
faces)
 
 1304         self.StyleClearAll()  
 
 1307         self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     
"face:%(helv)s,size:%(size)d" % self.
faces)
 
 1308         self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,  
"back:#C0C0C0,face:%(helv)s,size:%(size2)d" % self.
faces)
 
 1309         self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, 
"face:%(other)s" % self.
faces)
 
 1310         self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,  
"fore:#FFFFFF,back:#0000FF,bold")
 
 1311         self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,    
"fore:#000000,back:#FF0000,bold")
 
 1315         self.StyleSetSpec(stc.STC_P_DEFAULT, 
"fore:#000000,face:%(helv)s,size:%(size)d" % self.
faces)
 
 1317         self.StyleSetSpec(stc.STC_P_COMMENTLINE, 
"fore:#007F00,face:%(other)s,size:%(size)d" % self.
faces)
 
 1319         self.StyleSetSpec(stc.STC_P_NUMBER, 
"fore:#007F7F,size:%(size)d" % self.
faces)
 
 1321         self.StyleSetSpec(stc.STC_P_STRING, 
"fore:#7F007F,face:%(helv)s,size:%(size)d" % self.
faces)
 
 1323         self.StyleSetSpec(stc.STC_P_CHARACTER, 
"fore:#7F007F,face:%(helv)s,size:%(size)d" % self.
faces)
 
 1325         self.StyleSetSpec(stc.STC_P_WORD, 
"fore:#00007F,bold,size:%(size)d" % self.
faces)
 
 1327         self.StyleSetSpec(stc.STC_P_TRIPLE, 
"fore:#7F0000,size:%(size)d" % self.
faces)
 
 1329         self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, 
"fore:#7F0000,size:%(size)d" % self.
faces)
 
 1331         self.StyleSetSpec(stc.STC_P_CLASSNAME, 
"fore:#0000FF,bold,underline,size:%(size)d" % self.
faces)
 
 1333         self.StyleSetSpec(stc.STC_P_DEFNAME, 
"fore:#007F7F,bold,size:%(size)d" % self.
faces)
 
 1335         self.StyleSetSpec(stc.STC_P_OPERATOR, 
"bold,size:%(size)d" % self.
faces)
 
 1337         self.StyleSetSpec(stc.STC_P_IDENTIFIER, 
"fore:#000000,face:%(helv)s,size:%(size)d" % self.
faces)
 
 1339         self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, 
"fore:#7F7F7F,size:%(size)d" % self.
faces)
 
 1341         self.StyleSetSpec(stc.STC_P_STRINGEOL, 
"fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % self.
faces)
 
 1343         self.SetCaretForeground(
"BLUE")
 
 1348         @todo implement code completion (see wxPython demo) 
 1353                 self.statusbar.SetStatusText(_(
'Python script contains local modifications'), 0)
 
 1362         caretPos = self.GetCurrentPos()
 
 1365             charBefore  = self.GetCharAt(caretPos - 1)
 
 1366             styleBefore = self.GetStyleAt(caretPos - 1)
 
 1369         if charBefore 
and chr(charBefore) 
in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
 
 1370             braceAtCaret = caretPos - 1
 
 1373         if braceAtCaret < 0:
 
 1374             charAfter = self.GetCharAt(caretPos)
 
 1375             styleAfter = self.GetStyleAt(caretPos)
 
 1377             if charAfter 
and chr(charAfter) 
in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
 
 1378                 braceAtCaret = caretPos
 
 1380         if braceAtCaret >= 0:
 
 1381             braceOpposite = self.BraceMatch(braceAtCaret)
 
 1383         if braceAtCaret != -1  
and braceOpposite == -1:
 
 1384             self.BraceBadLight(braceAtCaret)
 
 1386             self.BraceHighlight(braceAtCaret, braceOpposite)
 
 1390         if evt.GetMargin() == 2:
 
 1391             if evt.GetShift() 
and evt.GetControl():
 
 1394                 lineClicked = self.LineFromPosition(evt.GetPosition())
 
 1396                 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
 
 1398                         self.SetFoldExpanded(lineClicked, 
True)
 
 1399                         self.
Expand(lineClicked, 
True, 
True, 1)
 
 1400                     elif evt.GetControl():
 
 1401                         if self.GetFoldExpanded(lineClicked):
 
 1402                             self.SetFoldExpanded(lineClicked, 
False)
 
 1403                             self.
Expand(lineClicked, 
False, 
True, 0)
 
 1405                             self.SetFoldExpanded(lineClicked, 
True)
 
 1406                             self.
Expand(lineClicked, 
True, 
True, 100)
 
 1408                         self.ToggleFold(lineClicked)
 
 1411         lineCount = self.GetLineCount()
 
 1415         for lineNum 
in range(lineCount):
 
 1416             if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
 
 1417                 expanding = 
not self.GetFoldExpanded(lineNum)
 
 1421         while lineNum < lineCount:
 
 1422             level = self.GetFoldLevel(lineNum)
 
 1423             if level & stc.STC_FOLDLEVELHEADERFLAG 
and \
 
 1424                (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
 
 1427                     self.SetFoldExpanded(lineNum, 
True)
 
 1428                     lineNum = self.
Expand(lineNum, 
True)
 
 1429                     lineNum = lineNum - 1
 
 1431                     lastChild = self.GetLastChild(lineNum, -1)
 
 1432                     self.SetFoldExpanded(lineNum, 
False)
 
 1434                     if lastChild > lineNum:
 
 1435                         self.HideLines(lineNum+1, lastChild)
 
 1437             lineNum = lineNum + 1
 
 1439     def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
 
 1440         lastChild = self.GetLastChild(line, level)
 
 1443         while line <= lastChild:
 
 1446                     self.ShowLines(line, line)
 
 1448                     self.HideLines(line, line)
 
 1451                     self.ShowLines(line, line)
 
 1454                 level = self.GetFoldLevel(line)
 
 1456             if level & stc.STC_FOLDLEVELHEADERFLAG:
 
 1459                         self.SetFoldExpanded(line, 
True)
 
 1461                         self.SetFoldExpanded(line, 
False)
 
 1463                     line = self.
Expand(line, doExpand, force, visLevels-1)
 
 1465                     if doExpand 
and self.GetFoldExpanded(line):
 
 1466                         line = self.
Expand(line, 
True, force, visLevels-1)
 
 1468                         line = self.
Expand(line, 
False, force, visLevels-1)
 
def EncodeString
Return encoded string using system locales. 
 
def AddTextWrapped
Add string to text area. 
 
def abort
Abort command(s) 
 
def WriteCmdLog
Write message in selected style. 
 
def OnOutputSave
Save (selected) text from output window to the file. 
 
def OnTextSelectionChanged
Copy selected text to clipboard and skip event. 
 
def SetCopyingOfSelectedText
Enable or disable copying of selected text in to clipboard. 
 
def WriteWarning
Write message in warning style. 
 
def OnCmdOutput
Print command output. 
 
def SetId
Set starting id. 
 
def GetProgressBar
Return progress bar widget. 
 
Create and manage output console for commands run by GUI. 
 
def OnSearchPaneChanged
Collapse search module box. 
 
def GetCmd
Get running command or None. 
 
def GetLog
Get widget used for logging. 
 
GMConsole standard output. 
 
def Redirect
Redirect stdout/stderr. 
 
def OnCmdProgress
Update progress message info. 
 
def RunCmd
Run command typed into console command prompt (GPrompt). 
 
def split
Platform spefic shlex.split. 
 
def MakeSearchPaneContent
Create search pane. 
 
def GetLayerNameFromCmd
Get map name from GRASS command. 
 
def SetStyle
Set styles for styled text output windows with type face and point size selected by user (Courier New...
 
def WriteLog
Generic method for writing log message in given style. 
 
def OnDestroy
The clipboard contents can be preserved after the app has exited. 
 
Styled Python output (see gmodeler::frame::PythonPanel for usage) 
 
def OnOutputClear
Clear content of output window. 
 
def WriteError
Write message in error style. 
 
def OnKeyPressed
Key pressed. 
 
def GrassCmd
Return GRASS command thread. 
 
def OnUpdateStatusBar
Update statusbar text. 
 
def OnCmdPrepare
Prepare for running command. 
 
def ResetFocus
Reset focus. 
 
def OnCmdAbort
Abort running command. 
 
Thread for GRASS commands. 
 
def OnProcessPendingOutputWindowEvents
 
def OnCmdDone
Command done (or aborted) 
 
def OnCmdProtocol
Save commands into file. 
 
GMConsole standard error output.