Blame gtk/gtk-builder-convert.system-python

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