Changeset 40068
- Timestamp:
- Dec 19, 2009, 10:37:42 AM (15 years ago)
- Location:
- grass/branches/develbranch_6/gui/wxpython
- Files:
-
- 3 edited
-
gui_modules/goutput.py (modified) (19 diffs)
-
gui_modules/prompt.py (modified) (4 diffs)
-
wxgui.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
r40054 r40068 37 37 import preferences 38 38 import menuform 39 import prompt 40 39 41 from debug import Debug as Debug 40 42 from preferences import globalSettings as UserSettings … … 146 148 self.lineWidth = 80 147 149 self.pageid = pageid 150 148 151 # remember position of line begining (used for '\r') 149 152 self.linePos = -1 … … 163 166 self.console_progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress) 164 167 # 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)) 166 169 self.btn_abort.SetToolTipString(_("Abort the running command")) 167 170 self.btn_abort.Bind(wx.EVT_BUTTON, self.OnCmdAbort) … … 180 183 181 184 # 185 # command prompt 186 # 187 self.cmd_prompt = prompt.GPrompt(self, id=wx.ID_ANY) 188 189 # 182 190 # stream redirection 183 191 # … … 193 201 # buttons 194 202 # 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) 197 207 self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear) 198 208 self.Bind(wx.EVT_BUTTON, self.SaveHistory, self.console_save) … … 205 215 """!Do layout""" 206 216 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 208 219 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 210 224 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) 212 226 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) 216 232 boxsizer1.Add(item=gridsizer1, proportion=0, 217 233 flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM, 218 234 border=5) 235 219 236 boxsizer2 = wx.BoxSizer(wx.HORIZONTAL) 220 237 boxsizer2.Add(item=self.console_progressbar, proportion=1, 221 238 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)225 239 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) 228 242 229 243 boxsizer1.Fit(self) … … 233 247 self.SetAutoLayout(True) 234 248 self.SetSizer(boxsizer1) 249 self.Layout() 235 250 236 251 def Redirect(self): … … 270 285 # p1 = self.cmd_output.GetCurrentPos() 271 286 p1 = self.cmd_output.GetEndStyled() 272 self.cmd_output.GotoPos(p1) 287 # self.cmd_output.GotoPos(p1) 288 self.cmd_output.DocumentEnd() 273 289 274 290 for line in text.splitlines(): … … 350 366 except AttributeError: 351 367 pass 352 368 369 # allow writing to output window 370 self.cmd_output.SetReadOnly(False) 371 353 372 if cmdlist[0] in globalvar.grassCmd['all']: 354 373 # send GRASS command without arguments to GUI command interface … … 411 430 del os.environ["GRASS_REGION"] 412 431 413 if len(cmdlist) == 1 and cmdlist[0] not in ('v.krige'):432 if len(cmdlist) == 1: 414 433 import menuform 415 434 # process GRASS command without argument … … 435 454 # if command is not a GRASS command, treat it like a shell command 436 455 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) 440 459 self.cmdThread.RunCmd(GrassCmd, 441 460 onDone, … … 446 465 except gcmd.CmdError, e: 447 466 print >> sys.stderr, e 467 468 # reset output window to read only 469 self.cmd_output.SetReadOnly(True) 448 470 449 471 return None … … 531 553 else: 532 554 self.cmd_output.AddTextWrapped(message, wrap=None) 533 555 534 556 p2 = self.cmd_output.GetCurrentPos() 535 557 … … 591 613 # set focus on prompt 592 614 if self.parent.GetName() == "LayerManager": 593 self. parent.cmdinput.SetFocus()615 self.cmd_prompt.SetFocus() 594 616 self.btn_abort.Enable(False) 595 617 else: … … 641 663 time.sleep(1) 642 664 dialog.Close() 643 665 644 666 event.Skip() 645 667 … … 757 779 wx.stc.StyledTextCtrl.__init__(self, parent, id) 758 780 self.parent = parent 781 self.SetUndoCollection(True) 782 self.SetReadOnly(True) 759 783 760 784 # … … 763 787 self.SetStyle() 764 788 765 766 789 # 767 790 # line margins … … 787 810 788 811 # 789 # bindin s812 # bindings 790 813 # 791 814 self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) … … 874 897 875 898 self.AddText(txt) 876 -
grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
r40054 r40068 2 2 @package prompt.py 3 3 4 @brief wxGUIprompt4 @brief GRASS prompt 5 5 6 6 Classes: 7 7 - 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 13 10 14 11 (C) 2009 by the GRASS Development Team … … 18 15 19 16 @author Martin Landa <landa.martin gmail.com> 17 @author Michael Barton <michael.barton@asu.edu> 20 18 """ 21 19 … … 25 23 26 24 import wx 27 import wx. lib.mixins.listctrl as listmix25 import wx.stc 28 26 29 27 from grass.script import core as grass 30 28 31 29 import globalvar 32 import utils33 import menuform34 30 import 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 31 import gcmd 32 33 class 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 145 404 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 146 425 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() 164 434 165 435 def OnCmdErase(self, event): 166 436 """!Erase command prompt""" 167 self.input.SetValue('') 437 self.Home() 438 self.DelLineRight() 168 439 169 440 def OnRunCmd(self, event): … … 195 466 self.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER")) 196 467 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 return204 205 modules = []206 for module, data in self.modules.iteritems():207 if self.searchBy.GetSelection() == 0: # -> description208 if text in data['desc']:209 modules.append(module)210 else: # -> keywords211 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 a227 list of choices. You can also change the choice list at any time228 by calling setChoices.229 230 Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete231 """232 self.statusbar = statusbar233 234 if kwargs.has_key('style'):235 kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']236 else:237 kwargs['style'] = wx.TE_PROCESS_ENTER238 239 wx.ComboBox.__init__(self, parent, id, **kwargs)240 241 # some variables242 self._choices = choices243 self._hideOnNoMatch = True244 self._module = None # currently selected module245 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 item248 249 # sort variable needed by listmix250 self.itemDataMap = dict()251 252 # widgets253 try:254 self.dropdown = wx.PopupWindow(self)255 except NotImplementedError:256 self.Destroy()257 raise NotImplementedError258 259 # create the list and bind the events260 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 module273 self.SetChoices(self._choicesCmd)274 275 self.SetMinSize(self.GetSize())276 # read history277 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 click286 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 data296 if self.dropdownlistbox.GetColumnCount() != 0:297 self.dropdownlistbox.DeleteAllColumns()298 self.dropdownlistbox.DeleteAllItems()299 # and update the dict300 if choices:301 for numVal, data in enumerate(choices):302 self.itemDataMap[numVal] = data303 else:304 numVal = 0305 self.SetColumnCount(numVal)306 307 def _setListSize(self):308 """!Set list size"""309 choices = self._choices310 longest = 0311 for choice in choices:312 longest = max(len(choice), longest)313 longest += 3314 itemcount = min(len( choices ), 7) + 2315 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 it323 (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 is342 always visible.343 """344 toSel = self.dropdownlistbox.GetFirstSelected()345 if toSel == -1:346 return347 self.dropdownlistbox.EnsureVisible(toSel)348 349 def _setModule(self, name):350 """!Set module's choices (flags, parameters)"""351 # get module's description352 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 = None357 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 return385 386 if self._colFetch != -1:387 col = self._colFetch388 else:389 col = self._colSearch390 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 map401 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 text413 self.SetValue(itemtext + ' ')414 415 # define module416 self._setModule(itemtext)417 418 # use parameters as default choices419 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.dropdownlistbox429 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 return441 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 return451 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 choices459 @param type type of choices (module, param, flag, raster, vector)460 """461 self._choices = choices462 self._choiceType = type463 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 maps470 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 = 0483 self._colFetch = -1484 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, return507 if toSel == -1: return508 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 sort518 if col == self._colSearch:519 self._ascending = not self._ascending520 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 return539 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 option553 if cmd[-1][0] == '-':554 # -> flags555 self.SetChoices(self._choicesMap['flag'], type = 'flag')556 pattern = cmd[-1].lstrip('-')557 else:558 # -> options559 self.SetChoices(self._choicesMap['param'], type = 'param')560 pattern = cmd[-1]561 else:562 # value563 pattern = cmd[-1].split('=', 1)[1]564 else:565 # search for GRASS modules566 if self._module:567 # -> switch back to GRASS modules list568 self.SetChoices(self._choicesCmd)569 self._module = None570 self._choiceType = None571 572 self._choiceType573 self._choicesMap574 found = False575 choices = self._choices576 for numCh, choice in enumerate(choices):577 if choice.lower().startswith(pattern):578 found = True579 if found:580 self._showDropDown(True)581 item = self.dropdownlistbox.GetItem(numCh)582 toSel = item.GetId()583 self.dropdownlistbox.Select(toSel)584 break585 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] == '-': # flag593 message = _("Warning: flag <%s> not found in '%s'") % \594 (cmd[-1][1:], self._module.name)595 else: # option596 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 map604 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 search613 """614 skip = True615 sel = self.dropdownlistbox.GetFirstSelected()616 visible = self.dropdown.IsShown()617 KC = event.GetKeyCode()618 619 if KC == wx.WXK_RIGHT:620 # right -> show choices621 if sel < (self.dropdownlistbox.GetItemCount() - 1):622 self.dropdownlistbox.Select(sel + 1)623 self._listItemVisible()624 self._showDropDown()625 skip = False626 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 = False633 else:634 self._historyItem -= 1635 try:636 self.SetValue(self.GetItems()[self._historyItem])637 except IndexError:638 self._historyItem += 1639 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 = False646 else:647 if self._historyItem < -1:648 self._historyItem += 1649 self.SetValue(self.GetItems()[self._historyItem])650 651 if visible:652 if event.GetKeyCode() == wx.WXK_RETURN:653 self._setValueFromSelected()654 skip = False655 if event.GetKeyCode() == wx.WXK_ESCAPE:656 self._showDropDown(False)657 skip = False658 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 133 133 self.menubar, self.menudata = self.__createMenuBar() 134 134 self.statusbar = self.CreateStatusBar(number=1) 135 self.cmdprompt, self.cmdinput = self.__createCommandPrompt()136 135 self.toolbar = self.__createToolBar() 137 136 … … 147 146 Left().CentrePane().BestSize((-1,-1)).Dockable(False). 148 147 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))154 148 155 149 self._auimgr.Update() 156 150 157 151 wx.CallAfter(self.notebook.SetSelection, 0) 158 wx.CallAfter(self. cmdinput.SetFocus)152 wx.CallAfter(self.goutput.cmd_prompt.SetFocus) 159 153 160 154 # use default window layout ? … … 193 187 self.curr_page.maptree.mapdisplay.Raise() 194 188 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 202 190 def __createMenuBar(self): 203 191 """!Creates menubar""" … … 368 356 if page == self.goutput.pageid: 369 357 # remove '(...)' 370 self.notebook.SetPageText(page, _("Command output"))358 self.notebook.SetPageText(page, _("Command console")) 371 359 372 360 event.Skip() … … 455 443 cmd = self.GetMenuCmd(event) 456 444 self.goutput.RunCmd(cmd, switchPage=True) 457 445 458 446 def OnMenuCmd(self, event, cmd = ''): 459 447 """!Parse command selected from menu""" … … 1545 1533 # quit wxGUI session 1546 1534 self.OnCloseWindow(event) 1547 1535 1548 1536 # quit GRASS shell 1549 1537 try:
Note:
See TracChangeset
for help on using the changeset viewer.
