Changeset 40068


Ignore:
Timestamp:
Dec 19, 2009, 10:37:42 AM (15 years ago)
Author:
cmbarton
Message:

Advanced grass command console. Try again with repaired subversion installation.

Location:
grass/branches/develbranch_6/gui/wxpython
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py

    r40054 r40068  
    3737import preferences
    3838import menuform
     39import prompt
     40
    3941from debug import Debug as Debug
    4042from preferences import globalSettings as UserSettings
     
    146148        self.lineWidth       = 80
    147149        self.pageid          = pageid
     150                       
    148151        # remember position of line begining (used for '\r')
    149152        self.linePos         = -1
     
    163166        self.console_progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
    164167        # abort
    165         self.btn_abort = wx.Button(parent=self, id=wx.ID_STOP)
     168        self.btn_abort = wx.Button(self, -1, "Abort command", size=(125,-1))
    166169        self.btn_abort.SetToolTipString(_("Abort the running command"))
    167170        self.btn_abort.Bind(wx.EVT_BUTTON, self.OnCmdAbort)
     
    180183       
    181184        #
     185        # command prompt
     186        #
     187        self.cmd_prompt = prompt.GPrompt(self, id=wx.ID_ANY)
     188
     189        #
    182190        # stream redirection
    183191        #
     
    193201        # buttons
    194202        #
    195         self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR)
    196         self.console_save  = wx.Button(parent=self, id=wx.ID_SAVE)
     203        self.console_clear = wx.Button(self, -1, "Clear output", size=(125,-1))
     204        self.cmd_clear = wx.Button(self, -1, "Clear command", size=(125,-1))
     205        self.console_save  = wx.Button(self, -1, "Save output", size=(125,-1))
     206        self.Bind(wx.EVT_BUTTON, self.cmd_prompt.OnCmdErase, self.cmd_clear)
    197207        self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear)
    198208        self.Bind(wx.EVT_BUTTON, self.SaveHistory,  self.console_save)
     
    205215        """!Do layout"""
    206216        boxsizer1 = wx.BoxSizer(wx.VERTICAL)
    207         gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0)
     217        gridsizer1 = wx.GridSizer(rows=1, cols=4, vgap=0, hgap=0)
     218       
    208219        boxsizer1.Add(item=self.cmd_output, proportion=1,
    209                       flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0)
     220                      flag=wx.EXPAND | wx.ALIGN_BOTTOM, border=0)
     221        boxsizer1.Add(item=self.cmd_prompt, proportion=0,
     222                      flag=wx.EXPAND | wx.FIXED_MINSIZE | wx.ALIGN_BOTTOM, border=0)
     223                                           
    210224        gridsizer1.Add(item=self.console_clear, proportion=0,
    211                        flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
     225                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
    212226        gridsizer1.Add(item=self.console_save, proportion=0,
    213                        flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
    214 
    215 
     227                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
     228        gridsizer1.Add(item=self.cmd_clear, proportion=0,
     229                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
     230        gridsizer1.Add(item=self.btn_abort, proportion=0,
     231                       flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
    216232        boxsizer1.Add(item=gridsizer1, proportion=0,
    217233                      flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM,
    218234                      border=5)
     235                     
    219236        boxsizer2 = wx.BoxSizer(wx.HORIZONTAL)
    220237        boxsizer2.Add(item=self.console_progressbar, proportion=1,
    221238                      flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL)
    222         boxsizer2.Add(item=self.btn_abort, proportion=0,
    223                       flag=wx.ALIGN_CENTRE_VERTICAL | wx.LEFT,
    224                       border = 5)
    225239        boxsizer1.Add(item=boxsizer2, proportion=0,
    226                       flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.ALL,
    227                       border=5)
     240                      flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.LEFT | wx.RIGHT |
     241                      wx.TOP, border=5)
    228242       
    229243        boxsizer1.Fit(self)
     
    233247        self.SetAutoLayout(True)
    234248        self.SetSizer(boxsizer1)
     249        self.Layout()
    235250
    236251    def Redirect(self):
     
    270285        # p1 = self.cmd_output.GetCurrentPos()
    271286        p1 = self.cmd_output.GetEndStyled()
    272         self.cmd_output.GotoPos(p1)
     287#        self.cmd_output.GotoPos(p1)
     288        self.cmd_output.DocumentEnd()
    273289       
    274290        for line in text.splitlines():
     
    350366            except AttributeError:
    351367                pass
    352        
     368
     369        # allow writing to output window
     370        self.cmd_output.SetReadOnly(False)
     371               
    353372        if cmdlist[0] in globalvar.grassCmd['all']:
    354373            # send GRASS command without arguments to GUI command interface
     
    411430                        del os.environ["GRASS_REGION"]
    412431                   
    413                 if len(cmdlist) == 1 and cmdlist[0] not in ('v.krige'):
     432                if len(cmdlist) == 1:
    414433                    import menuform
    415434                    # process GRASS command without argument
     
    435454            # if command is not a GRASS command, treat it like a shell command
    436455            try:
    437                 # gcmd.Command(cmdlist,
    438                 #             stdout=self.cmd_stdout,
    439                 #             stderr=self.cmd_stderr)
     456#                gcmd.Command(cmdlist,
     457#                         stdout=self.cmd_stdout,
     458#                         stderr=self.cmd_stderr)
    440459                self.cmdThread.RunCmd(GrassCmd,
    441460                                      onDone,
     
    446465            except gcmd.CmdError, e:
    447466                print >> sys.stderr, e
     467
     468        # reset output window to read only
     469        self.cmd_output.SetReadOnly(True)
    448470       
    449471        return None
     
    531553            else:
    532554                self.cmd_output.AddTextWrapped(message, wrap=None)
    533            
     555
    534556        p2 = self.cmd_output.GetCurrentPos()
    535557       
     
    591613        # set focus on prompt
    592614        if self.parent.GetName() == "LayerManager":
    593             self.parent.cmdinput.SetFocus()
     615            self.cmd_prompt.SetFocus()
    594616            self.btn_abort.Enable(False)
    595617        else:
     
    641663                time.sleep(1)
    642664                dialog.Close()
    643        
     665
    644666        event.Skip()
    645667       
     
    757779        wx.stc.StyledTextCtrl.__init__(self, parent, id)
    758780        self.parent = parent
     781        self.SetUndoCollection(True)
     782        self.SetReadOnly(True)
    759783
    760784        #
     
    763787        self.SetStyle()
    764788       
    765 
    766789        #
    767790        # line margins
     
    787810
    788811        #
    789         # bindins
     812        # bindings
    790813        #
    791814        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
     
    874897                   
    875898                self.AddText(txt)
    876    
  • grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py

    r40054 r40068  
    22@package prompt.py
    33
    4 @brief wxGUI prompt
     4@brief GRASS prompt
    55
    66Classes:
    77 - GPrompt
    8  - PromptListCtrl
    9  - TextCtrlAutoComplete
    10 
    11 @todo: fix TextCtrlAutoComplete to work also on Macs (missing
    12 wx.PopupWindow())
     8
     9@todo: reduce size of STC prompt to about 3 lines
    1310
    1411(C) 2009 by the GRASS Development Team
     
    1815
    1916@author Martin Landa <landa.martin gmail.com>
     17@author Michael Barton <michael.barton@asu.edu>
    2018"""
    2119
     
    2523
    2624import wx
    27 import wx.lib.mixins.listctrl as listmix
     25import wx.stc
    2826
    2927from grass.script import core as grass
    3028
    3129import globalvar
    32 import utils
    33 import menuform
    3430import menudata
    35 
    36 class GPrompt:
    37     """!Interactive GRASS prompt"""
    38     def __init__(self, parent):
    39         self.parent = parent # GMFrame
    40        
    41         # dictionary of modules (description, keywords, ...)
    42         self.modules = self.parent.menudata.GetModules()
    43        
    44         self.panel, self.input = self.__create()
    45        
    46     def __create(self):
    47         """!Create widget"""
    48         cmdprompt = wx.Panel(self.parent)
    49        
    50         #
    51         # search
    52         #
    53         searchTxt = wx.StaticText(parent = cmdprompt, id = wx.ID_ANY,
    54                                   label = _("Find module:"))
    55        
    56         self.searchBy = wx.Choice(parent = cmdprompt, id = wx.ID_ANY,
    57                              choices = [_("description"),
    58                                         _("keywords")])
    59         winHeight = self.searchBy.GetSize()[1]
    60 
    61         self.search = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
    62                              value = "", size = (-1, 25))
    63        
    64         label = wx.Button(parent = cmdprompt, id = wx.ID_ANY,
    65                           label = _("&Cmd >"), size = (-1, winHeight))
    66         label.SetToolTipString(_("Click for erasing command prompt"))
    67 
    68         ### todo: fix TextCtrlAutoComplete to work also on Macs
    69         ### reason: missing wx.PopupWindow()
    70         try:
    71             cmdinput = TextCtrlAutoComplete(parent = cmdprompt, id = wx.ID_ANY,
    72                                             value = "",
    73                                             style = wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
    74                                             size = (-1, winHeight),
    75                                             statusbar = self.parent.statusbar)
    76         except NotImplementedError:
    77             # wx.PopupWindow may be not available in wxMac
    78             # see http://trac.wxwidgets.org/ticket/9377
    79             cmdinput = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
    80                                    value = "",
    81                                    style=wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
    82                                    size = (-1, 25))
    83             self.searchBy.Enable(False)
    84             self.search.Enable(False)
    85        
    86         cmdinput.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, ''))
    87        
    88         wx.CallAfter(cmdinput.SetInsertionPoint, 0)
    89        
    90         # bidnings
    91         label.Bind(wx.EVT_BUTTON,        self.OnCmdErase)
    92         cmdinput.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
    93         cmdinput.Bind(wx.EVT_TEXT,       self.OnUpdateStatusBar)
    94         self.search.Bind(wx.EVT_TEXT,    self.OnSearchModule)
    95        
    96         # layout
    97         sizer = wx.GridBagSizer(hgap=5, vgap=5)
    98         sizer.AddGrowableRow(1)
    99         sizer.AddGrowableCol(2)
    100 
    101         sizer.Add(item = searchTxt,
    102                   flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL,
    103                   pos = (0, 0))
    104 
    105         sizer.Add(item = self.searchBy,
    106                   flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
    107                   pos = (0, 1))
    108        
    109         sizer.Add(item = self.search,
    110                   flag = wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
    111                   border = 5,
    112                   pos = (0, 2))
    113        
    114         sizer.Add(item = label,
    115                   flag = wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
    116                   border = 5,
    117                   pos = (1, 0))
    118        
    119         sizer.Add(item = cmdinput,
    120                   flag = wx.EXPAND | wx.RIGHT,
    121                   border = 5,
    122                   pos = (1, 1), span = (1, 2))
    123        
    124         cmdprompt.SetSizer(sizer)
    125         sizer.Fit(cmdprompt)
    126         cmdprompt.Layout()
    127        
    128         return cmdprompt, cmdinput
    129 
    130     def __checkKey(self, text, keywords):
    131         """!Check if text is in keywords"""
    132         found = 0
    133         keys = text.split(',')
    134         if len(keys) > 1: # -> multiple keys
    135             for k in keys[:-1]:
    136                 k = k.strip()
    137                 for key in keywords:
    138                     if k == key: # full match
    139                         found += 1
    140                         break
    141             k = keys[-1].strip()
    142             for key in keywords:
    143                 if k in key: # partial match
    144                     found +=1
     31import gcmd
     32
     33class GPrompt(wx.stc.StyledTextCtrl):
     34    """!Styled GRASS prompt with autocomplete and calltips"""   
     35    def __init__(self, parent, id, size=wx.DefaultSize, margin=False, wrap=None):
     36        wx.stc.StyledTextCtrl.__init__(self, parent, id)
     37        self.parent = parent
     38        self.SetUndoCollection(True)       
     39
     40        #
     41        # styles
     42        #               
     43        self.SetWrapMode(True)
     44       
     45        #
     46        # create command and map lists for autocompletion
     47        #
     48        self.AutoCompSetIgnoreCase(False)
     49       
     50        self.rastlist = []
     51        self.vectlist = []
     52        self.imglist = []
     53        self.r3list = []
     54        self.dblist = []
     55        self.genlist = []
     56        self.displist = []
     57       
     58        #
     59        # Get available GRASS commands and parse into lists by command type for autocomplete
     60        #
     61        for item in globalvar.grassCmd['all']:
     62            if len(item.split('.')) > 1:
     63                start,end = item.split('.',1)
     64                if start == 'r': self.rastlist.append(end)
     65                elif start == 'v': self.vectlist.append(end)
     66                elif start == 'i': self.imglist.append(end)
     67                elif start == 'r3': self.r3list.append(end)
     68                elif start == 'db': self.dblist.append(end)
     69                elif start == 'g': self.genlist.append(end)
     70                elif start == 'd': self.displist.append(end)
     71
     72        self.rastlist.sort()
     73        self.vectlist.sort()
     74        self.imglist.sort()
     75        self.r3list.sort()
     76        self.dblist.sort()
     77        self.genlist.sort()
     78        self.displist.sort()
     79                       
     80        #
     81        # Create lists of element types and possible arguments for autocomplete
     82        #
     83        self.datatypes = []
     84        self.maplists = {}
     85        self.maptype = ''
     86        self.datatypes = ['rast',
     87                        'rast3d',
     88                        'vect',
     89                        'oldvect',
     90                        'asciivect',
     91                        'labels',
     92                        'region',
     93                        'region3d',
     94                        'group',
     95                        '3dview']
     96
     97        self.drastcmd = ['d.rast',
     98                        'd.rgb',
     99                        'd.his',
     100                        'd.rast.arrow',
     101                        'd.rast.num']
     102                   
     103        self.dvectcmd = ['d.vect',
     104                        'd.vect.chart'
     105                        'd.thematic.area',
     106                        'd.vect.thematic']
     107       
     108        self.rastargs = ['map',
     109                        'input',
     110                        'rast',
     111                        'raster',
     112                        'red',
     113                        'green',
     114                        'blue',
     115                        'h_map',
     116                        'i_map',
     117                        's_map',
     118                        'hue_input',
     119                        'intensity_input',
     120                        'saturation_input',
     121                        'red_input',
     122                        'green_input',
     123                        'blue_input']
     124                       
     125        self.__getfiles()
     126
     127        #
     128        # command history buffer
     129        #
     130        self.cmdbuffer = []
     131        self.cmdindex = 0
     132
     133        #
     134        # line margins
     135        #
     136        # TODO print number only from cmdlog
     137        self.SetMarginWidth(1, 0)
     138        self.SetMarginWidth(2, 0)
     139        if margin:
     140            self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
     141            self.SetMarginWidth(0, 30)
     142        else:
     143            self.SetMarginWidth(0, 0)
     144
     145        #
     146        # miscellaneous
     147        #
     148        self.SetViewWhiteSpace(False)
     149#        self.SetTabWidth(4)
     150        self.SetUseTabs(False)
     151        self.UsePopUp(True)
     152        self.SetSelBackground(True, "#FFFF00")
     153        self.SetUseHorizontalScrollBar(True)
     154
     155        #
     156        # bindings
     157        #
     158        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
     159        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
     160 
     161    def __getfiles(self):   
     162        """!Get accessible files for autocomplete"""
     163        for item in self.datatypes:
     164            mlist = grass.read_command("g.mlist", "m", type=item).splitlines()
     165            mlist.sort()
     166            self.maplists[item] = mlist
     167           
     168    def OnKeyPressed(self, event):
     169        """!Key press capture for autocompletion, calltips, and command history"""
     170       
     171        #keycodes used: "." = 46, "=" = 61, "," = 44
     172        line = ''
     173        entry = ''
     174        usage = ''
     175        cmdtype = ''
     176        cmdname = ''
     177        cmd = ''
     178                           
     179        # CAN CHANGE: event.ControlDown() for manual autocomplete
     180       
     181        if event.GetKeyCode() == 46 and not event.ShiftDown():
     182            #GRASS command autocomplete when "." is pressed after r,v,i,g,db, or d
     183            listcmds = []
     184            pos = self.GetCurrentPos()
     185            self.InsertText(pos,'.')
     186            self.CharRight()
     187           
     188            entry = self.GetTextLeft()
     189            if entry not in ['r.','v.','i.','g.','db.','d.']:
     190                return
     191
     192            if entry == 'r.': listcmds = self.rastlist
     193            elif entry == 'v.': listcmds = self.vectlist
     194            elif entry == 'i.': listcmds = self.imglist
     195            elif entry == 'r3.': listcmds = self.r3list
     196            elif entry == 'db.': listcmds = self.dblist
     197            elif entry == 'g.': listcmds = self.genlist
     198            elif entry == 'd.': listcmds = self.displist
     199
     200            if listcmds == []:
     201                return
     202            else:
     203                self.AutoCompShow(0, " ".join(listcmds))                   
     204           
     205        elif event.GetKeyCode() == wx.WXK_TAB:
     206            #GRASS command calltips
     207                       
     208            #Must be a command to the left somewhere
     209            pos = self.GetCurrentPos()
     210            entry = self.GetTextLeft()
     211            cmd = entry.split()[0].strip()
     212            if cmd not in globalvar.grassCmd['all']:
     213                return
     214           
     215            usage, description = self.GetCommandUsage(cmd)
     216                                       
     217            self.CallTipSetBackground("PALE GREEN")
     218            self.CallTipSetForeground("BLACK")
     219            self.CallTipShow(pos, usage+'\n\n'+description)
     220           
     221        elif (event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown()) or \
     222            event.GetKeyCode() == 61 or event.GetKeyCode() == 44:
     223            #Autocompletion for map/data file name entry after '=', ',', or manually
     224           
     225            pos = self.GetCurrentPos()
     226            entry = self.GetTextLeft()
     227            if event.GetKeyCode() != 44:
     228                self.maptype = ''
     229            arg = ''
     230            cmdtype = ''
     231            cmdname = ''
     232            cmd = ''
     233
     234            if entry.strip()[0:2] in ['r.','v.','i.','g.','db.','d.']:
     235                cmdtype =  entry.strip()[0]
     236                cmd = entry.split()[0].strip()
     237                if cmd in globalvar.grassCmd['all']:
     238                    cmdname = cmd.split('.')[1]
     239                else:
     240                    #No complete GRASS command found
     241                    cmd = ''
     242                    cmdname = ''
     243            elif entry.strip()[0:4] == 'nviz':
     244                cmdtype = ''
     245                cmdname = cmd = 'nviz'
     246            else:
     247                #No partial or complete GRASS command found
     248                return
     249
     250            cmdargs = entry.strip('=')
     251            try:
     252                arg = cmdargs.rsplit(' ',1)[1]
     253            except:
     254                arg = ''
     255               
     256            if event.GetKeyCode() == 61:
     257                # autocompletion after '='
     258                # insert the '=' and move to after the '=', ready for a map name
     259                self.InsertText(pos,'=')
     260                self.CharRight()
     261
     262                maplist = []
     263                self.maptype = ''
     264
     265                #what kind of map/data type is desired?
     266                if (((cmdtype in ['r', 'i'] or cmd in self.drastcmd) and arg in self.rastargs) or
     267                  ((cmd=='nviz' or cmdtype=='r3') and arg in ['elevation','color']) or
     268                  arg in ['rast', 'raster']):
     269                    self.maptype = 'rast'
     270                elif (((cmdtype=='v' or cmd in self.dvectcmd) and arg in ['map', 'input']) or
     271                  (cmdtype=='r3' and arg=='input') or
     272                  arg in ['vect', 'vector', 'points']):
     273                    self.maptype = 'vect'
     274                elif ((cmdtype=='r3' and arg in ['map', 'input']) or
     275                  (cmdtype=='nviz' and arg=='volume') or arg=='rast3d'):
     276                    self.maptype = 'rast3d'
     277                elif arg=='labels':
     278                    self.maptype ='labels'
     279                elif arg=='region':
     280                    self.maptype ='region'
     281                elif arg=='region3d':
     282                    self.maptype ='region3d'
     283                elif arg=='group':
     284                    self.maptype ='group'
     285                elif arg=='3dview':
     286                    self.maptype ='3dview'
     287                   
     288                print 'maptype at end of = ' + str(self.maptype)
     289
     290            elif event.GetKeyCode() == 44:
     291                # autocompletion after ','
     292                # if comma is pressed, use the same maptype as previous for multiple map entries
     293               
     294                # insert the comma and move to after the comma ready for a map name
     295                self.InsertText(pos,',')
     296                self.CharRight()
     297               
     298                #must apply to an entry where '=[string]' has already been entered
     299                if '=' not in arg:
     300                    return
     301
     302            elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
     303                # manual autocompletion
     304                # map entries without arguments (as in r.info [mapname]) use ctrl-shift
     305               
     306                maplist = []
     307                if cmdtype=='r' or cmdtype=='i':
     308                    self.maptype = 'rast'
     309                elif cmdtype=='v':
     310                    self.maptype = 'vect'
     311                elif cmdtype=='r3':
     312                    self.maptype = 'rast3d'
     313                   
     314            if self.maptype == '':
     315                return
     316            else:
     317                maplist = self.maplists[self.maptype]
     318                self.AutoCompShow(0, " ".join(maplist))
     319                       
     320        elif event.GetKeyCode() in [wx.WXK_UP,wx.WXK_DOWN] and event.ControlDown():
     321            # Command history using ctrl-up and ctrl-down   
     322           
     323            if self.cmdbuffer == []: return
     324            txt = ''
     325
     326            self.DocumentEnd()
     327           
     328            # move through command history list index values
     329            if event.GetKeyCode() == wx.WXK_UP:
     330                self.cmdindex = self.cmdindex - 1
     331            if event.GetKeyCode() == wx.WXK_DOWN:
     332                self.cmdindex = self.cmdindex + 1
     333            if self.cmdindex < 0:
     334                self.cmdindex = 0
     335            if self.cmdindex > len(self.cmdbuffer) - 1:
     336                self.cmdindex = len(self.cmdbuffer) - 1
     337           
     338            try:
     339                txt = self.cmdbuffer[self.cmdindex]
     340            except:
     341                pass
     342               
     343            # clear current line and insert command history   
     344            self.DelLineLeft()
     345            self.DelLineRight()
     346            pos = self.GetCurrentPos()           
     347            self.InsertText(pos,txt)
     348            self.LineEnd()
     349           
     350        elif event.GetKeyCode() == wx.WXK_RETURN and self.AutoCompActive() == False:
     351            # Run command on line when <return> is pressed   
     352           
     353            # find the command to run
     354            line = str(self.GetCurLine()[0]).strip()
     355            if len(line) == 0:
     356                return
     357           
     358            # parse command into list
     359            # TODO: shell commands should probably be passed as string           
     360            cmd = shlex.split(str(line))
     361           
     362            #send the command list to the processor
     363            self.parent.RunCmd(cmd)
     364                           
     365            #add command to history   
     366            self.cmdbuffer.append(line)
     367           
     368            #keep command history to a managable size
     369            if len(self.cmdbuffer) > 200:
     370                del self.cmdbuffer[0]
     371            self.cmdindex = len(self.cmdbuffer)
     372
     373        else:
     374            event.Skip()
     375
     376    def GetTextLeft(self):
     377        """!Returns all text left of the caret"""
     378        entry = ''
     379        pos = self.GetCurrentPos()
     380        self.HomeExtend()
     381        entry = self.GetSelectedText().strip()
     382        self.SetCurrentPos(pos)
     383       
     384        return entry
     385
     386    def GetCommandUsage(self, command):
     387        """!Returns command syntax by running command help"""
     388        usage = ''
     389        description = ''
     390
     391        ret, out  = gcmd.RunCommand(command, 'help', getErrorMsg = True)
     392               
     393        if ret == 0:
     394            cmdhelp = out.splitlines()
     395            addline = False
     396            helplist = []
     397            description = ''
     398            for line in cmdhelp:
     399                if "Usage:" in line:
     400                    addline = True
     401                    continue
     402                elif "Flags:" in line:
     403                    addline = False
    145404                    break
     405                elif addline == True:
     406                    line = line.strip()
     407                    helplist.append(line)
     408
     409            for line in cmdhelp:
     410                if "Description:" in line:
     411                    addline = True
     412                    continue
     413                elif "Keywords:" in line:
     414                    addline = False
     415                    break
     416                elif addline == True:
     417                    description += (line + ' ')
     418               
     419            description = description.strip()
     420
     421            for line in helplist:
     422                usage += line + '\n'
     423
     424            return usage.strip(), description
    146425        else:
    147             for key in keywords:
    148                 if text in key: # partial match
    149                     found +=1
    150                     break
    151        
    152         if found == len(keys):
    153             return True
    154        
    155         return False
    156    
    157     def GetPanel(self):
    158         """!Get main widget panel"""
    159         return self.panel
    160 
    161     def GetInput(self):
    162         """!Get main prompt widget"""
    163         return self.input
     426            return ''   
     427
     428    def OnDestroy(self, evt):
     429        """!The clipboard contents can be preserved after
     430        the app has exited"""
     431       
     432        wx.TheClipboard.Flush()
     433        evt.Skip()
    164434   
    165435    def OnCmdErase(self, event):
    166436        """!Erase command prompt"""
    167         self.input.SetValue('')
     437        self.Home()
     438        self.DelLineRight()
    168439       
    169440    def OnRunCmd(self, event):
     
    195466            self.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
    196467            event.Skip()
    197        
    198     def OnSearchModule(self, event):
    199         """!Search module by metadata"""
    200         text = event.GetString()
    201         if not text:
    202             self.input.SetChoices(globalvar.grassCmd['all'])
    203             return
    204        
    205         modules = []
    206         for module, data in self.modules.iteritems():
    207             if self.searchBy.GetSelection() == 0: # -> description
    208                 if text in data['desc']:
    209                     modules.append(module)
    210             else: # -> keywords
    211                 if self.__checkKey(text, data['keywords']):
    212                     modules.append(module)
    213        
    214         self.parent.statusbar.SetStatusText(_("%d modules found") % len(modules))
    215         self.input.SetChoices(modules)
    216                    
    217 class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    218     def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition,
    219                  size = wx.DefaultSize, style = 0):
    220         wx.ListCtrl.__init__(self, parent, id, pos, size, style)
    221         listmix.ListCtrlAutoWidthMixin.__init__(self)
    222        
    223 class TextCtrlAutoComplete(wx.ComboBox, listmix.ColumnSorterMixin):
    224     def __init__ (self, parent, statusbar,
    225                   id = wx.ID_ANY, choices = [], **kwargs):
    226         """!Constructor works just like wx.TextCtrl except you can pass in a
    227         list of choices.  You can also change the choice list at any time
    228         by calling setChoices.
    229        
    230         Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete
    231         """
    232         self.statusbar = statusbar
    233        
    234         if kwargs.has_key('style'):
    235             kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']
    236         else:
    237             kwargs['style'] = wx.TE_PROCESS_ENTER
    238        
    239         wx.ComboBox.__init__(self, parent, id, **kwargs)
    240        
    241         # some variables
    242         self._choices = choices
    243         self._hideOnNoMatch = True
    244         self._module = None      # currently selected module
    245         self._choiceType = None  # type of choice (module, params, flags, raster, vector ...)
    246         self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
    247         self._historyItem = 0   # last item
    248        
    249         # sort variable needed by listmix
    250         self.itemDataMap = dict()
    251        
    252         # widgets
    253         try:
    254             self.dropdown = wx.PopupWindow(self)
    255         except NotImplementedError:
    256             self.Destroy()
    257             raise NotImplementedError
    258        
    259         # create the list and bind the events
    260         self.dropdownlistbox = PromptListCtrl(parent = self.dropdown,
    261                                               style = wx.LC_REPORT | wx.LC_SINGLE_SEL | \
    262                                                   wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER,
    263                                               pos = wx.Point(0, 0))
    264        
    265         listmix.ColumnSorterMixin.__init__(self, 1)
    266        
    267         # set choices (list of GRASS modules)
    268         self._choicesCmd = globalvar.grassCmd['all']
    269         self._choicesMap = dict()
    270         for type in ('raster', 'vector'):
    271             self._choicesMap[type] = grass.list_strings(type = type[:4])
    272         # first search for GRASS module
    273         self.SetChoices(self._choicesCmd)
    274        
    275         self.SetMinSize(self.GetSize())
    276         # read history
    277         self.SetHistoryItems()
    278        
    279         # bindings...
    280         self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
    281         self.Bind(wx.EVT_TEXT, self.OnEnteredText)
    282         self.Bind(wx.EVT_KEY_DOWN , self.OnKeyDown)
    283         ### self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
    284 
    285         # if need drop down on left click
    286         self.dropdown.Bind(wx.EVT_LISTBOX , self.OnListItemSelected, self.dropdownlistbox)
    287         self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.OnListClick)
    288         self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.OnListDClick)
    289         self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.OnListColClick)
    290 
    291         self.Bind(wx.EVT_COMBOBOX, self.OnCommandSelect)
    292        
    293     def _updateDataList(self, choices):
    294         """!Update data list"""
    295         # delete, if need, all the previous data
    296         if self.dropdownlistbox.GetColumnCount() != 0:
    297             self.dropdownlistbox.DeleteAllColumns()
    298             self.dropdownlistbox.DeleteAllItems()
    299         # and update the dict
    300         if choices:
    301             for numVal, data in enumerate(choices):
    302                 self.itemDataMap[numVal] = data
    303         else:
    304             numVal = 0
    305         self.SetColumnCount(numVal)
    306    
    307     def _setListSize(self):
    308         """!Set list size"""
    309         choices = self._choices
    310         longest = 0
    311         for choice in choices:
    312             longest = max(len(choice), longest)
    313         longest += 3
    314         itemcount = min(len( choices ), 7) + 2
    315         charheight = self.dropdownlistbox.GetCharHeight()
    316         charwidth = self.dropdownlistbox.GetCharWidth()
    317         self.popupsize = wx.Size(charwidth*longest, charheight*itemcount)
    318         self.dropdownlistbox.SetSize(self.popupsize)
    319         self.dropdown.SetClientSize(self.popupsize)
    320 
    321     def _showDropDown(self, show = True):
    322         """!Either display the drop down list (show = True) or hide it
    323         (show = False).
    324         """
    325         if show:
    326             size = self.dropdown.GetSize()
    327             width, height = self.GetSizeTuple()
    328             x, y = self.ClientToScreenXY(0, height)
    329             if size.GetWidth() != width:
    330                 size.SetWidth(width)
    331                 self.dropdown.SetSize(size)
    332                 self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
    333             if (y + size.GetHeight()) < self._screenheight:
    334                 self.dropdown.SetPosition(wx.Point(x, y))
    335             else:
    336                 self.dropdown.SetPosition(wx.Point(x, y - height - size.GetHeight()))
    337        
    338         self.dropdown.Show(show)
    339    
    340     def _listItemVisible(self):
    341         """!Moves the selected item to the top of the list ensuring it is
    342         always visible.
    343         """
    344         toSel = self.dropdownlistbox.GetFirstSelected()
    345         if toSel == -1:
    346             return
    347         self.dropdownlistbox.EnsureVisible(toSel)
    348 
    349     def _setModule(self, name):
    350         """!Set module's choices (flags, parameters)"""
    351         # get module's description
    352         if name in self._choicesCmd and not self._module:
    353             try:
    354                 self._module = menuform.GUI().ParseInterface(cmd = [name])
    355             except IOError:
    356                 self._module = None
    357              
    358         # set choices (flags)
    359         self._choicesMap['flag'] = self._module.get_list_flags()
    360         for idx in range(len(self._choicesMap['flag'])):
    361             item = self._choicesMap['flag'][idx]
    362             desc = self._module.get_flag(item)['label']
    363             if not desc:
    364                 desc = self._module.get_flag(item)['description']
    365            
    366             self._choicesMap['flag'][idx] = '%s (%s)' % (item, desc)
    367        
    368         # set choices (parameters)
    369         self._choicesMap['param'] = self._module.get_list_params()
    370         for idx in range(len(self._choicesMap['param'])):
    371             item = self._choicesMap['param'][idx]
    372             desc = self._module.get_param(item)['label']
    373             if not desc:
    374                 desc = self._module.get_param(item)['description']
    375            
    376             self._choicesMap['param'][idx] = '%s (%s)' % (item, desc)
    377    
    378     def _setValueFromSelected(self):
    379          """!Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
    380          Will do nothing if no item is selected in the wx.ListCtrl.
    381          """
    382          sel = self.dropdownlistbox.GetFirstSelected()
    383          if sel < 0:
    384              return
    385          
    386          if self._colFetch != -1:
    387              col = self._colFetch
    388          else:
    389              col = self._colSearch
    390          itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
    391          
    392          cmd = shlex.split(str(self.GetValue()))
    393          if len(cmd) > 0 and cmd[0] in self._choicesCmd:
    394              # -> append text (skip last item)
    395              if self._choiceType == 'param':
    396                  itemtext = itemtext.split(' ')[0]
    397                  self.SetValue(' '.join(cmd) + ' ' + itemtext + '=')
    398                  optType = self._module.get_param(itemtext)['prompt']
    399                  if optType in ('raster', 'vector'):
    400                      # -> raster/vector map
    401                      self.SetChoices(self._choicesMap[optType], optType)
    402              elif self._choiceType == 'flag':
    403                  itemtext = itemtext.split(' ')[0]
    404                  if len(itemtext) > 1:
    405                      prefix = '--'
    406                  else:
    407                      prefix = '-'
    408                  self.SetValue(' '.join(cmd[:-1]) + ' ' + prefix + itemtext)
    409              elif self._choiceType in ('raster', 'vector'):
    410                  self.SetValue(' '.join(cmd[:-1]) + ' ' + cmd[-1].split('=', 1)[0] + '=' + itemtext)
    411          else:
    412              # -> reset text
    413              self.SetValue(itemtext + ' ')
    414              
    415              # define module
    416              self._setModule(itemtext)
    417              
    418              # use parameters as default choices
    419              self._choiceType = 'param'
    420              self.SetChoices(self._choicesMap['param'], type = 'param')
    421          
    422          self.SetInsertionPointEnd()
    423          
    424          self._showDropDown(False)
    425          
    426     def GetListCtrl(self):
    427         """!Method required by listmix.ColumnSorterMixin"""
    428         return self.dropdownlistbox
    429    
    430     def SetHistoryItems(self):
    431         """!Read history file and update combobox items"""
    432         env = grass.gisenv()
    433         try:
    434             fileHistory = open(os.path.join(env['GISDBASE'],
    435                                             env['LOCATION_NAME'],
    436                                             env['MAPSET'],
    437                                             '.bash_history'), 'r')
    438         except IOError:
    439             self.SetItems([])
    440             return
    441        
    442         try:
    443             hist = []
    444             for line in fileHistory.readlines():
    445                 hist.append(line.replace('\n', ''))
    446            
    447             self.SetItems(hist)
    448         finally:
    449             fileHistory.close()
    450             return
    451        
    452         self.SetItems([])
    453        
    454     def SetChoices(self, choices, type = 'module'):
    455         """!Sets the choices available in the popup wx.ListBox.
    456         The items will be sorted case insensitively.
    457 
    458         @param choices list of choices
    459         @param type type of choices (module, param, flag, raster, vector)
    460         """
    461         self._choices = choices
    462         self._choiceType = type
    463        
    464         self.dropdownlistbox.SetWindowStyleFlag(wx.LC_REPORT | wx.LC_SINGLE_SEL |
    465                                                 wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER)
    466         if not isinstance(choices, list):
    467             self._choices = [ x for x in choices ]
    468         if self._choiceType not in ('raster', 'vector'):
    469             # do not sort raster/vector maps
    470             utils.ListSortLower(self._choices)
    471        
    472         self._updateDataList(self._choices)
    473        
    474         self.dropdownlistbox.InsertColumn(0, "")
    475         for num, colVal in enumerate(self._choices):
    476             index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
    477             self.dropdownlistbox.SetStringItem(index, 0, colVal)
    478             self.dropdownlistbox.SetItemData(index, num)
    479         self._setListSize()
    480        
    481         # there is only one choice for both search and fetch if setting a single column:
    482         self._colSearch = 0
    483         self._colFetch = -1
    484 
    485     def OnClick(self, event):
    486         """Left mouse button pressed"""
    487         sel = self.dropdownlistbox.GetFirstSelected()
    488         if not self.dropdown.IsShown():
    489             if sel > -1:
    490                 self.dropdownlistbox.Select(sel)
    491             else:
    492                 self.dropdownlistbox.Select(0)
    493             self._listItemVisible()
    494             self._showDropDown()
    495         else:
    496             self.dropdown.Hide()
    497        
    498     def OnCommandSelect(self, event):
    499         """!Command selected from history"""
    500         self._historyItem = event.GetSelection() - len(self.GetItems())
    501         self.SetFocus()
    502        
    503     def OnListClick(self, evt):
    504         """!Left mouse button pressed"""
    505         toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
    506         #no values on poition, return
    507         if toSel == -1: return
    508         self.dropdownlistbox.Select(toSel)
    509 
    510     def OnListDClick(self, evt):
    511         """!Mouse button double click"""
    512         self._setValueFromSelected()
    513 
    514     def OnListColClick(self, evt):
    515         """!Left mouse button pressed on column"""
    516         col = evt.GetColumn()
    517         # reverse the sort
    518         if col == self._colSearch:
    519             self._ascending = not self._ascending
    520         self.SortListItems( evt.GetColumn(), ascending=self._ascending )
    521         self._colSearch = evt.GetColumn()
    522         evt.Skip()
    523 
    524     def OnListItemSelected(self, event):
    525         """!Item selected"""
    526         self._setValueFromSelected()
    527         event.Skip()
    528 
    529     def OnEnteredText(self, event):
    530         """!Text entered"""
    531         text = event.GetString()
    532        
    533         if not text:
    534             # control is empty; hide dropdown if shown:
    535             if self.dropdown.IsShown():
    536                 self._showDropDown(False)
    537             event.Skip()
    538             return
    539        
    540         try:
    541             cmd = shlex.split(str(text))
    542         except ValueError, e:
    543             self.statusbar.SetStatusText(str(e))
    544             cmd = text.split(' ')
    545         pattern = str(text)
    546        
    547         if len(cmd) > 0 and cmd[0] in self._choicesCmd and not self._module:
    548             self._setModule(cmd[0])
    549         elif len(cmd) > 1 and cmd[0] in self._choicesCmd:
    550             if self._module:
    551                 if len(cmd[-1].split('=', 1)) == 1:
    552                     # new option
    553                     if cmd[-1][0] == '-':
    554                         # -> flags
    555                         self.SetChoices(self._choicesMap['flag'], type = 'flag')
    556                         pattern = cmd[-1].lstrip('-')
    557                     else:
    558                         # -> options
    559                         self.SetChoices(self._choicesMap['param'], type = 'param')
    560                         pattern = cmd[-1]
    561                 else:
    562                     # value
    563                     pattern = cmd[-1].split('=', 1)[1]
    564         else:
    565             # search for GRASS modules
    566             if self._module:
    567                 # -> switch back to GRASS modules list
    568                 self.SetChoices(self._choicesCmd)
    569                 self._module = None
    570                 self._choiceType = None
    571        
    572         self._choiceType
    573         self._choicesMap
    574         found = False
    575         choices = self._choices
    576         for numCh, choice in enumerate(choices):
    577             if choice.lower().startswith(pattern):
    578                 found = True
    579             if found:
    580                 self._showDropDown(True)
    581                 item = self.dropdownlistbox.GetItem(numCh)
    582                 toSel = item.GetId()
    583                 self.dropdownlistbox.Select(toSel)
    584                 break
    585        
    586         if not found:
    587             self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
    588             if self._hideOnNoMatch:
    589                 self._showDropDown(False)
    590                 if self._module and '=' not in cmd[-1]:
    591                     message = ''
    592                     if cmd[-1][0] == '-': # flag
    593                         message = _("Warning: flag <%s> not found in '%s'") % \
    594                             (cmd[-1][1:], self._module.name)
    595                     else: # option
    596                         message = _("Warning: option <%s> not found in '%s'") % \
    597                             (cmd[-1], self._module.name)
    598                     self.statusbar.SetStatusText(message)
    599        
    600         if self._module and len(cmd[-1]) == 2 and cmd[-1][-2] == '=':
    601             optType = self._module.get_param(cmd[-1][:-2])['prompt']
    602             if optType in ('raster', 'vector'):
    603                 # -> raster/vector map
    604                 self.SetChoices(self._choicesMap[optType], optType)
    605        
    606         self._listItemVisible()
    607        
    608         event.Skip()
    609        
    610     def OnKeyDown (self, event):
    611         """!Do some work when the user press on the keys: up and down:
    612         move the cursor left and right: move the search
    613         """
    614         skip = True
    615         sel = self.dropdownlistbox.GetFirstSelected()
    616         visible = self.dropdown.IsShown()
    617         KC = event.GetKeyCode()
    618        
    619         if KC == wx.WXK_RIGHT:
    620             # right -> show choices
    621             if sel < (self.dropdownlistbox.GetItemCount() - 1):
    622                 self.dropdownlistbox.Select(sel + 1)
    623                 self._listItemVisible()
    624             self._showDropDown()
    625             skip = False
    626         elif KC == wx.WXK_UP:
    627             if visible:
    628                 if sel > 0:
    629                     self.dropdownlistbox.Select(sel - 1)
    630                     self._listItemVisible()
    631                 self._showDropDown()
    632                 skip = False
    633             else:
    634                 self._historyItem -= 1
    635                 try:
    636                     self.SetValue(self.GetItems()[self._historyItem])
    637                 except IndexError:
    638                     self._historyItem += 1
    639         elif KC == wx.WXK_DOWN:
    640             if visible:
    641                 if sel < (self.dropdownlistbox.GetItemCount() - 1):
    642                     self.dropdownlistbox.Select(sel + 1)
    643                     self._listItemVisible()
    644                 self._showDropDown()
    645                 skip = False
    646             else:
    647                 if self._historyItem < -1:
    648                     self._historyItem += 1
    649                     self.SetValue(self.GetItems()[self._historyItem])
    650        
    651         if visible:
    652             if event.GetKeyCode() == wx.WXK_RETURN:
    653                 self._setValueFromSelected()
    654                 skip = False
    655             if event.GetKeyCode() == wx.WXK_ESCAPE:
    656                 self._showDropDown(False)
    657                 skip = False
    658         if skip:
    659             event.Skip()
    660        
    661     def OnControlChanged(self, event):
    662         """!Control changed"""
    663         if self.IsShown():
    664             self._showDropDown(False)
    665        
    666         event.Skip()
  • grass/branches/develbranch_6/gui/wxpython/wxgui.py

    r40054 r40068  
    133133        self.menubar, self.menudata = self.__createMenuBar()
    134134        self.statusbar = self.CreateStatusBar(number=1)
    135         self.cmdprompt, self.cmdinput = self.__createCommandPrompt()
    136135        self.toolbar   = self.__createToolBar()
    137136       
     
    147146                             Left().CentrePane().BestSize((-1,-1)).Dockable(False).
    148147                             CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
    149         self._auimgr.AddPane(self.cmdprompt, wx.aui.AuiPaneInfo().
    150                              Bottom().BestSize((-1, -1)).Dockable(False).
    151                              CloseButton(False).DestroyOnClose(True).
    152                              PaneBorder(False).Row(1).Layer(0).Position(0).
    153                              CaptionVisible(False))
    154148
    155149        self._auimgr.Update()
    156150
    157151        wx.CallAfter(self.notebook.SetSelection, 0)
    158         wx.CallAfter(self.cmdinput.SetFocus)
     152        wx.CallAfter(self.goutput.cmd_prompt.SetFocus)
    159153       
    160154        # use default window layout ?
     
    193187        self.curr_page.maptree.mapdisplay.Raise()
    194188        self.Raise()
    195        
    196     def __createCommandPrompt(self):
    197         """!Creates command-line input area"""
    198         p = prompt.GPrompt(self)
    199 
    200         return p.GetPanel(), p.GetInput()
    201    
     189           
    202190    def __createMenuBar(self):
    203191        """!Creates menubar"""
     
    368356        if page == self.goutput.pageid:
    369357            # remove '(...)'
    370             self.notebook.SetPageText(page, _("Command output"))
     358            self.notebook.SetPageText(page, _("Command console"))
    371359       
    372360        event.Skip()
     
    455443            cmd = self.GetMenuCmd(event)
    456444        self.goutput.RunCmd(cmd, switchPage=True)
    457        
     445
    458446    def OnMenuCmd(self, event, cmd = ''):
    459447        """!Parse command selected from menu"""
     
    15451533        # quit wxGUI session
    15461534        self.OnCloseWindow(event)
    1547        
     1535
    15481536        # quit GRASS shell
    15491537        try:
Note: See TracChangeset for help on using the changeset viewer.