menu.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. """!
  2. @package gui_core.menu
  3. @brief Menu classes for wxGUI
  4. Classes:
  5. - menu::Menu
  6. - menu::MenuTreeWindow
  7. - menu::MenuTree
  8. (C) 2010-2012 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. @author Martin Landa <landa.martin gmail.com>
  12. @author Pawel Netzel (menu customization)
  13. @author Milena Nowotarska (menu customization)
  14. @author Robert Szczepanek (menu customization)
  15. @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
  16. """
  17. import wx
  18. from core import globalvar
  19. from core import utils
  20. from core.gcmd import EncodeString
  21. from core.settings import UserSettings
  22. from gui_core.widgets import ItemTree
  23. from lmgr.menudata import LayerManagerMenuData
  24. from gui_core.ghelp import SearchModuleWindow
  25. class Menu(wx.MenuBar):
  26. def __init__(self, parent, data):
  27. """!Creates menubar"""
  28. wx.MenuBar.__init__(self)
  29. self.parent = parent
  30. self.menudata = data
  31. self.menucmd = dict()
  32. self.menustyle = UserSettings.Get(group = 'appearance', key = 'menustyle', subkey = 'selection')
  33. for eachMenuData in self.menudata.GetMenu():
  34. for eachHeading in eachMenuData:
  35. menuLabel = eachHeading[0]
  36. menuItems = eachHeading[1]
  37. self.Append(self._createMenu(menuItems), menuLabel)
  38. def _createMenu(self, menuData):
  39. """!Creates menu"""
  40. menu = wx.Menu()
  41. for eachItem in menuData:
  42. if len(eachItem) == 2:
  43. label = eachItem[0]
  44. subMenu = self._createMenu(eachItem[1])
  45. menu.AppendMenu(wx.ID_ANY, label, subMenu)
  46. else:
  47. self._createMenuItem(menu, self.menustyle, *eachItem)
  48. self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
  49. return menu
  50. def _createMenuItem(self, menu, menustyle, label, help, handler, gcmd, keywords,
  51. shortcut = '', wxId = wx.ID_ANY, kind = wx.ITEM_NORMAL):
  52. """!Creates menu items
  53. There are three menu styles (menu item text styles).
  54. 1 -- label only, 2 -- label and cmd name, 3 -- cmd name only
  55. """
  56. if not label:
  57. menu.AppendSeparator()
  58. return
  59. if gcmd:
  60. helpString = gcmd + ' -- ' + help
  61. if menustyle == 1:
  62. label += ' [' + gcmd + ']'
  63. elif menustyle == 2:
  64. label = ' [' + gcmd + ']'
  65. else:
  66. helpString = help
  67. if shortcut:
  68. label += '\t' + shortcut
  69. menuItem = menu.Append(wxId, label, helpString, kind)
  70. self.menucmd[menuItem.GetId()] = gcmd
  71. if gcmd:
  72. try:
  73. cmd = utils.split(str(gcmd))
  74. except UnicodeError:
  75. cmd = utils.split(EncodeString((gcmd)))
  76. if cmd and cmd[0] not in globalvar.grassCmd:
  77. menuItem.Enable(False)
  78. rhandler = eval('self.parent.' + handler)
  79. self.parent.Bind(wx.EVT_MENU, rhandler, menuItem)
  80. def GetData(self):
  81. """!Get menu data"""
  82. return self.menudata
  83. def GetCmd(self):
  84. """!Get list of commands
  85. @return list of commands
  86. """
  87. return self.menucmd
  88. def OnMenuHighlight(self, event):
  89. """
  90. Default menu help handler
  91. """
  92. # Show how to get menu item info from this event handler
  93. id = event.GetMenuId()
  94. item = self.FindItemById(id)
  95. if item:
  96. text = item.GetText()
  97. help = item.GetHelp()
  98. # but in this case just call Skip so the default is done
  99. event.Skip()
  100. class MenuTreeWindow(wx.Panel):
  101. """!Show menu tree"""
  102. def __init__(self, parent, id = wx.ID_ANY, **kwargs):
  103. self.parent = parent # LayerManager
  104. wx.Panel.__init__(self, parent = parent, id = id, **kwargs)
  105. self.dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
  106. label = " %s " % _("Menu tree (double-click or Ctrl-Enter to run command)"))
  107. # tree
  108. menuData = LayerManagerMenuData()
  109. self.tree = MenuTree(parent = self, data = menuData)
  110. self.tree.Load()
  111. # search widget
  112. self.search = SearchModuleWindow(parent = self,
  113. modulesData = menuData.GetModules(),
  114. showChoice = False)
  115. # buttons
  116. self.btnRun = wx.Button(self, id = wx.ID_OK, label = _("&Run"))
  117. self.btnRun.SetToolTipString(_("Run selected command from the menu tree"))
  118. self.btnRun.Enable(False)
  119. # bindings
  120. self.btnRun.Bind(wx.EVT_BUTTON, self.OnRun)
  121. self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
  122. self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
  123. self.search.GetCtrl().Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
  124. self.search.GetCtrl().Bind(wx.EVT_KEY_UP, self.OnKeyUp)
  125. self._layout()
  126. self.search.SetFocus()
  127. def _layout(self):
  128. """!Do dialog layout"""
  129. sizer = wx.BoxSizer(wx.VERTICAL)
  130. # body
  131. dataSizer = wx.StaticBoxSizer(self.dataBox, wx.HORIZONTAL)
  132. dataSizer.Add(item = self.tree, proportion =1,
  133. flag = wx.EXPAND)
  134. # buttons
  135. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  136. btnSizer.Add(item = self.btnRun, proportion = 0)
  137. sizer.Add(item = dataSizer, proportion = 1,
  138. flag = wx.EXPAND | wx.ALL, border = 5)
  139. sizer.Add(item = self.search, proportion = 0,
  140. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  141. sizer.Add(item = btnSizer, proportion = 0,
  142. flag = wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border = 5)
  143. sizer.Fit(self)
  144. sizer.SetSizeHints(self)
  145. self.SetSizer(sizer)
  146. self.Fit()
  147. self.SetAutoLayout(True)
  148. self.Layout()
  149. def OnCloseWindow(self, event):
  150. """!Close window"""
  151. self.Destroy()
  152. def OnRun(self, event):
  153. """!Run selected command"""
  154. if not self.tree.GetSelected():
  155. return # should not happen
  156. data = self.tree.GetPyData(self.tree.GetSelected())
  157. if not data:
  158. return
  159. handler = 'self.parent.' + data['handler'].lstrip('self.')
  160. if data['handler'] == 'self.OnXTerm':
  161. wx.MessageBox(parent = self,
  162. message = _('You must run this command from the menu or command line',
  163. 'This command require an XTerm'),
  164. caption = _('Message'), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
  165. elif data['command']:
  166. eval(handler)(event = None, cmd = data['command'].split())
  167. else:
  168. eval(handler)(None)
  169. def OnKeyUp(self, event):
  170. if event.GetKeyCode() == wx.WXK_RETURN:
  171. if event.ControlDown():
  172. self.OnRun(event)
  173. else:
  174. self.OnShowItem(event)
  175. def OnShowItem(self, event):
  176. """!Show selected item"""
  177. self.tree.OnShowItem(event)
  178. if self.tree.GetSelected():
  179. self.btnRun.Enable()
  180. else:
  181. self.btnRun.Enable(False)
  182. def OnItemActivated(self, event):
  183. """!Item activated (double-click)"""
  184. item = event.GetItem()
  185. if not item or not item.IsOk():
  186. return
  187. data = self.tree.GetPyData(item)
  188. if not data or 'command' not in data:
  189. return
  190. self.tree.itemSelected = item
  191. self.OnRun(None)
  192. def OnItemSelected(self, event):
  193. """!Item selected"""
  194. item = event.GetItem()
  195. if not item or not item.IsOk():
  196. return
  197. data = self.tree.GetPyData(item)
  198. if not data or 'command' not in data:
  199. return
  200. if data['command']:
  201. label = data['command'] + ' -- ' + data['description']
  202. else:
  203. label = data['description']
  204. self.parent.SetStatusText(label, 0)
  205. def OnUpdateStatusBar(self, event):
  206. """!Update statusbar text"""
  207. element = self.search.GetSelection()
  208. value = event.GetEventObject().GetValue()
  209. self.tree.SearchItems(element = element, value = value)
  210. nItems = len(self.tree.itemsMarked)
  211. if value:
  212. self.parent.SetStatusText(_("%d modules match") % nItems, 0)
  213. else:
  214. self.parent.SetStatusText("", 0)
  215. event.Skip()
  216. class MenuTree(ItemTree):
  217. """!Menu tree class"""
  218. def __init__(self, parent, data, **kwargs):
  219. self.parent = parent
  220. self.menudata = data
  221. super(MenuTree, self).__init__(parent, **kwargs)
  222. self.menustyle = UserSettings.Get(group = 'appearance', key = 'menustyle', subkey = 'selection')
  223. def Load(self, data = None):
  224. """!Load menu data tree
  225. @param data menu data (None to use self.menudata)
  226. """
  227. if not data:
  228. data = self.menudata
  229. self.itemsMarked = [] # list of marked items
  230. for eachMenuData in data.GetMenu():
  231. for label, items in eachMenuData:
  232. item = self.AppendItem(parentId = self.root,
  233. text = label.replace('&', ''))
  234. self.__AppendItems(item, items)
  235. def __AppendItems(self, item, data):
  236. """!Append items into tree (used by Load()
  237. @param item tree item (parent)
  238. @parent data menu data"""
  239. for eachItem in data:
  240. if len(eachItem) == 2:
  241. if eachItem[0]:
  242. itemSub = self.AppendItem(parentId = item,
  243. text = eachItem[0])
  244. self.__AppendItems(itemSub, eachItem[1])
  245. else:
  246. if eachItem[0]:
  247. label = eachItem[0]
  248. if eachItem[3]:
  249. if self.menustyle == 1:
  250. label += ' [' + eachItem[3] + ']'
  251. elif self.menustyle == 2:
  252. label = '[' + eachItem[3] + ']'
  253. itemNew = self.AppendItem(parentId = item,
  254. text = label)
  255. data = { 'item' : eachItem[0],
  256. 'description' : eachItem[1],
  257. 'handler' : eachItem[2],
  258. 'command' : eachItem[3],
  259. 'keywords' : eachItem[4] }
  260. self.SetPyData(itemNew, data)