[GRASS-SVN] r40068 - in grass/branches/develbranch_6/gui/wxpython: . gui_modules

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Dec 19 13:37:42 EST 2009


Author: cmbarton
Date: 2009-12-19 13:37:42 -0500 (Sat, 19 Dec 2009)
New Revision: 40068

Modified:
   grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
   grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
   grass/branches/develbranch_6/gui/wxpython/wxgui.py
Log:
Advanced grass command console. Try again with repaired subversion installation.

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py	2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py	2009-12-19 18:37:42 UTC (rev 40068)
@@ -36,6 +36,8 @@
 import utils
 import preferences
 import menuform
+import prompt
+
 from debug import Debug as Debug
 from preferences import globalSettings as UserSettings
 
@@ -145,6 +147,7 @@
             self._notebook = self.parent.notebook
         self.lineWidth       = 80
         self.pageid          = pageid
+                        
         # remember position of line begining (used for '\r')
         self.linePos         = -1
         
@@ -162,7 +165,7 @@
                                             style=wx.GA_HORIZONTAL)
         self.console_progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
         # abort
-        self.btn_abort = wx.Button(parent=self, id=wx.ID_STOP)
+        self.btn_abort = wx.Button(self, -1, "Abort command", size=(125,-1))
         self.btn_abort.SetToolTipString(_("Abort the running command"))
         self.btn_abort.Bind(wx.EVT_BUTTON, self.OnCmdAbort)
         self.btn_abort.Enable(False)
@@ -179,6 +182,11 @@
         self.Bind(EVT_CMD_DONE, self.OnCmdDone)
         
         #
+        # command prompt
+        #
+        self.cmd_prompt = prompt.GPrompt(self, id=wx.ID_ANY)
+
+        #
         # stream redirection
         #
         self.cmd_stdout = GMStdout(self)
@@ -192,8 +200,10 @@
         #
         # buttons
         #
-        self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR)
-        self.console_save  = wx.Button(parent=self, id=wx.ID_SAVE)
+        self.console_clear = wx.Button(self, -1, "Clear output", size=(125,-1))
+        self.cmd_clear = wx.Button(self, -1, "Clear command", size=(125,-1))
+        self.console_save  = wx.Button(self, -1, "Save output", size=(125,-1))
+        self.Bind(wx.EVT_BUTTON, self.cmd_prompt.OnCmdErase, self.cmd_clear)
         self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear)
         self.Bind(wx.EVT_BUTTON, self.SaveHistory,  self.console_save)
 
@@ -204,27 +214,31 @@
     def __layout(self):
         """!Do layout"""
         boxsizer1 = wx.BoxSizer(wx.VERTICAL)
-        gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0)
+        gridsizer1 = wx.GridSizer(rows=1, cols=4, vgap=0, hgap=0)
+        
         boxsizer1.Add(item=self.cmd_output, proportion=1,
-                      flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0)
+                      flag=wx.EXPAND | wx.ALIGN_BOTTOM, border=0)
+        boxsizer1.Add(item=self.cmd_prompt, proportion=0,
+                      flag=wx.EXPAND | wx.FIXED_MINSIZE | wx.ALIGN_BOTTOM, border=0)
+                                            
         gridsizer1.Add(item=self.console_clear, proportion=0,
-                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
+                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
         gridsizer1.Add(item=self.console_save, proportion=0,
-                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
-
-
+                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
+        gridsizer1.Add(item=self.cmd_clear, proportion=0,
+                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
+        gridsizer1.Add(item=self.btn_abort, proportion=0,
+                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
         boxsizer1.Add(item=gridsizer1, proportion=0,
                       flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM,
                       border=5)
+                      
         boxsizer2 = wx.BoxSizer(wx.HORIZONTAL)
         boxsizer2.Add(item=self.console_progressbar, proportion=1,
                       flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL)
-        boxsizer2.Add(item=self.btn_abort, proportion=0,
-                      flag=wx.ALIGN_CENTRE_VERTICAL | wx.LEFT,
-                      border = 5)
         boxsizer1.Add(item=boxsizer2, proportion=0,
-                      flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.ALL,
-                      border=5)
+                      flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.LEFT | wx.RIGHT |
+                      wx.TOP, border=5)
         
         boxsizer1.Fit(self)
         boxsizer1.SetSizeHints(self)
@@ -232,6 +246,7 @@
         # layout
         self.SetAutoLayout(True)
         self.SetSizer(boxsizer1)
+        self.Layout()
 
     def Redirect(self):
         """!Redirect stderr
@@ -269,7 +284,8 @@
         
         # p1 = self.cmd_output.GetCurrentPos()
         p1 = self.cmd_output.GetEndStyled()
-        self.cmd_output.GotoPos(p1)
+#        self.cmd_output.GotoPos(p1)
+        self.cmd_output.DocumentEnd()
         
         for line in text.splitlines():
             # fill space
@@ -349,7 +365,10 @@
                 self.parent.cmdinput.SetHistoryItems()
             except AttributeError:
                 pass
-        
+
+        # allow writing to output window
+        self.cmd_output.SetReadOnly(False)
+                
         if cmdlist[0] in globalvar.grassCmd['all']:
             # send GRASS command without arguments to GUI command interface
             # except display commands (they are handled differently)
@@ -410,7 +429,7 @@
                     if os.environ.has_key("GRASS_REGION"):
                         del os.environ["GRASS_REGION"]
                     
-                if len(cmdlist) == 1 and cmdlist[0] not in ('v.krige'):
+                if len(cmdlist) == 1:
                     import menuform
                     # process GRASS command without argument
                     menuform.GUI().ParseCommand(cmdlist, parentframe=self)
@@ -434,9 +453,9 @@
 
             # if command is not a GRASS command, treat it like a shell command
             try:
-                # gcmd.Command(cmdlist,
-                #             stdout=self.cmd_stdout,
-                #             stderr=self.cmd_stderr)
+#                gcmd.Command(cmdlist,
+#                         stdout=self.cmd_stdout,
+#                         stderr=self.cmd_stderr)
                 self.cmdThread.RunCmd(GrassCmd,
                                       onDone,
                                       cmdlist,
@@ -445,6 +464,9 @@
                 self.cmd_output_timer.Start(50)
             except gcmd.CmdError, e:
                 print >> sys.stderr, e
+
+        # reset output window to read only
+        self.cmd_output.SetReadOnly(True)
         
         return None
 
@@ -530,7 +552,7 @@
                 self.cmd_output.AddTextWrapped(message, wrap=60)
             else:
                 self.cmd_output.AddTextWrapped(message, wrap=None)
-	    
+
         p2 = self.cmd_output.GetCurrentPos()
         
         if p2 >= p1:
@@ -590,7 +612,7 @@
 
         # set focus on prompt
         if self.parent.GetName() == "LayerManager":
-            self.parent.cmdinput.SetFocus()
+            self.cmd_prompt.SetFocus()
             self.btn_abort.Enable(False)
         else:
             # updated command dialog
@@ -640,7 +662,7 @@
                     dialog.closebox.IsChecked():
                 time.sleep(1)
                 dialog.Close()
-        
+
         event.Skip()
         
     def OnProcessPendingOutputWindowEvents(self, event):
@@ -756,13 +778,14 @@
     def __init__(self, parent, id, margin=False, wrap=None):
         wx.stc.StyledTextCtrl.__init__(self, parent, id)
         self.parent = parent
+        self.SetUndoCollection(True)
+        self.SetReadOnly(True)
 
         #
         # styles
         #                
         self.SetStyle()
         
-
         #
         # line margins
         #
@@ -786,7 +809,7 @@
         self.SetUseHorizontalScrollBar(True)
 
         #
-        # bindins
+        # bindings
         #
         self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
         
@@ -872,5 +895,4 @@
                 else:
                     txt = _('Unable to encode text. Please set encoding in GUI preferences.') + '\n'
                     
-                self.AddText(txt) 
-    
+                self.AddText(txt) 
\ No newline at end of file

Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py	2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py	2009-12-19 18:37:42 UTC (rev 40068)
@@ -1,15 +1,12 @@
 """!
 @package prompt.py
 
- at brief wxGUI prompt
+ at brief GRASS prompt
 
 Classes:
  - GPrompt
- - PromptListCtrl
- - TextCtrlAutoComplete
 
- at todo: fix TextCtrlAutoComplete to work also on Macs (missing
-wx.PopupWindow())
+ at todo: reduce size of STC prompt to about 3 lines
 
 (C) 2009 by the GRASS Development Team
 This program is free software under the GNU General Public
@@ -17,6 +14,7 @@
 for details.
 
 @author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton <michael.barton at asu.edu>
 """
 
 import os
@@ -24,147 +22,420 @@
 import shlex
 
 import wx
-import wx.lib.mixins.listctrl as listmix
+import wx.stc
 
 from grass.script import core as grass
 
 import globalvar
-import utils
-import menuform
 import menudata
+import gcmd
 
-class GPrompt:
-    """!Interactive GRASS prompt"""
-    def __init__(self, parent):
-        self.parent = parent # GMFrame
+class GPrompt(wx.stc.StyledTextCtrl):
+    """!Styled GRASS prompt with autocomplete and calltips"""    
+    def __init__(self, parent, id, size=wx.DefaultSize, margin=False, wrap=None):
+        wx.stc.StyledTextCtrl.__init__(self, parent, id)
+        self.parent = parent
+        self.SetUndoCollection(True)        
+
+        #
+        # styles
+        #                
+        self.SetWrapMode(True)
         
-        # dictionary of modules (description, keywords, ...)
-        self.modules = self.parent.menudata.GetModules()
+        #
+        # create command and map lists for autocompletion
+        #
+        self.AutoCompSetIgnoreCase(False) 
         
-        self.panel, self.input = self.__create()
+        self.rastlist = []
+        self.vectlist = []
+        self.imglist = []
+        self.r3list = []
+        self.dblist = []
+        self.genlist = []
+        self.displist = []
         
-    def __create(self):
-        """!Create widget"""
-        cmdprompt = wx.Panel(self.parent)
-        
         #
-        # search
+        # Get available GRASS commands and parse into lists by command type for autocomplete
         #
-        searchTxt = wx.StaticText(parent = cmdprompt, id = wx.ID_ANY,
-                                  label = _("Find module:"))
-        
-        self.searchBy = wx.Choice(parent = cmdprompt, id = wx.ID_ANY,
-                             choices = [_("description"),
-                                        _("keywords")])
-        winHeight = self.searchBy.GetSize()[1]
+        for item in globalvar.grassCmd['all']:
+            if len(item.split('.')) > 1:
+                start,end = item.split('.',1)
+                if start == 'r': self.rastlist.append(end)
+                elif start == 'v': self.vectlist.append(end)
+                elif start == 'i': self.imglist.append(end)
+                elif start == 'r3': self.r3list.append(end)
+                elif start == 'db': self.dblist.append(end)
+                elif start == 'g': self.genlist.append(end)
+                elif start == 'd': self.displist.append(end)
 
-        self.search = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
-                             value = "", size = (-1, 25))
+        self.rastlist.sort()
+        self.vectlist.sort()
+        self.imglist.sort()
+        self.r3list.sort()
+        self.dblist.sort()
+        self.genlist.sort()
+        self.displist.sort()
+                        
+        #
+        # Create lists of element types and possible arguments for autocomplete
+        #
+        self.datatypes = []
+        self.maplists = {}
+        self.maptype = ''
+        self.datatypes = ['rast',
+                        'rast3d',
+                        'vect',
+                        'oldvect',
+                        'asciivect',
+                        'labels',
+                        'region',
+                        'region3d',
+                        'group',
+                        '3dview']
+
+        self.drastcmd = ['d.rast',
+                        'd.rgb',
+                        'd.his',
+                        'd.rast.arrow',
+                        'd.rast.num']
+                    
+        self.dvectcmd = ['d.vect',
+                        'd.vect.chart'
+                        'd.thematic.area',
+                        'd.vect.thematic']
         
-        label = wx.Button(parent = cmdprompt, id = wx.ID_ANY,
-                          label = _("&Cmd >"), size = (-1, winHeight))
-        label.SetToolTipString(_("Click for erasing command prompt"))
+        self.rastargs = ['map',
+                        'input',
+                        'rast',
+                        'raster',
+                        'red',
+                        'green',
+                        'blue',
+                        'h_map',
+                        'i_map',
+                        's_map',
+                        'hue_input',
+                        'intensity_input',
+                        'saturation_input',
+                        'red_input',
+                        'green_input',
+                        'blue_input']
+                        
+        self.__getfiles()
 
-        ### todo: fix TextCtrlAutoComplete to work also on Macs
-        ### reason: missing wx.PopupWindow()
-        try:
-            cmdinput = TextCtrlAutoComplete(parent = cmdprompt, id = wx.ID_ANY,
-                                            value = "",
-                                            style = wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
-                                            size = (-1, winHeight),
-                                            statusbar = self.parent.statusbar)
-        except NotImplementedError:
-            # wx.PopupWindow may be not available in wxMac
-            # see http://trac.wxwidgets.org/ticket/9377
-            cmdinput = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
-                                   value = "",
-                                   style=wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
-                                   size = (-1, 25))
-            self.searchBy.Enable(False)
-            self.search.Enable(False)
+        #
+        # command history buffer
+        #
+        self.cmdbuffer = []
+        self.cmdindex = 0
+
+        #
+        # line margins
+        #
+        # 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.SetViewWhiteSpace(False)
+#        self.SetTabWidth(4)
+        self.SetUseTabs(False)
+        self.UsePopUp(True)
+        self.SetSelBackground(True, "#FFFF00")
+        self.SetUseHorizontalScrollBar(True)
+
+        #
+        # bindings
+        #
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+ 
+    def __getfiles(self):   
+        """!Get accessible files for autocomplete"""
+        for item in self.datatypes:
+            mlist = grass.read_command("g.mlist", "m", type=item).splitlines()
+            mlist.sort()
+            self.maplists[item] = mlist
+            
+    def OnKeyPressed(self, event):
+        """!Key press capture for autocompletion, calltips, and command history"""
         
-        cmdinput.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, ''))
+        #keycodes used: "." = 46, "=" = 61, "," = 44 
+        line = ''
+        entry = ''
+        usage = ''
+        cmdtype = ''
+        cmdname = ''
+        cmd = ''
+                            
+        # CAN CHANGE: event.ControlDown() for manual autocomplete
         
-        wx.CallAfter(cmdinput.SetInsertionPoint, 0)
-        
-        # bidnings
-        label.Bind(wx.EVT_BUTTON,        self.OnCmdErase)
-        cmdinput.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
-        cmdinput.Bind(wx.EVT_TEXT,       self.OnUpdateStatusBar)
-        self.search.Bind(wx.EVT_TEXT,    self.OnSearchModule)
-        
-        # layout
-        sizer = wx.GridBagSizer(hgap=5, vgap=5)
-        sizer.AddGrowableRow(1)
-        sizer.AddGrowableCol(2)
+        if event.GetKeyCode() == 46 and not event.ShiftDown():
+            #GRASS command autocomplete when "." is pressed after r,v,i,g,db, or d
+            listcmds = []
+            pos = self.GetCurrentPos()
+            self.InsertText(pos,'.')
+            self.CharRight()
+            
+            entry = self.GetTextLeft()
+            if entry not in ['r.','v.','i.','g.','db.','d.']:
+                return
 
-        sizer.Add(item = searchTxt,
-                  flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL,
-                  pos = (0, 0))
+            if entry == 'r.': listcmds = self.rastlist
+            elif entry == 'v.': listcmds = self.vectlist
+            elif entry == 'i.': listcmds = self.imglist
+            elif entry == 'r3.': listcmds = self.r3list
+            elif entry == 'db.': listcmds = self.dblist
+            elif entry == 'g.': listcmds = self.genlist
+            elif entry == 'd.': listcmds = self.displist
 
-        sizer.Add(item = self.searchBy,
-                  flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
-                  pos = (0, 1))
+            if listcmds == []:
+                return
+            else:
+                self.AutoCompShow(0, " ".join(listcmds))                    
+            
+        elif event.GetKeyCode() == wx.WXK_TAB:
+            #GRASS command calltips
+                        
+            #Must be a command to the left somewhere
+            pos = self.GetCurrentPos()
+            entry = self.GetTextLeft()
+            cmd = entry.split()[0].strip()
+            if cmd not in globalvar.grassCmd['all']:
+                return
+            
+            usage, description = self.GetCommandUsage(cmd)
+                                        
+            self.CallTipSetBackground("PALE GREEN")
+            self.CallTipSetForeground("BLACK")
+            self.CallTipShow(pos, usage+'\n\n'+description)
+            
+        elif (event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown()) or \
+            event.GetKeyCode() == 61 or event.GetKeyCode() == 44:
+            #Autocompletion for map/data file name entry after '=', ',', or manually
+            
+            pos = self.GetCurrentPos()
+            entry = self.GetTextLeft()
+            if event.GetKeyCode() != 44:
+                self.maptype = ''
+            arg = ''
+            cmdtype = ''
+            cmdname = ''
+            cmd = ''
+
+            if entry.strip()[0:2] in ['r.','v.','i.','g.','db.','d.']:
+                cmdtype =  entry.strip()[0]
+                cmd = entry.split()[0].strip()
+                if cmd in globalvar.grassCmd['all']:
+                    cmdname = cmd.split('.')[1]
+                else:
+                    #No complete GRASS command found
+                    cmd = ''
+                    cmdname = ''
+            elif entry.strip()[0:4] == 'nviz':
+                cmdtype = ''
+                cmdname = cmd = 'nviz'
+            else:
+                #No partial or complete GRASS command found
+                return
+
+            cmdargs = entry.strip('=')
+            try:
+                arg = cmdargs.rsplit(' ',1)[1]
+            except:
+                arg = ''
+                
+            if event.GetKeyCode() == 61:
+                # autocompletion after '='
+                # insert the '=' and move to after the '=', ready for a map name
+                self.InsertText(pos,'=')
+                self.CharRight()
+
+                maplist = []
+                self.maptype = ''
+
+                #what kind of map/data type is desired?
+                if (((cmdtype in ['r', 'i'] or cmd in self.drastcmd) and arg in self.rastargs) or
+                  ((cmd=='nviz' or cmdtype=='r3') and arg in ['elevation','color']) or
+                  arg in ['rast', 'raster']):
+                    self.maptype = 'rast'
+                elif (((cmdtype=='v' or cmd in self.dvectcmd) and arg in ['map', 'input']) or
+                  (cmdtype=='r3' and arg=='input') or
+                  arg in ['vect', 'vector', 'points']):
+                    self.maptype = 'vect'
+                elif ((cmdtype=='r3' and arg in ['map', 'input']) or
+                  (cmdtype=='nviz' and arg=='volume') or arg=='rast3d'):
+                    self.maptype = 'rast3d'
+                elif arg=='labels':
+                    self.maptype ='labels'
+                elif arg=='region':
+                    self.maptype ='region'
+                elif arg=='region3d':
+                    self.maptype ='region3d'
+                elif arg=='group':
+                    self.maptype ='group'
+                elif arg=='3dview':
+                    self.maptype ='3dview'
+                    
+                print 'maptype at end of = ' + str(self.maptype)
+
+            elif event.GetKeyCode() == 44:
+                # autocompletion after ','
+                # if comma is pressed, use the same maptype as previous for multiple map entries
+                
+                # insert the comma and move to after the comma ready for a map name
+                self.InsertText(pos,',')
+                self.CharRight()
+                
+                #must apply to an entry where '=[string]' has already been entered
+                if '=' not in arg:
+                    return
+
+            elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
+                # manual autocompletion
+                # map entries without arguments (as in r.info [mapname]) use ctrl-shift
+                
+                maplist = []
+                if cmdtype=='r' or cmdtype=='i':
+                    self.maptype = 'rast'
+                elif cmdtype=='v':
+                    self.maptype = 'vect'
+                elif cmdtype=='r3':
+                    self.maptype = 'rast3d'
+                    
+            if self.maptype == '': 
+                return
+            else:
+                maplist = self.maplists[self.maptype]
+                self.AutoCompShow(0, " ".join(maplist))
+                        
+        elif event.GetKeyCode() in [wx.WXK_UP,wx.WXK_DOWN] and event.ControlDown():
+            # Command history using ctrl-up and ctrl-down   
+            
+            if self.cmdbuffer == []: return
+            txt = ''
+
+            self.DocumentEnd()
+            
+            # move through command history list index values
+            if event.GetKeyCode() == wx.WXK_UP:
+                self.cmdindex = self.cmdindex - 1
+            if event.GetKeyCode() == wx.WXK_DOWN:
+                self.cmdindex = self.cmdindex + 1
+            if self.cmdindex < 0:
+                self.cmdindex = 0
+            if self.cmdindex > len(self.cmdbuffer) - 1:
+                self.cmdindex = len(self.cmdbuffer) - 1
+            
+            try:
+                txt = self.cmdbuffer[self.cmdindex]
+            except:
+                pass
+                
+            # clear current line and insert command history    
+            self.DelLineLeft()
+            self.DelLineRight()
+            pos = self.GetCurrentPos()            
+            self.InsertText(pos,txt)
+            self.LineEnd()
+            
+        elif event.GetKeyCode() == wx.WXK_RETURN and self.AutoCompActive() == False:
+            # Run command on line when <return> is pressed    
+            
+            # find the command to run
+            line = str(self.GetCurLine()[0]).strip()
+            if len(line) == 0:
+                return
+            
+            # parse command into list
+            # TODO: shell commands should probably be passed as string           
+            cmd = shlex.split(str(line))
+            
+            #send the command list to the processor 
+            self.parent.RunCmd(cmd)
+                            
+            #add command to history    
+            self.cmdbuffer.append(line)
+            
+            #keep command history to a managable size
+            if len(self.cmdbuffer) > 200:
+                del self.cmdbuffer[0]
+            self.cmdindex = len(self.cmdbuffer)
+
+        else:
+            event.Skip()
+
+    def GetTextLeft(self):
+        """!Returns all text left of the caret"""
+        entry = ''
+        pos = self.GetCurrentPos()
+        self.HomeExtend()
+        entry = self.GetSelectedText().strip()
+        self.SetCurrentPos(pos)
         
-        sizer.Add(item = self.search,
-                  flag = wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
-                  border = 5,
-                  pos = (0, 2))
-        
-        sizer.Add(item = label, 
-                  flag = wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
-                  border = 5,
-                  pos = (1, 0))
-        
-        sizer.Add(item = cmdinput,
-                  flag = wx.EXPAND | wx.RIGHT,
-                  border = 5,
-                  pos = (1, 1), span = (1, 2))
-        
-        cmdprompt.SetSizer(sizer)
-        sizer.Fit(cmdprompt)
-        cmdprompt.Layout()
-        
-        return cmdprompt, cmdinput
+        return entry
 
-    def __checkKey(self, text, keywords):
-        """!Check if text is in keywords"""
-        found = 0
-        keys = text.split(',')
-        if len(keys) > 1: # -> multiple keys
-            for k in keys[:-1]:
-                k = k.strip()
-                for key in keywords: 
-                    if k == key: # full match
-                        found += 1
-                        break
-            k = keys[-1].strip()
-            for key in keywords:
-                if k in key: # partial match
-                    found +=1
+    def GetCommandUsage(self, command):
+        """!Returns command syntax by running command help"""
+        usage = ''
+        description = ''
+
+        ret, out  = gcmd.RunCommand(command, 'help', getErrorMsg = True)
+               
+        if ret == 0:
+            cmdhelp = out.splitlines()
+            addline = False
+            helplist = []
+            description = ''
+            for line in cmdhelp:
+                if "Usage:" in line:
+                    addline = True
+                    continue
+                elif "Flags:" in line:
+                    addline = False
                     break
-        else:
-            for key in keywords:
-                if text in key: # partial match
-                    found +=1
+                elif addline == True:
+                    line = line.strip()
+                    helplist.append(line)
+
+            for line in cmdhelp:
+                if "Description:" in line:
+                    addline = True
+                    continue
+                elif "Keywords:" in line:
+                    addline = False
                     break
+                elif addline == True:
+                    description += (line + ' ')
+                
+            description = description.strip()
+
+            for line in helplist:
+                usage += line + '\n'
+
+            return usage.strip(), description
+        else:
+            return ''   
+
+    def OnDestroy(self, evt):
+        """!The clipboard contents can be preserved after
+        the app has exited"""
         
-        if found == len(keys):
-            return True
-        
-        return False
+        wx.TheClipboard.Flush()
+        evt.Skip()
     
-    def GetPanel(self):
-        """!Get main widget panel"""
-        return self.panel
-
-    def GetInput(self):
-        """!Get main prompt widget"""
-        return self.input
-    
     def OnCmdErase(self, event):
         """!Erase command prompt"""
-        self.input.SetValue('')
+        self.Home()
+        self.DelLineRight()
         
     def OnRunCmd(self, event):
         """!Run command"""
@@ -193,474 +464,4 @@
             self.parent.statusbar.SetStatusText("")
         else:
             self.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
-            event.Skip()
-        
-    def OnSearchModule(self, event):
-        """!Search module by metadata"""
-        text = event.GetString()
-        if not text:
-            self.input.SetChoices(globalvar.grassCmd['all'])
-            return
-        
-        modules = []
-        for module, data in self.modules.iteritems():
-            if self.searchBy.GetSelection() == 0: # -> description
-                if text in data['desc']:
-                    modules.append(module)
-            else: # -> keywords
-                if self.__checkKey(text, data['keywords']):
-                    modules.append(module)
-        
-        self.parent.statusbar.SetStatusText(_("%d modules found") % len(modules))
-        self.input.SetChoices(modules)
-                    
-class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
-    def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition,
-                 size = wx.DefaultSize, style = 0):
-        wx.ListCtrl.__init__(self, parent, id, pos, size, style)
-        listmix.ListCtrlAutoWidthMixin.__init__(self)
-        
-class TextCtrlAutoComplete(wx.ComboBox, listmix.ColumnSorterMixin):
-    def __init__ (self, parent, statusbar,
-                  id = wx.ID_ANY, choices = [], **kwargs):
-        """!Constructor works just like wx.TextCtrl except you can pass in a
-        list of choices.  You can also change the choice list at any time
-        by calling setChoices.
-        
-        Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete
-        """
-        self.statusbar = statusbar
-        
-        if kwargs.has_key('style'):
-            kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']
-        else:
-            kwargs['style'] = wx.TE_PROCESS_ENTER
-        
-        wx.ComboBox.__init__(self, parent, id, **kwargs)
-        
-        # some variables
-        self._choices = choices
-        self._hideOnNoMatch = True
-        self._module = None      # currently selected module
-        self._choiceType = None  # type of choice (module, params, flags, raster, vector ...)
-        self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
-        self._historyItem = 0   # last item
-        
-        # sort variable needed by listmix
-        self.itemDataMap = dict()
-        
-        # widgets
-        try:
-            self.dropdown = wx.PopupWindow(self)
-        except NotImplementedError:
-            self.Destroy()
-            raise NotImplementedError
-        
-        # create the list and bind the events
-        self.dropdownlistbox = PromptListCtrl(parent = self.dropdown,
-                                              style = wx.LC_REPORT | wx.LC_SINGLE_SEL | \
-                                                  wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER,
-                                              pos = wx.Point(0, 0))
-        
-        listmix.ColumnSorterMixin.__init__(self, 1)
-        
-        # set choices (list of GRASS modules)
-        self._choicesCmd = globalvar.grassCmd['all']
-        self._choicesMap = dict()
-        for type in ('raster', 'vector'):
-            self._choicesMap[type] = grass.list_strings(type = type[:4])
-        # first search for GRASS module
-        self.SetChoices(self._choicesCmd)
-        
-        self.SetMinSize(self.GetSize())
-        # read history
-        self.SetHistoryItems()
-        
-        # bindings...
-        self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
-        self.Bind(wx.EVT_TEXT, self.OnEnteredText)
-        self.Bind(wx.EVT_KEY_DOWN , self.OnKeyDown)
-        ### self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
-
-        # if need drop down on left click
-        self.dropdown.Bind(wx.EVT_LISTBOX , self.OnListItemSelected, self.dropdownlistbox)
-        self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.OnListClick)
-        self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.OnListDClick)
-        self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.OnListColClick)
-
-        self.Bind(wx.EVT_COMBOBOX, self.OnCommandSelect)
-        
-    def _updateDataList(self, choices):
-        """!Update data list"""
-        # delete, if need, all the previous data
-        if self.dropdownlistbox.GetColumnCount() != 0:
-            self.dropdownlistbox.DeleteAllColumns()
-            self.dropdownlistbox.DeleteAllItems()
-        # and update the dict
-        if choices:
-            for numVal, data in enumerate(choices):
-                self.itemDataMap[numVal] = data
-        else:
-            numVal = 0
-        self.SetColumnCount(numVal)
-    
-    def _setListSize(self):
-        """!Set list size"""
-        choices = self._choices
-        longest = 0
-        for choice in choices:
-            longest = max(len(choice), longest)
-        longest += 3
-        itemcount = min(len( choices ), 7) + 2
-        charheight = self.dropdownlistbox.GetCharHeight()
-        charwidth = self.dropdownlistbox.GetCharWidth()
-        self.popupsize = wx.Size(charwidth*longest, charheight*itemcount)
-        self.dropdownlistbox.SetSize(self.popupsize)
-        self.dropdown.SetClientSize(self.popupsize)
-
-    def _showDropDown(self, show = True):
-        """!Either display the drop down list (show = True) or hide it
-        (show = False).
-        """
-        if show:
-            size = self.dropdown.GetSize()
-            width, height = self.GetSizeTuple()
-            x, y = self.ClientToScreenXY(0, height)
-            if size.GetWidth() != width:
-                size.SetWidth(width)
-                self.dropdown.SetSize(size)
-                self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
-            if (y + size.GetHeight()) < self._screenheight:
-                self.dropdown.SetPosition(wx.Point(x, y))
-            else:
-                self.dropdown.SetPosition(wx.Point(x, y - height - size.GetHeight()))
-        
-        self.dropdown.Show(show)
-    
-    def _listItemVisible(self):
-        """!Moves the selected item to the top of the list ensuring it is
-        always visible.
-        """
-        toSel = self.dropdownlistbox.GetFirstSelected()
-        if toSel == -1:
-            return
-        self.dropdownlistbox.EnsureVisible(toSel)
-
-    def _setModule(self, name):
-        """!Set module's choices (flags, parameters)""" 
-        # get module's description
-        if name in self._choicesCmd and not self._module:
-            try:
-                self._module = menuform.GUI().ParseInterface(cmd = [name])
-            except IOError:
-                self._module = None
-             
-        # set choices (flags)
-        self._choicesMap['flag'] = self._module.get_list_flags()
-        for idx in range(len(self._choicesMap['flag'])):
-            item = self._choicesMap['flag'][idx]
-            desc = self._module.get_flag(item)['label']
-            if not desc:
-                desc = self._module.get_flag(item)['description']
-            
-            self._choicesMap['flag'][idx] = '%s (%s)' % (item, desc)
-        
-        # set choices (parameters)
-        self._choicesMap['param'] = self._module.get_list_params()
-        for idx in range(len(self._choicesMap['param'])):
-            item = self._choicesMap['param'][idx]
-            desc = self._module.get_param(item)['label']
-            if not desc:
-                desc = self._module.get_param(item)['description']
-            
-            self._choicesMap['param'][idx] = '%s (%s)' % (item, desc)
-    
-    def _setValueFromSelected(self):
-         """!Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
-         Will do nothing if no item is selected in the wx.ListCtrl.
-         """
-         sel = self.dropdownlistbox.GetFirstSelected()
-         if sel < 0:
-             return
-         
-         if self._colFetch != -1:
-             col = self._colFetch
-         else:
-             col = self._colSearch
-         itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
-         
-         cmd = shlex.split(str(self.GetValue()))
-         if len(cmd) > 0 and cmd[0] in self._choicesCmd:
-             # -> append text (skip last item)
-             if self._choiceType == 'param':
-                 itemtext = itemtext.split(' ')[0]
-                 self.SetValue(' '.join(cmd) + ' ' + itemtext + '=')
-                 optType = self._module.get_param(itemtext)['prompt']
-                 if optType in ('raster', 'vector'):
-                     # -> raster/vector map
-                     self.SetChoices(self._choicesMap[optType], optType)
-             elif self._choiceType == 'flag':
-                 itemtext = itemtext.split(' ')[0]
-                 if len(itemtext) > 1:
-                     prefix = '--'
-                 else:
-                     prefix = '-'
-                 self.SetValue(' '.join(cmd[:-1]) + ' ' + prefix + itemtext)
-             elif self._choiceType in ('raster', 'vector'):
-                 self.SetValue(' '.join(cmd[:-1]) + ' ' + cmd[-1].split('=', 1)[0] + '=' + itemtext)
-         else:
-             # -> reset text
-             self.SetValue(itemtext + ' ')
-             
-             # define module
-             self._setModule(itemtext)
-             
-             # use parameters as default choices
-             self._choiceType = 'param'
-             self.SetChoices(self._choicesMap['param'], type = 'param')
-         
-         self.SetInsertionPointEnd()
-         
-         self._showDropDown(False)
-         
-    def GetListCtrl(self):
-        """!Method required by listmix.ColumnSorterMixin"""
-        return self.dropdownlistbox
-    
-    def SetHistoryItems(self):
-        """!Read history file and update combobox items"""
-        env = grass.gisenv()
-        try:
-            fileHistory = open(os.path.join(env['GISDBASE'],
-                                            env['LOCATION_NAME'],
-                                            env['MAPSET'],
-                                            '.bash_history'), 'r')
-        except IOError:
-            self.SetItems([])
-            return
-        
-        try:
-            hist = []
-            for line in fileHistory.readlines():
-                hist.append(line.replace('\n', ''))
-            
-            self.SetItems(hist)
-        finally:
-            fileHistory.close()
-            return
-        
-        self.SetItems([])
-        
-    def SetChoices(self, choices, type = 'module'):
-        """!Sets the choices available in the popup wx.ListBox.
-        The items will be sorted case insensitively.
-
-        @param choices list of choices
-        @param type type of choices (module, param, flag, raster, vector)
-        """
-        self._choices = choices
-        self._choiceType = type
-        
-        self.dropdownlistbox.SetWindowStyleFlag(wx.LC_REPORT | wx.LC_SINGLE_SEL |
-                                                wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER)
-        if not isinstance(choices, list):
-            self._choices = [ x for x in choices ]
-        if self._choiceType not in ('raster', 'vector'):
-            # do not sort raster/vector maps
-            utils.ListSortLower(self._choices)
-        
-        self._updateDataList(self._choices)
-        
-        self.dropdownlistbox.InsertColumn(0, "")
-        for num, colVal in enumerate(self._choices):
-            index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
-            self.dropdownlistbox.SetStringItem(index, 0, colVal)
-            self.dropdownlistbox.SetItemData(index, num)
-        self._setListSize()
-        
-        # there is only one choice for both search and fetch if setting a single column:
-        self._colSearch = 0
-        self._colFetch = -1
-
-    def OnClick(self, event):
-        """Left mouse button pressed"""
-        sel = self.dropdownlistbox.GetFirstSelected()
-        if not self.dropdown.IsShown():
-            if sel > -1:
-                self.dropdownlistbox.Select(sel)
-            else:
-                self.dropdownlistbox.Select(0)
-            self._listItemVisible()
-            self._showDropDown()
-        else:
-            self.dropdown.Hide()
-        
-    def OnCommandSelect(self, event):
-        """!Command selected from history"""
-        self._historyItem = event.GetSelection() - len(self.GetItems())
-        self.SetFocus()
-        
-    def OnListClick(self, evt):
-        """!Left mouse button pressed"""
-        toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
-        #no values on poition, return
-        if toSel == -1: return
-        self.dropdownlistbox.Select(toSel)
-
-    def OnListDClick(self, evt):
-        """!Mouse button double click"""
-        self._setValueFromSelected()
-
-    def OnListColClick(self, evt):
-        """!Left mouse button pressed on column"""
-        col = evt.GetColumn()
-        # reverse the sort
-        if col == self._colSearch:
-            self._ascending = not self._ascending
-        self.SortListItems( evt.GetColumn(), ascending=self._ascending )
-        self._colSearch = evt.GetColumn()
-        evt.Skip()
-
-    def OnListItemSelected(self, event):
-        """!Item selected"""
-        self._setValueFromSelected()
-        event.Skip()
-
-    def OnEnteredText(self, event):
-        """!Text entered"""
-        text = event.GetString()
-        
-        if not text:
-            # control is empty; hide dropdown if shown:
-            if self.dropdown.IsShown():
-                self._showDropDown(False)
-            event.Skip()
-            return
-        
-        try:
-            cmd = shlex.split(str(text))
-        except ValueError, e:
-            self.statusbar.SetStatusText(str(e))
-            cmd = text.split(' ')
-        pattern = str(text)
-        
-        if len(cmd) > 0 and cmd[0] in self._choicesCmd and not self._module:
-            self._setModule(cmd[0])
-        elif len(cmd) > 1 and cmd[0] in self._choicesCmd:
-            if self._module:
-                if len(cmd[-1].split('=', 1)) == 1:
-                    # new option
-                    if cmd[-1][0] == '-':
-                        # -> flags
-                        self.SetChoices(self._choicesMap['flag'], type = 'flag')
-                        pattern = cmd[-1].lstrip('-')
-                    else:
-                        # -> options
-                        self.SetChoices(self._choicesMap['param'], type = 'param')
-                        pattern = cmd[-1]
-                else:
-                    # value
-                    pattern = cmd[-1].split('=', 1)[1]
-        else:
-            # search for GRASS modules
-            if self._module:
-                # -> switch back to GRASS modules list
-                self.SetChoices(self._choicesCmd)
-                self._module = None
-                self._choiceType = None
-        
-        self._choiceType
-        self._choicesMap
-        found = False
-        choices = self._choices
-        for numCh, choice in enumerate(choices):
-            if choice.lower().startswith(pattern):
-                found = True
-            if found:
-                self._showDropDown(True)
-                item = self.dropdownlistbox.GetItem(numCh)
-                toSel = item.GetId()
-                self.dropdownlistbox.Select(toSel)
-                break
-        
-        if not found:
-            self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
-            if self._hideOnNoMatch:
-                self._showDropDown(False)
-                if self._module and '=' not in cmd[-1]:
-                    message = ''
-                    if cmd[-1][0] == '-': # flag
-                        message = _("Warning: flag <%s> not found in '%s'") % \
-                            (cmd[-1][1:], self._module.name)
-                    else: # option
-                        message = _("Warning: option <%s> not found in '%s'") % \
-                            (cmd[-1], self._module.name)
-                    self.statusbar.SetStatusText(message)
-        
-        if self._module and len(cmd[-1]) == 2 and cmd[-1][-2] == '=':
-            optType = self._module.get_param(cmd[-1][:-2])['prompt']
-            if optType in ('raster', 'vector'):
-                # -> raster/vector map
-                self.SetChoices(self._choicesMap[optType], optType)
-        
-        self._listItemVisible()
-        
-        event.Skip()
-        
-    def OnKeyDown (self, event):
-        """!Do some work when the user press on the keys: up and down:
-        move the cursor left and right: move the search
-        """
-        skip = True
-        sel = self.dropdownlistbox.GetFirstSelected()
-        visible = self.dropdown.IsShown()
-        KC = event.GetKeyCode()
-        
-        if KC == wx.WXK_RIGHT:
-            # right -> show choices
-            if sel < (self.dropdownlistbox.GetItemCount() - 1):
-                self.dropdownlistbox.Select(sel + 1)
-                self._listItemVisible()
-            self._showDropDown()
-            skip = False
-        elif KC == wx.WXK_UP:
-            if visible:
-                if sel > 0:
-                    self.dropdownlistbox.Select(sel - 1)
-                    self._listItemVisible()
-                self._showDropDown()
-                skip = False
-            else:
-                self._historyItem -= 1
-                try:
-                    self.SetValue(self.GetItems()[self._historyItem])
-                except IndexError:
-                    self._historyItem += 1
-        elif KC == wx.WXK_DOWN:
-            if visible:
-                if sel < (self.dropdownlistbox.GetItemCount() - 1):
-                    self.dropdownlistbox.Select(sel + 1)
-                    self._listItemVisible()
-                self._showDropDown()
-                skip = False
-            else:
-                if self._historyItem < -1:
-                    self._historyItem += 1
-                    self.SetValue(self.GetItems()[self._historyItem])
-        
-        if visible:
-            if event.GetKeyCode() == wx.WXK_RETURN:
-                self._setValueFromSelected()
-                skip = False
-            if event.GetKeyCode() == wx.WXK_ESCAPE:
-                self._showDropDown(False)
-                skip = False
-        if skip:
-            event.Skip()
-        
-    def OnControlChanged(self, event):
-        """!Control changed"""
-        if self.IsShown():
-            self._showDropDown(False)
-        
-        event.Skip()
+            event.Skip()
\ No newline at end of file

Modified: grass/branches/develbranch_6/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxgui.py	2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/wxgui.py	2009-12-19 18:37:42 UTC (rev 40068)
@@ -132,7 +132,6 @@
         self.notebook  = self.__createNoteBook()
         self.menubar, self.menudata = self.__createMenuBar()
         self.statusbar = self.CreateStatusBar(number=1)
-        self.cmdprompt, self.cmdinput = self.__createCommandPrompt()
         self.toolbar   = self.__createToolBar()
         
         # bindings
@@ -146,16 +145,11 @@
         self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
                              Left().CentrePane().BestSize((-1,-1)).Dockable(False).
                              CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
-        self._auimgr.AddPane(self.cmdprompt, wx.aui.AuiPaneInfo().
-                             Bottom().BestSize((-1, -1)).Dockable(False).
-                             CloseButton(False).DestroyOnClose(True).
-                             PaneBorder(False).Row(1).Layer(0).Position(0).
-                             CaptionVisible(False))
 
         self._auimgr.Update()
 
         wx.CallAfter(self.notebook.SetSelection, 0)
-        wx.CallAfter(self.cmdinput.SetFocus)
+        wx.CallAfter(self.goutput.cmd_prompt.SetFocus)
         
         # use default window layout ?
         if UserSettings.Get(group='general', key='defWindowPos', subkey='enabled') is True:
@@ -192,13 +186,7 @@
         # start with layer manager on top
         self.curr_page.maptree.mapdisplay.Raise()
         self.Raise()
-        
-    def __createCommandPrompt(self):
-        """!Creates command-line input area"""
-        p = prompt.GPrompt(self)
-
-        return p.GetPanel(), p.GetInput()
-    
+            
     def __createMenuBar(self):
         """!Creates menubar"""
 
@@ -367,7 +355,7 @@
         page = event.GetSelection()
         if page == self.goutput.pageid:
             # remove '(...)'
-            self.notebook.SetPageText(page, _("Command output"))
+            self.notebook.SetPageText(page, _("Command console"))
         
         event.Skip()
 
@@ -454,7 +442,7 @@
         if event:
             cmd = self.GetMenuCmd(event)
         self.goutput.RunCmd(cmd, switchPage=True)
-        
+
     def OnMenuCmd(self, event, cmd = ''):
         """!Parse command selected from menu"""
         if event:
@@ -1544,7 +1532,7 @@
         """!Quit GRASS session (wxGUI and shell)"""
         # quit wxGUI session
         self.OnCloseWindow(event)
-        
+
         # quit GRASS shell
         try:
             pid = int(os.environ['GIS_LOCK'])



More information about the grass-commit mailing list