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