[GRASS-SVN] r40068 - in grass/branches/develbranch_6/gui/wxpython:
. gui_modules
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Dec 19 13:37:42 EST 2009
Author: cmbarton
Date: 2009-12-19 13:37:42 -0500 (Sat, 19 Dec 2009)
New Revision: 40068
Modified:
grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
grass/branches/develbranch_6/gui/wxpython/wxgui.py
Log:
Advanced grass command console. Try again with repaired subversion installation.
Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py 2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/goutput.py 2009-12-19 18:37:42 UTC (rev 40068)
@@ -36,6 +36,8 @@
import utils
import preferences
import menuform
+import prompt
+
from debug import Debug as Debug
from preferences import globalSettings as UserSettings
@@ -145,6 +147,7 @@
self._notebook = self.parent.notebook
self.lineWidth = 80
self.pageid = pageid
+
# remember position of line begining (used for '\r')
self.linePos = -1
@@ -162,7 +165,7 @@
style=wx.GA_HORIZONTAL)
self.console_progressbar.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
# abort
- self.btn_abort = wx.Button(parent=self, id=wx.ID_STOP)
+ self.btn_abort = wx.Button(self, -1, "Abort command", size=(125,-1))
self.btn_abort.SetToolTipString(_("Abort the running command"))
self.btn_abort.Bind(wx.EVT_BUTTON, self.OnCmdAbort)
self.btn_abort.Enable(False)
@@ -179,6 +182,11 @@
self.Bind(EVT_CMD_DONE, self.OnCmdDone)
#
+ # command prompt
+ #
+ self.cmd_prompt = prompt.GPrompt(self, id=wx.ID_ANY)
+
+ #
# stream redirection
#
self.cmd_stdout = GMStdout(self)
@@ -192,8 +200,10 @@
#
# buttons
#
- self.console_clear = wx.Button(parent=self, id=wx.ID_CLEAR)
- self.console_save = wx.Button(parent=self, id=wx.ID_SAVE)
+ self.console_clear = wx.Button(self, -1, "Clear output", size=(125,-1))
+ self.cmd_clear = wx.Button(self, -1, "Clear command", size=(125,-1))
+ self.console_save = wx.Button(self, -1, "Save output", size=(125,-1))
+ self.Bind(wx.EVT_BUTTON, self.cmd_prompt.OnCmdErase, self.cmd_clear)
self.Bind(wx.EVT_BUTTON, self.ClearHistory, self.console_clear)
self.Bind(wx.EVT_BUTTON, self.SaveHistory, self.console_save)
@@ -204,27 +214,31 @@
def __layout(self):
"""!Do layout"""
boxsizer1 = wx.BoxSizer(wx.VERTICAL)
- gridsizer1 = wx.GridSizer(rows=1, cols=2, vgap=0, hgap=0)
+ gridsizer1 = wx.GridSizer(rows=1, cols=4, vgap=0, hgap=0)
+
boxsizer1.Add(item=self.cmd_output, proportion=1,
- flag=wx.EXPAND | wx.ADJUST_MINSIZE, border=0)
+ flag=wx.EXPAND | wx.ALIGN_BOTTOM, border=0)
+ boxsizer1.Add(item=self.cmd_prompt, proportion=0,
+ flag=wx.EXPAND | wx.FIXED_MINSIZE | wx.ALIGN_BOTTOM, border=0)
+
gridsizer1.Add(item=self.console_clear, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
+ flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
gridsizer1.Add(item=self.console_save, proportion=0,
- flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, border=0)
-
-
+ flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
+ gridsizer1.Add(item=self.cmd_clear, proportion=0,
+ flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
+ gridsizer1.Add(item=self.btn_abort, proportion=0,
+ flag=wx.ALIGN_CENTER_HORIZONTAL | wx.FIXED_MINSIZE, border=0)
boxsizer1.Add(item=gridsizer1, proportion=0,
flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.TOP | wx.BOTTOM,
border=5)
+
boxsizer2 = wx.BoxSizer(wx.HORIZONTAL)
boxsizer2.Add(item=self.console_progressbar, proportion=1,
flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL)
- boxsizer2.Add(item=self.btn_abort, proportion=0,
- flag=wx.ALIGN_CENTRE_VERTICAL | wx.LEFT,
- border = 5)
boxsizer1.Add(item=boxsizer2, proportion=0,
- flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.ALL,
- border=5)
+ flag=wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL | wx.LEFT | wx.RIGHT |
+ wx.TOP, border=5)
boxsizer1.Fit(self)
boxsizer1.SetSizeHints(self)
@@ -232,6 +246,7 @@
# layout
self.SetAutoLayout(True)
self.SetSizer(boxsizer1)
+ self.Layout()
def Redirect(self):
"""!Redirect stderr
@@ -269,7 +284,8 @@
# p1 = self.cmd_output.GetCurrentPos()
p1 = self.cmd_output.GetEndStyled()
- self.cmd_output.GotoPos(p1)
+# self.cmd_output.GotoPos(p1)
+ self.cmd_output.DocumentEnd()
for line in text.splitlines():
# fill space
@@ -349,7 +365,10 @@
self.parent.cmdinput.SetHistoryItems()
except AttributeError:
pass
-
+
+ # allow writing to output window
+ self.cmd_output.SetReadOnly(False)
+
if cmdlist[0] in globalvar.grassCmd['all']:
# send GRASS command without arguments to GUI command interface
# except display commands (they are handled differently)
@@ -410,7 +429,7 @@
if os.environ.has_key("GRASS_REGION"):
del os.environ["GRASS_REGION"]
- if len(cmdlist) == 1 and cmdlist[0] not in ('v.krige'):
+ if len(cmdlist) == 1:
import menuform
# process GRASS command without argument
menuform.GUI().ParseCommand(cmdlist, parentframe=self)
@@ -434,9 +453,9 @@
# if command is not a GRASS command, treat it like a shell command
try:
- # gcmd.Command(cmdlist,
- # stdout=self.cmd_stdout,
- # stderr=self.cmd_stderr)
+# gcmd.Command(cmdlist,
+# stdout=self.cmd_stdout,
+# stderr=self.cmd_stderr)
self.cmdThread.RunCmd(GrassCmd,
onDone,
cmdlist,
@@ -445,6 +464,9 @@
self.cmd_output_timer.Start(50)
except gcmd.CmdError, e:
print >> sys.stderr, e
+
+ # reset output window to read only
+ self.cmd_output.SetReadOnly(True)
return None
@@ -530,7 +552,7 @@
self.cmd_output.AddTextWrapped(message, wrap=60)
else:
self.cmd_output.AddTextWrapped(message, wrap=None)
-
+
p2 = self.cmd_output.GetCurrentPos()
if p2 >= p1:
@@ -590,7 +612,7 @@
# set focus on prompt
if self.parent.GetName() == "LayerManager":
- self.parent.cmdinput.SetFocus()
+ self.cmd_prompt.SetFocus()
self.btn_abort.Enable(False)
else:
# updated command dialog
@@ -640,7 +662,7 @@
dialog.closebox.IsChecked():
time.sleep(1)
dialog.Close()
-
+
event.Skip()
def OnProcessPendingOutputWindowEvents(self, event):
@@ -756,13 +778,14 @@
def __init__(self, parent, id, margin=False, wrap=None):
wx.stc.StyledTextCtrl.__init__(self, parent, id)
self.parent = parent
+ self.SetUndoCollection(True)
+ self.SetReadOnly(True)
#
# styles
#
self.SetStyle()
-
#
# line margins
#
@@ -786,7 +809,7 @@
self.SetUseHorizontalScrollBar(True)
#
- # bindins
+ # bindings
#
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
@@ -872,5 +895,4 @@
else:
txt = _('Unable to encode text. Please set encoding in GUI preferences.') + '\n'
- self.AddText(txt)
-
+ self.AddText(txt)
\ No newline at end of file
Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py 2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/prompt.py 2009-12-19 18:37:42 UTC (rev 40068)
@@ -1,15 +1,12 @@
"""!
@package prompt.py
- at brief wxGUI prompt
+ at brief GRASS prompt
Classes:
- GPrompt
- - PromptListCtrl
- - TextCtrlAutoComplete
- at todo: fix TextCtrlAutoComplete to work also on Macs (missing
-wx.PopupWindow())
+ at todo: reduce size of STC prompt to about 3 lines
(C) 2009 by the GRASS Development Team
This program is free software under the GNU General Public
@@ -17,6 +14,7 @@
for details.
@author Martin Landa <landa.martin gmail.com>
+ at author Michael Barton <michael.barton at asu.edu>
"""
import os
@@ -24,147 +22,420 @@
import shlex
import wx
-import wx.lib.mixins.listctrl as listmix
+import wx.stc
from grass.script import core as grass
import globalvar
-import utils
-import menuform
import menudata
+import gcmd
-class GPrompt:
- """!Interactive GRASS prompt"""
- def __init__(self, parent):
- self.parent = parent # GMFrame
+class GPrompt(wx.stc.StyledTextCtrl):
+ """!Styled GRASS prompt with autocomplete and calltips"""
+ def __init__(self, parent, id, size=wx.DefaultSize, margin=False, wrap=None):
+ wx.stc.StyledTextCtrl.__init__(self, parent, id)
+ self.parent = parent
+ self.SetUndoCollection(True)
+
+ #
+ # styles
+ #
+ self.SetWrapMode(True)
- # dictionary of modules (description, keywords, ...)
- self.modules = self.parent.menudata.GetModules()
+ #
+ # create command and map lists for autocompletion
+ #
+ self.AutoCompSetIgnoreCase(False)
- self.panel, self.input = self.__create()
+ self.rastlist = []
+ self.vectlist = []
+ self.imglist = []
+ self.r3list = []
+ self.dblist = []
+ self.genlist = []
+ self.displist = []
- def __create(self):
- """!Create widget"""
- cmdprompt = wx.Panel(self.parent)
-
#
- # search
+ # Get available GRASS commands and parse into lists by command type for autocomplete
#
- searchTxt = wx.StaticText(parent = cmdprompt, id = wx.ID_ANY,
- label = _("Find module:"))
-
- self.searchBy = wx.Choice(parent = cmdprompt, id = wx.ID_ANY,
- choices = [_("description"),
- _("keywords")])
- winHeight = self.searchBy.GetSize()[1]
+ for item in globalvar.grassCmd['all']:
+ if len(item.split('.')) > 1:
+ start,end = item.split('.',1)
+ if start == 'r': self.rastlist.append(end)
+ elif start == 'v': self.vectlist.append(end)
+ elif start == 'i': self.imglist.append(end)
+ elif start == 'r3': self.r3list.append(end)
+ elif start == 'db': self.dblist.append(end)
+ elif start == 'g': self.genlist.append(end)
+ elif start == 'd': self.displist.append(end)
- self.search = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
- value = "", size = (-1, 25))
+ self.rastlist.sort()
+ self.vectlist.sort()
+ self.imglist.sort()
+ self.r3list.sort()
+ self.dblist.sort()
+ self.genlist.sort()
+ self.displist.sort()
+
+ #
+ # Create lists of element types and possible arguments for autocomplete
+ #
+ self.datatypes = []
+ self.maplists = {}
+ self.maptype = ''
+ self.datatypes = ['rast',
+ 'rast3d',
+ 'vect',
+ 'oldvect',
+ 'asciivect',
+ 'labels',
+ 'region',
+ 'region3d',
+ 'group',
+ '3dview']
+
+ self.drastcmd = ['d.rast',
+ 'd.rgb',
+ 'd.his',
+ 'd.rast.arrow',
+ 'd.rast.num']
+
+ self.dvectcmd = ['d.vect',
+ 'd.vect.chart'
+ 'd.thematic.area',
+ 'd.vect.thematic']
- label = wx.Button(parent = cmdprompt, id = wx.ID_ANY,
- label = _("&Cmd >"), size = (-1, winHeight))
- label.SetToolTipString(_("Click for erasing command prompt"))
+ self.rastargs = ['map',
+ 'input',
+ 'rast',
+ 'raster',
+ 'red',
+ 'green',
+ 'blue',
+ 'h_map',
+ 'i_map',
+ 's_map',
+ 'hue_input',
+ 'intensity_input',
+ 'saturation_input',
+ 'red_input',
+ 'green_input',
+ 'blue_input']
+
+ self.__getfiles()
- ### todo: fix TextCtrlAutoComplete to work also on Macs
- ### reason: missing wx.PopupWindow()
- try:
- cmdinput = TextCtrlAutoComplete(parent = cmdprompt, id = wx.ID_ANY,
- value = "",
- style = wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
- size = (-1, winHeight),
- statusbar = self.parent.statusbar)
- except NotImplementedError:
- # wx.PopupWindow may be not available in wxMac
- # see http://trac.wxwidgets.org/ticket/9377
- cmdinput = wx.TextCtrl(parent = cmdprompt, id = wx.ID_ANY,
- value = "",
- style=wx.TE_LINEWRAP | wx.TE_PROCESS_ENTER,
- size = (-1, 25))
- self.searchBy.Enable(False)
- self.search.Enable(False)
+ #
+ # command history buffer
+ #
+ self.cmdbuffer = []
+ self.cmdindex = 0
+
+ #
+ # line margins
+ #
+ # TODO print number only from cmdlog
+ self.SetMarginWidth(1, 0)
+ self.SetMarginWidth(2, 0)
+ if margin:
+ self.SetMarginType(0, wx.stc.STC_MARGIN_NUMBER)
+ self.SetMarginWidth(0, 30)
+ else:
+ self.SetMarginWidth(0, 0)
+
+ #
+ # miscellaneous
+ #
+ self.SetViewWhiteSpace(False)
+# self.SetTabWidth(4)
+ self.SetUseTabs(False)
+ self.UsePopUp(True)
+ self.SetSelBackground(True, "#FFFF00")
+ self.SetUseHorizontalScrollBar(True)
+
+ #
+ # bindings
+ #
+ self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+
+ def __getfiles(self):
+ """!Get accessible files for autocomplete"""
+ for item in self.datatypes:
+ mlist = grass.read_command("g.mlist", "m", type=item).splitlines()
+ mlist.sort()
+ self.maplists[item] = mlist
+
+ def OnKeyPressed(self, event):
+ """!Key press capture for autocompletion, calltips, and command history"""
- cmdinput.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.NORMAL, 0, ''))
+ #keycodes used: "." = 46, "=" = 61, "," = 44
+ line = ''
+ entry = ''
+ usage = ''
+ cmdtype = ''
+ cmdname = ''
+ cmd = ''
+
+ # CAN CHANGE: event.ControlDown() for manual autocomplete
- wx.CallAfter(cmdinput.SetInsertionPoint, 0)
-
- # bidnings
- label.Bind(wx.EVT_BUTTON, self.OnCmdErase)
- cmdinput.Bind(wx.EVT_TEXT_ENTER, self.OnRunCmd)
- cmdinput.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
- self.search.Bind(wx.EVT_TEXT, self.OnSearchModule)
-
- # layout
- sizer = wx.GridBagSizer(hgap=5, vgap=5)
- sizer.AddGrowableRow(1)
- sizer.AddGrowableCol(2)
+ if event.GetKeyCode() == 46 and not event.ShiftDown():
+ #GRASS command autocomplete when "." is pressed after r,v,i,g,db, or d
+ listcmds = []
+ pos = self.GetCurrentPos()
+ self.InsertText(pos,'.')
+ self.CharRight()
+
+ entry = self.GetTextLeft()
+ if entry not in ['r.','v.','i.','g.','db.','d.']:
+ return
- sizer.Add(item = searchTxt,
- flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL,
- pos = (0, 0))
+ if entry == 'r.': listcmds = self.rastlist
+ elif entry == 'v.': listcmds = self.vectlist
+ elif entry == 'i.': listcmds = self.imglist
+ elif entry == 'r3.': listcmds = self.r3list
+ elif entry == 'db.': listcmds = self.dblist
+ elif entry == 'g.': listcmds = self.genlist
+ elif entry == 'd.': listcmds = self.displist
- sizer.Add(item = self.searchBy,
- flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
- pos = (0, 1))
+ if listcmds == []:
+ return
+ else:
+ self.AutoCompShow(0, " ".join(listcmds))
+
+ elif event.GetKeyCode() == wx.WXK_TAB:
+ #GRASS command calltips
+
+ #Must be a command to the left somewhere
+ pos = self.GetCurrentPos()
+ entry = self.GetTextLeft()
+ cmd = entry.split()[0].strip()
+ if cmd not in globalvar.grassCmd['all']:
+ return
+
+ usage, description = self.GetCommandUsage(cmd)
+
+ self.CallTipSetBackground("PALE GREEN")
+ self.CallTipSetForeground("BLACK")
+ self.CallTipShow(pos, usage+'\n\n'+description)
+
+ elif (event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown()) or \
+ event.GetKeyCode() == 61 or event.GetKeyCode() == 44:
+ #Autocompletion for map/data file name entry after '=', ',', or manually
+
+ pos = self.GetCurrentPos()
+ entry = self.GetTextLeft()
+ if event.GetKeyCode() != 44:
+ self.maptype = ''
+ arg = ''
+ cmdtype = ''
+ cmdname = ''
+ cmd = ''
+
+ if entry.strip()[0:2] in ['r.','v.','i.','g.','db.','d.']:
+ cmdtype = entry.strip()[0]
+ cmd = entry.split()[0].strip()
+ if cmd in globalvar.grassCmd['all']:
+ cmdname = cmd.split('.')[1]
+ else:
+ #No complete GRASS command found
+ cmd = ''
+ cmdname = ''
+ elif entry.strip()[0:4] == 'nviz':
+ cmdtype = ''
+ cmdname = cmd = 'nviz'
+ else:
+ #No partial or complete GRASS command found
+ return
+
+ cmdargs = entry.strip('=')
+ try:
+ arg = cmdargs.rsplit(' ',1)[1]
+ except:
+ arg = ''
+
+ if event.GetKeyCode() == 61:
+ # autocompletion after '='
+ # insert the '=' and move to after the '=', ready for a map name
+ self.InsertText(pos,'=')
+ self.CharRight()
+
+ maplist = []
+ self.maptype = ''
+
+ #what kind of map/data type is desired?
+ if (((cmdtype in ['r', 'i'] or cmd in self.drastcmd) and arg in self.rastargs) or
+ ((cmd=='nviz' or cmdtype=='r3') and arg in ['elevation','color']) or
+ arg in ['rast', 'raster']):
+ self.maptype = 'rast'
+ elif (((cmdtype=='v' or cmd in self.dvectcmd) and arg in ['map', 'input']) or
+ (cmdtype=='r3' and arg=='input') or
+ arg in ['vect', 'vector', 'points']):
+ self.maptype = 'vect'
+ elif ((cmdtype=='r3' and arg in ['map', 'input']) or
+ (cmdtype=='nviz' and arg=='volume') or arg=='rast3d'):
+ self.maptype = 'rast3d'
+ elif arg=='labels':
+ self.maptype ='labels'
+ elif arg=='region':
+ self.maptype ='region'
+ elif arg=='region3d':
+ self.maptype ='region3d'
+ elif arg=='group':
+ self.maptype ='group'
+ elif arg=='3dview':
+ self.maptype ='3dview'
+
+ print 'maptype at end of = ' + str(self.maptype)
+
+ elif event.GetKeyCode() == 44:
+ # autocompletion after ','
+ # if comma is pressed, use the same maptype as previous for multiple map entries
+
+ # insert the comma and move to after the comma ready for a map name
+ self.InsertText(pos,',')
+ self.CharRight()
+
+ #must apply to an entry where '=[string]' has already been entered
+ if '=' not in arg:
+ return
+
+ elif event.GetKeyCode() == wx.WXK_SPACE and event.ControlDown():
+ # manual autocompletion
+ # map entries without arguments (as in r.info [mapname]) use ctrl-shift
+
+ maplist = []
+ if cmdtype=='r' or cmdtype=='i':
+ self.maptype = 'rast'
+ elif cmdtype=='v':
+ self.maptype = 'vect'
+ elif cmdtype=='r3':
+ self.maptype = 'rast3d'
+
+ if self.maptype == '':
+ return
+ else:
+ maplist = self.maplists[self.maptype]
+ self.AutoCompShow(0, " ".join(maplist))
+
+ elif event.GetKeyCode() in [wx.WXK_UP,wx.WXK_DOWN] and event.ControlDown():
+ # Command history using ctrl-up and ctrl-down
+
+ if self.cmdbuffer == []: return
+ txt = ''
+
+ self.DocumentEnd()
+
+ # move through command history list index values
+ if event.GetKeyCode() == wx.WXK_UP:
+ self.cmdindex = self.cmdindex - 1
+ if event.GetKeyCode() == wx.WXK_DOWN:
+ self.cmdindex = self.cmdindex + 1
+ if self.cmdindex < 0:
+ self.cmdindex = 0
+ if self.cmdindex > len(self.cmdbuffer) - 1:
+ self.cmdindex = len(self.cmdbuffer) - 1
+
+ try:
+ txt = self.cmdbuffer[self.cmdindex]
+ except:
+ pass
+
+ # clear current line and insert command history
+ self.DelLineLeft()
+ self.DelLineRight()
+ pos = self.GetCurrentPos()
+ self.InsertText(pos,txt)
+ self.LineEnd()
+
+ elif event.GetKeyCode() == wx.WXK_RETURN and self.AutoCompActive() == False:
+ # Run command on line when <return> is pressed
+
+ # find the command to run
+ line = str(self.GetCurLine()[0]).strip()
+ if len(line) == 0:
+ return
+
+ # parse command into list
+ # TODO: shell commands should probably be passed as string
+ cmd = shlex.split(str(line))
+
+ #send the command list to the processor
+ self.parent.RunCmd(cmd)
+
+ #add command to history
+ self.cmdbuffer.append(line)
+
+ #keep command history to a managable size
+ if len(self.cmdbuffer) > 200:
+ del self.cmdbuffer[0]
+ self.cmdindex = len(self.cmdbuffer)
+
+ else:
+ event.Skip()
+
+ def GetTextLeft(self):
+ """!Returns all text left of the caret"""
+ entry = ''
+ pos = self.GetCurrentPos()
+ self.HomeExtend()
+ entry = self.GetSelectedText().strip()
+ self.SetCurrentPos(pos)
- sizer.Add(item = self.search,
- flag = wx.EXPAND | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
- border = 5,
- pos = (0, 2))
-
- sizer.Add(item = label,
- flag = wx.LEFT | wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER,
- border = 5,
- pos = (1, 0))
-
- sizer.Add(item = cmdinput,
- flag = wx.EXPAND | wx.RIGHT,
- border = 5,
- pos = (1, 1), span = (1, 2))
-
- cmdprompt.SetSizer(sizer)
- sizer.Fit(cmdprompt)
- cmdprompt.Layout()
-
- return cmdprompt, cmdinput
+ return entry
- def __checkKey(self, text, keywords):
- """!Check if text is in keywords"""
- found = 0
- keys = text.split(',')
- if len(keys) > 1: # -> multiple keys
- for k in keys[:-1]:
- k = k.strip()
- for key in keywords:
- if k == key: # full match
- found += 1
- break
- k = keys[-1].strip()
- for key in keywords:
- if k in key: # partial match
- found +=1
+ def GetCommandUsage(self, command):
+ """!Returns command syntax by running command help"""
+ usage = ''
+ description = ''
+
+ ret, out = gcmd.RunCommand(command, 'help', getErrorMsg = True)
+
+ if ret == 0:
+ cmdhelp = out.splitlines()
+ addline = False
+ helplist = []
+ description = ''
+ for line in cmdhelp:
+ if "Usage:" in line:
+ addline = True
+ continue
+ elif "Flags:" in line:
+ addline = False
break
- else:
- for key in keywords:
- if text in key: # partial match
- found +=1
+ elif addline == True:
+ line = line.strip()
+ helplist.append(line)
+
+ for line in cmdhelp:
+ if "Description:" in line:
+ addline = True
+ continue
+ elif "Keywords:" in line:
+ addline = False
break
+ elif addline == True:
+ description += (line + ' ')
+
+ description = description.strip()
+
+ for line in helplist:
+ usage += line + '\n'
+
+ return usage.strip(), description
+ else:
+ return ''
+
+ def OnDestroy(self, evt):
+ """!The clipboard contents can be preserved after
+ the app has exited"""
- if found == len(keys):
- return True
-
- return False
+ wx.TheClipboard.Flush()
+ evt.Skip()
- def GetPanel(self):
- """!Get main widget panel"""
- return self.panel
-
- def GetInput(self):
- """!Get main prompt widget"""
- return self.input
-
def OnCmdErase(self, event):
"""!Erase command prompt"""
- self.input.SetValue('')
+ self.Home()
+ self.DelLineRight()
def OnRunCmd(self, event):
"""!Run command"""
@@ -193,474 +464,4 @@
self.parent.statusbar.SetStatusText("")
else:
self.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
- event.Skip()
-
- def OnSearchModule(self, event):
- """!Search module by metadata"""
- text = event.GetString()
- if not text:
- self.input.SetChoices(globalvar.grassCmd['all'])
- return
-
- modules = []
- for module, data in self.modules.iteritems():
- if self.searchBy.GetSelection() == 0: # -> description
- if text in data['desc']:
- modules.append(module)
- else: # -> keywords
- if self.__checkKey(text, data['keywords']):
- modules.append(module)
-
- self.parent.statusbar.SetStatusText(_("%d modules found") % len(modules))
- self.input.SetChoices(modules)
-
-class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
- def __init__(self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition,
- size = wx.DefaultSize, style = 0):
- wx.ListCtrl.__init__(self, parent, id, pos, size, style)
- listmix.ListCtrlAutoWidthMixin.__init__(self)
-
-class TextCtrlAutoComplete(wx.ComboBox, listmix.ColumnSorterMixin):
- def __init__ (self, parent, statusbar,
- id = wx.ID_ANY, choices = [], **kwargs):
- """!Constructor works just like wx.TextCtrl except you can pass in a
- list of choices. You can also change the choice list at any time
- by calling setChoices.
-
- Inspired by http://wiki.wxpython.org/TextCtrlAutoComplete
- """
- self.statusbar = statusbar
-
- if kwargs.has_key('style'):
- kwargs['style'] = wx.TE_PROCESS_ENTER | kwargs['style']
- else:
- kwargs['style'] = wx.TE_PROCESS_ENTER
-
- wx.ComboBox.__init__(self, parent, id, **kwargs)
-
- # some variables
- self._choices = choices
- self._hideOnNoMatch = True
- self._module = None # currently selected module
- self._choiceType = None # type of choice (module, params, flags, raster, vector ...)
- self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
- self._historyItem = 0 # last item
-
- # sort variable needed by listmix
- self.itemDataMap = dict()
-
- # widgets
- try:
- self.dropdown = wx.PopupWindow(self)
- except NotImplementedError:
- self.Destroy()
- raise NotImplementedError
-
- # create the list and bind the events
- self.dropdownlistbox = PromptListCtrl(parent = self.dropdown,
- style = wx.LC_REPORT | wx.LC_SINGLE_SEL | \
- wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER,
- pos = wx.Point(0, 0))
-
- listmix.ColumnSorterMixin.__init__(self, 1)
-
- # set choices (list of GRASS modules)
- self._choicesCmd = globalvar.grassCmd['all']
- self._choicesMap = dict()
- for type in ('raster', 'vector'):
- self._choicesMap[type] = grass.list_strings(type = type[:4])
- # first search for GRASS module
- self.SetChoices(self._choicesCmd)
-
- self.SetMinSize(self.GetSize())
- # read history
- self.SetHistoryItems()
-
- # bindings...
- self.Bind(wx.EVT_KILL_FOCUS, self.OnControlChanged)
- self.Bind(wx.EVT_TEXT, self.OnEnteredText)
- self.Bind(wx.EVT_KEY_DOWN , self.OnKeyDown)
- ### self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
-
- # if need drop down on left click
- self.dropdown.Bind(wx.EVT_LISTBOX , self.OnListItemSelected, self.dropdownlistbox)
- self.dropdownlistbox.Bind(wx.EVT_LEFT_DOWN, self.OnListClick)
- self.dropdownlistbox.Bind(wx.EVT_LEFT_DCLICK, self.OnListDClick)
- self.dropdownlistbox.Bind(wx.EVT_LIST_COL_CLICK, self.OnListColClick)
-
- self.Bind(wx.EVT_COMBOBOX, self.OnCommandSelect)
-
- def _updateDataList(self, choices):
- """!Update data list"""
- # delete, if need, all the previous data
- if self.dropdownlistbox.GetColumnCount() != 0:
- self.dropdownlistbox.DeleteAllColumns()
- self.dropdownlistbox.DeleteAllItems()
- # and update the dict
- if choices:
- for numVal, data in enumerate(choices):
- self.itemDataMap[numVal] = data
- else:
- numVal = 0
- self.SetColumnCount(numVal)
-
- def _setListSize(self):
- """!Set list size"""
- choices = self._choices
- longest = 0
- for choice in choices:
- longest = max(len(choice), longest)
- longest += 3
- itemcount = min(len( choices ), 7) + 2
- charheight = self.dropdownlistbox.GetCharHeight()
- charwidth = self.dropdownlistbox.GetCharWidth()
- self.popupsize = wx.Size(charwidth*longest, charheight*itemcount)
- self.dropdownlistbox.SetSize(self.popupsize)
- self.dropdown.SetClientSize(self.popupsize)
-
- def _showDropDown(self, show = True):
- """!Either display the drop down list (show = True) or hide it
- (show = False).
- """
- if show:
- size = self.dropdown.GetSize()
- width, height = self.GetSizeTuple()
- x, y = self.ClientToScreenXY(0, height)
- if size.GetWidth() != width:
- size.SetWidth(width)
- self.dropdown.SetSize(size)
- self.dropdownlistbox.SetSize(self.dropdown.GetClientSize())
- if (y + size.GetHeight()) < self._screenheight:
- self.dropdown.SetPosition(wx.Point(x, y))
- else:
- self.dropdown.SetPosition(wx.Point(x, y - height - size.GetHeight()))
-
- self.dropdown.Show(show)
-
- def _listItemVisible(self):
- """!Moves the selected item to the top of the list ensuring it is
- always visible.
- """
- toSel = self.dropdownlistbox.GetFirstSelected()
- if toSel == -1:
- return
- self.dropdownlistbox.EnsureVisible(toSel)
-
- def _setModule(self, name):
- """!Set module's choices (flags, parameters)"""
- # get module's description
- if name in self._choicesCmd and not self._module:
- try:
- self._module = menuform.GUI().ParseInterface(cmd = [name])
- except IOError:
- self._module = None
-
- # set choices (flags)
- self._choicesMap['flag'] = self._module.get_list_flags()
- for idx in range(len(self._choicesMap['flag'])):
- item = self._choicesMap['flag'][idx]
- desc = self._module.get_flag(item)['label']
- if not desc:
- desc = self._module.get_flag(item)['description']
-
- self._choicesMap['flag'][idx] = '%s (%s)' % (item, desc)
-
- # set choices (parameters)
- self._choicesMap['param'] = self._module.get_list_params()
- for idx in range(len(self._choicesMap['param'])):
- item = self._choicesMap['param'][idx]
- desc = self._module.get_param(item)['label']
- if not desc:
- desc = self._module.get_param(item)['description']
-
- self._choicesMap['param'][idx] = '%s (%s)' % (item, desc)
-
- def _setValueFromSelected(self):
- """!Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
- Will do nothing if no item is selected in the wx.ListCtrl.
- """
- sel = self.dropdownlistbox.GetFirstSelected()
- if sel < 0:
- return
-
- if self._colFetch != -1:
- col = self._colFetch
- else:
- col = self._colSearch
- itemtext = self.dropdownlistbox.GetItem(sel, col).GetText()
-
- cmd = shlex.split(str(self.GetValue()))
- if len(cmd) > 0 and cmd[0] in self._choicesCmd:
- # -> append text (skip last item)
- if self._choiceType == 'param':
- itemtext = itemtext.split(' ')[0]
- self.SetValue(' '.join(cmd) + ' ' + itemtext + '=')
- optType = self._module.get_param(itemtext)['prompt']
- if optType in ('raster', 'vector'):
- # -> raster/vector map
- self.SetChoices(self._choicesMap[optType], optType)
- elif self._choiceType == 'flag':
- itemtext = itemtext.split(' ')[0]
- if len(itemtext) > 1:
- prefix = '--'
- else:
- prefix = '-'
- self.SetValue(' '.join(cmd[:-1]) + ' ' + prefix + itemtext)
- elif self._choiceType in ('raster', 'vector'):
- self.SetValue(' '.join(cmd[:-1]) + ' ' + cmd[-1].split('=', 1)[0] + '=' + itemtext)
- else:
- # -> reset text
- self.SetValue(itemtext + ' ')
-
- # define module
- self._setModule(itemtext)
-
- # use parameters as default choices
- self._choiceType = 'param'
- self.SetChoices(self._choicesMap['param'], type = 'param')
-
- self.SetInsertionPointEnd()
-
- self._showDropDown(False)
-
- def GetListCtrl(self):
- """!Method required by listmix.ColumnSorterMixin"""
- return self.dropdownlistbox
-
- def SetHistoryItems(self):
- """!Read history file and update combobox items"""
- env = grass.gisenv()
- try:
- fileHistory = open(os.path.join(env['GISDBASE'],
- env['LOCATION_NAME'],
- env['MAPSET'],
- '.bash_history'), 'r')
- except IOError:
- self.SetItems([])
- return
-
- try:
- hist = []
- for line in fileHistory.readlines():
- hist.append(line.replace('\n', ''))
-
- self.SetItems(hist)
- finally:
- fileHistory.close()
- return
-
- self.SetItems([])
-
- def SetChoices(self, choices, type = 'module'):
- """!Sets the choices available in the popup wx.ListBox.
- The items will be sorted case insensitively.
-
- @param choices list of choices
- @param type type of choices (module, param, flag, raster, vector)
- """
- self._choices = choices
- self._choiceType = type
-
- self.dropdownlistbox.SetWindowStyleFlag(wx.LC_REPORT | wx.LC_SINGLE_SEL |
- wx.LC_SORT_ASCENDING | wx.LC_NO_HEADER)
- if not isinstance(choices, list):
- self._choices = [ x for x in choices ]
- if self._choiceType not in ('raster', 'vector'):
- # do not sort raster/vector maps
- utils.ListSortLower(self._choices)
-
- self._updateDataList(self._choices)
-
- self.dropdownlistbox.InsertColumn(0, "")
- for num, colVal in enumerate(self._choices):
- index = self.dropdownlistbox.InsertImageStringItem(sys.maxint, colVal, -1)
- self.dropdownlistbox.SetStringItem(index, 0, colVal)
- self.dropdownlistbox.SetItemData(index, num)
- self._setListSize()
-
- # there is only one choice for both search and fetch if setting a single column:
- self._colSearch = 0
- self._colFetch = -1
-
- def OnClick(self, event):
- """Left mouse button pressed"""
- sel = self.dropdownlistbox.GetFirstSelected()
- if not self.dropdown.IsShown():
- if sel > -1:
- self.dropdownlistbox.Select(sel)
- else:
- self.dropdownlistbox.Select(0)
- self._listItemVisible()
- self._showDropDown()
- else:
- self.dropdown.Hide()
-
- def OnCommandSelect(self, event):
- """!Command selected from history"""
- self._historyItem = event.GetSelection() - len(self.GetItems())
- self.SetFocus()
-
- def OnListClick(self, evt):
- """!Left mouse button pressed"""
- toSel, flag = self.dropdownlistbox.HitTest( evt.GetPosition() )
- #no values on poition, return
- if toSel == -1: return
- self.dropdownlistbox.Select(toSel)
-
- def OnListDClick(self, evt):
- """!Mouse button double click"""
- self._setValueFromSelected()
-
- def OnListColClick(self, evt):
- """!Left mouse button pressed on column"""
- col = evt.GetColumn()
- # reverse the sort
- if col == self._colSearch:
- self._ascending = not self._ascending
- self.SortListItems( evt.GetColumn(), ascending=self._ascending )
- self._colSearch = evt.GetColumn()
- evt.Skip()
-
- def OnListItemSelected(self, event):
- """!Item selected"""
- self._setValueFromSelected()
- event.Skip()
-
- def OnEnteredText(self, event):
- """!Text entered"""
- text = event.GetString()
-
- if not text:
- # control is empty; hide dropdown if shown:
- if self.dropdown.IsShown():
- self._showDropDown(False)
- event.Skip()
- return
-
- try:
- cmd = shlex.split(str(text))
- except ValueError, e:
- self.statusbar.SetStatusText(str(e))
- cmd = text.split(' ')
- pattern = str(text)
-
- if len(cmd) > 0 and cmd[0] in self._choicesCmd and not self._module:
- self._setModule(cmd[0])
- elif len(cmd) > 1 and cmd[0] in self._choicesCmd:
- if self._module:
- if len(cmd[-1].split('=', 1)) == 1:
- # new option
- if cmd[-1][0] == '-':
- # -> flags
- self.SetChoices(self._choicesMap['flag'], type = 'flag')
- pattern = cmd[-1].lstrip('-')
- else:
- # -> options
- self.SetChoices(self._choicesMap['param'], type = 'param')
- pattern = cmd[-1]
- else:
- # value
- pattern = cmd[-1].split('=', 1)[1]
- else:
- # search for GRASS modules
- if self._module:
- # -> switch back to GRASS modules list
- self.SetChoices(self._choicesCmd)
- self._module = None
- self._choiceType = None
-
- self._choiceType
- self._choicesMap
- found = False
- choices = self._choices
- for numCh, choice in enumerate(choices):
- if choice.lower().startswith(pattern):
- found = True
- if found:
- self._showDropDown(True)
- item = self.dropdownlistbox.GetItem(numCh)
- toSel = item.GetId()
- self.dropdownlistbox.Select(toSel)
- break
-
- if not found:
- self.dropdownlistbox.Select(self.dropdownlistbox.GetFirstSelected(), False)
- if self._hideOnNoMatch:
- self._showDropDown(False)
- if self._module and '=' not in cmd[-1]:
- message = ''
- if cmd[-1][0] == '-': # flag
- message = _("Warning: flag <%s> not found in '%s'") % \
- (cmd[-1][1:], self._module.name)
- else: # option
- message = _("Warning: option <%s> not found in '%s'") % \
- (cmd[-1], self._module.name)
- self.statusbar.SetStatusText(message)
-
- if self._module and len(cmd[-1]) == 2 and cmd[-1][-2] == '=':
- optType = self._module.get_param(cmd[-1][:-2])['prompt']
- if optType in ('raster', 'vector'):
- # -> raster/vector map
- self.SetChoices(self._choicesMap[optType], optType)
-
- self._listItemVisible()
-
- event.Skip()
-
- def OnKeyDown (self, event):
- """!Do some work when the user press on the keys: up and down:
- move the cursor left and right: move the search
- """
- skip = True
- sel = self.dropdownlistbox.GetFirstSelected()
- visible = self.dropdown.IsShown()
- KC = event.GetKeyCode()
-
- if KC == wx.WXK_RIGHT:
- # right -> show choices
- if sel < (self.dropdownlistbox.GetItemCount() - 1):
- self.dropdownlistbox.Select(sel + 1)
- self._listItemVisible()
- self._showDropDown()
- skip = False
- elif KC == wx.WXK_UP:
- if visible:
- if sel > 0:
- self.dropdownlistbox.Select(sel - 1)
- self._listItemVisible()
- self._showDropDown()
- skip = False
- else:
- self._historyItem -= 1
- try:
- self.SetValue(self.GetItems()[self._historyItem])
- except IndexError:
- self._historyItem += 1
- elif KC == wx.WXK_DOWN:
- if visible:
- if sel < (self.dropdownlistbox.GetItemCount() - 1):
- self.dropdownlistbox.Select(sel + 1)
- self._listItemVisible()
- self._showDropDown()
- skip = False
- else:
- if self._historyItem < -1:
- self._historyItem += 1
- self.SetValue(self.GetItems()[self._historyItem])
-
- if visible:
- if event.GetKeyCode() == wx.WXK_RETURN:
- self._setValueFromSelected()
- skip = False
- if event.GetKeyCode() == wx.WXK_ESCAPE:
- self._showDropDown(False)
- skip = False
- if skip:
- event.Skip()
-
- def OnControlChanged(self, event):
- """!Control changed"""
- if self.IsShown():
- self._showDropDown(False)
-
- event.Skip()
+ event.Skip()
\ No newline at end of file
Modified: grass/branches/develbranch_6/gui/wxpython/wxgui.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/wxgui.py 2009-12-19 18:33:28 UTC (rev 40067)
+++ grass/branches/develbranch_6/gui/wxpython/wxgui.py 2009-12-19 18:37:42 UTC (rev 40068)
@@ -132,7 +132,6 @@
self.notebook = self.__createNoteBook()
self.menubar, self.menudata = self.__createMenuBar()
self.statusbar = self.CreateStatusBar(number=1)
- self.cmdprompt, self.cmdinput = self.__createCommandPrompt()
self.toolbar = self.__createToolBar()
# bindings
@@ -146,16 +145,11 @@
self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
Left().CentrePane().BestSize((-1,-1)).Dockable(False).
CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
- self._auimgr.AddPane(self.cmdprompt, wx.aui.AuiPaneInfo().
- Bottom().BestSize((-1, -1)).Dockable(False).
- CloseButton(False).DestroyOnClose(True).
- PaneBorder(False).Row(1).Layer(0).Position(0).
- CaptionVisible(False))
self._auimgr.Update()
wx.CallAfter(self.notebook.SetSelection, 0)
- wx.CallAfter(self.cmdinput.SetFocus)
+ wx.CallAfter(self.goutput.cmd_prompt.SetFocus)
# use default window layout ?
if UserSettings.Get(group='general', key='defWindowPos', subkey='enabled') is True:
@@ -192,13 +186,7 @@
# start with layer manager on top
self.curr_page.maptree.mapdisplay.Raise()
self.Raise()
-
- def __createCommandPrompt(self):
- """!Creates command-line input area"""
- p = prompt.GPrompt(self)
-
- return p.GetPanel(), p.GetInput()
-
+
def __createMenuBar(self):
"""!Creates menubar"""
@@ -367,7 +355,7 @@
page = event.GetSelection()
if page == self.goutput.pageid:
# remove '(...)'
- self.notebook.SetPageText(page, _("Command output"))
+ self.notebook.SetPageText(page, _("Command console"))
event.Skip()
@@ -454,7 +442,7 @@
if event:
cmd = self.GetMenuCmd(event)
self.goutput.RunCmd(cmd, switchPage=True)
-
+
def OnMenuCmd(self, event, cmd = ''):
"""!Parse command selected from menu"""
if event:
@@ -1544,7 +1532,7 @@
"""!Quit GRASS session (wxGUI and shell)"""
# quit wxGUI session
self.OnCloseWindow(event)
-
+
# quit GRASS shell
try:
pid = int(os.environ['GIS_LOCK'])
More information about the grass-commit
mailing list