#!/usr/bin/env python2

# yes, this requires python 2.x and an XML parser module (eg. PyExpat)

import re
import sys
import string
import getopt
import xml.dom.minidom

translatable_properties = [
    'label', 'title', 'text', 'format', 'copyright', 'comments',
    'preview_text', 'tooltip'
]

# --- Code to represent a widget in memory, and dump it to stdout ---

class WidgetDef:
    def __init__(self):
        self.wclass = None
        self.name = None
        self.property_names = [ ]
        self.properties = { }
        self.signals = []
        self.accels = []
        self.children = []

    def __getitem__(self, name):
        if name == 'name':
            return self.name
        if name == 'class':
            return self.wclass
        return self.properties[name]
    def __setitem__(self, name, value):
        if name == 'name':
            self.name = value
            return
        if name == 'class':
            self.wclass = value
            return
        if self.properties.has_key(name):
            self.property_names.remove(name)
            del self.properties[name]
        if value == 'True': value = 'yes'
        if value == 'False': value = 'no'
        self.property_names.append(name)
        self.properties[name] = value
    def __delitem__(self, name):
        if self.properties.has_key(name):
            self.property_names.remove(name)
            del self.properties[name]
        else:
            raise KeyError, "unknown property `%s'" % name
    def has_prop(self, name):
        return self.properties.has_key(name)
    def rename_prop(self, old_name, new_name):
        if self.has_prop(old_name):
            self[new_name] = self[old_name]
            del self[old_name]
    def remove_prop(self, name):
        if self.properties.has_key(name):
            self.property_names.remove(name)
            del self.properties[name]
            
    def mark_obsolete (self):
        self.properties ['obsolete'] = 'yes'

    def add_signal(self, name, handler, object=None, after=0):
        self.signals.append((name, handler, object, after))
    def add_accel(self, key, modifiers, signal):
        self.accels.append((key, modifiers, signal))

    class ChildDef:
        def __init__(self, widget, internal_child=None):
            self.internal_child = internal_child
            self.property_names = []
            self.properties = {}
            self.widget = widget
        def __getitem__(self, name):
            return self.properties[name]
        def __setitem__(self, name, value):
            if self.properties.has_key(name):
                self.property_names.remove(name)
                del self.properties[name]
            if value == 'True': value = 'yes'
            if value == 'False': value = 'no'
            self.property_names.append(name)
            self.properties[name] = value
        def __delitem__(self, name):
            if self.properties.has_key(name):
                self.property_names.remove(name)
                del self.properties[name]
            else:
                raise KeyError, "unknown property `%s'" % name
        def has_prop(self, name):
            return self.properties.has_key(name)
        def rename_prop(self, old_name, new_name):
            if self.has_prop(old_name):
                self[new_name] = self[old_name]
                del self[old_name]
        def remove_prop(self, name):
            if self.properties.has_key(name):
                self.property_names.remove(name)
                del self.properties[name]
                
        def dump(self, indent):
            if self.widget.has_prop('obsolete'):
                return

            if self.internal_child:
                print '%s<child internal-child="%s">' % \
                      (indent, self.internal_child)
            else:
                print '%s<child>' % indent
            self.widget.dump(indent + '  ')
            if self.properties:
                print '%s  <packing>' % indent
                for name in self.property_names:
                    if name in translatable_properties:
                        print '%s    <property name="%s" translatable="yes">%s</property>' % \
                              (indent, name, self.properties[name])
                    else:
                        print '%s    <property name="%s">%s</property>' % \
                              (indent, name, self.properties[name])
                print '%s  </packing>' % indent
            print '%s</child>' % indent

    def add_child(self, widget, internal_child=None):
        child = self.ChildDef(widget, internal_child)
        self.children.append(child)
        return child

    def dump(self, indent):        
        print '%s<widget class="%s" id="%s">' %(indent, self.wclass, self.name)
        want_newline = 0
        for name in self.property_names:
            if name in translatable_properties:
                print '%s  <property name="%s" translatable="yes">%s</property>' % \
                      (indent, name, self.properties[name])
            else:
                print '%s  <property name="%s">%s</property>' % \
                      (indent, name, self.properties[name])
            want_newline = 1
        if want_newline and (self.signals or self.accels or self.children):
            print

        want_newline = 0
        for name, handler, object, after in self.signals:
            print '%s  <signal name="%s" handler="%s"' % (indent, name,
                                                          handler),
            if object: print 'object="%s"' % object,
            if after: print 'after="yes"',
            print '/>'
            want_newline = 1
        if want_newline and (self.accels or self.children): print

        want_newline = 0
        for key, modifiers, signal in self.accels:
            print '%s  <accelerator key="%s" modifiers="%s" signal="%s" />' % \
                  (indent, key, modifiers, signal)
            want_newline = 1
        if want_newline and self.children: print

        want_newline = 0
        for child in self.children:
            if want_newline: print
            child.dump(indent + '  ')
            want_newline = 1
        print '%s</widget>' % indent


# --- Code to parse the glade1 XML files into WidgetDef instances ---

def totext(nodelist):
    return string.join(map(lambda node: node.toxml(), nodelist), '')

def handle_signal(widget, signalnode):
    name = None
    handler = None
    object = None
    after = 0
    for node in signalnode.childNodes:
	if node.nodeType != node.ELEMENT_NODE:
	    continue
	if node.nodeName == 'name':
	    name = totext(node.childNodes)
	elif node.nodeName == 'handler':
	    handler = totext(node.childNodes)
	elif node.nodeName == 'object':
	    object = totext(node.childNodes)
	elif node.nodeName == 'after':
	    after = (totext(node.childNodes) == 'True')
    widget.add_signal(name, handler, object, after)

def handle_accel(widget, accelnode):
    key = None
    modifiers = None
    signal = None
    for node in accelnode.childNodes:
	if node.nodeType != node.ELEMENT_NODE:
	    continue
	if node.nodeName == 'key':
	    key = totext(node.childNodes)
	    if key[:4] == 'GDK_': key = key[4:]
	elif node.nodeName == 'modifiers':
	    modifiers = totext(node.childNodes)
	elif node.nodeName == 'signal':
	    signal = totext(node.childNodes)
    widget.add_accel(key, modifiers, signal)

def get_child_props(childdef, widgetnode):
    for node in widgetnode.childNodes:
	if node.nodeType != node.ELEMENT_NODE:
	    continue
	if node.nodeName == 'child':
	    child = node
	    break
    else:
	return []
    for node in child.childNodes:
	if node.nodeType != node.ELEMENT_NODE:
	    continue
        childdef[node.nodeName] = totext(node.childNodes)

def handle_widget(widgetnode):
    widget = WidgetDef()
    properties = []
    signals = []
    accels = []
    children = []
    for node in widgetnode.childNodes:
	if node.nodeType != node.ELEMENT_NODE:
	    continue
	if node.nodeName == 'widget':
            child_widget = handle_widget(node)
            childdef = widget.add_child(child_widget)
            get_child_props(childdef, node)
	elif node.nodeName in ('signal', 'Signal'):
	    handle_signal(widget, node)
	elif node.nodeName in ('accelerator', 'Accelerator'):
	    handle_accel(widget, node)
	elif node.nodeName == 'child':
	    pass # handled by the parent widget
	else:
            widget[node.nodeName] = totext(node.childNodes)
    return widget


# --- Code to do widget type specific cleanups ---

name_counter = 0
def make_name():
    global name_counter
    name_counter = name_counter + 1
    return 'convertwidget' + str(name_counter)

# properties to change on all widgets
global_obsolete_props = [ ]
global_renamed_props = [
    ('width', 'width-request'),
    ('height', 'height-request'),
]

# properties to change on specific widgets
obsolete_props = {
    'GtkWindow': [ 'auto_shrink' ],
    'GnomePropertyBox': [ 'auto_shrink' ],
    'GtkMenuItem': [ 'right_justify' ],
    'GtkGammaCurve': [ 'curve_type', 'min_x', 'max_x', 'min_y', 'max_y' ],
    'GtkHPaned': [ 'handle_size', 'gutter_size' ],
    'GtkVPaned': [ 'handle_size', 'gutter_size' ],
    'GtkHScale': [ 'policy' ],
    'GtkVScale': [ 'policy' ],
    'GtkHScrollbar': [ 'policy' ],
    'GtkVScrollbar': [ 'policy' ],
    'GtkHRuler': [ 'metric' ],
    'GtkVRuler': [ 'metric' ],
    'GnomeFileEntry' : [ 'max_saved' ],
}

renamed_props = {
    'GtkWindow': [ ('position', 'window-position') ],
    'GtkEntry': [ ('text_max_length', 'max-length'),
                  ('text_visible', 'visibility') ],
    'GtkFrame': [ ('shadow_type', 'shadow') ],
    'GtkHandleBox': [ ('shadow_type', 'shadow') ],
    'GtkNotebook': [ ('popup_enable', 'enable-popup') ],
    'GtkRange': [ ('policy', 'update-policy') ],
    'GtkTable': [ ('rows', 'n-rows'), ('columns', 'n-columns') ],
    'GtkSpinButton' : [ ('snap', 'snap_to_ticks') ],
    'GtkCombo' : [ ('use_arrows', 'enable_arrow_keys'),
                   ('use_arrows_always', 'enable_arrows_always'),
                   ('ok_if_empty', 'allow_empty') ],
    'GnomeFileEntry' : [ ( 'directory', 'directory_entry' ) ],
    'GtkLabel' : [ ('default_focus_target', 'mnemonic_widget') ],
    'GtkCList' : [ ('columns', 'n_columns' ) ],
}

# child properties to change on specific widgets
obsolete_child_props = {
}
renamed_child_props = {
    'GtkTable' : [ ('xpad', 'x_padding'), ('ypad', 'y_padding') ],
}

def collect_adjustment(widgetdef, prop_prefix, new_name):
    value, lower, upper, step, page, page_size = (0, 0, 100, 1, 10, 10)
    adj_set = 0
    if widgetdef.has_prop(prop_prefix + 'value'):
        value = widgetdef[prop_prefix + 'value']
        del widgetdef[prop_prefix + 'value']
        adj_set = 1
    if widgetdef.has_prop(prop_prefix + 'lower'):
        lower = widgetdef[prop_prefix + 'lower']
        del widgetdef[prop_prefix + 'lower']
        adj_set = 1
    if widgetdef.has_prop(prop_prefix + 'upper'):
        upper = widgetdef[prop_prefix + 'upper']
        del widgetdef[prop_prefix + 'upper']
        adj_set = 1
    if widgetdef.has_prop(prop_prefix + 'step'):
        step = widgetdef[prop_prefix + 'step']
        del widgetdef[prop_prefix + 'step']
        adj_set = 1
    if widgetdef.has_prop(prop_prefix + 'page'):
        page = widgetdef[prop_prefix + 'page']
        del widgetdef[prop_prefix + 'page']
        adj_set = 1
    if widgetdef.has_prop(prop_prefix + 'page_size'):
        page_size = widgetdef[prop_prefix + 'page_size']
        del widgetdef[prop_prefix + 'page_size']
        adj_set = 1
    if adj_set:
        widgetdef[new_name] = '%s %s %s %s %s %s' % (value, lower, upper,
                                                     step, page, page_size)


parent_table = {
    'GtkContainer'      : 'GtkWidget',
    'GtkBin'            : 'GtkContainer',
    'GtkDialog'         : 'GtkWindow',
    'GnomePropertyBox'  : 'GtkDialog',
    'GnomeAbout'        : 'GtkDialog',
    'GnomeApp'          : 'GtkDialog',
    'GnomeScores'       : 'GtkDialog',
    'GnomeDialog'       : 'GtkWindow',
    'GnomeDruid'        : 'GtkContainer',
    'GnomeEntry'        : 'GtkCombo',
    'GtkCheckMenuItem'  : 'GtkMenuItem',
    'GtkRadioMenuItem'  : 'GtkMenuItem',
    'GtkImageMenuItem'  : 'GtkMenuItem',
    'GtkFontSelectionDialog' : 'GtkDialog',
    'GnomeColorPicker'  : 'GtkButton',
    'GtkToggleButton'   : 'GtkButton',
    'GtkCheckButton'    : 'GtkToggleButton',
}

global_group_map = { }

def find_parent(type):
    if parent_table.has_key(type):
        return parent_table[type]
    return ''

# fix up attribute naming, and possibly adding missing children.
def fixup_widget(widget):

    type = widget['class']
    while (type and not fixup_as_type (widget, type)):
        type = find_parent (type)
        
    for childdef in widget.children:
        fixup_widget(childdef.widget)

def new_label(class_type, text, accel_object):
    label = WidgetDef()
    label['class'] = class_type
    label['name'] = make_name()
    label['label'] = text;

    if not class_type == 'GtkMenuItem':
        label['xalign'] = '0.0'

    if class_type == 'GtkAccelLabel':
        label['accel-object'] = accel_object
        label['use-underline'] = 'yes'        

    return label

stock_pixmaps = {
    'REVERT':      'gtk-revert-to-saved',
    'SCORES':      'gnome-stock-scores',
    'SEARCH':      'gtk-find',
    'SEARCHRPL':   'gtk-find-and-replace',
    'BACK':        'gtk-go-back',
    'FORWARD':     'gtk-go-forward',
    'FIRST':       'gtk-goto-first',
    'LAST':        'gtk-goto-last',
    'TIMER':       'gnome-stock-timer',
    'TIMER_STOP':  'gnome-stock-timer-stop',
    'MAIL':        'gnome-stock-mail',
    'MAIL_RCV':    'gnome-stock-mail-rcv',
    'MAIL_SND':    'gnome-stock-mail-send',
    'MAIL_RPL':    'gnome-stock-mail-rply',
    'MAIL_FWD':    'gnome-stock-mail-fwd',
    'MAIL_NEW':    'gnome-stock-mail-new',
    'TRASH':       'gnome-stock-trash',
    'TRASH_FULL':  'gnome-stock-trash-full',
    'SPELLCHECK':  'gtk-spell-check',
    'MIC':         'gnome-stock-mic',
    'LINE_IN':     'gnome-stock-line-in',
    'VOLUME':      'gnome-stock-volume',
    'MIDI':        'gnome-stock-midi',
    'BOOK_RED':    'gnome-stock-book-red',
    'BOOK_GREEN':  'gnome-stock-book-green',
    'BOOK_BLUE':   'gnome-stock-book-blue',
    'BOOK_YELLOW': 'gnome-stock-book-yellow',
    'BOOK_OPEN':   'gnome-stock-book-open',
    'ABOUT':       'gnome-stock-about',
    'MULTIPLE':    'gnome-stock-multiple-file',
    'NOT':         'gnome-stock-not',
    'UP':          'gtk-go-up',
    'DOWN':        'gtk-go-down',
    'TOP':         'gtk-goto-top',
    'BOTTOM':      'gtk-goto-bottom',
    'ATTACH':      'gnome-stock-attach',
    'FONT':        'gtk-select-font',
    'EXEC':        'gtk-execute',

    'ALIGN_LEFT':    'gtk-justify-left',
    'ALIGN_RIGHT':   'gtk-justify-right',
    'ALIGN_CENTER':  'gtk-justify-center',
    'ALIGN_JUSTIFY': 'gtk-justify-fill',

    'TEXT_BOLD':      'gtk-bold',
    'TEXT_ITALIC':    'gtk-italic',
    'TEXT_UNDERLINE': 'gtk-underline',
    'TEXT_STRIKEOUT': 'gtk-strikethrough',

    'TEXT_INDENT':    'gnome-stock-text-indent',
    'TEXT_UNINDENT':  'gnome-stock-text-unindent',
    'EXIT':           'gtk-quit',
    'COLORSELECTOR':  'gtk-select-color',

    'TABLE_BORDERS':  'gnome-stock-table-borders',
    'TABLE_FILL':     'gnome-stock-table-fill',

    'TEXT_BULLETED_LIST': 'gnome-stock-text-bulleted-list',
    'TEXT_NUMBERED_LIST': 'gnome-stock-text-numbered-list',

    'NEXT': 'gtk-go-forward',
    'PREV': 'gtk-go-back'
    }

def stock_icon_translate(old_name):
    if re.match ('GNOME_STOCK_MENU_.*', old_name):
        name = re.sub('GNOME_STOCK_MENU_', '', old_name, 1)
        try:
            return stock_pixmaps[name]
        except KeyError:
            name = re.sub('_', '-', name)
            return 'gtk-' + name.lowere ()
    else:
        return old_name

def stock_button_translate(old_name):
    if re.match ('GNOME_STOCK_BUTTON_.*', old_name):
        name = re.sub('GNOME_STOCK_BUTTON_', '', old_name)
        try:
            return stock_pixmaps[name]
        except KeyError:
            name = re.sub('_', '-', name)
            return 'gtk-' + name.lower ()
    else:
        return old_name

def fixup_as_type(widget, type):

    # table based property removals/renames
    for name in global_obsolete_props:
        widget.remove_prop(name)
    for old, new in global_renamed_props:
        widget.rename_prop(old, new)

    if obsolete_props.has_key(type):
        for name in obsolete_props[type]:
            widget.remove_prop(name)

    if renamed_props.has_key(type):
        for old, new in renamed_props[type]:
            widget.rename_prop(old, new)

    if obsolete_child_props.has_key(type):
        for name in obsolete_child_props[type]:
            for childdef in widget.children:
                childdef.remove_prop(name)

    if renamed_child_props.has_key(type):
        for old, new in renamed_child_props[type]:
            for childdef in widget.children:
                childdef.rename_prop(old, new)

    # add the visible property if missing:
    if not widget.has_prop('visible'):
        widget['visible'] = 'yes'

    # fix up child packing properties for tables
    if type == 'GtkTable':
        for childdef in widget.children:
            options = []
            if childdef.has_prop('xexpand'):
                if childdef['xexpand'] == 'yes':
                    options.append('expand')
                del childdef['xexpand']
            if childdef.has_prop('xshrink'):
                if childdef['xshrink'] == 'yes':
                    options.append('shrink')
                del childdef['xshrink']
            if childdef.has_prop('xfill'):
                if childdef['xfill'] == 'yes':
                    options.append('fill')
                del childdef['xfill']
            if options:
                childdef['x_options'] = string.join(options,'|')
            else: # Gtk+ has some wierd defaults here clobber them
                childdef['x_options'] = ''
            
            options = []
            if childdef.has_prop('yexpand'):
                if childdef['yexpand'] == 'yes':
                    options.append('expand')
                del childdef['yexpand']
            if childdef.has_prop('yshrink'):
                if childdef['yshrink'] == 'yes':
                    options.append('shrink')
                del childdef['yshrink']
            if childdef.has_prop('yfill'):
                if childdef['yfill'] == 'yes':
                    options.append('fill')
                del childdef['yfill']
            if options:
                childdef['y_options'] = string.join(options,'|')
            else: # Gtk+ has some wierd defaults here clobber them
                childdef['y_options'] = ''

    # fixup GtkNotebook child tab widgets.
    if type == 'GtkNotebook':
        for childdef in widget.children:
            if childdef.widget.has_prop ('child_name'):
                if childdef.widget['child_name'] == 'Notebook:tab':
                    del childdef.widget['child_name']
                    childdef['type'] = 'tab';
                else:
                    print >> sys.stderr , 'Unknown child_name', \
                          childdef.widget['child_name']

    # fix up adjustment properties
    if type in ('GtkHScale', 'GtkHScrollbar',
                           'GtkVScale', 'GtkVScrollbar',
                           'GtkSpinButton'):
        collect_adjustment(widget, 'h', 'adjustment') # compat
        collect_adjustment(widget, 'v', 'adjustment') # compat
        collect_adjustment(widget, '', 'adjustment')
    if type in ('GtkViewport', 'GtkLayout', 'GtkScrolledWindow'):
        collect_adjustment(widget, 'h', 'hadjustment')
        collect_adjustment(widget, 'v', 'vadjustment')

    # add label children to menu items.
    if type == 'GtkMenuItem':
        if widget.has_prop('label'):
            widget.add_child ( \
                new_label('GtkAccelLabel', \
                          widget['label'], \
                          widget['name']))
            del widget['label']

    if type == 'GtkImageMenuItem':
        if widget.has_prop('stock_icon'):
            icon = WidgetDef()
            icon['class'] = 'GtkImage'
            icon['name'] = make_name ()
            icon['stock'] = stock_icon_translate (widget['stock_icon'])
            widget.add_child (icon, 'image')
            del widget['stock_icon']

    if type == 'GtkButton':
        if widget.has_prop('stock_button'):
            widget['label'] = stock_button_translate (widget['stock_button'])
            widget['use_stock'] = 'yes'
            widget['use_underline'] = 'yes'
            del widget['stock_button']

    if type == 'GtkDialog':
        childdef = widget.children[0]
        childdef.internal_child = 'vbox'
        del childdef.widget['child_name']

        childdef = filter(lambda x: x.widget.has_prop('child_name'),
                          childdef.widget.children)[0]
        childdef.widget['class'] = 'GtkHButtonBox'
        childdef.internal_child = 'action_area'
        del childdef.widget['child_name']

    if type == 'GtkOptionMenu':
        if widget.has_prop('items'):
            # FIXME: this needs continuing, we need a GtkMenu
            # item, and a hacked up special case to do the
            # set_menu on the optionmenu with it, then we need
            # to pack these ( working ) MenuItems into it
            if not widget['items'] == '':
                menu = WidgetDef()
                menu['class'] = 'GtkMenu'
                menu['name'] = make_name ()
                widget.add_child (menu, 'menu')
                items = widget['items'].split ('\n')
                for item in items:
                    if not item == '':
                        menu.add_child ( \
                            new_label ('GtkMenuItem', \
                                       item, widget['name']))
            del widget['items']
        if widget.has_prop('initial_choice'):
            widget['history'] = widget['initial_choice']
            del widget['initial_choice']

    if type == 'GtkScrolledWindow':
        if widget.has_prop ('hupdate_policy'):
            scroll = WidgetDef ()
            scroll['class'] = 'GtkHScrollbar'
            scroll['name'] = make_name ()
            scroll['update_policy'] = widget['hupdate_policy']
            widget.add_child(scroll, 'hscrollbar')
            del widget['hupdate_policy']
        if widget.has_prop ('vupdate_policy'):
            scroll = WidgetDef ()
            scroll['class'] = 'GtkVScrollbar'
            scroll['name'] = make_name ()
            scroll['update_policy'] = widget['vupdate_policy']
            widget.add_child(scroll, 'vscrollbar')
            del widget['vupdate_policy']


    if type == 'GtkCombo':
        childdef = widget.children[0]
        childdef.internal_child = 'entry'
        del childdef.widget['child_name']

        if widget.has_prop('items'):
            items = widget['items'].split('\n')
            del widget['items']
            list = WidgetDef()
            list['class'] = 'GtkList'
            list['name'] = make_name()
            widget.add_child(list, 'list')
            for item in items:
                listitem = WidgetDef()
                listitem['class'] = 'GtkListItem'
                listitem['name'] = make_name()
                list.add_child(listitem)
                listitem.add_child (new_label ('GtkLabel', item, ''))

    if type == 'GtkCList':
        for childdef in widget.children:
            childdef.internal_child = 'title'
            del childdef.widget['child_name']

    if type == 'GtkLabel' or type == 'GtkButton':
        if widget.has_prop('label'):
            if re.match('.*_.*', widget['label']):
                widget['use_underline'] = 'yes'

    if type == 'GnomeFileEntry':
        childdef = widget.children[0]
        childdef.internal_child = 'entry'
        del childdef.widget['child_name']

    if type == 'GnomePropertyBox':
        childdef = widget.children[0]
        childdef.internal_child = 'notebook'
        del childdef.widget['child_name']
        fixup_as_type (widget, 'GtkWindow')
        return 1 # don't let GtkDialog mangle us ...

    # Whole hog conversion - GnomeDialog is a dead duck.
    if type == 'GnomeDialog':
        widget['class'] = 'GtkDialog'
        fixup_as_type (widget, 'GtkDialog')

    # Fixup radio groups, the 'group' property has to
    # have the glade id of the root group widget.
    if type == 'GtkRadioButton' or type == 'GtkRadioMenuItem':
        if widget.has_prop ('group'):
            if global_group_map.has_key (widget['group']):
                widget['group'] = global_group_map[widget['group']]
            else:
                global_group_map[widget['group']] = widget['name']
                del widget['group']

    return 0

# upgrade widgets to their gtk/gnome 2.0 equivalents
def upgrade_widget(widget):
    do_children = 1

    # use GtkImage for image display now.
    if widget['class'] == 'GtkPixmap':
        widget['class'] = 'GtkImage'
        widget.rename_prop('filename', 'pixbuf')
        widget.remove_prop('build_insensitive')
    if widget['class'] == 'GnomeFontSelector':
        widget['class'] = 'GtkFontSelectionDialog'
    if widget['class'] == 'GnomePixmap':
        widget['class'] = 'GtkImage'
        widget.rename_prop('filename', 'pixbuf')
    if widget['class'] == 'GtkPixmapMenuItem':
        widget['class'] = 'GtkImageMenuItem'

    if do_children:
        for childdef in widget.children:
            upgrade_widget(childdef.widget)

# warn about removed widgets, and build a list of libraries used
bad_widgets = {
    'GtkText': 'broken',
    'GtkTree': 'broken',
    'GtkTreeItem': 'broken',
    'GtkCList': 'deprecated',
    'GtkCTree': 'deprecated',
    'GtkPixmap': 'deprecated',
    'GnomePixmap': 'deprecated',
    'GnomeFontPicker': 'removed',
    'GtkPixmapMenuItem': 'removed'
}
def check_widget(widget, requirelist=[]):
    try:
        error = bad_widgets[widget['class']]
        print >> sys.stderr , 'widget %s of class %s is %s.' % \
              (widget['name'], widget['class'], error)
        if error == 'removed':
                widget.mark_obsolete ()
    except KeyError:
        pass

    if widget['class'] == 'GnomeCanvas':
        if 'canvas' not in requirelist:
            requirelist.append('canvas')
    elif widget['class'][:5] == 'Gnome' and 'gnome' not in requirelist:
        requirelist.append('gnome')
    elif widget['class'][:6] == 'Bonobo' and 'bonobo' not in requirelist:
        requirelist.append('bonobo')

    for childdef in widget.children:
        check_widget(childdef.widget, requirelist)

def hide_toplevel(widget):
    if not widget.has_prop('visible'):
        widget['visible'] = 'no'

# --- parse the file for widget definitions, fixup problems and dump.

def handle_file(filename):
    document = xml.dom.minidom.parse(filename)
    
    widgets = []
    for node in document.documentElement.childNodes:
	if node.nodeType == node.ELEMENT_NODE and \
	   node.nodeName == 'widget':
            widgets.append(handle_widget(node))

    requireslist = []

    for widgetdef in widgets:
        hide_toplevel(widgetdef)
        upgrade_widget(widgetdef)
        fixup_widget(widgetdef)
        check_widget(widgetdef, requireslist)

    print '<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->'
    print '<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd" >'
    print
    print '<glade-interface>'

    for requirement in requireslist:
        print '  <requires lib="%s" />' % requirement
    if requireslist:
        print

    indent = '  '
    for widgetdef in widgets:
        widgetdef.dump(indent)

    print '</glade-interface>'
    document.unlink() # only needed for python interpreters without cyclic gc

usage = 'usage: libglade-convert [--no-upgrade] oldfile.glade'

def main():
    opts, args = getopt.getopt(sys.argv[1:], '',
                               ['no-upgrade', 'help'])
    upgrade = 1
    for opt, arg in opts:
        if opt == '--no-upgrade':
            upgrade = 0
        elif opt == '--help':
            print usage
            sys.exit(0)
    if len(args) != 1:
	print >> sys.stderr, usage
	sys.exit(1)
    handle_file(args[0])

if __name__ == '__main__':
    main()
