[GRASS-SVN] r30486 - grass/trunk/gui/wxpython/gui_modules

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Mar 6 11:49:55 EST 2008


Author: martinl
Date: 2008-03-06 11:49:55 -0500 (Thu, 06 Mar 2008)
New Revision: 30486

Modified:
   grass/trunk/gui/wxpython/gui_modules/gcmd.py
   grass/trunk/gui/wxpython/gui_modules/menuform.py
   grass/trunk/gui/wxpython/gui_modules/preferences.py
   grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
Log:
wxGUI (menuform) Abort running command
(preferences) 'Command' settings (overwrite, close)


Modified: grass/trunk/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/gcmd.py	2008-03-06 07:05:05 UTC (rev 30485)
+++ grass/trunk/gui/wxpython/gui_modules/gcmd.py	2008-03-06 16:49:55 UTC (rev 30486)
@@ -25,6 +25,7 @@
 import sys
 import time
 import errno
+import signal
 
 import wx
 
@@ -123,7 +124,14 @@
     def _close(self, which):
         getattr(self, which).close()
         setattr(self, which, None)
-    
+
+    def kill(self):
+        """Try to kill running process"""
+        try:
+            os.kill(-self.pid, signal.SIGTERM) # kill whole group
+        except OSError:
+            pass
+
     if subprocess.mswindows:
         def send(self, input):
             if not self.stdin:
@@ -205,6 +213,22 @@
                 if not conn.closed:
                     fcntl.fcntl(conn, fcntl.F_SETFL, flags)
 
+# Define notification event for thread completion
+EVT_RESULT_ID = wx.NewId()
+
+def EVT_RESULT(win, func):
+    """Define Result Event"""
+    win.Connect(-1, -1, EVT_RESULT_ID, func)
+
+class ResultEvent(wx.PyEvent):
+    """Simple event to carry arbitrary result data"""
+    def __init__(self, data):
+        wx.PyEvent.__init__(self)
+
+        self.SetEventType(EVT_RESULT_ID)
+
+        self.cmdThread = data
+
 class Command:
     """
     Run GRASS command in separate thread
@@ -428,16 +452,22 @@
 
         Thread.__init__(self)
         
-        self.cmd          = cmd
-        self.stdin        = stdin
-        self.stdout       = stdout
-        self.stderr       = stderr
+        self.cmd    = cmd
+        self.stdin  = stdin
+        self.stdout = stdout
+        self.stderr = stderr
 
-        self.module       = None
-        self.rerr         = ''
+        self.module = None
+        self.rerr   = ''
 
+        self._want_abort = False
+        self.startTime = None
+
+        self.setDaemon(True)
+        
     def run(self):
         """Run command"""
+        self.startTime = time.time()
         # TODO: wx.Exectute/wx.Process (?)
         self.module = Popen(self.cmd,
                             stdin=subprocess.PIPE,
@@ -491,6 +521,12 @@
         # wait for the process to end, sucking in stuff until it does end
         while self.module.poll() is None:
             time.sleep(.1)
+            if self._want_abort: # abort running process
+                if hasattr(self.stderr, "gmstc"):
+                    self.module.kill()
+                    # -> GMConsole
+                    wx.PostEvent(self.stderr.gmstc.parent, ResultEvent(None))
+                return 
             if self.stdout:
                 line = self.__read_all(self.module.stdout)
                 self.stdout.write(line)
@@ -508,6 +544,17 @@
 
         self.rerr = self.__parseString(line)
 
+        if hasattr(self.stderr, "gmstc"):
+            # -> GMConsole
+            if self._want_abort: # abort running process
+                wx.PostEvent(self.stderr.gmstc.parent, ResultEvent(None))
+            else:
+                wx.PostEvent(self.stderr.gmstc.parent, ResultEvent(self))
+
+    def abort(self):
+        """Abort running process, used by main thread to signal an abort"""
+        self._want_abort = True
+
     def __parseString(self, string):
         """Parse line
 

Modified: grass/trunk/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/menuform.py	2008-03-06 07:05:05 UTC (rev 30485)
+++ grass/trunk/gui/wxpython/gui_modules/menuform.py	2008-03-06 16:49:55 UTC (rev 30486)
@@ -88,6 +88,8 @@
 import grassenv
 import gselect
 import gcmd
+import wxgui_utils
+from preferences import globalSettings as UserSettings
 try:
     import subprocess
 except:
@@ -602,7 +604,8 @@
         guisizer.Add (item=topsizer, proportion=0, flag=wx.EXPAND)
 
         # notebooks
-        self.notebookpanel = cmdPanel (parent=self.panel, task=self.task, standalone=self.standalone)
+        self.notebookpanel = cmdPanel (parent=self.panel, task=self.task, standalone=self.standalone,
+                                       mainFrame=self)
         ### add 'command output' tab also for dialog open from menu
         #         if self.standalone:
         self.goutput = self.notebookpanel.goutput
@@ -644,31 +647,39 @@
             btn_ok.Bind(wx.EVT_BUTTON, self.OnOK)
         else: # We're standalone
             # run
-            btn_run = wx.Button(parent=self.panel, id=wx.ID_OK, label= _("&Run"))
-            btn_run.SetToolTipString(_("Run the command"))
-            btn_run.SetDefault()
+            self.btn_run = wx.Button(parent=self.panel, id=wx.ID_OK, label= _("&Run"))
+            self.btn_run.SetToolTipString(_("Run the command"))
+            self.btn_run.SetDefault()
+            # abort
+            btn_abort = wx.Button(parent=self.panel, id=wx.ID_STOP)
+            btn_abort.SetToolTipString(_("Abort the running command"))
             # copy
-            btn_clipboard = wx.Button(parent=self.panel, id=wx.ID_COPY, label=_("C&opy"))
+            btn_clipboard = wx.Button(parent=self.panel, id=wx.ID_COPY)
             btn_clipboard.SetToolTipString(_("Copy the current command string to the clipboard"))
 
-            btnsizer.Add(item=btn_run, proportion=0,
+            btnsizer.Add(item=btn_abort, proportion=0,
                          flag=wx.ALL | wx.ALIGN_CENTER,
                          border=10)
 
+            btnsizer.Add(item=self.btn_run, proportion=0,
+                         flag=wx.ALL | wx.ALIGN_CENTER,
+                         border=10)
+
             btnsizer.Add(item=btn_clipboard, proportion=0,
                          flag=wx.ALL | wx.ALIGN_CENTER,
                          border=10)
 
-            btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
+            self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
+            btn_abort.Bind(wx.EVT_BUTTON, self.OnAbort)
             btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
 
         guisizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_CENTER)
 
         if self.get_dcmd is None:
-            # close dialog on run?
+            # close dialog when command is terminated
             self.closebox = wx.CheckBox(parent=self.panel,
-                                        label=_('Close dialog on run'), style = wx.NO_BORDER)
-            self.closebox.SetValue(False)
+                                        label=_('Close dialog on finish'), style = wx.NO_BORDER)
+            self.closebox.SetValue(UserSettings.Get(group='cmd', key='closeDlg', subkey='enabled'))
             guisizer.Add(item=self.closebox, proportion=0,
                          flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                          border=5)
@@ -680,12 +691,16 @@
         #self.notebookpanel.SetSize( (constrained_size[0] + 25, constrained_size[1]) ) 
         #self.notebookpanel.Layout()
 
-        # for too long descriptions
+        #
+        # put module description
+        #
         self.description = StaticWrapText (parent=self.panel, label=self.task.description)
         topsizer.Add (item=self.description, proportion=1, border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
 
+        #
         # do layout
+        #
         guisizer.SetSizeHints(self.panel)
         # called automatically by SetSizer()
         self.panel.SetAutoLayout(True) 
@@ -726,6 +741,9 @@
 
     def OnRun(self, event):
         """Run the command"""
+        if len(self.goutput.GetListOfCmdThreads()) > 0:
+            return
+
         cmd = self.createCmd()
 
         if cmd == [] or cmd == None:
@@ -741,17 +759,21 @@
                 print >> sys.stderr, "parent window is: %s" % (str(self.parent))
             # Send any other command to the shell.
         else:
-            runCmd = gcmd.Command(cmd)
+            gcmd.Command(cmd)
 
-        #if self.standalone:
+        # if self.standalone:
         # change page if needed
         if self.notebookpanel.notebook.GetSelection() != self.notebookpanel.outpageid:
             self.notebookpanel.notebook.SetSelection(self.notebookpanel.outpageid)
 
-        if self.get_dcmd is None:
-            # close dialog?
-            if self.closebox.IsChecked():
-                self.Close()
+        self.btn_run.Enable(False)
+        
+    def OnAbort(self, event):
+        """Abort running command"""
+        try:
+            self.goutput.GetListOfCmdThreads()[0].abort()
+        except KeyError:
+            pass
 
     def OnCopy(self, event):
         """Copy the command"""
@@ -802,9 +824,10 @@
     """
     A panel containing a notebook dividing in tabs the different guisections of the GRASS cmd.
     """
-    def __init__( self, parent, task, standalone, *args, **kwargs ):
+    def __init__( self, parent, task, standalone, mainFrame, *args, **kwargs ):
         wx.Panel.__init__( self, parent, *args, **kwargs )
 
+        self.parent = mainFrame
         self.task = task
         fontsize = 10
 
@@ -853,8 +876,7 @@
         # are we running from command line?
         ### add 'command output' tab regardless standalone dialog
         #        if standalone:
-        from gui_modules import wxgui_utils
-        self.goutput = wxgui_utils.GMConsole(self)
+        self.goutput = wxgui_utils.GMConsole(parent=self, margin=False)
         self.outpage = self.notebook.AddPage(self.goutput, text=_("Command output") )
         self.outpageid = self.notebook.GetPageCount() - 1
 
@@ -895,7 +917,9 @@
             chk.Bind(wx.EVT_CHECKBOX, self.OnSetValue)
             if f['name'] in ('verbose', 'quiet'):
                 chk.Bind(wx.EVT_CHECKBOX, self.OnVerbosity)
-
+            elif f['name'] == 'overwrite':
+                chk.SetValue(UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'))
+                
         #
         # parameters
         #

Modified: grass/trunk/gui/wxpython/gui_modules/preferences.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/preferences.py	2008-03-06 07:05:05 UTC (rev 30485)
+++ grass/trunk/gui/wxpython/gui_modules/preferences.py	2008-03-06 16:49:55 UTC (rev 30486)
@@ -75,6 +75,14 @@
             'leftDbClick' : { 'selection' : 0 },
             },
             #
+            # Command
+            #
+            'cmd': {
+            'overwrite' : { 'enabled' : False },
+            'closeDlg' : { 'enabled' : False },
+            'verbosity' : { 'verbose' : 'grassenv' },
+            },
+            #
             # vdigit
             #
             'vdigit' : {
@@ -149,6 +157,9 @@
                                                                      'silk']
         self.internalSettings['advanced']['digitInterface']['choices'] = ['vedit',
                                                                           'vdigit']
+        self.internalSettings['cmd']['verbosity']['choices'] = ['grassenv',
+                                                                'verbose',
+                                                                'quiet']
 
     def GetMapsetPath(self):
         """Store mapset search path"""
@@ -323,7 +334,7 @@
     """User preferences dialog"""
     def __init__(self, parent, title=_("User settings"),
                  settings=globalSettings,
-                 style=wx.DEFAULT_DIALOG_STYLE):
+                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
         self.parent = parent # GMFrame
         self.title = title
         wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title,
@@ -339,6 +350,7 @@
         # create notebook pages
         self.__CreateGeneralPage(notebook)
         self.__CreateDisplayPage(notebook)
+        self.__CreateCmdPage(notebook)
         self.__CreateAttributeManagerPage(notebook)
         self.__CreateAdvancedPage(notebook)
 
@@ -405,7 +417,7 @@
                       pos=(row, 1))
         
         sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
-        border.Add(item=sizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=3)
+        border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
 
         panel.SetSizer(border)
         
@@ -474,6 +486,56 @@
         
         return panel
 
+    def __CreateCmdPage(self, notebook):
+        """Create notebook page for commad dialog settings"""
+        panel = wx.Panel(parent=notebook, id=wx.ID_ANY)
+        notebook.AddPage(page=panel, text=_("Command"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        box   = wx.StaticBox (parent=panel, id=wx.ID_ANY, label=" %s " % _("Command dialog settings"))
+        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+        gridSizer = wx.GridBagSizer (hgap=3, vgap=3)
+        gridSizer.AddGrowableCol(0)
+
+        #
+        # command dialog settings
+        #
+        row = 0
+        # overwrite
+        overwrite = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+                                label=_("Allow output files to overwrite existing files"),
+                                name="IsChecked")
+        overwrite.SetValue(self.settings.Get(group='cmd', key='overwrite', subkey='enabled'))
+        self.winId['cmd:overwrite:enabled'] = overwrite.GetId()
+
+        gridSizer.Add(item=overwrite,
+                      pos=(row, 0), span=(1, 2))
+        row += 1
+        # close
+        close = wx.CheckBox(parent=panel, id=wx.ID_ANY,
+                            label=_("Close on finish"),
+                            name="IsChecked")
+        close.SetValue(self.settings.Get(group='cmd', key='closeDlg', subkey='enabled'))
+        self.winId['cmd:closeDlg:enabled'] = close.GetId()
+
+        gridSizer.Add(item=close,
+                      pos=(row, 0), span=(1, 2))
+        row += 1
+        # verbosity
+        verbosity = wx.Choice(parent=panel, id=wx.ID_ANY, size=(200, -1),
+                              choices=self.settings.Get(group='general', key='verbosity', subkey='choices', internal=True),
+                              name="GetSelection")
+        mapsetPath.SetSelection(self.settings.Get(group='general', key='mapsetPath', subkey='selection'))
+        self.winId['general:mapsetPath:selection'] = mapsetPath.GetId()
+
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
+        border.Add(item=sizer, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
+
+        panel.SetSizer(border)
+        
+        return panel
+
     def __CreateAttributeManagerPage(self, notebook):
         """Create notebook page concerning for 'Attribute Table Manager' settings"""
         panel = wx.Panel(parent=notebook, id=wx.ID_ANY)

Modified: grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py	2008-03-06 07:05:05 UTC (rev 30485)
+++ grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py	2008-03-06 16:49:55 UTC (rev 30486)
@@ -1022,15 +1022,15 @@
     Create and manage output console for commands entered on the
     GIS Manager command line.
     """
-    def __init__(self, parent, id=wx.ID_ANY,
+    def __init__(self, parent, id=wx.ID_ANY, margin=False,
                  pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=wx.TAB_TRAVERSAL|wx.FULL_REPAINT_ON_RESIZE):
+                 style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE):
         wx.Panel.__init__(self, parent, id, pos, size, style)
 
         # initialize variables
         self.Map             = None
-        self.parent          = parent              # GMFrame
-        self.cmdThreads      = []                  # list of command threads (alive or dead)
+        self.parent          = parent # GMFrame
+        self.cmdThreads      = []     # list of running commands (alive or dead)
 
         # progress bar
         self.console_progressbar = wx.Gauge(parent=self, id=wx.ID_ANY,
@@ -1038,11 +1038,7 @@
                                             style=wx.GA_HORIZONTAL)
 
         # text control for command output
-        ### self.cmd_output = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="",
-        ### style=wx.TE_MULTILINE| wx.TE_READONLY)
-        ### self.cmd_output.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN,
-        ### wx.NORMAL, wx.NORMAL, 0, ''))
-        self.cmd_output = GMStc(parent=self, id=wx.ID_ANY)
+        self.cmd_output = GMStc(parent=self, id=wx.ID_ANY, margin=margin)
         # redirect
         self.cmd_stdout = GMStdout(self.cmd_output)
         self.cmd_stderr = GMStderr(self.cmd_output,
@@ -1054,7 +1050,7 @@
         self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear)
         self.Bind(wx.EVT_BUTTON, self.SaveHistory,  self.console_save)
 
-         # output control layout
+        # output control layout
         boxsizer1 = wx.BoxSizer(wx.VERTICAL)
         gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0)
         boxsizer1.Add(item=self.cmd_output, proportion=1,
@@ -1074,12 +1070,32 @@
         boxsizer1.Fit(self)
         boxsizer1.SetSizeHints(self)
 
+        # set up event handler for any command thread results
+        gcmd.EVT_RESULT(self, self.OnResult)
+
+        # layout
         self.SetAutoLayout(True)
         self.SetSizer(boxsizer1)
 
+    def WriteCmdLog(self, line, pid=None):
+        """Write out line in selected style"""
+        self.cmd_output.GotoPos(self.cmd_output.GetEndStyled())
+        p1 = self.cmd_output.GetCurrentPos()
+        if pid:
+            line = '(' + str(pid) + ') ' + line
+        if len(line) < 80:
+            diff = 80 - len(line)
+            line += diff * ' '
+            line += '%s' % os.linesep
+            self.cmd_output.AddText(line)
+            self.cmd_output.EnsureCaretVisible()
+            p2 = self.cmd_output.GetCurrentPos()
+            self.cmd_output.StartStyling(p1, 0xff)
+            self.cmd_output.SetStyling(p2 - p1, self.cmd_output.StyleCommand)
+        
     def RunCmd(self, command):
         """
-        Run in GUI or shell GRASS (or other) commands typed into
+        Run in GUI GRASS (or other) commands typed into
         console command text widget, and send stdout output to output
         text widget.
 
@@ -1098,8 +1114,8 @@
         except:
             curr_disp = None
 
+        # command given as a string ?
         try:
-            # if command is not already a list, make it one
             cmdlist = command.strip().split(' ')
         except:
             cmdlist = command
@@ -1127,47 +1143,28 @@
                     wx.MessageBox(message=_("Command '%s' not yet implemented") % cmdlist[0])
                     return False
 
-                # add layer
+                # add layer into layer tree
                 self.parent.curr_page.maptree.AddLayer(ltype=layertype,
                                                        lcmd=cmdlist)
 
-            else: # other GRASS commands
+            else: # other GRASS commands (r|v|g|...)
                 if self.parent.notebook.GetSelection() != 1:
                     # select 'Command output' tab
                     self.parent.notebook.SetSelection(1)
                 
-                if len(self.GetListOfCmdThreads(onlyAlive=True)) > 0:
-                    busy = wx.BusyInfo(message=_("Please wait, there is another command "
-                                                 "currently running"),
-                                       parent=self.parent)
-                    # wx.Yield()
-                    time.sleep(3)
-                    busy.Destroy()
-                else:
                     # activate computational region (set with g.region)
                     # for all non-display commands.
                     tmpreg = os.getenv("GRASS_REGION")
                     os.unsetenv("GRASS_REGION")
 
                     if len(cmdlist) == 1:
-                        #process GRASS command without argument
+                        # process GRASS command without argument
                         menuform.GUI().ParseCommand(cmdlist, parentframe=self)
                     else:
                         # process GRASS command with argument
-                        self.cmd_output.GotoPos(self.cmd_output.GetEndStyled())
-                        p1 = self.cmd_output.GetCurrentPos()
-                        line = '$ %s' % ' '.join(cmdlist)
-                        if len(line) < 80:
-                            diff = 80 - len(line)
-                            line += diff * ' '
-                        line += '%s' % os.linesep
-                        self.cmd_output.AddText(line)
-                        self.cmd_output.EnsureCaretVisible()
-                        p2 = self.cmd_output.GetCurrentPos()
-                        self.cmd_output.StartStyling(p1, 0xff)
-                        self.cmd_output.SetStyling(p2 - p1, self.cmd_output.StyleCommand)
-
-                        # TODO: allow running multiple instances
+                        self.cmdPID = len(self.cmdThreads)+1
+                        self.WriteCmdLog('%s' % ' '.join(cmdlist), pid=self.cmdPID)
+                                                
                         grassCmd = gcmd.Command(cmdlist, wait=False,
                                                 stdout=self.cmd_stdout,
                                                 stderr=self.cmd_stderr)
@@ -1178,6 +1175,7 @@
                     if tmpreg:
                         os.environ["GRASS_REGION"] = tmpreg
 
+                    return grassCmd
         else:
             # Send any other command to the shell. Send output to
             # console output window
@@ -1191,13 +1189,12 @@
             # if command is not a GRASS command, treat it like a shell command
             generalCmd = subprocess.Popen(cmdlist,
                                           stdout=subprocess.PIPE,
-                                          stderr=subprocess.PIPE,
-                                          close_fds=True)
+                                          stderr=subprocess.PIPE)
             
             for outline in generalCmd.stdout:
                 print outline
                    
-        return True
+            return None
 
     def ClearHistory(self, event):
         """Clear history of commands"""
@@ -1231,7 +1228,7 @@
 
         dlg.Destroy()
 
-    def GetListOfCmdThreads(self, onlyAlive=False):
+    def GetListOfCmdThreads(self, onlyAlive=True):
         """Return list of command threads)"""
         list = []
         for t in self.cmdThreads:
@@ -1243,6 +1240,26 @@
 
         return list
 
+    def OnResult(self, event):
+        """Show result status"""
+        if event.cmdThread is None:
+            # Thread aborted (using our convention of None return)
+            self.WriteCmdLog(_('Command aborted'),
+                             pid=self.cmdPID)
+        else:
+            # Process results here
+            self.WriteCmdLog(_('Command finished (%d sec)') % (time.time() - event.cmdThread.startTime),
+                             pid=self.cmdPID)
+
+        self.console_progressbar.SetValue(0) # reset progress bar on '0%'
+        if hasattr(self.parent.parent, "btn_run"): # menuform.mainFrame
+            dialog = self.parent.parent
+            dialog.btn_run.Enable(True)
+            if dialog.get_dcmd is None and \
+                   dialog.closebox.IsChecked():
+                time.sleep(1)
+                dialog.Close()
+
 class GMStdout:
     """GMConsole standard output
 
@@ -1297,7 +1314,7 @@
                 if value < 100:
                     self.gmgauge.SetValue(value)
                 else:
-                    self.gmgauge.SetValue(0) # reset progress bar on '100%'
+                    self.gmgauge.SetValue(0) # reset progress bar on '0%'
             elif 'GRASS_INFO_MESSAGE' in line:
                 type = 'message'
                 message += line.split(':')[1].strip()
@@ -1346,7 +1363,7 @@
     Copyright: (c) 2005-2007 Jean-Michel Fauth
     Licence:   GPL
     """    
-    def __init__(self, parent, id):
+    def __init__(self, parent, id, margin=False):
         wx.stc.StyledTextCtrl.__init__(self, parent, id)
         self.parent = parent
         
@@ -1381,23 +1398,25 @@
         self.StyleSetSpec(self.StyleWarning, self.StyleWarningSpec)
         self.StyleSetSpec(self.StyleMessage, self.StyleMessageSpec)
         self.StyleSetSpec(self.StyleUnknown, self.StyleUnknownSpec)
-        
+
         #
-        # margin widths
+        # line margins
         #
-        self.SetMarginWidth(0, 0)
+        # TODO print number only from cmdlog
         self.SetMarginWidth(1, 0)
         self.SetMarginWidth(2, 0)
+        if margin:
+            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+            self.SetMarginWidth(0, 30)
+        else:
+            self.SetMarginWidth(0, 0)
 
         #
         # miscellaneous
         #
-        self.SetMarginLeft(2)
         self.SetViewWhiteSpace(False)
         self.SetTabWidth(4)
         self.SetUseTabs(False)
-        # self.SetEOLMode(wx.stc.STC_EOL_CRLF)
-        # self.SetViewEOL(True)
         self.UsePopUp(True)
         self.SetSelBackground(True, "#FFFF00")
         self.SetUseHorizontalScrollBar(True)



More information about the grass-commit mailing list