"""
@package core.menutree
@brief Creates tree structure for wxGUI menus (former menudata.py)
Classes:
- menutree::MenuTreeModelBuilder
Usage:
@code
python menutree.py [action] [menu]
@endcode
where action:
- strings (default, used for translations)
- tree (simple tree structure)
- commands (command names and their place in tree)
- dump (tree structure with stored data)
and menu:
- manager (Main menu in Layer Manager)
- module_tree (Module tree in Layer Manager)
- modeler (Graphical Modeler)
- psmap (Cartographic Composer)
(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
@author Glynn Clements (menudata.py)
@author Martin Landa (menudata.py)
@author Anna Petrasova
"""
import os
import sys
import copy
try:
import xml.etree.ElementTree as etree
except ImportError:
import elementtree.ElementTree as etree # Python <= 2.4
import wx
from core.treemodel import TreeModel, ModuleNode
from core.settings import UserSettings
from core.toolboxes import expandAddons as expAddons
from core.utils import _
if not os.getenv("GISBASE"):
sys.exit("GRASS is not running. Exiting...")
# TODO: change the system to remove strange derived classes
class MenuTreeModelBuilder:
"""Abstract menu data class"""
def __init__(self, filename, expandAddons=True):
self.menustyle = UserSettings.Get(group = 'appearance',
key = 'menustyle',
subkey = 'selection')
xmlTree = etree.parse(filename)
if expandAddons:
expAddons(xmlTree)
self.model = TreeModel(ModuleNode)
self._createModel(xmlTree)
def _createModel(self, xmlTree):
root = xmlTree.getroot()
menubar = root.findall('menubar')[0]
menus = menubar.findall('menu')
for m in menus:
self._createMenu(m, self.model.root)
def _createMenu(self, menu, node):
label = _(menu.find('label').text)
items = menu.find('items')
node = self.model.AppendNode(parent=node, label=label)
for item in items:
self._createItem(item, node)
def _createItem(self, item, node):
if item.tag == 'separator':
data = dict(label='', description='', handler='',
command='', keywords='', shortcut='', wxId='', icon='')
self.model.AppendNode(parent=node, label='', data=data)
elif item.tag == 'menuitem':
origLabel = _(item.find('label').text)
handler = item.find('handler').text
desc = item.find('help') # optional
gcmd = item.find('command') # optional
keywords = item.find('keywords') # optional
shortcut = item.find('shortcut') # optional
wxId = item.find('id') # optional
icon = item.find('icon') # optional
if gcmd != None:
gcmd = gcmd.text
else:
gcmd = ""
if desc.text:
desc = _(desc.text)
else:
desc = ""
if keywords is None or keywords.text is None:
keywords = ""
else:
keywords = keywords.text
if shortcut != None:
shortcut = shortcut.text
else:
shortcut = ""
if wxId != None:
wxId = eval('wx.' + wxId.text)
else:
wxId = wx.ID_ANY
if icon != None:
icon = icon.text
else:
icon = ''
label = origLabel
if gcmd:
if self.menustyle == 1:
label += ' [' + gcmd + ']'
elif self.menustyle == 2:
label = ' [' + gcmd + ']'
data = dict(label=origLabel, description=desc, handler=handler,
command=gcmd, keywords=keywords, shortcut=shortcut, wxId=wxId, icon=icon)
self.model.AppendNode(parent=node, label=label, data=data)
elif item.tag == 'menu':
self._createMenu(item, node)
else:
raise ValueError(_("Unknow tag %s") % item.tag)
def GetModel(self, separators=False):
"""Returns copy of model with or without separators
(for menu or for search tree).
"""
if separators:
return copy.deepcopy(self.model)
else:
model = copy.deepcopy(self.model)
removeSeparators(model)
return model
def PrintTree(self, fh):
for child in self.model.root.children:
printTree(node=child, fh=fh)
def PrintStrings(self, fh):
"""Print menu strings to file (used for localization)
:param fh: file descriptor
"""
className = str(self.__class__).split('.', 1)[1]
fh.write('menustrings_%s = [\n' % className)
for child in self.model.root.children:
printStrings(child, fh)
fh.write(' \'\']\n')
def PrintCommands(self, fh):
printCommands(self.model.root, fh, itemSep=' | ', menuSep=' > ')
def removeSeparators(model, node=None):
if not node:
node = model.root
if node.label:
for child in reversed(node.children):
removeSeparators(model, child)
else:
model.RemoveNode(node)
def printTree(node, fh, indent=0):
if not node.label:
return
text = '%s- %s\n' % (' ' * indent, node.label.replace('&', ''))
fh.write(text)
for child in node.children:
printTree(node=child, fh=fh, indent=indent + 2)
def printStrings(node, fh):
# node.label - with module in brackets
# node.data['label'] - without module in brackets
if node.label and not node.data:
fh.write(' _(%r),\n' % str(node.label))
if node.data:
if 'label' in node.data and node.data['label']:
fh.write(' _(%r),\n' % str(node.data['label']))
if 'description' in node.data and node.data['description']:
fh.write(' _(%r),\n' % str(node.data['description']))
for child in node.children:
printStrings(node=child, fh=fh)
def printCommands(node, fh, itemSep, menuSep):
def collectParents(node, parents):
parent = node.parent
if parent.parent:
parents.insert(0, node.parent)
collectParents(node.parent, parents)
data = node.data
if data and 'command' in data and data['command']:
fh.write('%s%s' % (data['command'], itemSep))
parents = [node]
collectParents(node, parents)
labels = [parent.label.replace('&', '') for parent in parents]
fh.write(menuSep.join(labels))
fh.write('\n')
for child in node.children:
printCommands(child, fh, itemSep, menuSep)
if __name__ == "__main__":
action = 'strings'
menu = 'manager'
for arg in sys.argv:
if arg in ('strings', 'tree', 'commands', 'dump'):
action = arg
elif arg in ('manager', 'module_tree', 'modeler', 'psmap'):
menu = arg
# FIXME: cross-dependencies
if menu == 'manager':
from lmgr.menudata import LayerManagerMenuData
from core.globalvar import WXGUIDIR
filename = os.path.join(WXGUIDIR, 'xml', 'menudata.xml')
menudata = LayerManagerMenuData(filename)
# FIXME: since module descriptions are used again we have now the third copy of the same string (one is in modules)
elif menu == 'module_tree':
from lmgr.menudata import LayerManagerModuleTree
from core.globalvar import WXGUIDIR
filename = os.path.join(WXGUIDIR, 'xml', 'module_tree_menudata.xml')
menudata = LayerManagerModuleTree(filename)
elif menu == 'modeler':
from gmodeler.menudata import ModelerMenuData
menudata = ModelerMenuData()
elif menu == 'psmap':
from psmap.menudata import PsMapMenuData
menudata = PsMapMenuData()
else:
import grass.script.core as gscore
gscore.fatal("Unknown value for parameter menu: " % menu)
if action == 'strings':
menudata.PrintStrings(sys.stdout)
elif action == 'tree':
menudata.PrintTree(sys.stdout)
elif action == 'commands':
menudata.PrintCommands(sys.stdout)
elif action == 'dump':
print menudata.model
else:
import grass.script.core as gscore
gscore.fatal("Unknown value for parameter action: " % action)
sys.exit(0)