menu.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. """!
  2. @package gui_core.menu
  3. @brief Menu classes for wxGUI
  4. Classes:
  5. - menu::Menu
  6. - menu::SearchModuleWindow
  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.modulesdata import ModulesData
  21. from core.gcmd import EncodeString
  22. from core.settings import UserSettings
  23. from gui_core.widgets import ItemTree, SearchModuleWidget
  24. from lmgr.menudata import LayerManagerMenuData
  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 SearchModuleWindow(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 = SearchModuleWidget(parent = self,
  113. modulesData = 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)