""" @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)