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.