Drop gtk-builder-convert
It will still be shipped in gtk 2.24.
This commit is contained in:
@ -135,7 +135,6 @@ content_files = \
|
|||||||
x11.sgml \
|
x11.sgml \
|
||||||
gtk-query-immodules-3.0.xml \
|
gtk-query-immodules-3.0.xml \
|
||||||
gtk-update-icon-cache.xml \
|
gtk-update-icon-cache.xml \
|
||||||
gtk-builder-convert.xml \
|
|
||||||
visual_index.xml \
|
visual_index.xml \
|
||||||
getting_started.xml \
|
getting_started.xml \
|
||||||
overview.xml
|
overview.xml
|
||||||
@ -374,8 +373,7 @@ EXTRA_DIST += version.xml.in
|
|||||||
|
|
||||||
man_MANS = \
|
man_MANS = \
|
||||||
gtk-query-immodules-3.0.1 \
|
gtk-query-immodules-3.0.1 \
|
||||||
gtk-update-icon-cache.1 \
|
gtk-update-icon-cache.1
|
||||||
gtk-builder-convert.1
|
|
||||||
|
|
||||||
if ENABLE_MAN
|
if ENABLE_MAN
|
||||||
|
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
<refentry id="gtk-builder-convert">
|
|
||||||
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>gtk-builder-convert</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname>gtk-builder-convert</refname>
|
|
||||||
<refpurpose>Glade file conversion utility</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
|
|
||||||
<refsynopsisdiv>
|
|
||||||
<cmdsynopsis>
|
|
||||||
<command>gtk-builder-convert</command>
|
|
||||||
<arg choice="opt">--skip-windows</arg>
|
|
||||||
<arg choice="opt">--target-version <replaceable>version</replaceable></arg>
|
|
||||||
<arg choice="opt">--root <replaceable>name</replaceable></arg>
|
|
||||||
<arg choice="req">input</arg>
|
|
||||||
<arg choice="req">output</arg>
|
|
||||||
</cmdsynopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
|
|
||||||
<refsect1><title>Description</title>
|
|
||||||
<para><command>gtk-builder-convert</command> converts glade files
|
|
||||||
into XML files which can be loaded with GtkBuilder.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
It expects the name of a glade file as the first argument, and writes
|
|
||||||
its output the file specified as the second argument.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1><title>Options</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term>--skip-windows</term>
|
|
||||||
<term>-w</term>
|
|
||||||
<listitem><para>Convert everything but GtkWindow subclasses.</para></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term>--target-version</term>
|
|
||||||
<term>-t</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Some widgets and properties are different between GTK+ versions 2.0 and
|
|
||||||
3.0, so this option allows to set the desired GTK+ target version.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term>--root</term>
|
|
||||||
<term>-r</term>
|
|
||||||
<listitem><para>Convert only the widget named <replaceable>name</replaceable>
|
|
||||||
and its children.</para></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1><title>Bugs</title>
|
|
||||||
<para>
|
|
||||||
Toolbars are not handled.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Support for accessibility is not yet implemented.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The script requires a python interpreter to run.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
</refentry>
|
|
@ -358,7 +358,6 @@
|
|||||||
<title>GTK+ Tools</title>
|
<title>GTK+ Tools</title>
|
||||||
<xi:include href="gtk-query-immodules-3.0.xml" />
|
<xi:include href="gtk-query-immodules-3.0.xml" />
|
||||||
<xi:include href="gtk-update-icon-cache.xml" />
|
<xi:include href="gtk-update-icon-cache.xml" />
|
||||||
<xi:include href="gtk-builder-convert.xml" />
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<xi:include href="glossary.xml" />
|
<xi:include href="glossary.xml" />
|
||||||
|
@ -1006,8 +1006,6 @@ if BUILD_ICON_CACHE
|
|||||||
bin_PROGRAMS += gtk-update-icon-cache
|
bin_PROGRAMS += gtk-update-icon-cache
|
||||||
endif
|
endif
|
||||||
|
|
||||||
bin_SCRIPTS = gtk-builder-convert
|
|
||||||
|
|
||||||
if OS_WIN32
|
if OS_WIN32
|
||||||
|
|
||||||
# Workaround for UAC silliness: programs with "update" in their name
|
# Workaround for UAC silliness: programs with "update" in their name
|
||||||
@ -1017,8 +1015,7 @@ if OS_WIN32
|
|||||||
|
|
||||||
GTK_UPDATE_ICON_CACHE_MANIFEST = gtk-update-icon-cache.exe.manifest
|
GTK_UPDATE_ICON_CACHE_MANIFEST = gtk-update-icon-cache.exe.manifest
|
||||||
|
|
||||||
bin_SCRIPTS += \
|
bin_SCRIPTS = $(GTK_UPDATE_ICON_CACHE_MANIFEST)
|
||||||
$(GTK_UPDATE_ICON_CACHE_MANIFEST)
|
|
||||||
|
|
||||||
$(GTK_UPDATE_ICON_CACHE_MANIFEST):
|
$(GTK_UPDATE_ICON_CACHE_MANIFEST):
|
||||||
(echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' ; \
|
(echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' ; \
|
||||||
@ -1363,7 +1360,6 @@ EXTRA_DIST += \
|
|||||||
tree_minus.xpm \
|
tree_minus.xpm \
|
||||||
tree_plus.xpm \
|
tree_plus.xpm \
|
||||||
gtk.def \
|
gtk.def \
|
||||||
gtk-builder-convert \
|
|
||||||
gtk-win32.rc \
|
gtk-win32.rc \
|
||||||
gtk-win32.rc.in \
|
gtk-win32.rc.in \
|
||||||
gtkwin32embed.h \
|
gtkwin32embed.h \
|
||||||
|
@ -1,799 +0,0 @@
|
|||||||
#!/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-3.0 [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-3.0 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 = "3.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))
|
|
Reference in New Issue
Block a user