404

[ Avaa Bypassed ]




Upload:

Command:

botdev@3.137.143.141: ~ $
""" CLass to edit XDG Menus """

from xdg.Menu import *
from xdg.BaseDirectory import *
from xdg.Exceptions import *
from xdg.DesktopEntry import *
from xdg.Config import *

import xml.dom.minidom
import os
import re

# XML-Cleanups: Move / Exclude
# FIXME: proper reverte/delete
# FIXME: pass AppDirs/DirectoryDirs around in the edit/move functions
# FIXME: catch Exceptions
# FIXME: copy functions
# FIXME: More Layout stuff
# FIXME: unod/redo function / remove menu...
# FIXME: Advanced MenuEditing Stuff: LegacyDir/MergeFile
#        Complex Rules/Deleted/OnlyAllocated/AppDirs/DirectoryDirs

class MenuEditor:
    def __init__(self, menu=None, filename=None, root=False):
        self.menu = None
        self.filename = None
        self.doc = None
        self.parse(menu, filename, root)

        # fix for creating two menus with the same name on the fly
        self.filenames = []

    def parse(self, menu=None, filename=None, root=False):
        if root == True:
            setRootMode(True)

        if isinstance(menu, Menu):
            self.menu = menu
        elif menu:
            self.menu = parse(menu)
        else:
            self.menu = parse()

        if root == True:
            self.filename = self.menu.Filename
        elif filename:
            self.filename = filename
        else:
            self.filename = os.path.join(xdg_config_dirs[0], "menus", os.path.split(self.menu.Filename)[1])

        try:
            self.doc = xml.dom.minidom.parse(self.filename)
        except IOError:
            self.doc = xml.dom.minidom.parseString('<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" "http://standards.freedesktop.org/menu-spec/menu-1.0.dtd"><Menu><Name>Applications</Name><MergeFile type="parent">'+self.menu.Filename+'</MergeFile></Menu>')
        except xml.parsers.expat.ExpatError:
            raise ParsingError('Not a valid .menu file', self.filename)

        self.__remove_whilespace_nodes(self.doc)

    def save(self):
        self.__saveEntries(self.menu)
        self.__saveMenu()

    def createMenuEntry(self, parent, name, command=None, genericname=None, comment=None, icon=None, terminal=None, after=None, before=None):
        menuentry = MenuEntry(self.__getFileName(name, ".desktop"))
        menuentry = self.editMenuEntry(menuentry, name, genericname, comment, command, icon, terminal)

        self.__addEntry(parent, menuentry, after, before)

        sort(self.menu)

        return menuentry

    def createMenu(self, parent, name, genericname=None, comment=None, icon=None, after=None, before=None):
        menu = Menu()

        menu.Parent = parent
        menu.Depth = parent.Depth + 1
        menu.Layout = parent.DefaultLayout
        menu.DefaultLayout = parent.DefaultLayout

        menu = self.editMenu(menu, name, genericname, comment, icon)

        self.__addEntry(parent, menu, after, before)

        sort(self.menu)

        return menu

    def createSeparator(self, parent, after=None, before=None):
        separator = Separator(parent)

        self.__addEntry(parent, separator, after, before)

        sort(self.menu)

        return separator

    def moveMenuEntry(self, menuentry, oldparent, newparent, after=None, before=None):
        self.__deleteEntry(oldparent, menuentry, after, before)
        self.__addEntry(newparent, menuentry, after, before)

        sort(self.menu)

        return menuentry

    def moveMenu(self, menu, oldparent, newparent, after=None, before=None):
        self.__deleteEntry(oldparent, menu, after, before)
        self.__addEntry(newparent, menu, after, before)

        root_menu = self.__getXmlMenu(self.menu.Name)
        if oldparent.getPath(True) != newparent.getPath(True):
            self.__addXmlMove(root_menu, os.path.join(oldparent.getPath(True), menu.Name), os.path.join(newparent.getPath(True), menu.Name))

        sort(self.menu)

        return menu

    def moveSeparator(self, separator, parent, after=None, before=None):
        self.__deleteEntry(parent, separator, after, before)
        self.__addEntry(parent, separator, after, before)

        sort(self.menu)

        return separator

    def copyMenuEntry(self, menuentry, oldparent, newparent, after=None, before=None):
        self.__addEntry(newparent, menuentry, after, before)

        sort(self.menu)

        return menuentry

    def editMenuEntry(self, menuentry, name=None, genericname=None, comment=None, command=None, icon=None, terminal=None, nodisplay=None, hidden=None):
        deskentry = menuentry.DesktopEntry

        if name:
            if not deskentry.hasKey("Name"):
                deskentry.set("Name", name)
            deskentry.set("Name", name, locale = True)
        if comment:
            if not deskentry.hasKey("Comment"):
                deskentry.set("Comment", comment)
            deskentry.set("Comment", comment, locale = True)
        if genericname:
            if not deskentry.hasKey("GnericNe"):
                deskentry.set("GenericName", genericname)
            deskentry.set("GenericName", genericname, locale = True)
        if command:
            deskentry.set("Exec", command)
        if icon:
            deskentry.set("Icon", icon)

        if terminal == True:
            deskentry.set("Terminal", "true")
        elif terminal == False:
            deskentry.set("Terminal", "false")

        if nodisplay == True:
            deskentry.set("NoDisplay", "true")
        elif nodisplay == False:
            deskentry.set("NoDisplay", "false")

        if hidden == True:
            deskentry.set("Hidden", "true")
        elif hidden == False:
            deskentry.set("Hidden", "false")

        menuentry.updateAttributes()

        if len(menuentry.Parents) > 0:
            sort(self.menu)

        return menuentry

    def editMenu(self, menu, name=None, genericname=None, comment=None, icon=None, nodisplay=None, hidden=None):
        # Hack for legacy dirs
        if isinstance(menu.Directory, MenuEntry) and menu.Directory.Filename == ".directory":
            xml_menu = self.__getXmlMenu(menu.getPath(True, True))
            self.__addXmlTextElement(xml_menu, 'Directory', menu.Name + ".directory")
            menu.Directory.setAttributes(menu.Name + ".directory")
        # Hack for New Entries
        elif not isinstance(menu.Directory, MenuEntry):
            if not name:
                name = menu.Name
            filename = self.__getFileName(name, ".directory").replace("/", "")
            if not menu.Name:
                menu.Name = filename.replace(".directory", "")
            xml_menu = self.__getXmlMenu(menu.getPath(True, True))
            self.__addXmlTextElement(xml_menu, 'Directory', filename)
            menu.Directory = MenuEntry(filename)

        deskentry = menu.Directory.DesktopEntry

        if name:
            if not deskentry.hasKey("Name"):
                deskentry.set("Name", name)
            deskentry.set("Name", name, locale = True)
        if genericname:
            if not deskentry.hasKey("GenericName"):
                deskentry.set("GenericName", genericname)
            deskentry.set("GenericName", genericname, locale = True)
        if comment:
            if not deskentry.hasKey("Comment"):
                deskentry.set("Comment", comment)
            deskentry.set("Comment", comment, locale = True)
        if icon:
            deskentry.set("Icon", icon)

        if nodisplay == True:
            deskentry.set("NoDisplay", "true")
        elif nodisplay == False:
            deskentry.set("NoDisplay", "false")

        if hidden == True:
            deskentry.set("Hidden", "true")
        elif hidden == False:
            deskentry.set("Hidden", "false")

        menu.Directory.updateAttributes()

        if isinstance(menu.Parent, Menu):
            sort(self.menu)

        return menu

    def hideMenuEntry(self, menuentry):
        self.editMenuEntry(menuentry, nodisplay = True)

    def unhideMenuEntry(self, menuentry):
        self.editMenuEntry(menuentry, nodisplay = False, hidden = False)

    def hideMenu(self, menu):
        self.editMenu(menu, nodisplay = True)

    def unhideMenu(self, menu):
        self.editMenu(menu, nodisplay = False, hidden = False)
        xml_menu = self.__getXmlMenu(menu.getPath(True,True), False)
        for node in self.__getXmlNodesByName(["Deleted", "NotDeleted"], xml_menu):
            node.parentNode.removeChild(node)

    def deleteMenuEntry(self, menuentry):
        if self.getAction(menuentry) == "delete":
            self.__deleteFile(menuentry.DesktopEntry.filename)
            for parent in menuentry.Parents:
                self.__deleteEntry(parent, menuentry)
            sort(self.menu)
        return menuentry

    def revertMenuEntry(self, menuentry):
        if self.getAction(menuentry) == "revert":
            self.__deleteFile(menuentry.DesktopEntry.filename)
            menuentry.Original.Parents = []
            for parent in menuentry.Parents:
                index = parent.Entries.index(menuentry)
                parent.Entries[index] = menuentry.Original
                index = parent.MenuEntries.index(menuentry)
                parent.MenuEntries[index] = menuentry.Original
                menuentry.Original.Parents.append(parent)
            sort(self.menu)
        return menuentry

    def deleteMenu(self, menu):
        if self.getAction(menu) == "delete":
            self.__deleteFile(menu.Directory.DesktopEntry.filename)
            self.__deleteEntry(menu.Parent, menu)
            xml_menu = self.__getXmlMenu(menu.getPath(True, True))
            xml_menu.parentNode.removeChild(xml_menu)
            sort(self.menu)
        return menu

    def revertMenu(self, menu):
        if self.getAction(menu) == "revert":
            self.__deleteFile(menu.Directory.DesktopEntry.filename)
            menu.Directory = menu.Directory.Original
            sort(self.menu)
        return menu

    def deleteSeparator(self, separator):
        self.__deleteEntry(separator.Parent, separator, after=True)

        sort(self.menu)

        return separator

    """ Private Stuff """
    def getAction(self, entry):
        if isinstance(entry, Menu):
            if not isinstance(entry.Directory, MenuEntry):
                return "none"
            elif entry.Directory.getType() == "Both":
                return "revert"
            elif entry.Directory.getType() == "User" \
            and (len(entry.Submenus) + len(entry.MenuEntries)) == 0:
                return "delete"

        elif isinstance(entry, MenuEntry):
            if entry.getType() == "Both":
                return "revert"
            elif entry.getType() == "User":
                return "delete"
            else:
                return "none"

        return "none"

    def __saveEntries(self, menu):
        if not menu:
            menu = self.menu
        if isinstance(menu.Directory, MenuEntry):
            menu.Directory.save()
        for entry in menu.getEntries(hidden=True):
            if isinstance(entry, MenuEntry):
                entry.save()
            elif isinstance(entry, Menu):
                self.__saveEntries(entry)

    def __saveMenu(self):
        if not os.path.isdir(os.path.dirname(self.filename)):
            os.makedirs(os.path.dirname(self.filename))
        fd = open(self.filename, 'w')
        fd.write(re.sub("\n[\s]*([^\n<]*)\n[\s]*</", "\\1</", self.doc.toprettyxml().replace('<?xml version="1.0" ?>\n', '')))
        fd.close()

    def __getFileName(self, name, extension):
        postfix = 0
        while 1:
            if postfix == 0:
                filename = name + extension
            else:
                filename = name + "-" + str(postfix) + extension
            if extension == ".desktop":
                dir = "applications"
            elif extension == ".directory":
                dir = "desktop-directories"
            if not filename in self.filenames and not \
                os.path.isfile(os.path.join(xdg_data_dirs[0], dir, filename)):
                self.filenames.append(filename)
                break
            else:
                postfix += 1

        return filename

    def __getXmlMenu(self, path, create=True, element=None):
        if not element:
            element = self.doc

        if "/" in path:
            (name, path) = path.split("/", 1)
        else:
            name = path
            path = ""

        found = None
        for node in self.__getXmlNodesByName("Menu", element):
            for child in self.__getXmlNodesByName("Name", node):
                if child.childNodes[0].nodeValue == name:
                    if path:
                        found = self.__getXmlMenu(path, create, node)
                    else:
                        found = node
                    break
            if found:
                break
        if not found and create == True:
            node = self.__addXmlMenuElement(element, name)
            if path:
                found = self.__getXmlMenu(path, create, node)
            else:
                found = node

        return found

    def __addXmlMenuElement(self, element, name):
        node = self.doc.createElement('Menu')
        self.__addXmlTextElement(node, 'Name', name)
        return element.appendChild(node)

    def __addXmlTextElement(self, element, name, text):
        node = self.doc.createElement(name)
        text = self.doc.createTextNode(text)
        node.appendChild(text)
        return element.appendChild(node)

    def __addXmlFilename(self, element, filename, type = "Include"):
        # 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 = self.doc.createElement(type)
        node.appendChild(self.__addXmlTextElement(node, 'Filename', filename))
        return element.appendChild(node)

    def __addXmlMove(self, element, old, new):
        node = self.doc.createElement("Move")
        node.appendChild(self.__addXmlTextElement(node, 'Old', old))
        node.appendChild(self.__addXmlTextElement(node, 'New', new))
        return element.appendChild(node)

    def __addXmlLayout(self, element, layout):
        # remove old layout
        for node in self.__getXmlNodesByName("Layout", element):
            element.removeChild(node)

        # add new layout
        node = self.doc.createElement("Layout")
        for order in layout.order:
            if order[0] == "Separator":
                child = self.doc.createElement("Separator")
                node.appendChild(child)
            elif order[0] == "Filename":
                child = self.__addXmlTextElement(node, "Filename", order[1])
            elif order[0] == "Menuname":
                child = self.__addXmlTextElement(node, "Menuname", order[1])
            elif order[0] == "Merge":
                child = self.doc.createElement("Merge")
                child.setAttribute("type", order[1])
                node.appendChild(child)
        return element.appendChild(node)

    def __getXmlNodesByName(self, name, element):
        for child in element.childNodes:
            if child.nodeType == xml.dom.Node.ELEMENT_NODE and child.nodeName in name:
                yield child

    def __addLayout(self, parent):
        layout = Layout()
        layout.order = []
        layout.show_empty = parent.Layout.show_empty
        layout.inline = parent.Layout.inline
        layout.inline_header = parent.Layout.inline_header
        layout.inline_alias = parent.Layout.inline_alias
        layout.inline_limit = parent.Layout.inline_limit

        layout.order.append(["Merge", "menus"])
        for entry in parent.Entries:
            if isinstance(entry, Menu):
                layout.parseMenuname(entry.Name)
            elif isinstance(entry, MenuEntry):
                layout.parseFilename(entry.DesktopFileID)
            elif isinstance(entry, Separator):
                layout.parseSeparator()
        layout.order.append(["Merge", "files"])

        parent.Layout = layout

        return layout

    def __addEntry(self, parent, entry, after=None, before=None):
        if after or before:
            if after:
                index = parent.Entries.index(after) + 1
            elif before:
                index = parent.Entries.index(before)
            parent.Entries.insert(index, entry)
        else:
            parent.Entries.append(entry)

        xml_parent = self.__getXmlMenu(parent.getPath(True, True))

        if isinstance(entry, MenuEntry):
            parent.MenuEntries.append(entry)
            entry.Parents.append(parent)
            self.__addXmlFilename(xml_parent, entry.DesktopFileID, "Include")
        elif isinstance(entry, Menu):
            parent.addSubmenu(entry)

        if after or before:
            self.__addLayout(parent)
            self.__addXmlLayout(xml_parent, parent.Layout)

    def __deleteEntry(self, parent, entry, after=None, before=None):
        parent.Entries.remove(entry)

        xml_parent = self.__getXmlMenu(parent.getPath(True, True))

        if isinstance(entry, MenuEntry):
            entry.Parents.remove(parent)
            parent.MenuEntries.remove(entry)
            self.__addXmlFilename(xml_parent, entry.DesktopFileID, "Exclude")
        elif isinstance(entry, Menu):
            parent.Submenus.remove(entry)

        if after or before:
            self.__addLayout(parent)
            self.__addXmlLayout(xml_parent, parent.Layout)

    def __deleteFile(self, filename):
        try:
            os.remove(filename)
        except OSError:
            pass
        try:
            self.filenames.remove(filename)
        except ValueError:
            pass

    def __remove_whilespace_nodes(self, node):
        remove_list = []
        for child in node.childNodes:
            if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
                child.data = child.data.strip()
                if not child.data.strip():
                    remove_list.append(child)
            elif child.hasChildNodes():
                self.__remove_whilespace_nodes(child)
        for node in remove_list:
            node.parentNode.removeChild(node)

Filemanager

Name Type Size Permission Actions
__pycache__ Folder 0755
BaseDirectory.py File 5.62 KB 0644
Config.py File 728 B 0644
DesktopEntry.py File 16.41 KB 0644
Exceptions.py File 1.49 KB 0644
IconTheme.py File 15.72 KB 0644
IniFile.py File 13.18 KB 0644
Locale.py File 2.11 KB 0644
Menu.py File 38.14 KB 0644
MenuEditor.py File 17.97 KB 0644
Mime.py File 15.64 KB 0644
RecentFiles.py File 5.99 KB 0644
__init__.py File 171 B 0644
util.py File 164 B 0644