Blame gtk/gtk-builder-convert.python3-compat

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