"""
@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
"""
from __future__ import print_function
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.toolboxes import getMessages as getToolboxMessages
from core.toolboxes import clearMessages as clearToolboxMessages
from core.gcmd import GError
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"""
# TODO: message_handler=GError is just for backwards compatibility
# message_handler=GError should be replaced by None
def __init__(self, filename, expandAddons=True, message_handler=GError):
self.menustyle = UserSettings.Get(
group="appearance", key="menustyle", subkey="selection"
)
xmlTree = etree.parse(filename)
if expandAddons:
expAddons(xmlTree)
for message in getToolboxMessages():
message_handler(message)
clearToolboxMessages()
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 is not 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 is not None:
shortcut = shortcut.text
else:
shortcut = ""
if wxId is not None:
wxId = eval("wx." + wxId.text)
else:
wxId = wx.ID_ANY
if icon is not 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 = self.__class__.__name__
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 or node is model.root:
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)