# -*- coding: utf-8 -*- # Mozo Menu Editor - Simple fd.o Compliant Menu Editor # Copyright (C) 2006 Travis Watkins, Heinrich Wendel # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import codecs import os import re import xml.dom.minidom import xml.parsers.expat import locale import matemenu from gi.repository import GLib from Mozo import util class Menu: tree = None visible_tree = None path = None dom = None class MenuEditor: def __init__(self): self.locale = locale.getdefaultlocale()[0] self.__loadMenus() self.__undo = [] self.__redo = [] def __loadMenus(self): self.applications = Menu() self.applications.tree = matemenu.lookup_tree('mate-applications.menu', matemenu.FLAGS_SHOW_EMPTY|matemenu.FLAGS_INCLUDE_EXCLUDED|matemenu.FLAGS_INCLUDE_NODISPLAY|matemenu.FLAGS_SHOW_ALL_SEPARATORS) self.applications.visible_tree = matemenu.lookup_tree('mate-applications.menu') self.applications.tree.sort_key = matemenu.SORT_DISPLAY_NAME self.applications.visible_tree.sort_key = matemenu.SORT_DISPLAY_NAME self.applications.path = os.path.join(util.getUserMenuPath(), self.applications.tree.get_menu_file()) try: self.applications.dom = xml.dom.minidom.parse(self.applications.path) except (IOError, xml.parsers.expat.ExpatError): self.applications.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.applications.tree)) util.removeWhitespaceNodes(self.applications.dom) self.settings = Menu() self.settings.tree = matemenu.lookup_tree('mate-settings.menu', matemenu.FLAGS_SHOW_EMPTY|matemenu.FLAGS_INCLUDE_EXCLUDED|matemenu.FLAGS_INCLUDE_NODISPLAY|matemenu.FLAGS_SHOW_ALL_SEPARATORS) self.settings.visible_tree = matemenu.lookup_tree('mate-settings.menu') self.settings.tree.sort_key = matemenu.SORT_DISPLAY_NAME self.settings.visible_tree.sort_key = matemenu.SORT_DISPLAY_NAME self.settings.path = os.path.join(util.getUserMenuPath(), self.settings.tree.get_menu_file()) try: self.settings.dom = xml.dom.minidom.parse(self.settings.path) except (IOError, xml.parsers.expat.ExpatError): self.settings.dom = xml.dom.minidom.parseString(util.getUserMenuXml(self.settings.tree)) util.removeWhitespaceNodes(self.settings.dom) self.save(True) def save(self, from_loading=False): for menu in ('applications', 'settings'): with codecs.open(getattr(self, menu).path, 'w', 'utf-8') as f: f.write(getattr(self, menu).dom.toprettyxml()) if not from_loading: self.__loadMenus() def quit(self): for file_name in os.listdir(util.getUserItemPath()): if file_name[-6:-2] in ('redo', 'undo'): file_path = os.path.join(util.getUserItemPath(), file_name) os.unlink(file_path) for file_name in os.listdir(util.getUserDirectoryPath()): if file_name[-6:-2] in ('redo', 'undo'): file_path = os.path.join(util.getUserDirectoryPath(), file_name) os.unlink(file_path) for file_name in os.listdir(util.getUserMenuPath()): if file_name[-6:-2] in ('redo', 'undo'): file_path = os.path.join(util.getUserMenuPath(), file_name) os.unlink(file_path) def revert(self): for name in ('applications', 'settings'): menu = getattr(self, name) self.revertTree(menu.tree.root) path = os.path.join(util.getUserMenuPath(), menu.tree.get_menu_file()) try: os.unlink(path) except OSError: pass #reload DOM for each menu try: menu.dom = xml.dom.minidom.parse(menu.path) except (IOError, xml.parsers.expat.ExpatError): menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree)) util.removeWhitespaceNodes(menu.dom) #reset undo/redo, no way to recover from this self.__undo, self.__redo = [], [] self.save() def revertTree(self, menu): for child in menu.get_contents(): if child.get_type() == matemenu.TYPE_DIRECTORY: self.revertTree(child) elif child.get_type() == matemenu.TYPE_ENTRY: self.revertItem(child) self.revertMenu(menu) def revertItem(self, item): if not self.canRevert(item): return self.__addUndo([item,]) try: os.remove(item.get_desktop_file_path()) except OSError: pass self.save() def revertMenu(self, menu): if not self.canRevert(menu): return #wtf happened here? oh well, just bail if not menu.get_desktop_file_path(): return self.__addUndo([menu,]) file_id = os.path.split(menu.get_desktop_file_path())[1] path = os.path.join(util.getUserDirectoryPath(), file_id) try: os.remove(path) except OSError: pass self.save() def undo(self): if len(self.__undo) == 0: return files = self.__undo.pop() redo = [] for file_path in files: new_path = file_path.rsplit('.', 1)[0] redo_path = util.getUniqueRedoFile(new_path) f_file_path = codecs.open(new_path, 'r', 'utf-8') f_new_path = codecs.open(new_path, 'rw', 'utf-8') f_redo_path = codecs.open(redo_path, 'rw', 'utf-8') data = f_new_path.read() f_redo_path.write(data) data = f_file_path.read() f_new_path.write(data) f_file_path.close() f_new_path.close() f_redo_path.close() os.unlink(file_path) redo.append(redo_path) # reload DOM to make changes stick for name in ('applications', 'settings'): menu = getattr(self, name) try: menu.dom = xml.dom.minidom.parse(menu.path) except (IOError, xml.parsers.expat.ExpatError): menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree)) util.removeWhitespaceNodes(menu.dom) self.__redo.append(redo) def redo(self): if len(self.__redo) == 0: return files = self.__redo.pop() undo = [] for file_path in files: new_path = file_path.rsplit('.', 1)[0] undo_path = util.getUniqueUndoFile(new_path) f_file_path = codecs.open(new_path, 'r', 'utf-8') f_new_path = codecs.open(new_path, 'rw', 'utf-8') f_undo_path = codecs.open(undo_path, 'rw', 'utf-8') data = f_new_path.read() f_undo_path.write(data) data = f_file_path.read() f_new_path.write(data) os.unlink(file_path) undo.append(undo_path) f_file_path.close() f_new_path.close() f_undo_path.close() #reload DOM to make changes stick for name in ('applications', 'settings'): menu = getattr(self, name) try: menu.dom = xml.dom.minidom.parse(menu.path) except (IOError, xml.parsers.expat.ExpatError): menu.dom = xml.dom.minidom.parseString(util.getUserMenuXml(menu.tree)) util.removeWhitespaceNodes(menu.dom) self.__undo.append(undo) def getMenus(self, parent=None): if parent is None: yield self.applications.tree.root yield self.settings.tree.root else: for menu in parent.get_contents(): if menu.get_type() == matemenu.TYPE_DIRECTORY: yield (menu, self.__isVisible(menu)) def getItems(self, menu): for item in menu.get_contents(): if item.get_type() == matemenu.TYPE_SEPARATOR: yield (item, True) else: if item.get_type() == matemenu.TYPE_ENTRY and item.get_desktop_file_id()[-19:] == '-usercustom.desktop': continue yield (item, self.__isVisible(item)) def canRevert(self, item): if item.get_type() == matemenu.TYPE_ENTRY: if util.getItemPath(item.get_desktop_file_id()) is not None: path = util.getUserItemPath() if os.path.isfile(os.path.join(path, item.get_desktop_file_id())): return True elif item.get_type() == matemenu.TYPE_DIRECTORY: if item.get_desktop_file_path(): file_id = os.path.split(item.get_desktop_file_path())[1] else: file_id = item.get_menu_id() + '.directory' if util.getDirectoryPath(file_id) is not None: path = util.getUserDirectoryPath() if os.path.isfile(os.path.join(path, file_id)): return True return False def setVisible(self, item, visible): dom = self.__getMenu(item).dom if item.get_type() == matemenu.TYPE_ENTRY: self.__addUndo([self.__getMenu(item), item]) menu_xml = self.__getXmlMenu(self.__getPath(item.get_parent()), dom.documentElement, dom) if visible: self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Include') self.__writeItem(item, NoDisplay=False) else: self.__addXmlFilename(menu_xml, dom, item.get_desktop_file_id(), 'Exclude') self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom) elif item.get_type() == matemenu.TYPE_DIRECTORY: self.__addUndo([self.__getMenu(item), item]) #don't mess with it if it's empty if len(item.get_contents()) == 0: return menu_xml = self.__getXmlMenu(self.__getPath(item), dom.documentElement, dom) for node in self.__getXmlNodesByName(['Deleted', 'NotDeleted'], menu_xml): node.parentNode.removeChild(node) self.__writeMenu(item, NoDisplay=not visible) self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom) self.save() def createItem(self, parent, before, after, **kwargs): file_id = self.__writeItem(None, **kwargs) self.insertExternalItem(file_id, parent.menu_id, before, after) def insertExternalItem(self, file_id, parent_id, before=None, after=None): parent = self.__findMenu(parent_id) dom = self.__getMenu(parent).dom self.__addItem(parent, file_id, dom) self.__positionItem(parent, ('Item', file_id), before, after) self.__addUndo([self.__getMenu(parent), ('Item', file_id)]) self.save() def insertExternalMenu(self, file_id, parent_id, before=None, after=None): menu_id = file_id.rsplit('.', 1)[0] parent = self.__findMenu(parent_id) dom = self.__getMenu(parent).dom self.__addXmlDefaultLayout(self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom) , dom) menu_xml = self.__getXmlMenu(self.__getPath(parent) + [menu_id], dom.documentElement, dom) self.__addXmlTextElement(menu_xml, 'Directory', file_id, dom) self.__positionItem(parent, ('Menu', menu_id), before, after) self.__addUndo([self.__getMenu(parent), ('Menu', file_id)]) self.save() def createSeparator(self, parent, before=None, after=None): self.__positionItem(parent, ('Separator',), before, after) self.__addUndo([self.__getMenu(parent), ('Separator',)]) self.save() def editItem(self, item, icon, name, comment, command, use_term, parent=None, final=True): #if nothing changed don't make a user copy if icon == item.get_icon() and name == item.get_display_name() and comment == item.get_comment() and command == item.get_exec() and use_term == item.get_launch_in_terminal(): return #hack, item.get_parent() seems to fail a lot if not parent: parent = item.get_parent() if final: self.__addUndo([self.__getMenu(parent), item]) self.__writeItem(item, Icon=icon, Name=name, Comment=comment, Exec=command, Terminal=use_term) if final: dom = self.__getMenu(parent).dom menu_xml = self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom) self.__addXmlTextElement(menu_xml, 'AppDir', util.getUserItemPath(), dom) self.save() def editMenu(self, menu, icon, name, comment, final=True): #if nothing changed don't make a user copy if icon == menu.get_icon() and name == menu.get_name() and comment == menu.get_comment(): return #we don't use this, we just need to make sure the exists #otherwise changes won't show up dom = self.__getMenu(menu).dom menu_xml = self.__getXmlMenu(self.__getPath(menu), dom.documentElement, dom) self.__writeMenu(menu, Icon=icon, Name=name, Comment=comment) if final: self.__addXmlTextElement(menu_xml, 'DirectoryDir', util.getUserDirectoryPath(), dom) self.__addUndo([self.__getMenu(menu), menu]) self.save() def copyItem(self, item, new_parent, before=None, after=None): dom = self.__getMenu(new_parent).dom file_path = item.get_desktop_file_path() keyfile = GLib.KeyFile() keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) util.fillKeyFile(keyfile, dict(Categories=[], Hidden=False)) file_id = util.getUniqueFileId(item.get_name().replace(os.sep, '-'), '.desktop') out_path = os.path.join(util.getUserItemPath(), file_id) contents, length = keyfile.to_data() with open(out_path, 'w') as f: f.write(contents) self.__addItem(new_parent, file_id, dom) self.__positionItem(new_parent, ('Item', file_id), before, after) self.__addUndo([self.__getMenu(new_parent), ('Item', file_id)]) self.save() return file_id def moveItem(self, item, new_parent, before=None, after=None): undo = [] if item.get_parent() != new_parent: #hide old item self.deleteItem(item) undo.append(item) file_id = self.copyItem(item, new_parent) item = ('Item', file_id) undo.append(item) self.__positionItem(new_parent, item, before, after) undo.append(self.__getMenu(new_parent)) self.__addUndo(undo) self.save() def moveMenu(self, menu, new_parent, before=None, after=None): parent = new_parent #don't move a menu into it's child while parent.get_parent(): parent = parent.get_parent() if parent == menu: return False #don't move a menu into itself if new_parent == menu: return False #can't move between top-level menus if self.__getMenu(menu) != self.__getMenu(new_parent): return False if menu.get_parent() != new_parent: dom = self.__getMenu(menu).dom path = self.__getPath(menu) root_path = path[0] xml_root = self.__getXmlMenu(root_path, dom.documentElement, dom) old_path = path[1:] new_path = self.__getPath(new_parent)[1:] + [menu.get_menu_id()] self.__addXmlMove(xml_root, '/'.join(old_path), '/'.join(new_path), dom) self.__positionItem(new_parent, menu, before, after) self.__addUndo([self.__getMenu(new_parent),]) self.save() def moveSeparator(self, separator, new_parent, before=None, after=None): undo = [] # remove the original separator if its parent is not the new destination if separator.get_parent() != new_parent: self.deleteSeparator(separator) undo.append(separator) # this adds the new separator to the specified position self.__positionItem(new_parent, separator, before, after) undo.append(self.__getMenu(new_parent)) self.__addUndo(undo) self.save() def deleteItem(self, item): self.__addUndo([item,]) self.__writeItem(item, Hidden=True) self.save() def deleteMenu(self, menu): dom = self.__getMenu(menu).dom menu_xml = self.__getXmlMenu(self.__getPath(menu), dom.documentElement, dom) self.__addDeleted(menu_xml, dom) self.__addUndo([self.__getMenu(menu),]) self.save() def deleteSeparator(self, item): parent = item.get_parent() contents = parent.get_contents() contents.remove(item) layout = self.__createLayout(contents) dom = self.__getMenu(parent).dom menu_xml = self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom) self.__addXmlLayout(menu_xml, layout, dom) self.__addUndo([self.__getMenu(item.get_parent()),]) self.save() #private stuff def __addUndo(self, items): self.__undo.append([]) for item in items: if isinstance(item, Menu): file_path = item.path elif isinstance(item, tuple): if item[0] == 'Item': file_path = os.path.join(util.getUserItemPath(), item[1]) if not os.path.isfile(file_path): file_path = util.getItemPath(item[1]) elif item[0] == 'Menu': file_path = os.path.join(util.getUserDirectoryPath(), item[1]) if not os.path.isfile(file_path): file_path = util.getDirectoryPath(item[1]) else: continue elif item.get_type() == matemenu.TYPE_DIRECTORY: if item.get_desktop_file_path() is None: continue file_path = os.path.join(util.getUserDirectoryPath(), os.path.split(item.get_desktop_file_path())[1]) if not os.path.isfile(file_path): file_path = item.get_desktop_file_path() elif item.get_type() == matemenu.TYPE_ENTRY: file_path = os.path.join(util.getUserItemPath(), item.get_desktop_file_id()) if not os.path.isfile(file_path): file_path = item.get_desktop_file_path() else: continue with codecs.open(file_path, 'r', 'utf-8') as f: data = f.read() undo_path = util.getUniqueUndoFile(file_path) with codecs.open(undo_path, 'w', 'utf-8') as f: f.write(data) self.__undo[-1].append(undo_path) def __getMenu(self, item): root = item.get_parent() if not root: #already at the top root = item else: while True: if root.get_parent(): root = root.get_parent() else: break if root.menu_id == self.applications.tree.root.menu_id: return self.applications return self.settings def __findMenu(self, menu_id, parent=None): if parent is None: menu = self.__findMenu(menu_id, self.applications.tree.root) if menu is not None: return menu else: return self.__findMenu(menu_id, self.settings.tree.root) if menu_id == self.applications.tree.root.menu_id: return self.applications.tree.root if menu_id == self.settings.tree.root.menu_id: return self.settings.tree.root for item in parent.get_contents(): if item.get_type() == matemenu.TYPE_DIRECTORY: if item.menu_id == menu_id: return item menu = self.__findMenu(menu_id, item) if menu is not None: return menu def __isVisible(self, item): if item.get_type() == matemenu.TYPE_ENTRY: return not (item.get_is_excluded() or item.get_is_nodisplay()) menu = self.__getMenu(item) if menu == self.applications: root = self.applications.visible_tree.root elif menu == self.settings: root = self.settings.visible_tree.root if item.get_type() == matemenu.TYPE_DIRECTORY: if self.__findMenu(item.menu_id, root) is None: return False return True def __getPath(self, menu): names = [] current = menu while current is not None: names.append(current.get_menu_id()) current = current.get_parent() # XXX - don't append root menu name, mozo doesn't # expect it. look into this more. names.pop(-1) return names[::-1] def __getXmlMenuPart(self, element, name): for node in self.__getXmlNodesByName('Menu', element): for child in self.__getXmlNodesByName('Name', node): if child.childNodes[0].nodeValue == name: return node return None def __getXmlMenu(self, path, element, dom): for name in path: found = self.__getXmlMenuPart(element, name) if found is not None: element = found else: element = self.__addXmlMenuElement(element, name, dom) return element def __addXmlMenuElement(self, element, name, dom): if isinstance(name, bytes): name = name.decode('utf-8') node = dom.createElement('Menu') self.__addXmlTextElement(node, 'Name', name, dom) return element.appendChild(node) def __addXmlTextElement(self, element, name, text, dom): if isinstance(name, bytes): name = name.decode('utf-8') if isinstance(text, bytes): text = text.decode('utf-8') for temp in element.childNodes: if temp.nodeName == name: if temp.childNodes[0].nodeValue == text: return node = dom.createElement(name) text = dom.createTextNode(text) node.appendChild(text) return element.appendChild(node) def __addXmlFilename(self, element, dom, filename, type = 'Include'): if isinstance(filename, bytes): filename = filename.decode('utf-8') # remove old filenames for node in self.__getXmlNodesByName(['Include', 'Exclude'], element): if node.childNodes[0].nodeName == 'Filename' and node.childNodes[0].childNodes[0].nodeValue == filename: element.removeChild(node) # add new filename node = dom.createElement(type) node.appendChild(self.__addXmlTextElement(node, 'Filename', filename, dom)) return element.appendChild(node) def __addDeleted(self, element, dom): node = dom.createElement('Deleted') return element.appendChild(node) def __makeKeyFile(self, file_path, kwargs): if 'KeyFile' in kwargs: return kwargs['KeyFile'] keyfile = GLib.KeyFile() if file_path is not None: keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) util.fillKeyFile(keyfile, kwargs) return keyfile def __writeItem(self, item, **kwargs): if item is not None: file_path = item.get_desktop_file_path() else: file_path = None keyfile = self.__makeKeyFile(file_path, kwargs) if item is not None: file_id = item.get_desktop_file_id() else: file_id = util.getUniqueFileId(keyfile.get_string(GLib.KEY_FILE_DESKTOP_GROUP, 'Name'), '.desktop') contents, length = keyfile.to_data() with open(os.path.join(util.getUserItemPath(), file_id), 'w') as f: f.write(contents) return file_id def __writeMenu(self, menu, **kwargs): if menu is not None: file_id = os.path.split(menu.get_desktop_file_path())[1] file_path = menu.get_desktop_file_path() keyfile = GLib.KeyFile() keyfile.load_from_file(file_path, util.KEY_FILE_FLAGS) elif menu is None and 'Name' not in kwargs: raise Exception('New menus need a name') else: file_id = util.getUniqueFileId(kwargs['Name'], '.directory') keyfile = GLib.KeyFile() util.fillKeyFile(keyfile, kwargs) contents, length = keyfile.to_data() with open(os.path.join(util.getUserDirectoryPath(), file_id), 'w') as f: f.write(contents) return file_id def __getXmlNodesByName(self, name, element): for child in element.childNodes: if child.nodeType == xml.dom.Node.ELEMENT_NODE: if isinstance(name, str) and child.nodeName == name: yield child elif isinstance(name, list) or isinstance(name, tuple): if child.nodeName in name: yield child def __addXmlMove(self, element, old, new, dom): if not self.__undoMoves(element, old, new, dom): node = dom.createElement('Move') node.appendChild(self.__addXmlTextElement(node, 'Old', old, dom)) node.appendChild(self.__addXmlTextElement(node, 'New', new, dom)) #are parsed in reverse order, need to put at the beginning return element.insertBefore(node, element.firstChild) def __addXmlLayout(self, element, layout, dom): # remove old layout for node in self.__getXmlNodesByName('Layout', element): element.removeChild(node) # add new layout node = dom.createElement('Layout') for order in layout.order: if order[0] == 'Separator': child = dom.createElement('Separator') node.appendChild(child) elif order[0] == 'Filename': child = self.__addXmlTextElement(node, 'Filename', order[1], dom) elif order[0] == 'Menuname': child = self.__addXmlTextElement(node, 'Menuname', order[1], dom) elif order[0] == 'Merge': child = dom.createElement('Merge') child.setAttribute('type', order[1]) node.appendChild(child) return element.appendChild(node) def __addXmlDefaultLayout(self, element, dom): # remove old default layout for node in self.__getXmlNodesByName('DefaultLayout', element): element.removeChild(node) # add new layout node = dom.createElement('DefaultLayout') node.setAttribute('inline', 'false') return element.appendChild(node) def __createLayout(self, items): layout = Layout() layout.order = [] layout.order.append(['Merge', 'menus']) for item in items: if isinstance(item, tuple): if item[0] == 'Separator': layout.parseSeparator() elif item[0] == 'Menu': layout.parseMenuname(item[1]) elif item[0] == 'Item': layout.parseFilename(item[1]) elif item.get_type() == matemenu.TYPE_DIRECTORY: layout.parseMenuname(item.get_menu_id()) elif item.get_type() == matemenu.TYPE_ENTRY: layout.parseFilename(item.get_desktop_file_id()) elif item.get_type() == matemenu.TYPE_SEPARATOR: layout.parseSeparator() layout.order.append(['Merge', 'files']) return layout def __addItem(self, parent, file_id, dom): xml_parent = self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom) self.__addXmlFilename(xml_parent, dom, file_id, 'Include') def __positionItem(self, parent, item, before=None, after=None): if after: index = parent.contents.index(after) + 1 elif before: index = parent.contents.index(before) else: # append the item to the list index = len(parent.contents) contents = parent.contents #if this is a move to a new parent you can't remove the item if item in contents: # decrease the destination index, if we shorten the list if (before and (contents.index(item) < index)) \ or (after and (contents.index(item) < index - 1)): index -= 1 contents.remove(item) contents.insert(index, item) layout = self.__createLayout(contents) dom = self.__getMenu(parent).dom menu_xml = self.__getXmlMenu(self.__getPath(parent), dom.documentElement, dom) self.__addXmlLayout(menu_xml, layout, dom) def __undoMoves(self, element, old, new, dom): nodes = [] matches = [] original_old = old final_old = old #get all elements for node in self.__getXmlNodesByName(['Move'], element): nodes.insert(0, node) #if the matches our old parent we've found a stage to undo for node in nodes: xml_old = node.getElementsByTagName('Old')[0] xml_new = node.getElementsByTagName('New')[0] if xml_new.childNodes[0].nodeValue == old: matches.append(node) #we should end up with this path when completed final_old = xml_old.childNodes[0].nodeValue #undoing s for node in matches: element.removeChild(node) if len(matches) > 0: for node in nodes: xml_old = node.getElementsByTagName('Old')[0] xml_new = node.getElementsByTagName('New')[0] path = os.path.split(xml_new.childNodes[0].nodeValue) if path[0] == original_old: element.removeChild(node) for node in dom.getElementsByTagName('Menu'): name_node = node.getElementsByTagName('Name')[0] name = name_node.childNodes[0].nodeValue if name == os.path.split(new)[1]: #copy app and dir directory info from old root_path = dom.getElementsByTagName('Menu')[0].getElementsByTagName('Name')[0].childNodes[0].nodeValue xml_menu = self.__getXmlMenu(root_path + '/' + new, dom.documentElement, dom) for app_dir in node.getElementsByTagName('AppDir'): xml_menu.appendChild(app_dir) for dir_dir in node.getElementsByTagName('DirectoryDir'): xml_menu.appendChild(dir_dir) parent = node.parentNode parent.removeChild(node) node = dom.createElement('Move') node.appendChild(self.__addXmlTextElement(node, 'Old', xml_old.childNodes[0].nodeValue, dom)) node.appendChild(self.__addXmlTextElement(node, 'New', os.path.join(new, path[1]), dom)) element.appendChild(node) if final_old == new: return True node = dom.createElement('Move') node.appendChild(self.__addXmlTextElement(node, 'Old', final_old, dom)) node.appendChild(self.__addXmlTextElement(node, 'New', new, dom)) return element.appendChild(node) class Layout: def __init__(self, node=None): self.order = [] def parseMenuname(self, value): self.order.append(['Menuname', value]) def parseSeparator(self): self.order.append(['Separator']) def parseFilename(self, value): self.order.append(['Filename', value]) def parseMerge(self, merge_type='all'): self.order.append(['Merge', merge_type])