[GRASS-SVN] r53989 - in grass/trunk/gui/wxpython: . core gmodeler gui_core lmgr psmap scripts

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Nov 23 06:54:53 PST 2012


Author: wenzeslaus
Date: 2012-11-23 06:54:53 -0800 (Fri, 23 Nov 2012)
New Revision: 53989

Added:
   grass/trunk/gui/wxpython/core/gconsole.py
Modified:
   grass/trunk/gui/wxpython/gmodeler/frame.py
   grass/trunk/gui/wxpython/gui_core/forms.py
   grass/trunk/gui/wxpython/gui_core/goutput.py
   grass/trunk/gui/wxpython/lmgr/frame.py
   grass/trunk/gui/wxpython/lmgr/giface.py
   grass/trunk/gui/wxpython/psmap/frame.py
   grass/trunk/gui/wxpython/scripts/vkrige.py
   grass/trunk/gui/wxpython/wxpythonlib.dox
Log:
wxGUI/GConsole: splitted into two classes GConsole (logic) and GConsoleWindow (GUI) (co-author: annakrat)

Added: grass/trunk/gui/wxpython/core/gconsole.py
===================================================================
--- grass/trunk/gui/wxpython/core/gconsole.py	                        (rev 0)
+++ grass/trunk/gui/wxpython/core/gconsole.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -0,0 +1,640 @@
+"""!
+ at package core.gconsole
+
+ at brief Command output widgets
+
+Classes:
+ - goutput::CmdThread
+ - goutput::GStdout
+ - goutput::GStderr
+ - goutput::GConsole
+
+(C) 2007-2012 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Michael Barton (Arizona State University)
+ at author Martin Landa <landa.martin gmail.com>
+ at author Vaclav Petras <wenzeslaus gmail.com> (refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (refactoring)
+"""
+
+import os
+import sys
+import re
+import time
+import threading
+import Queue
+import codecs
+import locale
+
+import wx
+from wx.lib.newevent import NewEvent
+
+import grass.script as grass
+from   grass.script import task as gtask
+
+from core import globalvar
+from core.gcmd import CommandThread, GError, GException
+from core.events import gMapCreated
+from gui_core.forms import GUI
+from core.debug import Debug
+from core.settings import UserSettings
+
+
+wxCmdOutput, EVT_CMD_OUTPUT = NewEvent()
+wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
+wxCmdRun, EVT_CMD_RUN = NewEvent()
+wxCmdDone, EVT_CMD_DONE = NewEvent()
+wxCmdAbort, EVT_CMD_ABORT = NewEvent()
+wxCmdPrepare, EVT_CMD_PREPARE = NewEvent()
+
+
+def GrassCmd(cmd, env=None, stdout=None, stderr=None):
+    """!Return GRASS command thread"""
+    return CommandThread(cmd, env=env,
+                         stdout=stdout, stderr=stderr)
+
+
+class CmdThread(threading.Thread):
+    """!Thread for GRASS commands"""
+    requestId = 0
+
+    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
+        """!
+        @param receiver event receiver (used in PostEvent)
+        """
+        threading.Thread.__init__(self, **kwds)
+
+        if requestQ is None:
+            self.requestQ = Queue.Queue()
+        else:
+            self.requestQ = requestQ
+
+        if resultQ is None:
+            self.resultQ = Queue.Queue()
+        else:
+            self.resultQ = resultQ
+
+        self.setDaemon(True)
+
+        self.receiver = receiver
+        self._want_abort_all = False
+
+        self.start()
+
+    def RunCmd(self, *args, **kwds):
+        """!Run command in queue
+
+        @param args unnamed command arguments
+        @param kwds named command arguments
+
+        @return request id in queue
+        """
+        CmdThread.requestId += 1
+
+        self.requestCmd = None
+        self.requestQ.put((CmdThread.requestId, args, kwds))
+
+        return CmdThread.requestId
+
+    def SetId(self, id):
+        """!Set starting id"""
+        CmdThread.requestId = id
+
+    def run(self):
+        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
+        while True:
+            requestId, args, kwds = self.requestQ.get()
+            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
+                if key in kwds:
+                    vars()[key] = kwds[key]
+                    del kwds[key]
+                else:
+                    vars()[key] = None
+
+            if not vars()['callable']:
+                vars()['callable'] = GrassCmd
+
+            requestTime = time.time()
+
+            # prepare
+            event = wxCmdPrepare(cmd=args[0],
+                                 time=requestTime,
+                                 pid=requestId,
+                                 onPrepare=vars()['onPrepare'],
+                                 userData=vars()['userData'])
+            wx.PostEvent(self.receiver, event)
+
+            # run command
+            event = wxCmdRun(cmd=args[0],
+                             pid=requestId)
+
+            wx.PostEvent(self.receiver, event)
+
+            time.sleep(.1)
+            self.requestCmd = vars()['callable'](*args, **kwds)
+            if self._want_abort_all:
+                self.requestCmd.abort()
+                if self.requestQ.empty():
+                    self._want_abort_all = False
+
+            self.resultQ.put((requestId, self.requestCmd.run()))
+
+            try:
+                returncode = self.requestCmd.module.returncode
+            except AttributeError:
+                returncode = 0  # being optimistic
+
+            try:
+                aborted = self.requestCmd.aborted
+            except AttributeError:
+                aborted = False
+
+            time.sleep(.1)
+
+            # set default color table for raster data
+            if UserSettings.Get(group='rasterLayer',
+                                key='colorTable', subkey='enabled') and \
+                    args[0][0][:2] == 'r.':
+                colorTable = UserSettings.Get(group='rasterLayer',
+                                              key='colorTable',
+                                              subkey='selection')
+                mapName = None
+                if args[0][0] == 'r.mapcalc':
+                    try:
+                        mapName = args[0][1].split('=', 1)[0].strip()
+                    except KeyError:
+                        pass
+                else:
+                    moduleInterface = GUI(show=None).ParseCommand(args[0])
+                    outputParam = moduleInterface.get_param(value='output',
+                                                            raiseError=False)
+                    if outputParam and outputParam['prompt'] == 'raster':
+                        mapName = outputParam['value']
+
+                if mapName:
+                    argsColor = list(args)
+                    argsColor[0] = ['r.colors',
+                                    'map=%s' % mapName,
+                                    'color=%s' % colorTable]
+                    self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
+                    self.resultQ.put((requestId, self.requestCmdColor.run()))
+
+            event = wxCmdDone(cmd=args[0],
+                              aborted=aborted,
+                              returncode=returncode,
+                              time=requestTime,
+                              pid=requestId,
+                              onDone=vars()['onDone'],
+                              userData=vars()['userData'])
+
+            # send event
+            wx.PostEvent(self.receiver, event)
+
+    def abort(self, abortall=True):
+        """!Abort command(s)"""
+        if abortall:
+            self._want_abort_all = True
+        self.requestCmd.abort()
+        if self.requestQ.empty():
+            self._want_abort_all = False
+
+
+class GStdout:
+    """!GConsole standard output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, receiver):
+        """!
+        @param receiver event receiver (used in PostEvent)
+        """
+        self.receiver = receiver
+
+    def write(self, s):
+        if len(s) == 0 or s == '\n':
+            return
+
+        for line in s.splitlines():
+            if len(line) == 0:
+                continue
+
+            evt = wxCmdOutput(text=line + '\n',
+                              type='')
+            wx.PostEvent(self.receiver, evt)
+
+
+class GStderr:
+    """!GConsole standard error output
+
+    Based on FrameOutErr.py
+
+    Name:      FrameOutErr.py
+    Purpose:   Redirecting stdout / stderr
+    Author:    Jean-Michel Fauth, Switzerland
+    Copyright: (c) 2005-2007 Jean-Michel Fauth
+    Licence:   GPL
+    """
+    def __init__(self, receiver):
+        """!
+        @param receiver event receiver (used in PostEvent)
+        """
+        self.receiver = receiver
+        self.type = ''
+        self.message = ''
+        self.printMessage = False
+
+    def flush(self):
+        pass
+
+    def write(self, s):
+        if "GtkPizza" in s:
+            return
+
+        # remove/replace escape sequences '\b' or '\r' from stream
+        progressValue = -1
+
+        for line in s.splitlines():
+            if len(line) == 0:
+                continue
+
+            if 'GRASS_INFO_PERCENT' in line:
+                value = int(line.rsplit(':', 1)[1].strip())
+                if value >= 0 and value < 100:
+                    progressValue = value
+                else:
+                    progressValue = 0
+            elif 'GRASS_INFO_MESSAGE' in line:
+                self.type = 'message'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_WARNING' in line:
+                self.type = 'warning'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_ERROR' in line:
+                self.type = 'error'
+                self.message += line.split(':', 1)[1].strip() + '\n'
+            elif 'GRASS_INFO_END' in line:
+                self.printMessage = True
+            elif self.type == '':
+                if len(line) == 0:
+                    continue
+                evt = wxCmdOutput(text=line,
+                                  type='')
+                wx.PostEvent(self.receiver, evt)
+            elif len(line) > 0:
+                self.message += line.strip() + '\n'
+
+            if self.printMessage and len(self.message) > 0:
+                evt = wxCmdOutput(text=self.message,
+                                  type=self.type)
+                wx.PostEvent(self.receiver, evt)
+
+                self.type = ''
+                self.message = ''
+                self.printMessage = False
+
+        # update progress message
+        if progressValue > -1:
+            # self.gmgauge.SetValue(progressValue)
+            evt = wxCmdProgress(value=progressValue)
+            wx.PostEvent(self.receiver, evt)
+
+
+# events related to messages
+# TODO: create separete class for handling messages?
+gWriteLog, EVT_WRITE_LOG = NewEvent()
+gWriteCmdLog, EVT_WRITE_CMD_LOG = NewEvent()
+gWriteWarning, EVT_WRITE_WARNING = NewEvent()
+gWriteError, EVT_WRITE_ERROR = NewEvent()
+
+# Occurs when ignored command is called.
+# Attribute cmd contains command (as a list).
+gIgnoredCmdRun, EVT_IGNORED_CMD_RUN = NewEvent()
+
+
+class GConsole(wx.EvtHandler):
+    """!
+    """
+    def __init__(self, guiparent=None, lmgr=None, ignoredCmdPattern=None):
+        """!
+        @param guiparent parent window for created GUI objects
+        @param lmgr layer manager window (TODO: replace by giface)
+        @param ignoredCmdPattern regular expression specifying commads
+        to be ignored (e.g. @c '^d\..*' for display commands)
+        """
+        wx.EvtHandler.__init__(self)
+
+        self._guiparent = guiparent
+        self._lmgr = lmgr
+        self._ignoredCmdPattern = ignoredCmdPattern
+
+        # create queues
+        self.requestQ = Queue.Queue()
+        self.resultQ = Queue.Queue()
+
+        self.cmdOutputTimer = wx.Timer(self)
+        self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
+        self.Bind(EVT_CMD_RUN, self.OnCmdRun)
+        self.Bind(EVT_CMD_DONE, self.OnCmdDone)
+        self.Bind(EVT_CMD_ABORT, self.OnCmdAbort)
+
+        # stream redirection
+        self.cmdStdOut = GStdout(receiver=self)
+        self.cmdStdErr = GStderr(receiver=self)
+
+        # thread
+        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
+
+    def Redirect(self):
+        """!Redirect stdout/stderr
+        """
+        if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
+            # don't redirect when debugging is enabled
+            sys.stdout = self.cmdStdOut
+            sys.stderr = self.cmdStdErr
+        else:
+            enc = locale.getdefaultlocale()[1]
+            if enc:
+                sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
+                sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
+            else:
+                sys.stdout = sys.__stdout__
+                sys.stderr = sys.__stderr__
+
+    def WriteLog(self, text, style=None, wrap=None,
+                 switchPage=False, priority=1):
+        """!Generic method for writing log message in
+        given style
+
+        @param line text line
+        @param switchPage for backward compatibility
+        (replace by priority: False=1, True=2)
+        @param priority priority of this message
+        (0=no priority, 1=normal, 2=medium, 3=high)
+        """
+        event = gWriteLog(text=text, wrap=wrap,
+                          switchPage=switchPage, priority=priority)
+        wx.PostEvent(self, event)
+
+    def WriteCmdLog(self, line, pid=None, switchPage=True):
+        """!Write message in selected style
+
+        @param line message to be printed
+        @param pid process pid or None
+        @param switchPage True to switch page
+        """
+        event = gWriteCmdLog(line=line, pid=pid,
+                             switchPage=switchPage)
+        wx.PostEvent(self, event)
+
+    def WriteWarning(self, line):
+        """!Write message in warning style"""
+        event = gWriteWarning(line=line)
+        wx.PostEvent(self, event)
+
+    def WriteError(self, line):
+        """!Write message in error style"""
+        event = gWriteError(line=line)
+        wx.PostEvent(self, event)
+
+    def RunCmd(self, command, compReg=True, switchPage=False, skipInterface=False,
+               onDone=None, onPrepare=None, userData=None):
+        """!Run command typed into console command prompt (GPrompt).
+
+        @todo Document the other event.
+        @todo Solve problem with the other event
+        (now uses gOutputText event but there is no text,
+        use onPrepare handler instead?)
+
+        Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
+        (according to ignoredCmdPattern) is run.
+        For example, see layer manager which handles d.* on its own.
+
+        @todo all switchPage and priority params are currently broken in this class)
+
+        @param command command given as a list (produced e.g. by utils.split())
+        @param compReg True use computation region
+        @param switchPage switch to output page
+        @param skipInterface True to do not launch GRASS interface
+        parser when command has no arguments given
+        @param onDone function to be called when command is finished
+        @param onPrepare function to be called before command is launched
+        @param userData data defined for the command
+        """
+        if len(command) == 0:
+            Debug.msg(2, "GPrompt:RunCmd(): empty command")
+            return
+
+        # update history file
+        env = grass.gisenv()
+        try:
+            filePath = os.path.join(env['GISDBASE'],
+                                    env['LOCATION_NAME'],
+                                    env['MAPSET'],
+                                    '.bash_history')
+            fileHistory = codecs.open(filePath, encoding='utf-8', mode='a')
+        except IOError, e:
+            GError(_("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") % 
+                    {'filePath': filePath, 'error': e},
+                   parent=self._guiparent)
+            fileHistory = None
+
+        if fileHistory:
+            try:
+                fileHistory.write(' '.join(command) + os.linesep)
+            finally:
+                fileHistory.close()
+
+        if command[0] in globalvar.grassCmd:
+            # send GRASS command without arguments to GUI command interface
+            # except ignored commands (event is emitted)
+
+            if self._ignoredCmdPattern and \
+              re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
+              '--help' not in command:
+                event = gIgnoredCmdRun(cmd=command)
+                wx.PostEvent(self, event)
+                return
+
+            else:
+                # other GRASS commands (r|v|g|...)
+                try:
+                    task = GUI(show=None).ParseCommand(command)
+                except GException, e:
+                    GError(parent=self._guiparent,
+                           message=unicode(e),
+                           showTraceback=False)
+                    return
+
+                hasParams = False
+                if task:
+                    options = task.get_options()
+                    hasParams = options['params'] and options['flags']
+                    # check for <input>=-
+                    for p in options['params']:
+                        if p.get('prompt', '') == 'input' and \
+                                p.get('element', '') == 'file' and \
+                                p.get('age', 'new') == 'old' and \
+                                p.get('value', '') == '-':
+                            GError(parent=self._guiparent,
+                                   message=_("Unable to run command:\n%(cmd)s\n\n"
+                                             "Option <%(opt)s>: read from standard input is not "
+                                             "supported by wxGUI") % {'cmd': ' '.join(command),
+                                                                      'opt': p.get('name', '')})
+                            return
+
+                if len(command) == 1 and hasParams and \
+                        command[0] != 'v.krige':
+                    # no arguments given
+                    try:
+                        GUI(parent = self._guiparent, lmgr = self._lmgr).ParseCommand(command)
+                    except GException, e:
+                        print >> sys.stderr, e
+                    return
+
+                # documenting old behavior/implementation:
+                # switch and focus if required
+                # TODO: this probably should be run command event
+                # TODO: this should be solved by the user using userData and onDone
+
+                # activate computational region (set with g.region)
+                # for all non-display commands.
+                if compReg:
+                    tmpreg = os.getenv("GRASS_REGION")
+                    if "GRASS_REGION" in os.environ:
+                        del os.environ["GRASS_REGION"]
+
+                # process GRASS command with argument
+                self.cmdThread.RunCmd(command,
+                                      stdout=self.cmdStdOut,
+                                      stderr=self.cmdStdErr,
+                                      onDone=onDone, onPrepare=onPrepare,
+                                      userData=userData,
+                                      env=os.environ.copy())
+                self.cmdOutputTimer.Start(50)
+
+                # deactivate computational region and return to display settings
+                if compReg and tmpreg:
+                    os.environ["GRASS_REGION"] = tmpreg
+        else:
+            # Send any other command to the shell. Send output to
+            # console output window
+            if len(command) == 1 and not skipInterface:
+                try:
+                    task = gtask.parse_interface(command[0])
+                except:
+                    task = None
+            else:
+                task = None
+
+            if task:
+                # process GRASS command without argument
+                GUI(parent=self._guiparent, lmgr=self._lmgr).ParseCommand(command)
+            else:
+                self.cmdThread.RunCmd(command,
+                                      stdout=self.cmdStdOut,
+                                      stderr=self.cmdStdErr,
+                                      onDone=onDone, onPrepare=onPrepare,
+                                      userData=userData)
+            self.cmdOutputTimer.Start(50)
+
+    def GetLog(self, err=False):
+        """!Get widget used for logging
+
+        @todo what's this?
+
+        @param err True to get stderr widget
+        """
+        if err:
+            return self.cmdStdErr
+
+        return self.cmdStdOut
+
+    def GetCmd(self):
+        """!Get running command or None"""
+        return self.requestQ.get()
+
+    def OnCmdAbort(self, event):
+        """!Abort running command"""
+        self.cmdThread.abort()
+        event.Skip()
+
+    def OnCmdRun(self, event):
+        """!Run command"""
+        self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
+        event.Skip()
+
+    def OnCmdDone(self, event):
+        """!Command done (or aborted)
+
+        Posts event EVT_MAP_CREATED.
+        """
+        # Process results here
+        try:
+            ctime = time.time() - event.time
+            if ctime < 60:
+                stime = _("%d sec") % int(ctime)
+            else:
+                mtime = int(ctime / 60)
+                stime = _("%(min)d min %(sec)d sec") % {'min': mtime,
+                                                        'sec': int(ctime - (mtime * 60))}
+        except KeyError:
+            # stopped deamon
+            stime = _("unknown")
+
+        if event.aborted:
+            # Thread aborted (using our convention of None return)
+            self.WriteWarning(_('Please note that the data are left in'
+                                ' inconsistent state and may be corrupted'))
+            msg = _('Command aborted')
+        else:
+            msg = _('Command finished')
+
+        self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime))
+
+        if event.onDone:
+            event.onDone(cmd=event.cmd, returncode=event.returncode)
+
+        self.cmdOutputTimer.Stop()
+
+        if event.cmd[0] == 'g.gisenv':
+            Debug.SetLevel()
+            self.Redirect()
+
+        # do nothing when no map added
+        if event.returncode != 0 or event.aborted:
+            event.Skip()
+            return
+
+        # find which maps were created
+        try:
+            task = GUI(show=None).ParseCommand(event.cmd)
+        except GException, e:
+            print >> sys.stderr, e
+            task = None
+            return
+
+        for p in task.get_options()['params']:
+            prompt = p.get('prompt', '')
+            if prompt in ('raster', 'vector', '3d-raster') and \
+                    p.get('age', 'old') == 'new' and \
+                    p.get('value', None):
+                name = p.get('value')
+                if '@' not in name:
+                    name = name + '@' + grass.gisenv()['MAPSET']
+                mapEvent = gMapCreated(wx.ID_ANY,
+                                       name=name, ltype=prompt, add=None)
+                wx.PostEvent(self, mapEvent)
+
+        event.Skip()
+
+    def OnProcessPendingOutputWindowEvents(self, event):
+        wx.GetApp().ProcessPendingEvents()
\ No newline at end of file

Modified: grass/trunk/gui/wxpython/gmodeler/frame.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/frame.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gmodeler/frame.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -34,8 +34,9 @@
 
 from core                 import globalvar
 from gui_core.widgets     import GNotebook
-from gui_core.goutput     import GConsole, \
-    EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE, EVT_OUTPUT_TEXT
+from core.gconsole        import GConsole, \
+    EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE, EVT_CMD_RUN, EVT_CMD_DONE
+from gui_core.goutput     import GConsoleWindow
 from core.events          import EVT_MAP_CREATED, EVT_SHOW_NOTIFICATION
 from core.debug           import Debug
 from core.gcmd            import GMessage, GException, GWarning, GError, RunCommand
@@ -107,8 +108,15 @@
         
         self.pythonPanel = PythonPanel(parent = self)
         
-        self.goutput = GConsole(parent = self)
-        self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+        self._gconsole = GConsole(guiparent = self)
+        self.goutput = GConsoleWindow(parent = self, gconsole = self._gconsole)
+        # here events are binded twice
+        self._gconsole.Bind(EVT_CMD_RUN,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 2))
+        self._gconsole.Bind(EVT_CMD_DONE,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 3))
         self.Bind(EVT_CMD_RUN, self.OnCmdRun)
         self.Bind(EVT_CMD_DONE, self.OnCmdDone)
         self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
@@ -481,7 +489,7 @@
         
     def OnRunModel(self, event):
         """!Run entire model"""
-        self.model.Run(self.goutput, self.OnDone, parent = self)
+        self.model.Run(self._gconsole, self.OnDone, parent = self)
         
     def OnDone(self, cmd, returncode):
         """!Computation finished"""
@@ -699,13 +707,17 @@
         
         self.canvas.Refresh()
 
-    def OnOutputText(self, event):
+    def _switchPageHandler(self, event, priority):
+        self._switchPage(priority = priority)
+        event.Skip()
+
+    def _switchPage(self, priority):
         """!Manages @c 'output' notebook page according to event priority."""
-        if event.priority == 1:
+        if priority == 1:
             self.notebook.HighlightPageByName('output')
-        if event.priority >= 2:
+        if priority >= 2:
             self.notebook.SetSelectionByName('output')
-        if event.priority >= 3:
+        if priority >= 3:
             self.SetFocus()
             self.Raise()
 

Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gui_core/forms.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -434,6 +434,7 @@
         # notebooks
         self.notebookpanel = CmdPanel(parent = self.panel, task = self.task,
                                       frame = self, lmgr = self.lmgr)
+        self._gconsole = self.notebookpanel._gconsole
         self.goutput = self.notebookpanel.goutput
         self.notebookpanel.OnUpdateValues = self.updateValuesHook
         guisizer.Add(item = self.notebookpanel, proportion = 1, flag = wx.EXPAND)
@@ -676,7 +677,7 @@
                 if self.task.path:
                     cmd[0] = self.task.path # full path
                 
-                ret = self.goutput.RunCmd(cmd, onDone = self.OnDone)
+                ret = self._gconsole.RunCmd(cmd, onDone = self.OnDone)
             except AttributeError, e:
                 print >> sys.stderr, "%s: Probably not running in wxgui.py session?" % (e)
                 print >> sys.stderr, "parent window is: %s" % (str(self.parent))
@@ -1619,16 +1620,24 @@
         # are we running from command line?
         ### add 'command output' tab regardless standalone dialog
         if self.parent.GetName() == "MainFrame" and self.parent.get_dcmd is None:
-            from gui_core.goutput import GConsole, EVT_OUTPUT_TEXT
-            self.goutput = GConsole(parent = self.notebook, margin = False)
-            self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+            from core.gconsole import GConsole, EVT_CMD_RUN, EVT_CMD_DONE
+            from gui_core.goutput import GConsoleWindow
+            self._gconsole = GConsole(guiparent = self.notebook)
+            self.goutput = GConsoleWindow(parent = self.notebook, gconsole = self._gconsole, margin = False)
+            self._gconsole.Bind(EVT_CMD_RUN,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 2))
+            self._gconsole.Bind(EVT_CMD_DONE,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 3))
             self.outpage = self.notebook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
             index = self.AddBitmapToImageList(section = 'output', imageList = imageList)
             if index >= 0:
                 self.notebook.SetPageImage('output', index)
         else:
             self.goutput = None
-        
+            self._gconsole = None
+
         self.manualTab = HelpPanel(parent = self.notebook, command = self.task.name)
         if not self.manualTab.GetFile():
             self.manualTab.Hide()
@@ -1848,13 +1857,17 @@
             # event is somehow propagated?
             event.StopPropagation()
 
-    def OnOutputText(self, event):
+    def _switchPageHandler(self, event, priority):
+        self._switchPage(priority = priority)
+        event.Skip()
+
+    def _switchPage(self, priority):
         """!Manages @c 'output' notebook page according to event priority."""
-        if event.priority == 1:
+        if priority == 1:
             self.notebook.HighlightPageByName('output')
-        if event.priority >= 2:
+        if priority >= 2:
             self.notebook.SetSelectionByName('output')
-        if event.priority >= 3:
+        if priority >= 3:
             self.SetFocus()
             self.Raise()
 

Modified: grass/trunk/gui/wxpython/gui_core/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/goutput.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/gui_core/goutput.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -4,11 +4,9 @@
 @brief Command output widgets
 
 Classes:
- - goutput::CmdThread
- - goutput::GConsole
- - goutput::GStdout
- - goutput::GStderr
+ - goutput::GConsoleWindow
  - goutput::GStc
+ - goutput::GConsoleFrame
 
 (C) 2007-2012 by the GRASS Development Team
 
@@ -17,218 +15,41 @@
 
 @author Michael Barton (Arizona State University)
 @author Martin Landa <landa.martin gmail.com>
- at author Vaclav Petras <wenzeslaus gmail.com> (copy&paste customization)
+ at author Vaclav Petras <wenzeslaus gmail.com>  (refactoring)
+ at author Anna Kratochvilova <kratochanna gmail.com> (refactoring)
 """
 
 import os
 import sys
-import re
 import textwrap
-import time
-import threading
-import Queue
-import codecs
-import locale
 
 sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
 
 import wx
 from   wx import stc
-from wx.lib.newevent import NewEvent
 
-import grass.script as grass
-from   grass.script import task as gtask
-
-from core            import globalvar
-from core            import utils
-from core.gcmd       import CommandThread, GMessage, GError, GException, EncodeString
-from core.events     import gShowNotification, gMapCreated
-from gui_core.forms  import GUI
+from core.gcmd       import GError, EncodeString
+from core.events     import gShowNotification
+from core.gconsole   import GConsole, \
+    EVT_CMD_OUTPUT, EVT_CMD_PROGRESS, EVT_CMD_RUN, EVT_CMD_DONE, \
+    EVT_WRITE_LOG, EVT_WRITE_CMD_LOG, EVT_WRITE_WARNING, EVT_WRITE_ERROR
 from gui_core.prompt import GPromptSTC, EVT_GPROMPT_RUN_CMD
-from core.debug      import Debug
 from core.settings   import UserSettings
 from gui_core.widgets import SearchModuleWidget, EVT_MODULE_SELECTED
 from core.modulesdata import ModulesData
 
-wxCmdOutput,   EVT_CMD_OUTPUT   = NewEvent()
-wxCmdProgress, EVT_CMD_PROGRESS = NewEvent()
-wxCmdRun,      EVT_CMD_RUN      = NewEvent()
-wxCmdDone,     EVT_CMD_DONE     = NewEvent()
-wxCmdAbort,    EVT_CMD_ABORT    = NewEvent()
-wxCmdPrepare,  EVT_CMD_PREPARE  = NewEvent()
 
-
 GC_EMPTY = 0
 GC_SEARCH = 1
 GC_PROMPT = 2
 
 
-def GrassCmd(cmd, env = None, stdout = None, stderr = None):
-    """!Return GRASS command thread"""
-    return CommandThread(cmd, env = env,
-                         stdout = stdout, stderr = stderr)
-
-class CmdThread(threading.Thread):
-    """!Thread for GRASS commands"""
-    requestId = 0
-    def __init__(self, receiver, requestQ = None, resultQ = None, **kwds):
-        """!
-        @param receiver event receiver (used in PostEvent)
-        """
-        threading.Thread.__init__(self, **kwds)
-        
-        if requestQ is None:
-            self.requestQ = Queue.Queue()
-        else:
-            self.requestQ = requestQ
-        
-        if resultQ is None:
-            self.resultQ = Queue.Queue()
-        else:
-            self.resultQ = resultQ
-        
-        self.setDaemon(True)
-        
-        self.receiver = receiver
-        self._want_abort_all = False
-        
-        self.start()
-
-    def RunCmd(self, *args, **kwds):
-        """!Run command in queue
-
-        @param args unnamed command arguments
-        @param kwds named command arguments
-
-        @return request id in queue
-        """
-        CmdThread.requestId += 1
-        
-        self.requestCmd = None
-        self.requestQ.put((CmdThread.requestId, args, kwds))
-        
-        return CmdThread.requestId
-
-    def SetId(self, id):
-        """!Set starting id"""
-        CmdThread.requestId = id
-        
-    def run(self):
-        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-        while True:
-            requestId, args, kwds = self.requestQ.get()
-            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-                if key in kwds:
-                    vars()[key] = kwds[key]
-                    del kwds[key]
-                else:
-                    vars()[key] = None
-            
-            if not vars()['callable']:
-                vars()['callable'] = GrassCmd
-            
-            requestTime = time.time()
-            
-            # prepare
-            event = wxCmdPrepare(cmd = args[0],
-                                 time = requestTime,
-                                 pid = requestId,
-                                 onPrepare = vars()['onPrepare'],
-                                 userData = vars()['userData'])
-            wx.PostEvent(self.receiver, event)
-            
-            # run command
-            event = wxCmdRun(cmd = args[0],
-                             pid = requestId)
-            
-            wx.PostEvent(self.receiver, event)
-            
-            time.sleep(.1)
-            self.requestCmd = vars()['callable'](*args, **kwds)
-            if self._want_abort_all:
-                self.requestCmd.abort()
-                if self.requestQ.empty():
-                    self._want_abort_all = False
-            
-            self.resultQ.put((requestId, self.requestCmd.run()))
-            
-            try:
-                returncode = self.requestCmd.module.returncode
-            except AttributeError:
-                returncode = 0 # being optimistic
-            
-            try:
-                aborted = self.requestCmd.aborted
-            except AttributeError:
-                aborted = False
-            
-            time.sleep(.1)
-
-            # set default color table for raster data
-            if UserSettings.Get(group = 'rasterLayer', key = 'colorTable', subkey = 'enabled') and \
-                    args[0][0][:2] == 'r.':
-                colorTable = UserSettings.Get(group = 'rasterLayer', key = 'colorTable', subkey = 'selection')
-                mapName = None
-                if args[0][0] == 'r.mapcalc':
-                    try:
-                        mapName = args[0][1].split('=', 1)[0].strip()
-                    except KeyError:
-                        pass
-                else:
-                    moduleInterface = GUI(show = None).ParseCommand(args[0])
-                    outputParam = moduleInterface.get_param(value = 'output', raiseError = False)
-                    if outputParam and outputParam['prompt'] == 'raster':
-                        mapName = outputParam['value']
-                
-                if mapName:
-                    argsColor = list(args)
-                    argsColor[0] = [ 'r.colors',
-                                     'map=%s' % mapName,
-                                     'color=%s' % colorTable ]
-                    self.requestCmdColor = vars()['callable'](*argsColor, **kwds)
-                    self.resultQ.put((requestId, self.requestCmdColor.run()))
-            
-            event = wxCmdDone(cmd = args[0],
-                              aborted = aborted,
-                              returncode = returncode,
-                              time = requestTime,
-                              pid = requestId,
-                              onDone = vars()['onDone'],
-                              userData = vars()['userData'])
-            
-            # send event
-            wx.PostEvent(self.receiver, event)
-            
-    def abort(self, abortall = True):
-        """!Abort command(s)"""
-        if abortall:
-            self._want_abort_all = True
-        self.requestCmd.abort()
-        if self.requestQ.empty():
-            self._want_abort_all = False
-
-
-# Occurs when some new text appears.
-# Text priority is specified by priority attribute.
-# Priority is 1 (lowest), 2, 3 (highest);
-# value 0 is currently not used and probably will not be used.
-# In theory, it can be used when text is completely uninteresting.
-# It is similar to wx.EVT_TEXT.
-# However, the new text or the whole text are not event attributes.
-gOutputText, EVT_OUTPUT_TEXT = NewEvent()
-
-# Occurs when ignored command is called.
-# Attribute cmd contains command (as a list).
-gIgnoredCmdRun, EVT_IGNORED_CMD_RUN = NewEvent()
-
-
-class GConsole(wx.SplitterWindow):
+class GConsoleWindow(wx.SplitterWindow):
     """!Create and manage output console for commands run by GUI.
     """
-    def __init__(self, parent, margin = False,
+    def __init__(self, parent, gconsole, margin = False,
                  style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
                  gcstyle = GC_EMPTY,
-                 ignoredCmdPattern = None,
                  **kwargs):
         """!
         @param parent gui parent
@@ -248,28 +69,40 @@
 
         # initialize variables
         self.parent = parent # GMFrame | CmdPanel | ?
+        self._gconsole = gconsole
 
         self._gcstyle = gcstyle
         self.lineWidth       = 80
-        self._ignoredCmdPattern = ignoredCmdPattern
-        # create queues
-        self.requestQ = Queue.Queue()
-        self.resultQ = Queue.Queue()
-        
+
         # progress bar
         self.progressbar = wx.Gauge(parent = self.panelOutput, id = wx.ID_ANY,
                                     range = 100, pos = (110, 50), size = (-1, 25),
                                     style = wx.GA_HORIZONTAL)
-        self.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
-        
+        self._gconsole.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
+        self._gconsole.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
+        self._gconsole.Bind(EVT_CMD_RUN, self.OnCmdRun)
+        self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone)
+        self._gconsole.Bind(EVT_WRITE_LOG,
+                            lambda event:
+                                self.WriteLog(text = event.text,
+                                              wrap = event.wrap,
+                                              switchPage = event.switchPage,
+                                              priority = event.priority))
+        self._gconsole.Bind(EVT_WRITE_CMD_LOG,
+                            lambda event:
+                                self.WriteCmdLog(line = event.line,
+                                                 pid = event.pid,
+                                                 switchPage = event.switchPage))
+        self._gconsole.Bind(EVT_WRITE_WARNING,
+                            lambda event:
+                                self.WriteWarning(line = event.line))
+        self._gconsole.Bind(EVT_WRITE_ERROR,
+                            lambda event:
+                                self.WriteError(line = event.line))
+
         # text control for command output
         self.cmdOutput = GStc(parent = self.panelOutput, id = wx.ID_ANY, margin = margin,
-                               wrap = None) 
-        self.cmdOutputTimer = wx.Timer(self.cmdOutput, id = wx.ID_ANY)
-        self.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
-        self.Bind(wx.EVT_TIMER, self.OnProcessPendingOutputWindowEvents)
-        self.Bind(EVT_CMD_RUN,     self.OnCmdRun)
-        self.Bind(EVT_CMD_DONE,    self.OnCmdDone)
+                               wrap = None)
 
         # information about available modules
         modulesData = ModulesData()
@@ -279,7 +112,8 @@
         # search depends on cmd prompt
         self.cmdPrompt = GPromptSTC(parent = self, modulesData = modulesData)
         self.cmdPrompt.Bind(EVT_GPROMPT_RUN_CMD, 
-                            lambda event: self.RunCmd(command = event.cmd))
+                            lambda event:
+                                self._gconsole.RunCmd(command = event.cmd))
 
         if not self._gcstyle & GC_PROMPT:
             self.cmdPrompt.Hide()
@@ -301,13 +135,6 @@
         else:
             self.search = None
 
-        # stream redirection
-        self.cmdStdOut = GStdout(self)
-        self.cmdStdErr = GStderr(self)
-        
-        # thread
-        self.cmdThread = CmdThread(self, self.requestQ, self.resultQ)
-        
         self.outputBox = wx.StaticBox(parent = self.panelOutput, id = wx.ID_ANY,
                                       label = " %s " % _("Output window"))
 
@@ -341,8 +168,7 @@
         self.btnCmdClear.Bind(wx.EVT_BUTTON,     self.cmdPrompt.OnCmdErase)
         self.btnOutputClear.Bind(wx.EVT_BUTTON,  self.OnOutputClear)
         self.btnOutputSave.Bind(wx.EVT_BUTTON,   self.OnOutputSave)
-        self.btnCmdAbort.Bind(wx.EVT_BUTTON,     self.OnCmdAbort)
-        self.Bind(EVT_CMD_ABORT,                 self.OnCmdAbort)
+        self.btnCmdAbort.Bind(wx.EVT_BUTTON,     self._gconsole.OnCmdAbort)
         self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.OnCmdProtocol)
         
         self._layout()
@@ -449,23 +275,7 @@
             return self.panelPrompt
 
         return self.panelOutput
-    
-    def Redirect(self):
-        """!Redirect stdout/stderr
-        """
-        if Debug.GetLevel() == 0 and int(grass.gisenv().get('DEBUG', 0)) == 0:
-            # don't redirect when debugging is enabled
-            sys.stdout = self.cmdStdOut
-            sys.stderr = self.cmdStdErr
-        else:
-            enc = locale.getdefaultlocale()[1]
-            if enc:
-                sys.stdout = codecs.getwriter(enc)(sys.__stdout__)
-                sys.stderr = codecs.getwriter(enc)(sys.__stderr__)
-            else:
-                sys.stdout = sys.__stdout__
-                sys.stderr = sys.__stderr__
-        
+
     def WriteLog(self, text, style = None, wrap = None,
                  switchPage = False, priority = 1):
         """!Generic method for writing log message in 
@@ -484,12 +294,8 @@
 
         # documenting old behavior/implementation:
         # switch notebook if required
-        if priority == 1:
-            if switchPage:
-                priority = 2
-        event = gOutputText(priority = priority)
-        wx.PostEvent(self, event)
-        
+        # now, let user to bind to the old event
+
         if not style:
             style = self.cmdOutput.StyleDefault
         
@@ -532,142 +338,6 @@
         """!Write message in error style"""
         self.WriteLog(line, style = self.cmdOutput.StyleError, switchPage = True)
 
-    def RunCmd(self, command, compReg = True, switchPage = False, skipInterface = False,
-               onDone = None, onPrepare = None, userData = None):
-        """!Run command typed into console command prompt (GPrompt).
-
-        @todo Document the other event.
-        @todo Solve problem with the other event
-        (now uses gOutputText event but there is no text,
-        use onPrepare handler instead?)
-
-        Posts event EVT_IGNORED_CMD_RUN when command which should be ignored
-        (according to ignoredCmdPattern) is run.
-        For example, see layer manager which handles d.* on its own.
-
-        @param command command given as a list (produced e.g. by utils.split())
-        @param compReg True use computation region
-        @param switchPage switch to output page
-        @param skipInterface True to do not launch GRASS interface
-        parser when command has no arguments given
-        @param onDone function to be called when command is finished
-        @param onPrepare function to be called before command is launched
-        @param userData data defined for the command
-        """
-        if len(command) == 0:
-            Debug.msg(2, "GPrompt:RunCmd(): empty command")
-            return
-        
-        # update history file
-        env = grass.gisenv()
-        try:
-            filePath = os.path.join(env['GISDBASE'],
-                                    env['LOCATION_NAME'],
-                                    env['MAPSET'],
-                                    '.bash_history')
-            fileHistory = codecs.open(filePath, encoding = 'utf-8', mode = 'a')
-        except IOError, e:
-            GError(_("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s") % 
-                    {'filePath': filePath, 'error' : e },
-                   parent = self)
-            fileHistory = None
-        
-        if fileHistory:
-            try:
-                fileHistory.write(' '.join(command) + os.linesep)
-            finally:
-                fileHistory.close()
-        
-        if command[0] in globalvar.grassCmd:
-            # send GRASS command without arguments to GUI command interface
-            # except ignored commands (event is emitted)
-
-            if self._ignoredCmdPattern and \
-              re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
-              '--help' not in command:
-                event = gIgnoredCmdRun(cmd = command)
-                wx.PostEvent(self, event)
-                return
-
-            else:
-                # other GRASS commands (r|v|g|...)
-                try:
-                    task = GUI(show = None).ParseCommand(command)
-                except GException, e:
-                    GError(parent = self,
-                           message = unicode(e),
-                           showTraceback = False)
-                    return
-                
-                hasParams = False
-                if task:
-                    options = task.get_options()
-                    hasParams = options['params'] and options['flags']
-                    # check for <input>=-
-                    for p in options['params']:
-                        if p.get('prompt', '') == 'input' and \
-                                p.get('element', '') == 'file' and \
-                                p.get('age', 'new') == 'old' and \
-                                p.get('value', '') == '-':
-                            GError(parent = self,
-                                   message = _("Unable to run command:\n%(cmd)s\n\n"
-                                               "Option <%(opt)s>: read from standard input is not "
-                                               "supported by wxGUI") % { 'cmd': ' '.join(command),
-                                                                         'opt': p.get('name', '') })
-                            return
-                
-                if len(command) == 1 and hasParams and \
-                        command[0] != 'v.krige':
-                    # no arguments given
-                    try:
-                        GUI(parent = self, lmgr = self.parent).ParseCommand(command)
-                    except GException, e:
-                        print >> sys.stderr, e
-                    return
-
-                # documenting old behavior/implementation:
-                # switch and focus if required
-                # TODO: this probably should be run command event
-                if switchPage:
-                    priority = 3
-                    event = gOutputText(priority = priority)
-                    wx.PostEvent(self, event)
-
-                # activate computational region (set with g.region)
-                # for all non-display commands.
-                if compReg:
-                    tmpreg = os.getenv("GRASS_REGION")
-                    if "GRASS_REGION" in os.environ:
-                        del os.environ["GRASS_REGION"]
-                
-                # process GRASS command with argument
-                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
-                                      onDone = onDone, onPrepare = onPrepare, userData = userData,
-                                      env = os.environ.copy())
-                self.cmdOutputTimer.Start(50)
-                
-                # deactivate computational region and return to display settings
-                if compReg and tmpreg:
-                    os.environ["GRASS_REGION"] = tmpreg
-        else:
-            # Send any other command to the shell. Send output to
-            # console output window
-            if len(command) == 1 and not skipInterface:
-                try:
-                    task = gtask.parse_interface(command[0])
-                except:
-                    task = None
-            else:
-                task = None
-                
-            if task:
-                # process GRASS command without argument
-                GUI(parent = self, lmgr = self.parent).ParseCommand(command)
-            else:
-                self.cmdThread.RunCmd(command, stdout = self.cmdStdOut, stderr = self.cmdStdErr,
-                                      onDone = onDone, onPrepare = onPrepare, userData = userData)
-            self.cmdOutputTimer.Start(50)
-        
     def OnOutputClear(self, event):
         """!Clear content of output window"""
         self.cmdOutput.SetReadOnly(False)
@@ -678,17 +348,7 @@
     def GetProgressBar(self):
         """!Return progress bar widget"""
         return self.progressbar
-    
-    def GetLog(self, err = False):
-        """!Get widget used for logging
 
-        @param err True to get stderr widget
-        """
-        if err:
-            return self.cmdStdErr
-        
-        return self.cmdStdOut
-    
     def OnOutputSave(self, event):
         """!Save (selected) text from output window to the file"""
         text = self.cmdOutput.GetSelectedText()
@@ -722,10 +382,6 @@
         
         dlg.Destroy()
 
-    def GetCmd(self):
-        """!Get running command or None"""
-        return self.requestQ.get()
-    
     def SetCopyingOfSelectedText(self, copy):
         """!Enable or disable copying of selected text in to clipboard.
         Effects prompt and output.
@@ -751,8 +407,6 @@
 
         # documenting old behavior/implementation:
         # add elipses if not active
-        event = gOutputText(priority = 1)
-        wx.PostEvent(self, event)
 
     def OnCmdProgress(self, event):
         """!Update progress message info"""
@@ -803,90 +457,21 @@
             dlg.Destroy()
             
         event.Skip()
-        
-    def OnCmdAbort(self, event):
-        """!Abort running command"""
-        self.cmdThread.abort()
-        event.Skip()
-        
+
     def OnCmdRun(self, event):
         """!Run command"""
-        self.WriteCmdLog('(%s)\n%s' % (str(time.ctime()), ' '.join(event.cmd)))
         self.btnCmdAbort.Enable()
 
         event.Skip()
 
     def OnCmdDone(self, event):
         """!Command done (or aborted)
-
-        Posts event EVT_MAP_CREATED.
         """
-
-        # Process results here
-        try:
-            ctime = time.time() - event.time
-            if ctime < 60:
-                stime = _("%d sec") % int(ctime)
-            else:
-                mtime = int(ctime / 60)
-                stime = _("%(min)d min %(sec)d sec") %  { 'min' : mtime, 
-                                                          'sec' : int(ctime - (mtime * 60)) }
-        except KeyError:
-            # stopped deamon
-            stime = _("unknown")
-        
-        if event.aborted:
-            # Thread aborted (using our convention of None return)
-            self.WriteLog(_('Please note that the data are left in inconsistent state '
-                            'and may be corrupted'), self.cmdOutput.StyleWarning)
-            msg = _('Command aborted')
-        else:
-            msg = _('Command finished')
-            
-        self.WriteCmdLog('(%s) %s (%s)' % (str(time.ctime()), msg, stime))
         self.btnCmdAbort.Enable(False)
-        
-        if event.onDone:
-            event.onDone(cmd = event.cmd, returncode = event.returncode)
-        
-        self.progressbar.SetValue(0) # reset progress bar on '0%'
 
-        self.cmdOutputTimer.Stop()
-
-        if event.cmd[0] == 'g.gisenv':
-            Debug.SetLevel()
-            self.Redirect()
-
-        # do nothing when no map added
-        if event.returncode != 0 or event.aborted:
-            event.Skip()
-            return
-
-        # find which maps were created
-        try:
-            task = GUI(show = None).ParseCommand(event.cmd)
-        except GException, e:
-            print >> sys.stderr, e
-            task = None
-            return
-            
-        for p in task.get_options()['params']:
-            prompt = p.get('prompt', '')
-            if prompt in ('raster', 'vector', '3d-raster') and \
-                    p.get('age', 'old') == 'new' and \
-                    p.get('value', None):
-                name = p.get('value')
-                if '@' not in name:
-                    name = name + '@' + grass.gisenv()['MAPSET']
-                mapEvent = gMapCreated(self.GetId(),
-                                       name = name, ltype = prompt, add = None)
-                wx.PostEvent(self, mapEvent)
-
+        self.progressbar.SetValue(0) # reset progress bar on '0%'
         event.Skip()
 
-    def OnProcessPendingOutputWindowEvents(self, event):
-        wx.GetApp().ProcessPendingEvents()
-
     def ResetFocus(self):
         """!Reset focus"""
         self.cmdPrompt.SetFocus()
@@ -894,112 +479,8 @@
     def GetPrompt(self):
         """!Get prompt"""
         return self.cmdPrompt
-    
-class GStdout:
-    """!GConsole standard output
 
-    Based on FrameOutErr.py
 
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, receiver):
-        """!
-        @param receiver event receiver (used in PostEvent)
-        """
-        self.receiver = receiver
-
-    def write(self, s):
-        if len(s) == 0 or s == '\n':
-            return
-
-        for line in s.splitlines():
-            if len(line) == 0:
-                continue
-            
-            evt = wxCmdOutput(text = line + '\n',
-                              type = '')
-            wx.PostEvent(self.receiver, evt)
-        
-class GStderr:
-    """!GConsole standard error output
-
-    Based on FrameOutErr.py
-
-    Name:      FrameOutErr.py
-    Purpose:   Redirecting stdout / stderr
-    Author:    Jean-Michel Fauth, Switzerland
-    Copyright: (c) 2005-2007 Jean-Michel Fauth
-    Licence:   GPL
-    """
-    def __init__(self, receiver):
-        """!
-        @param receiver event receiver (used in PostEvent)
-        """
-        self.receiver = receiver
-        
-        self.type = ''
-        self.message = ''
-        self.printMessage = False
-        
-    def flush(self):
-        pass
-    
-    def write(self, s):
-        if "GtkPizza" in s:
-            return
-        
-        # remove/replace escape sequences '\b' or '\r' from stream
-        progressValue = -1
-        
-        for line in s.splitlines():
-            if len(line) == 0:
-                continue
-            
-            if 'GRASS_INFO_PERCENT' in line:
-                value = int(line.rsplit(':', 1)[1].strip())
-                if value >= 0 and value < 100:
-                    progressValue = value
-                else:
-                    progressValue = 0
-            elif 'GRASS_INFO_MESSAGE' in line:
-                self.type = 'message'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_WARNING' in line:
-                self.type = 'warning'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_ERROR' in line:
-                self.type = 'error'
-                self.message += line.split(':', 1)[1].strip() + '\n'
-            elif 'GRASS_INFO_END' in line:
-                self.printMessage = True
-            elif self.type == '':
-                if len(line) == 0:
-                    continue
-                evt = wxCmdOutput(text = line,
-                                  type = '')
-                wx.PostEvent(self.receiver, evt)
-            elif len(line) > 0:
-                self.message += line.strip() + '\n'
-
-            if self.printMessage and len(self.message) > 0:
-                evt = wxCmdOutput(text = self.message,
-                                  type = self.type)
-                wx.PostEvent(self.receiver, evt)
-
-                self.type = ''
-                self.message = ''
-                self.printMessage = False
-
-        # update progress message
-        if progressValue > -1:
-            # self.gmgauge.SetValue(progressValue)
-            evt = wxCmdProgress(value = progressValue)
-            wx.PostEvent(self.receiver, evt)
-            
 class GStc(stc.StyledTextCtrl):
     """!Styled text control for GRASS stdout and stderr.
 
@@ -1218,7 +699,10 @@
         wx.Frame.__init__(self, parent = parent, id = id, title = title)
 
         panel = wx.Panel(self, id = wx.ID_ANY)
-        self.goutput = GConsole(parent = panel, gcstyle = GC_SEARCH | GC_PROMPT)
+        
+        self.gconsole = GConsole(guiparent=self)
+        self.goutput = GConsoleWindow(parent = panel, gconsole = self.gconsole,
+                                      gcstyle = GC_SEARCH | GC_PROMPT)
 
         mainSizer = wx.BoxSizer(wx.VERTICAL)
         mainSizer.Add(item = self.goutput, proportion = 1, flag = wx.EXPAND, border = 0)

Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/lmgr/frame.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -51,7 +51,9 @@
 from modules.mcalc_builder import MapCalcFrame
 from dbmgr.manager         import AttributeManager
 from core.workspace        import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
-from gui_core.goutput      import GConsole, GC_SEARCH, GC_PROMPT, EVT_OUTPUT_TEXT, EVT_IGNORED_CMD_RUN
+from core.gconsole         import GConsole, \
+    EVT_CMD_OUTPUT, EVT_CMD_RUN, EVT_CMD_DONE, EVT_IGNORED_CMD_RUN
+from gui_core.goutput      import GConsoleWindow, GC_SEARCH, GC_PROMPT
 from gui_core.dialogs      import GdalOutputDialog, DxfImportDialog, GdalImportDialog, MapLayersDialog
 from gui_core.dialogs      import EVT_APPLY_MAP_LAYERS
 from gui_core.dialogs      import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog
@@ -208,7 +210,7 @@
             mapdisp.Show()
         
         # redirect stderr to log area
-        self.goutput.Redirect()
+        self._gconsole.Redirect()
         
         # fix goutput's pane size (required for Mac OSX)`
         self.goutput.SetSashPosition(int(self.GetSize()[1] * .8))
@@ -263,11 +265,20 @@
         self.notebook.AddPage(page = self.notebookLayers, text = _("Map layers"), name = 'layers')
         
         # create 'command output' text area
-        self.goutput = GConsole(self,
-                                gcstyle = GC_SEARCH | GC_PROMPT,
-                                ignoredCmdPattern = '^d\..*|^r[3]?\.mapcalc$')
+        self._gconsole = GConsole(guiparent = self, lmgr = self,
+                                  ignoredCmdPattern = '^d\..*|^r[3]?\.mapcalc$')
+        self.goutput = GConsoleWindow(parent = self, gconsole = self._gconsole,
+                                      gcstyle = GC_SEARCH | GC_PROMPT)
         self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
-        self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
+        self._gconsole.Bind(EVT_CMD_OUTPUT,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 1))        
+        self._gconsole.Bind(EVT_CMD_RUN,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 2))
+        self._gconsole.Bind(EVT_CMD_DONE,
+                                lambda event:
+                                    self._switchPageHandler(event = event, priority = 3))
         self.goutput.Bind(EVT_IGNORED_CMD_RUN,
                           lambda event: self.RunSpecialCmd(event.cmd))
         self._setCopyingOfSelectedText()
@@ -530,13 +541,17 @@
 
         event.Skip()
 
-    def OnOutputText(self, event):
+    def _switchPageHandler(self, event, priority):
+        self._switchPage(priority = priority)
+        event.Skip()
+
+    def _switchPage(self, priority):
         """!Manages @c 'output' notebook page according to event priority."""
-        if event.priority == 1:
+        if priority == 1:
             self.notebook.HighlightPageByName('output')
-        if event.priority >= 2:
+        if priority >= 2:
             self.notebook.SetSelectionByName('output')
-        if event.priority >= 3:
+        if priority >= 3:
             self.SetFocus()
             self.Raise()
 

Modified: grass/trunk/gui/wxpython/lmgr/giface.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/giface.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/lmgr/giface.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -19,7 +19,7 @@
         self.lmgr = lmgr
 
     def RunCmd(self, *args, **kwargs):
-        self.lmgr.goutput.RunCmd(*args, **kwargs)
+        self.lmgr._gconsole.RunCmd(*args, **kwargs)
 
     def Help(self, entry):
         cmdlist = ['g.manual', 'entry=%s' % entry]
@@ -27,17 +27,17 @@
 
     def WriteLog(self, text, wrap = None,
                  switchPage = False, priority = 1):
-        self.lmgr.goutput.WriteLog(text = text, wrap = wrap, switchPage = switchPage,
+        self.lmgr._gconsole.WriteLog(text = text, wrap = wrap, switchPage = switchPage,
                                    priority = priority)
 
     def WriteCmdLog(self, line, pid = None, switchPage = True):
-        self.lmgr.goutput.WriteCmdLog(line = line, pid = pid, switchPage = switchPage)
+        self.lmgr._gconsole.WriteCmdLog(line = line, pid = pid, switchPage = switchPage)
 
     def WriteWarning(self, line):
-        self.lmgr.goutput.WriteWarning(line = line)
+        self.lmgr._gconsole.WriteWarning(line = line)
 
     def WriteError(self, line):
-        self.lmgr.goutput.WriteError(line = line)
+        self.lmgr._gconsole.WriteError(line = line)
 
     def GetLayerTree(self):
         return self.lmgr.GetLayerTree()

Modified: grass/trunk/gui/wxpython/psmap/frame.py
===================================================================
--- grass/trunk/gui/wxpython/psmap/frame.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/psmap/frame.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -34,7 +34,7 @@
 import grass.script as grass
 
 from gui_core.menu      import Menu
-from gui_core.goutput   import CmdThread, EVT_CMD_DONE
+from core.gconsole      import CmdThread, EVT_CMD_DONE
 from psmap.toolbars     import PsMapToolbar
 from core.gcmd          import RunCommand, GError, GMessage
 from core.settings      import UserSettings

Modified: grass/trunk/gui/wxpython/scripts/vkrige.py
===================================================================
--- grass/trunk/gui/wxpython/scripts/vkrige.py	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/scripts/vkrige.py	2012-11-23 14:54:53 UTC (rev 53989)
@@ -38,6 +38,7 @@
 
 from core import globalvar
 from gui_core import gselect
+from core import gconsole
 from gui_core import goutput
 from core.settings import UserSettings
 from gui_core.widgets import GNotebook
@@ -101,8 +102,12 @@
         self.goutput = goutput.GConsole(parent = self, margin = False)
         self.goutputId = self.RPackagesBook.GetPageCount()
         self.outpage = self.RPackagesBook.AddPage(page = self.goutput, text = _("Command output"), name = 'output')
-        self.goutput.Bind(goutput.EVT_OUTPUT_TEXT, self.OnOutputText)
-        
+        self._gconsole.Bind(gconsole.EVT_CMD_RUN,
+                            lambda event:
+                                self._switchPageHandler(event = event, priority = 2))
+        self._gconsole.Bind(gconsole.EVT_CMD_DONE,
+                            lambda event:
+                                self._switchPageHandler(event = event, priority = 3))
         self.RPackagesBook.SetSelection(0)
         KrigingSizer.Add(self.RPackagesBook, proportion = 1, flag = wx.EXPAND)
         
@@ -255,13 +260,17 @@
     def OnVarianceCBChecked(self, event):
         self.OutputVarianceMapName.Enable(event.IsChecked())
 
-    def OnOutputText(self, event):
-        """!Manages @c 'output' notebook page according to event priority."""
-        if event.priority == 1:
-            self.RPackagesBook.HighlightPageByName('output')
-        if event.priority >= 2:
-            self.RPackagesBook.SetSelectionByName('output')
-        if event.priority >= 3:
+    def _switchPageHandler(self, event, priority):
+        self._switchPage(priority = priority)
+        event.Skip()
+
+    def _switchPage(self, priority):
+        """!Manages @c 'output' notebook page according to priority."""
+        if priority == 1:
+            self.notebook.HighlightPageByName('output')
+        if priority >= 2:
+            self.notebook.SetSelectionByName('output')
+        if priority >= 3:
             self.SetFocus()
             self.Raise()
 

Modified: grass/trunk/gui/wxpython/wxpythonlib.dox
===================================================================
--- grass/trunk/gui/wxpython/wxpythonlib.dox	2012-11-23 14:53:41 UTC (rev 53988)
+++ grass/trunk/gui/wxpython/wxpythonlib.dox	2012-11-23 14:54:53 UTC (rev 53989)
@@ -66,6 +66,11 @@
  - gcmd::Popen
  - gcmd::Command
  - gcmd::CommandThread
+- core::gconsole
+ - goutput::CmdThread
+ - goutput::GStdout
+ - goutput::GStderr
+ - goutput::GConsole
 - core::menudata
  - menudata::MenuData
 - core::modulesdata
@@ -118,11 +123,8 @@
  - ghelp::HelpWindow
  - ghelp::HelpPanel
 - gui_core::goutput
- - goutput::CmdThread
- - goutput::GConsole
+ - goutput::GConsoleWindow
  - goutput::GStc
- - goutput::GStdout
- - goutput::GStderr
 - gui_core::gselect
  - gselect::Select
  - gselect::VectorSelect



More information about the grass-commit mailing list