Blame gtk/gtk-builder-convert

Packit 98cdb6
#!/usr/bin/env python
Packit 98cdb6
#
Packit 98cdb6
# Copyright (C) 2006-2008 Async Open Source
Packit 98cdb6
#                         Henrique Romano <henrique@async.com.br>
Packit 98cdb6
#                         Johan Dahlin <jdahlin@async.com.br>
Packit 98cdb6
#
Packit 98cdb6
# This program is free software; you can redistribute it and/or
Packit 98cdb6
# modify it under the terms of the GNU Lesser General Public License
Packit 98cdb6
# as published by the Free Software Foundation; either version 2
Packit 98cdb6
# of the License, or (at your option) any later version.
Packit 98cdb6
#
Packit 98cdb6
# This program is distributed in the hope that it will be useful,
Packit 98cdb6
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 98cdb6
# GNU General Public License for more details.
Packit 98cdb6
#
Packit 98cdb6
# You should have received a copy of the GNU Lesser General Public License
Packit 98cdb6
# along with this program; if not, write to the Free Software
Packit 98cdb6
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Packit 98cdb6
#
Packit 98cdb6
# TODO:
Packit 98cdb6
#  Toolbars
Packit 98cdb6
Packit 98cdb6
"""Usage: gtk-builder-convert [OPTION] [INPUT] [OUTPUT]
Packit 98cdb6
Converts Glade files into XML files which can be loaded with GtkBuilder.
Packit 98cdb6
The [INPUT] file is
Packit 98cdb6
Packit 98cdb6
  -w, --skip-windows     Convert everything but GtkWindow subclasses.
Packit 98cdb6
  -r, --root             Convert only widget named root and its children
Packit 98cdb6
  -h, --help             display this help and exit
Packit 98cdb6
Packit 98cdb6
When OUTPUT is -, write to standard output.
Packit 98cdb6
Packit 98cdb6
Examples:
Packit 98cdb6
  gtk-builder-convert preference.glade preferences.ui
Packit 98cdb6
Packit 98cdb6
Report bugs to http://bugzilla.gnome.org/."""
Packit 98cdb6
Packit 98cdb6
import getopt
Packit 98cdb6
import os
Packit 98cdb6
import sys
Packit 98cdb6
Packit 98cdb6
from xml.dom import minidom, Node
Packit 98cdb6
Packit 98cdb6
DIALOGS = ['GtkDialog',
Packit 98cdb6
           'GtkFileChooserDialog',
Packit 98cdb6
           'GtkMessageDialog']
Packit 98cdb6
WINDOWS = ['GtkWindow'] + DIALOGS
Packit 98cdb6
Packit 98cdb6
# The subprocess is only available in Python 2.4+
Packit 98cdb6
try:
Packit 98cdb6
    import subprocess
Packit 98cdb6
    subprocess # pyflakes
Packit 98cdb6
except ImportError:
Packit 98cdb6
    subprocess = None
Packit 98cdb6
Packit 98cdb6
def get_child_nodes(node):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    nodes = []
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if child.tagName != 'child':
Packit 98cdb6
            continue
Packit 98cdb6
        nodes.append(child)
Packit 98cdb6
    return nodes
Packit 98cdb6
Packit 98cdb6
def get_properties(node):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    properties = {}
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if child.tagName != 'property':
Packit 98cdb6
            continue
Packit 98cdb6
        value = child.childNodes[0].data
Packit 98cdb6
        properties[child.getAttribute('name')] = value
Packit 98cdb6
    return properties
Packit 98cdb6
Packit 98cdb6
def get_property(node, property_name):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    properties = get_properties(node)
Packit 98cdb6
    return properties.get(property_name)
Packit 98cdb6
Packit 98cdb6
def get_property_node(node, property_name):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    properties = {}
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if child.tagName != 'property':
Packit 98cdb6
            continue
Packit 98cdb6
        if child.getAttribute('name') == property_name:
Packit 98cdb6
            return child
Packit 98cdb6
Packit 98cdb6
def get_signal_nodes(node):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    signals = []
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if child.tagName == 'signal':
Packit 98cdb6
            signals.append(child)
Packit 98cdb6
    return signals
Packit 98cdb6
Packit 98cdb6
def get_property_nodes(node):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    properties = []
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        # FIXME: handle comments
Packit 98cdb6
        if child.tagName == 'property':
Packit 98cdb6
            properties.append(child)
Packit 98cdb6
    return properties
Packit 98cdb6
Packit 98cdb6
def get_accelerator_nodes(node):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    accelerators = []
Packit 98cdb6
    for child in node.childNodes:
Packit 98cdb6
        if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if child.tagName == 'accelerator':
Packit 98cdb6
            accelerators.append(child)
Packit 98cdb6
    return accelerators
Packit 98cdb6
Packit 98cdb6
def get_object_node(child_node):
Packit 98cdb6
    assert child_node.tagName == 'child', child_node
Packit 98cdb6
    nodes = []
Packit 98cdb6
    for node in child_node.childNodes:
Packit 98cdb6
        if node.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
            continue
Packit 98cdb6
        if node.tagName == 'object':
Packit 98cdb6
            nodes.append(node)
Packit 98cdb6
    assert len(nodes) == 1, nodes
Packit 98cdb6
    return nodes[0]
Packit 98cdb6
Packit 98cdb6
def copy_properties(node, props, prop_dict):
Packit 98cdb6
    assert node.tagName == 'object'
Packit 98cdb6
    for prop_name in props:
Packit 98cdb6
        child = get_property_node(node, prop_name)
Packit 98cdb6
        if child is not None:
Packit 98cdb6
            prop_dict[prop_name] = child
Packit 98cdb6
Packit 98cdb6
    return node
Packit 98cdb6
Packit 98cdb6
class GtkBuilderConverter(object):
Packit 98cdb6
Packit 98cdb6
    def __init__(self, skip_windows, target_version, root):
Packit 98cdb6
        self.skip_windows = skip_windows
Packit 98cdb6
        self.target_version = target_version
Packit 98cdb6
        self.root = root
Packit 98cdb6
        self.root_objects = []
Packit 98cdb6
        self.objects = {}
Packit 98cdb6
Packit 98cdb6
    #
Packit 98cdb6
    # Public API
Packit 98cdb6
    #
Packit 98cdb6
Packit 98cdb6
    def parse_file(self, file):
Packit 98cdb6
        self._dom = minidom.parse(file)
Packit 98cdb6
        self._parse()
Packit 98cdb6
Packit 98cdb6
    def parse_buffer(self, buffer):
Packit 98cdb6
        self._dom = minidom.parseString(buffer)
Packit 98cdb6
        self._parse()
Packit 98cdb6
Packit 98cdb6
    def to_xml(self):
Packit 98cdb6
        xml = self._dom.toprettyxml("", "")
Packit 98cdb6
        return xml.encode('utf-8')
Packit 98cdb6
Packit 98cdb6
    #
Packit 98cdb6
    # Private
Packit 98cdb6
    #
Packit 98cdb6
Packit 98cdb6
    def _get_object(self, name):
Packit 98cdb6
        return self.objects.get(name)
Packit 98cdb6
Packit 98cdb6
    def _get_objects_by_attr(self, attribute, value):
Packit 98cdb6
        return [w for w in self._dom.getElementsByTagName("object")
Packit 98cdb6
                      if w.getAttribute(attribute) == value]
Packit 98cdb6
Packit 98cdb6
    def _create_object(self, obj_class, obj_id, template=None, properties=None):
Packit 98cdb6
        """
Packit 98cdb6
        Creates a new <object> tag.
Packit 98cdb6
        Optionally a name template can be provided which will be used
Packit 98cdb6
        to avoid naming collisions.
Packit 98cdb6
        The properties dictionary can either contain string values or Node
Packit 98cdb6
        values. If a node is provided the name of the node will be overridden
Packit 98cdb6
        by the dictionary key.
Packit 98cdb6
Packit 98cdb6
        @param obj_class: class of the object (class tag)
Packit 98cdb6
        @param obj_id: identifier of the object (id tag)
Packit 98cdb6
        @param template: name template to use, for example 'button'
Packit 98cdb6
        @param properties: dictionary of properties
Packit 98cdb6
        @type properties: string or Node.
Packit 98cdb6
        @returns: Newly created node of the object
Packit 98cdb6
        """
Packit 98cdb6
        if template is not None:
Packit 98cdb6
            count = 1
Packit 98cdb6
            while True:
Packit 98cdb6
                obj_id = template + str(count)
Packit 98cdb6
                widget = self._get_object(obj_id)
Packit 98cdb6
                if widget is None:
Packit 98cdb6
                    break
Packit 98cdb6
Packit 98cdb6
                count += 1
Packit 98cdb6
Packit 98cdb6
        obj = self._dom.createElement('object')
Packit 98cdb6
        obj.setAttribute('class', obj_class)
Packit 98cdb6
        obj.setAttribute('id', obj_id)
Packit 98cdb6
        if properties:
Packit 98cdb6
            for name, value in properties.items():
Packit 98cdb6
                if isinstance(value, Node):
Packit 98cdb6
                    # Reuse the node, so translatable and context still will be
Packit 98cdb6
                    # set when converting nodes. See also #509153
Packit 98cdb6
                    prop = value
Packit 98cdb6
                else:
Packit 98cdb6
                    prop = self._dom.createElement('property')
Packit 98cdb6
                    prop.appendChild(self._dom.createTextNode(value))
Packit 98cdb6
Packit 98cdb6
                prop.setAttribute('name', str(name))
Packit 98cdb6
                obj.appendChild(prop)
Packit 98cdb6
        self.objects[obj_id] = obj
Packit 98cdb6
        return obj
Packit 98cdb6
Packit 98cdb6
    def _create_root_object(self, obj_class, template, properties=None):
Packit 98cdb6
        obj = self._create_object(obj_class, None, template, properties)
Packit 98cdb6
        self.root_objects.append(obj)
Packit 98cdb6
        return obj
Packit 98cdb6
Packit 98cdb6
    def _parse(self):
Packit 98cdb6
        glade_iface = self._dom.getElementsByTagName("glade-interface")
Packit 98cdb6
        assert glade_iface, ("Badly formed XML, there is "
Packit 98cdb6
                             "no <glade-interface> tag.")
Packit 98cdb6
        # Rename glade-interface to interface
Packit 98cdb6
        glade_iface[0].tagName = 'interface'
Packit 98cdb6
        self._interface = glade_iface[0]
Packit 98cdb6
Packit 98cdb6
        # Remove glade-interface doc type
Packit 98cdb6
        for node in self._dom.childNodes:
Packit 98cdb6
            if node.nodeType == Node.DOCUMENT_TYPE_NODE:
Packit 98cdb6
                if node.name == 'glade-interface':
Packit 98cdb6
                    self._dom.removeChild(node)
Packit 98cdb6
Packit 98cdb6
        # Strip unsupported tags
Packit 98cdb6
        for tag in ['requires', 'requires-version']:
Packit 98cdb6
            for child in self._dom.getElementsByTagName(tag):
Packit 98cdb6
                child.parentNode.removeChild(child)
Packit 98cdb6
Packit 98cdb6
        if self.root:
Packit 98cdb6
            self._strip_root(self.root)
Packit 98cdb6
Packit 98cdb6
        # Rename widget to object
Packit 98cdb6
        objects = self._dom.getElementsByTagName("widget")
Packit 98cdb6
        for node in objects:
Packit 98cdb6
            node.tagName = "object"
Packit 98cdb6
Packit 98cdb6
        for node in objects:
Packit 98cdb6
            self._convert(node.getAttribute("class"), node)
Packit 98cdb6
            if self._get_object(node.getAttribute('id')) is not None:
Packit 98cdb6
		print "WARNING: duplicate id \"" + node.getAttribute('id') + "\""
Packit 98cdb6
            self.objects[node.getAttribute('id')] = node
Packit 98cdb6
Packit 98cdb6
        # Convert Gazpachos UI tag
Packit 98cdb6
        for node in self._dom.getElementsByTagName("ui"):
Packit 98cdb6
            self._convert_ui(node)
Packit 98cdb6
Packit 98cdb6
        # Convert accessibility tag
Packit 98cdb6
        for node in self._dom.getElementsByTagName("accessibility"):
Packit 98cdb6
            self._convert_accessibility(node)
Packit 98cdb6
Packit 98cdb6
        # Output the newly created root objects and sort them
Packit 98cdb6
        # by attribute id
Packit 98cdb6
        # FIXME: Use sorted(self.root_objects,
Packit 98cdb6
        #                   key=lambda n: n.getAttribute('id'),
Packit 98cdb6
        #                   reverse=True):
Packit 98cdb6
        # when we can depend on python 2.4 or higher
Packit 98cdb6
        root_objects = self.root_objects[:]
Packit 98cdb6
        root_objects.sort(lambda a, b: cmp(b.getAttribute('id'),
Packit 98cdb6
                                           a.getAttribute('id')))
Packit 98cdb6
        for obj in root_objects:
Packit 98cdb6
            self._interface.childNodes.insert(0, obj)
Packit 98cdb6
Packit 98cdb6
    def _convert(self, klass, node):
Packit 98cdb6
        if klass == 'GtkNotebook':
Packit 98cdb6
            self._packing_prop_to_child_attr(node, "type", "tab")
Packit 98cdb6
        elif klass in ['GtkExpander', 'GtkFrame']:
Packit 98cdb6
            self._packing_prop_to_child_attr(
Packit 98cdb6
                node, "type", "label_item", "label")
Packit 98cdb6
        elif klass == "GtkMenuBar":
Packit 98cdb6
            self._convert_menu(node)
Packit 98cdb6
        elif klass == "GtkMenu":
Packit 98cdb6
            # Only convert toplevel popups
Packit 98cdb6
            if node.parentNode == self._interface:
Packit 98cdb6
                self._convert_menu(node, popup=True)
Packit 98cdb6
        elif klass in WINDOWS and self.skip_windows:
Packit 98cdb6
            self._remove_window(node)
Packit 98cdb6
Packit 98cdb6
        if self.target_version == "3.0":
Packit 98cdb6
            if klass == "GtkComboBoxEntry":
Packit 98cdb6
                node.setAttribute("class","GtkComboBox")
Packit 98cdb6
                prop = self._dom.createElement("property")
Packit 98cdb6
                prop.setAttribute("name", "has-entry")
Packit 98cdb6
                prop.appendChild(self._dom.createTextNode("True"))
Packit 98cdb6
                node.appendChild(prop)
Packit 98cdb6
            elif klass == "GtkDialog":
Packit 98cdb6
                for child in node.childNodes:
Packit 98cdb6
                    if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
                        continue
Packit 98cdb6
                    if child.tagName != 'property':
Packit 98cdb6
                        continue
Packit 98cdb6
                    if (child.getAttribute("name") not in ("has-separator", "has_separator")):
Packit 98cdb6
                        continue;
Packit 98cdb6
                    node.removeChild(child)
Packit 98cdb6
                    break
Packit 98cdb6
Packit 98cdb6
        self._default_widget_converter(node)
Packit 98cdb6
Packit 98cdb6
    def _default_widget_converter(self, node):
Packit 98cdb6
        klass = node.getAttribute("class")
Packit 98cdb6
        for prop in get_property_nodes(node):
Packit 98cdb6
            prop_name = prop.getAttribute("name")
Packit 98cdb6
            if prop_name == "sizegroup":
Packit 98cdb6
                self._convert_sizegroup(node, prop)
Packit 98cdb6
            elif prop_name == "tooltip" and klass != "GtkAction":
Packit 98cdb6
                prop.setAttribute("name", "tooltip-text")
Packit 98cdb6
            elif prop_name in ["response_id", 'response-id']:
Packit 98cdb6
                # It does not make sense to convert responses when
Packit 98cdb6
                # we're not going to output dialogs
Packit 98cdb6
                if self.skip_windows:
Packit 98cdb6
                    continue
Packit 98cdb6
                object_id = node.getAttribute('id')
Packit 98cdb6
                response = prop.childNodes[0].data
Packit 98cdb6
                self._convert_dialog_response(node, object_id, response)
Packit 98cdb6
                prop.parentNode.removeChild(prop)
Packit 98cdb6
            elif prop_name == "adjustment":
Packit 98cdb6
                self._convert_adjustment(prop)
Packit 98cdb6
            elif prop_name == "items" and klass in ['GtkComboBox',
Packit 98cdb6
                                                    'GtkComboBoxEntry']:
Packit 98cdb6
                self._convert_combobox_items(node, prop)
Packit 98cdb6
            elif prop_name == "text" and klass == 'GtkTextView':
Packit 98cdb6
                self._convert_textview_text(prop)
Packit 98cdb6
Packit 98cdb6
    def _remove_window(self, node):
Packit 98cdb6
        object_node = get_object_node(get_child_nodes(node)[0])
Packit 98cdb6
        parent = node.parentNode
Packit 98cdb6
        parent.removeChild(node)
Packit 98cdb6
        parent.appendChild(object_node)
Packit 98cdb6
Packit 98cdb6
    def _convert_menu(self, node, popup=False):
Packit 98cdb6
        if node.hasAttribute('constructor'):
Packit 98cdb6
            return
Packit 98cdb6
Packit 98cdb6
        uimgr = self._create_root_object('GtkUIManager',
Packit 98cdb6
                                         template='uimanager')
Packit 98cdb6
Packit 98cdb6
        if popup:
Packit 98cdb6
            name = 'popup'
Packit 98cdb6
        else:
Packit 98cdb6
            name = 'menubar'
Packit 98cdb6
Packit 98cdb6
        menu = self._dom.createElement(name)
Packit 98cdb6
        menu.setAttribute('name', node.getAttribute('id'))
Packit 98cdb6
        node.setAttribute('constructor', uimgr.getAttribute('id'))
Packit 98cdb6
Packit 98cdb6
        for child in get_child_nodes(node):
Packit 98cdb6
            obj_node = get_object_node(child)
Packit 98cdb6
            item = self._convert_menuitem(uimgr, obj_node)
Packit 98cdb6
            menu.appendChild(item)
Packit 98cdb6
            child.removeChild(obj_node)
Packit 98cdb6
            child.parentNode.removeChild(child)
Packit 98cdb6
Packit 98cdb6
        ui = self._dom.createElement('ui')
Packit 98cdb6
        uimgr.appendChild(ui)
Packit 98cdb6
Packit 98cdb6
        ui.appendChild(menu)
Packit 98cdb6
Packit 98cdb6
    def _convert_menuitem(self, uimgr, obj_node):
Packit 98cdb6
        children = get_child_nodes(obj_node)
Packit 98cdb6
        name = 'menuitem'
Packit 98cdb6
        if children:
Packit 98cdb6
            child_node = children[0]
Packit 98cdb6
            menu_node = get_object_node(child_node)
Packit 98cdb6
            # Can be GtkImage, which will take care of later.
Packit 98cdb6
            if menu_node.getAttribute('class') == 'GtkMenu':
Packit 98cdb6
                name = 'menu'
Packit 98cdb6
Packit 98cdb6
        object_class = obj_node.getAttribute('class')
Packit 98cdb6
        if object_class in ['GtkMenuItem',
Packit 98cdb6
                            'GtkImageMenuItem',
Packit 98cdb6
                            'GtkCheckMenuItem',
Packit 98cdb6
                            'GtkRadioMenuItem']:
Packit 98cdb6
            menu = self._dom.createElement(name)
Packit 98cdb6
        elif object_class == 'GtkSeparatorMenuItem':
Packit 98cdb6
            return self._dom.createElement('separator')
Packit 98cdb6
        else:
Packit 98cdb6
            raise NotImplementedError(object_class)
Packit 98cdb6
Packit 98cdb6
        menu.setAttribute('action', obj_node.getAttribute('id'))
Packit 98cdb6
        self._add_action_from_menuitem(uimgr, obj_node)
Packit 98cdb6
        if children:
Packit 98cdb6
            for child in get_child_nodes(menu_node):
Packit 98cdb6
                obj_node = get_object_node(child)
Packit 98cdb6
                item = self._convert_menuitem(uimgr, obj_node)
Packit 98cdb6
                menu.appendChild(item)
Packit 98cdb6
                child.removeChild(obj_node)
Packit 98cdb6
                child.parentNode.removeChild(child)
Packit 98cdb6
        return menu
Packit 98cdb6
Packit 98cdb6
    def _menuitem_to_action(self, node, properties):
Packit 98cdb6
        copy_properties(node, ['label', 'tooltip'], properties)
Packit 98cdb6
Packit 98cdb6
    def _togglemenuitem_to_action(self, node, properties):
Packit 98cdb6
        self._menuitem_to_action(node, properties)
Packit 98cdb6
        copy_properties(node, ['active'], properties)
Packit 98cdb6
Packit 98cdb6
    def _radiomenuitem_to_action(self, node, properties):
Packit 98cdb6
        self._togglemenuitem_to_action(node, properties)
Packit 98cdb6
        copy_properties(node, ['group'], properties)
Packit 98cdb6
Packit 98cdb6
    def _add_action_from_menuitem(self, uimgr, node):
Packit 98cdb6
        properties = {}
Packit 98cdb6
        object_class = node.getAttribute('class')
Packit 98cdb6
        object_id = node.getAttribute('id')
Packit 98cdb6
        if object_class == 'GtkMenuItem':
Packit 98cdb6
            name = 'GtkAction'
Packit 98cdb6
            self._menuitem_to_action(node, properties)
Packit 98cdb6
        elif object_class == 'GtkCheckMenuItem':
Packit 98cdb6
            name = 'GtkToggleAction'
Packit 98cdb6
            self._togglemenuitem_to_action(node, properties)
Packit 98cdb6
        elif object_class == 'GtkRadioMenuItem':
Packit 98cdb6
            name = 'GtkRadioAction'
Packit 98cdb6
            self._radiomenuitem_to_action(node, properties)
Packit 98cdb6
        elif object_class == 'GtkImageMenuItem':
Packit 98cdb6
            name = 'GtkAction'
Packit 98cdb6
            children = get_child_nodes(node)
Packit 98cdb6
            if (children and
Packit 98cdb6
                children[0].getAttribute('internal-child') == 'image'):
Packit 98cdb6
                image = get_object_node(children[0])
Packit 98cdb6
                child = get_property_node(image, 'stock')
Packit 98cdb6
                if child is not None:
Packit 98cdb6
                    properties['stock_id'] = child
Packit 98cdb6
            self._menuitem_to_action(node, properties)
Packit 98cdb6
        elif object_class == 'GtkSeparatorMenuItem':
Packit 98cdb6
            return
Packit 98cdb6
        else:
Packit 98cdb6
            raise NotImplementedError(object_class)
Packit 98cdb6
Packit 98cdb6
        if get_property(node, 'use_stock') == 'True':
Packit 98cdb6
            if 'label' in properties:
Packit 98cdb6
                properties['stock_id'] = properties['label']
Packit 98cdb6
                del properties['label']
Packit 98cdb6
Packit 98cdb6
        properties['name'] = object_id
Packit 98cdb6
        action = self._create_object(name,
Packit 98cdb6
                                     object_id,
Packit 98cdb6
                                     properties=properties)
Packit 98cdb6
        for signal in get_signal_nodes(node):
Packit 98cdb6
            signal_name = signal.getAttribute('name')
Packit 98cdb6
            if signal_name in ['activate', 'toggled']:
Packit 98cdb6
                action.appendChild(signal)
Packit 98cdb6
            else:
Packit 98cdb6
                print 'Unhandled signal %s::%s' % (node.getAttribute('class'),
Packit 98cdb6
                                                   signal_name)
Packit 98cdb6
Packit 98cdb6
        if not uimgr.childNodes:
Packit 98cdb6
            child = self._dom.createElement('child')
Packit 98cdb6
            uimgr.appendChild(child)
Packit 98cdb6
Packit 98cdb6
            group = self._create_object('GtkActionGroup', None,
Packit 98cdb6
                                        template='actiongroup')
Packit 98cdb6
            child.appendChild(group)
Packit 98cdb6
        else:
Packit 98cdb6
            group = uimgr.childNodes[0].childNodes[0]
Packit 98cdb6
Packit 98cdb6
        child = self._dom.createElement('child')
Packit 98cdb6
        group.appendChild(child)
Packit 98cdb6
        child.appendChild(action)
Packit 98cdb6
Packit 98cdb6
        for accelerator in get_accelerator_nodes(node):
Packit 98cdb6
            signal_name = accelerator.getAttribute('signal')
Packit 98cdb6
            if signal_name != 'activate':
Packit 98cdb6
                print 'Unhandled accelerator signal for %s::%s' % (
Packit 98cdb6
                    node.getAttribute('class'), signal_name)
Packit 98cdb6
                continue
Packit 98cdb6
            accelerator.removeAttribute('signal')
Packit 98cdb6
            child.appendChild(accelerator)
Packit 98cdb6
Packit 98cdb6
    def _convert_sizegroup(self, node, prop):
Packit 98cdb6
        # This is Gazpacho only
Packit 98cdb6
        node.removeChild(prop)
Packit 98cdb6
        obj = self._get_object(prop.childNodes[0].data)
Packit 98cdb6
        if obj is None:
Packit 98cdb6
            widgets = self._get_objects_by_attr("class", "GtkSizeGroup")
Packit 98cdb6
            if widgets:
Packit 98cdb6
                obj = widgets[-1]
Packit 98cdb6
            else:
Packit 98cdb6
                obj = self._create_root_object('GtkSizeGroup',
Packit 98cdb6
                                               template='sizegroup')
Packit 98cdb6
Packit 98cdb6
        widgets = obj.getElementsByTagName("widgets")
Packit 98cdb6
        if widgets:
Packit 98cdb6
            assert len(widgets) == 1
Packit 98cdb6
            widgets = widgets[0]
Packit 98cdb6
        else:
Packit 98cdb6
            widgets = self._dom.createElement("widgets")
Packit 98cdb6
            obj.appendChild(widgets)
Packit 98cdb6
Packit 98cdb6
        member = self._dom.createElement("widget")
Packit 98cdb6
        member.setAttribute("name", node.getAttribute("id"))
Packit 98cdb6
        widgets.appendChild(member)
Packit 98cdb6
Packit 98cdb6
    def _convert_dialog_response(self, node, object_name, response):
Packit 98cdb6
        # 1) Get parent dialog node
Packit 98cdb6
        while True:
Packit 98cdb6
            # If we can't find the parent dialog, give up
Packit 98cdb6
            if node == self._dom:
Packit 98cdb6
                return
Packit 98cdb6
Packit 98cdb6
            if (node.tagName == 'object' and
Packit 98cdb6
                node.getAttribute('class') in DIALOGS):
Packit 98cdb6
                dialog = node
Packit 98cdb6
                break
Packit 98cdb6
            node = node.parentNode
Packit 98cdb6
            assert node
Packit 98cdb6
Packit 98cdb6
        # 2) Get dialogs action-widgets tag, create if not found
Packit 98cdb6
        for child in dialog.childNodes:
Packit 98cdb6
            if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
                continue
Packit 98cdb6
            if child.tagName == 'action-widgets':
Packit 98cdb6
                actions = child
Packit 98cdb6
                break
Packit 98cdb6
        else:
Packit 98cdb6
            actions = self._dom.createElement("action-widgets")
Packit 98cdb6
            dialog.appendChild(actions)
Packit 98cdb6
Packit 98cdb6
        # 3) Add action-widget tag for the response
Packit 98cdb6
        action = self._dom.createElement("action-widget")
Packit 98cdb6
        action.setAttribute("response", response)
Packit 98cdb6
        action.appendChild(self._dom.createTextNode(object_name))
Packit 98cdb6
        actions.appendChild(action)
Packit 98cdb6
Packit 98cdb6
    def _convert_adjustment(self, prop):
Packit 98cdb6
        properties = {}
Packit 98cdb6
        if prop.childNodes:
Packit 98cdb6
            data = prop.childNodes[0].data
Packit 98cdb6
            value, lower, upper, step, page, page_size = data.split(' ')
Packit 98cdb6
            properties.update(value=value,
Packit 98cdb6
                              lower=lower,
Packit 98cdb6
                              upper=upper,
Packit 98cdb6
                              step_increment=step,
Packit 98cdb6
                              page_increment=page,
Packit 98cdb6
                              page_size=page_size)
Packit 98cdb6
        else:
Packit 98cdb6
            prop.appendChild(self._dom.createTextNode(""))
Packit 98cdb6
Packit 98cdb6
        adj = self._create_root_object("GtkAdjustment",
Packit 98cdb6
                                       template='adjustment',
Packit 98cdb6
                                       properties=properties)
Packit 98cdb6
        prop.childNodes[0].data = adj.getAttribute('id')
Packit 98cdb6
Packit 98cdb6
    def _convert_combobox_items(self, node, prop):
Packit 98cdb6
        parent = prop.parentNode
Packit 98cdb6
        if not prop.childNodes:
Packit 98cdb6
            parent.removeChild(prop)
Packit 98cdb6
            return
Packit 98cdb6
Packit 98cdb6
        translatable_attr = prop.attributes.get('translatable')
Packit 98cdb6
        translatable = translatable_attr is not None and translatable_attr.value == 'yes'
Packit 98cdb6
        has_context_attr = prop.attributes.get('context')
Packit 98cdb6
        has_context = has_context_attr is not None and has_context_attr.value == 'yes'
Packit 98cdb6
        comments_attr = prop.attributes.get('comments')
Packit 98cdb6
        comments = comments_attr is not None and comments_attr.value or None
Packit 98cdb6
Packit 98cdb6
        value = prop.childNodes[0].data
Packit 98cdb6
        model = self._create_root_object("GtkListStore",
Packit 98cdb6
                                         template="model")
Packit 98cdb6
Packit 98cdb6
        columns = self._dom.createElement('columns')
Packit 98cdb6
        model.appendChild(columns)
Packit 98cdb6
Packit 98cdb6
        column = self._dom.createElement('column')
Packit 98cdb6
        column.setAttribute('type', 'gchararray')
Packit 98cdb6
        columns.appendChild(column)
Packit 98cdb6
Packit 98cdb6
        data = self._dom.createElement('data')
Packit 98cdb6
        model.appendChild(data)
Packit 98cdb6
Packit 98cdb6
        if value.endswith('\n'):
Packit 98cdb6
            value = value[:-1]
Packit 98cdb6
        for item in value.split('\n'):
Packit 98cdb6
            row = self._dom.createElement('row')
Packit 98cdb6
            data.appendChild(row)
Packit 98cdb6
Packit 98cdb6
            col = self._dom.createElement('col')
Packit 98cdb6
            col.setAttribute('id', '0')
Packit 98cdb6
            if translatable:
Packit 98cdb6
                col.setAttribute('translatable', 'yes')
Packit 98cdb6
            if has_context:
Packit 98cdb6
                splitting = item.split('|', 1)
Packit 98cdb6
                if len(splitting) == 2:
Packit 98cdb6
                    context, item = splitting
Packit 98cdb6
                    col.setAttribute('context', context)
Packit 98cdb6
            if comments is not None:
Packit 98cdb6
                col.setAttribute('comments', comments)
Packit 98cdb6
            col.appendChild(self._dom.createTextNode(item))
Packit 98cdb6
            row.appendChild(col)
Packit 98cdb6
Packit 98cdb6
        model_prop = self._dom.createElement('property')
Packit 98cdb6
        model_prop.setAttribute('name', 'model')
Packit 98cdb6
        model_prop.appendChild(
Packit 98cdb6
            self._dom.createTextNode(model.getAttribute('id')))
Packit 98cdb6
        parent.appendChild(model_prop)
Packit 98cdb6
Packit 98cdb6
        parent.removeChild(prop)
Packit 98cdb6
Packit 98cdb6
        child = self._dom.createElement('child')
Packit 98cdb6
        node.appendChild(child)
Packit 98cdb6
        cell_renderer = self._create_object('GtkCellRendererText', None,
Packit 98cdb6
                                            template='renderer')
Packit 98cdb6
        child.appendChild(cell_renderer)
Packit 98cdb6
Packit 98cdb6
        attributes = self._dom.createElement('attributes')
Packit 98cdb6
        child.appendChild(attributes)
Packit 98cdb6
Packit 98cdb6
        attribute = self._dom.createElement('attribute')
Packit 98cdb6
        attributes.appendChild(attribute)
Packit 98cdb6
        attribute.setAttribute('name', 'text')
Packit 98cdb6
        attribute.appendChild(self._dom.createTextNode('0'))
Packit 98cdb6
Packit 98cdb6
    def _convert_textview_text(self, prop):
Packit 98cdb6
        if not prop.childNodes:
Packit 98cdb6
            prop.parentNode.removeChild(prop)
Packit 98cdb6
            return
Packit 98cdb6
Packit 98cdb6
        data = prop.childNodes[0].data
Packit 98cdb6
        if prop.hasAttribute('translatable'):
Packit 98cdb6
            prop.removeAttribute('translatable')
Packit 98cdb6
        tbuffer = self._create_root_object("GtkTextBuffer",
Packit 98cdb6
                                           template='textbuffer',
Packit 98cdb6
                                           properties=dict(text=data))
Packit 98cdb6
        prop.childNodes[0].data = tbuffer.getAttribute('id')
Packit 98cdb6
        prop.setAttribute('name', 'buffer')
Packit 98cdb6
Packit 98cdb6
    def _packing_prop_to_child_attr(self, node, prop_name, prop_val,
Packit 98cdb6
                                   attr_val=None):
Packit 98cdb6
        for child in get_child_nodes(node):
Packit 98cdb6
            packing_props = [p for p in child.childNodes if p.nodeName == "packing"]
Packit 98cdb6
            if not packing_props:
Packit 98cdb6
                continue
Packit 98cdb6
            assert len(packing_props) == 1
Packit 98cdb6
            packing_prop = packing_props[0]
Packit 98cdb6
            properties = packing_prop.getElementsByTagName("property")
Packit 98cdb6
            for prop in properties:
Packit 98cdb6
                if (prop.getAttribute("name") != prop_name or
Packit 98cdb6
                    prop.childNodes[0].data != prop_val):
Packit 98cdb6
                    continue
Packit 98cdb6
                packing_prop.removeChild(prop)
Packit 98cdb6
                child.setAttribute(prop_name, attr_val or prop_val)
Packit 98cdb6
            if len(properties) == 1:
Packit 98cdb6
                child.removeChild(packing_prop)
Packit 98cdb6
Packit 98cdb6
    def _convert_ui(self, node):
Packit 98cdb6
        cdata = node.childNodes[0]
Packit 98cdb6
        data = cdata.toxml().strip()
Packit 98cdb6
        if not data.startswith(""):
Packit 98cdb6
            return
Packit 98cdb6
        data = data[9:-3]
Packit 98cdb6
        child = minidom.parseString(data).childNodes[0]
Packit 98cdb6
        nodes = child.childNodes[:]
Packit 98cdb6
        for child_node in nodes:
Packit 98cdb6
            node.appendChild(child_node)
Packit 98cdb6
        node.removeChild(cdata)
Packit 98cdb6
        if not node.hasAttribute("id"):
Packit 98cdb6
            return
Packit 98cdb6
Packit 98cdb6
        # Updating references made by widgets
Packit 98cdb6
        parent_id = node.parentNode.getAttribute("id")
Packit 98cdb6
        for widget in self._get_objects_by_attr("constructor",
Packit 98cdb6
                                                node.getAttribute("id")):
Packit 98cdb6
            widget.getAttributeNode("constructor").value = parent_id
Packit 98cdb6
        node.removeAttribute("id")
Packit 98cdb6
Packit 98cdb6
    def _convert_accessibility(self, node):
Packit 98cdb6
        objectNode = node.parentNode
Packit 98cdb6
        parent_id = objectNode.getAttribute("id")
Packit 98cdb6
Packit 98cdb6
        properties = {}
Packit 98cdb6
        for node in node.childNodes:
Packit 98cdb6
            if node.nodeName == 'atkproperty':
Packit 98cdb6
                node.tagName = 'property'
Packit 98cdb6
                properties[node.getAttribute('name')] = node
Packit 98cdb6
                node.parentNode.removeChild(node)
Packit 98cdb6
            elif node.nodeName == 'atkrelation':
Packit 98cdb6
                node.tagName = 'relation'
Packit 98cdb6
                relation_type = node.getAttribute('type')
Packit 98cdb6
                relation_type = relation_type.replace('_', '-')
Packit 98cdb6
                node.setAttribute('type', relation_type)
Packit 98cdb6
            elif node.nodeName == 'atkaction':
Packit 98cdb6
                node.tagName = 'action'
Packit 98cdb6
Packit 98cdb6
        if properties:
Packit 98cdb6
            child = self._dom.createElement('child')
Packit 98cdb6
            child.setAttribute("internal-child", "accessible")
Packit 98cdb6
Packit 98cdb6
            atkobject = self._create_object(
Packit 98cdb6
                "AtkObject", None,
Packit 98cdb6
                template='a11y-%s' % (parent_id,),
Packit 98cdb6
                properties=properties)
Packit 98cdb6
            child.appendChild(atkobject)
Packit 98cdb6
            objectNode.appendChild(child)
Packit 98cdb6
Packit 98cdb6
    def _strip_root(self, root_name):
Packit 98cdb6
        for widget in self._dom.getElementsByTagName("widget"):
Packit 98cdb6
            if widget.getAttribute('id') == root_name:
Packit 98cdb6
                break
Packit 98cdb6
        else:
Packit 98cdb6
            raise SystemExit("Could not find an object called `%s'" % (
Packit 98cdb6
                root_name))
Packit 98cdb6
Packit 98cdb6
        for child in self._interface.childNodes[:]:
Packit 98cdb6
            if child.nodeType != Node.ELEMENT_NODE:
Packit 98cdb6
                continue
Packit 98cdb6
            child.parentNode.removeChild(child)
Packit 98cdb6
Packit 98cdb6
        self._interface.appendChild(widget)
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
def _indent(output):
Packit 98cdb6
    if not subprocess:
Packit 98cdb6
        return output
Packit 98cdb6
Packit 98cdb6
    for directory in os.environ['PATH'].split(os.pathsep):
Packit 98cdb6
        filename = os.path.join(directory, 'xmllint')
Packit 98cdb6
        if os.path.exists(filename):
Packit 98cdb6
            break
Packit 98cdb6
    else:
Packit 98cdb6
        return output
Packit 98cdb6
Packit 98cdb6
    s = subprocess.Popen([filename, '--format', '-'],
Packit 98cdb6
                         stdin=subprocess.PIPE,
Packit 98cdb6
                         stdout=subprocess.PIPE)
Packit 98cdb6
    s.stdin.write(output)
Packit 98cdb6
    s.stdin.close()
Packit 98cdb6
    return s.stdout.read()
Packit 98cdb6
Packit 98cdb6
def usage():
Packit 98cdb6
    print __doc__
Packit 98cdb6
Packit 98cdb6
def main(args):
Packit 98cdb6
    try:
Packit 98cdb6
        opts, args = getopt.getopt(args[1:], "hwr:",
Packit 98cdb6
                                   ["help",
Packit 98cdb6
                                    "skip-windows",
Packit 98cdb6
                                    "target-version=",
Packit 98cdb6
                                    "root="])
Packit 98cdb6
    except getopt.GetoptError:
Packit 98cdb6
        usage()
Packit 98cdb6
        return 2
Packit 98cdb6
Packit 98cdb6
    if len(args) != 2:
Packit 98cdb6
        usage()
Packit 98cdb6
        return 2
Packit 98cdb6
Packit 98cdb6
    input_filename, output_filename = args
Packit 98cdb6
Packit 98cdb6
    skip_windows = False
Packit 98cdb6
    split = False
Packit 98cdb6
    root = None
Packit 98cdb6
    target_version = "2.0"
Packit 98cdb6
    for o, a in opts:
Packit 98cdb6
        if o in ("-h", "--help"):
Packit 98cdb6
            usage()
Packit 98cdb6
            sys.exit()
Packit 98cdb6
        elif o in ("-r", "--root"):
Packit 98cdb6
            root = a
Packit 98cdb6
        elif o in ("-w", "--skip-windows"):
Packit 98cdb6
            skip_windows = True
Packit 98cdb6
        elif o in ("-t", "--target-version"):
Packit 98cdb6
            target_version = a
Packit 98cdb6
Packit 98cdb6
    conv = GtkBuilderConverter(skip_windows=skip_windows,
Packit 98cdb6
                               target_version=target_version,
Packit 98cdb6
                               root=root)
Packit 98cdb6
    conv.parse_file(input_filename)
Packit 98cdb6
Packit 98cdb6
    xml = _indent(conv.to_xml())
Packit 98cdb6
    if output_filename == "-":
Packit 98cdb6
        print xml
Packit 98cdb6
    else:
Packit 98cdb6
        open(output_filename, 'w').write(xml)
Packit 98cdb6
        print "Wrote", output_filename
Packit 98cdb6
Packit 98cdb6
    return 0
Packit 98cdb6
Packit 98cdb6
if __name__ == "__main__":
Packit 98cdb6
    sys.exit(main(sys.argv))