menutree.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. """
  2. @package core.menutree
  3. @brief Creates tree structure for wxGUI menus (former menudata.py)
  4. Classes:
  5. - menutree::MenuTreeModelBuilder
  6. Usage:
  7. @code
  8. python menutree.py [action] [menu]
  9. @endcode
  10. where <i>action</i>:
  11. - strings (default, used for translations)
  12. - tree (simple tree structure)
  13. - commands (command names and their place in tree)
  14. - dump (tree structure with stored data)
  15. and <i>menu</i>:
  16. - manager (Main menu in Layer Manager)
  17. - module_tree (Module tree in Layer Manager)
  18. - modeler (Graphical Modeler)
  19. - psmap (Cartographic Composer)
  20. (C) 2013 by the GRASS Development Team
  21. This program is free software under the GNU General Public License
  22. (>=v2). Read the file COPYING that comes with GRASS for details.
  23. @author Glynn Clements (menudata.py)
  24. @author Martin Landa <landa.martin gmail.com> (menudata.py)
  25. @author Anna Petrasova <kratochanna gmail.com>
  26. """
  27. import os
  28. import sys
  29. import copy
  30. try:
  31. import xml.etree.ElementTree as etree
  32. except ImportError:
  33. import elementtree.ElementTree as etree # Python <= 2.4
  34. import wx
  35. from core.treemodel import TreeModel, ModuleNode
  36. from core.settings import UserSettings
  37. from core.toolboxes import expandAddons as expAddons
  38. from core.utils import _
  39. if not os.getenv("GISBASE"):
  40. sys.exit("GRASS is not running. Exiting...")
  41. # TODO: change the system to remove strange derived classes
  42. class MenuTreeModelBuilder:
  43. """Abstract menu data class"""
  44. def __init__(self, filename, expandAddons=True):
  45. self.menustyle = UserSettings.Get(group='appearance',
  46. key='menustyle',
  47. subkey='selection')
  48. xmlTree = etree.parse(filename)
  49. if expandAddons:
  50. expAddons(xmlTree)
  51. self.model = TreeModel(ModuleNode)
  52. self._createModel(xmlTree)
  53. def _createModel(self, xmlTree):
  54. root = xmlTree.getroot()
  55. menubar = root.findall('menubar')[0]
  56. menus = menubar.findall('menu')
  57. for m in menus:
  58. self._createMenu(m, self.model.root)
  59. def _createMenu(self, menu, node):
  60. label = _(menu.find('label').text)
  61. items = menu.find('items')
  62. node = self.model.AppendNode(parent=node, label=label)
  63. for item in items:
  64. self._createItem(item, node)
  65. def _createItem(self, item, node):
  66. if item.tag == 'separator':
  67. data = dict(label='', description='', handler='',
  68. command='', keywords='', shortcut='', wxId='', icon='')
  69. self.model.AppendNode(parent=node, label='', data=data)
  70. elif item.tag == 'menuitem':
  71. origLabel = _(item.find('label').text)
  72. handler = item.find('handler').text
  73. desc = item.find('help') # optional
  74. gcmd = item.find('command') # optional
  75. keywords = item.find('keywords') # optional
  76. shortcut = item.find('shortcut') # optional
  77. wxId = item.find('id') # optional
  78. icon = item.find('icon') # optional
  79. if gcmd is not None:
  80. gcmd = gcmd.text
  81. else:
  82. gcmd = ""
  83. if desc.text:
  84. desc = _(desc.text)
  85. else:
  86. desc = ""
  87. if keywords is None or keywords.text is None:
  88. keywords = ""
  89. else:
  90. keywords = keywords.text
  91. if shortcut is not None:
  92. shortcut = shortcut.text
  93. else:
  94. shortcut = ""
  95. if wxId is not None:
  96. wxId = eval('wx.' + wxId.text)
  97. else:
  98. wxId = wx.ID_ANY
  99. if icon is not None:
  100. icon = icon.text
  101. else:
  102. icon = ''
  103. label = origLabel
  104. if gcmd:
  105. if self.menustyle == 1:
  106. label += ' [' + gcmd + ']'
  107. elif self.menustyle == 2:
  108. label = ' [' + gcmd + ']'
  109. data = dict(
  110. label=origLabel,
  111. description=desc,
  112. handler=handler,
  113. command=gcmd,
  114. keywords=keywords,
  115. shortcut=shortcut,
  116. wxId=wxId,
  117. icon=icon)
  118. self.model.AppendNode(parent=node, label=label, data=data)
  119. elif item.tag == 'menu':
  120. self._createMenu(item, node)
  121. else:
  122. raise ValueError(_("Unknow tag %s") % item.tag)
  123. def GetModel(self, separators=False):
  124. """Returns copy of model with or without separators
  125. (for menu or for search tree).
  126. """
  127. if separators:
  128. return copy.deepcopy(self.model)
  129. else:
  130. model = copy.deepcopy(self.model)
  131. removeSeparators(model)
  132. return model
  133. def PrintTree(self, fh):
  134. for child in self.model.root.children:
  135. printTree(node=child, fh=fh)
  136. def PrintStrings(self, fh):
  137. """Print menu strings to file (used for localization)
  138. :param fh: file descriptor
  139. """
  140. className = str(self.__class__).split('.', 1)[1]
  141. fh.write('menustrings_%s = [\n' % className)
  142. for child in self.model.root.children:
  143. printStrings(child, fh)
  144. fh.write(' \'\']\n')
  145. def PrintCommands(self, fh):
  146. printCommands(self.model.root, fh, itemSep=' | ', menuSep=' > ')
  147. def removeSeparators(model, node=None):
  148. if not node:
  149. node = model.root
  150. if node.label:
  151. for child in reversed(node.children):
  152. removeSeparators(model, child)
  153. else:
  154. model.RemoveNode(node)
  155. def printTree(node, fh, indent=0):
  156. if not node.label:
  157. return
  158. text = '%s- %s\n' % (' ' * indent, node.label.replace('&', ''))
  159. fh.write(text)
  160. for child in node.children:
  161. printTree(node=child, fh=fh, indent=indent + 2)
  162. def printStrings(node, fh):
  163. # node.label - with module in brackets
  164. # node.data['label'] - without module in brackets
  165. if node.label and not node.data:
  166. fh.write(' _(%r),\n' % str(node.label))
  167. if node.data:
  168. if 'label' in node.data and node.data['label']:
  169. fh.write(' _(%r),\n' % str(node.data['label']))
  170. if 'description' in node.data and node.data['description']:
  171. fh.write(' _(%r),\n' % str(node.data['description']))
  172. for child in node.children:
  173. printStrings(node=child, fh=fh)
  174. def printCommands(node, fh, itemSep, menuSep):
  175. def collectParents(node, parents):
  176. parent = node.parent
  177. if parent.parent:
  178. parents.insert(0, node.parent)
  179. collectParents(node.parent, parents)
  180. data = node.data
  181. if data and 'command' in data and data['command']:
  182. fh.write('%s%s' % (data['command'], itemSep))
  183. parents = [node]
  184. collectParents(node, parents)
  185. labels = [parent.label.replace('&', '') for parent in parents]
  186. fh.write(menuSep.join(labels))
  187. fh.write('\n')
  188. for child in node.children:
  189. printCommands(child, fh, itemSep, menuSep)
  190. if __name__ == "__main__":
  191. action = 'strings'
  192. menu = 'manager'
  193. for arg in sys.argv:
  194. if arg in ('strings', 'tree', 'commands', 'dump'):
  195. action = arg
  196. elif arg in ('manager', 'module_tree', 'modeler', 'psmap'):
  197. menu = arg
  198. # FIXME: cross-dependencies
  199. if menu == 'manager':
  200. from lmgr.menudata import LayerManagerMenuData
  201. from core.globalvar import WXGUIDIR
  202. filename = os.path.join(WXGUIDIR, 'xml', 'menudata.xml')
  203. menudata = LayerManagerMenuData(filename)
  204. # FIXME: since module descriptions are used again we have now the third
  205. # copy of the same string (one is in modules)
  206. elif menu == 'module_tree':
  207. from lmgr.menudata import LayerManagerModuleTree
  208. from core.globalvar import WXGUIDIR
  209. filename = os.path.join(WXGUIDIR, 'xml', 'module_tree_menudata.xml')
  210. menudata = LayerManagerModuleTree(filename)
  211. elif menu == 'modeler':
  212. from gmodeler.menudata import ModelerMenuData
  213. menudata = ModelerMenuData()
  214. elif menu == 'psmap':
  215. from psmap.menudata import PsMapMenuData
  216. menudata = PsMapMenuData()
  217. else:
  218. import grass.script.core as gscore
  219. gscore.fatal("Unknown value for parameter menu: " % menu)
  220. if action == 'strings':
  221. menudata.PrintStrings(sys.stdout)
  222. elif action == 'tree':
  223. menudata.PrintTree(sys.stdout)
  224. elif action == 'commands':
  225. menudata.PrintCommands(sys.stdout)
  226. elif action == 'dump':
  227. print menudata.model
  228. else:
  229. import grass.script.core as gscore
  230. gscore.fatal("Unknown value for parameter action: " % action)
  231. sys.exit(0)