#!/usr/bin/env python
'''This application shows a nice tree view of the UML meta model.

Somehow, this peace of code seems to crash by X server. I thinnk it's a bug in
GTK+. ... but how do I isolate the bug?
'''

import sys
sys.path.append("..")

from gaphor.UML import *
import gtk
import gobject
import types


# to create a new GtkTreeModel from python, you must derive from
# GenericTreeModel.
class TreeModel(gtk.GenericTreeModel):
    ''' The node is defined by a "name" tuple. '''

    def __init__(self, klass):
	'''constructor for the model.  Make sure you call
	PyTreeModel.__init__'''
	self.iter = None # Value used to keep track of iterations.
	self.klass = klass;
	
	gtk.GenericTreeModel.__init__(self)

    def class_from_node(self, node):
        klass = self.klass
        for n in node:
	    attrdef = klass._attrdef[n]
	    klass = attrdef[1]
	return klass

    # the implementations for TreeModel methods are prefixed with on_
    def on_get_flags(self):
	'''returns the GtkTreeModelFlags for this particular type of model'''
	return 0

    def on_get_n_columns(self):
	'''returns the number of columns in the model'''
	return 1

    def on_get_column_type(self, index):
	'''returns the type of a column in the model'''
	return gobject.TYPE_STRING

    def on_get_path(self, node):
	'''returns the tree path (a tuple of indices at the various
	levels) for a particular node.'''
	print "on_get_path", node
	return node

    def on_get_iter(self, path):
        '''returns the node corresponding to the given path. The patch is a
	   tuple of values, like (0 1 1). We have to figure out a path that is
	   easy to use by on_get_value() and can also be easely extended by
	   on_iter_children() and chopped by on_iter_parent()'''
	def get_iter(klass, path):
	    item = klass._attrdef.items()[path[0]]
	    if len(path) == 1:
		return (item[0],)
	    else:
	        subklass = klass._attrdef.items()[path[0]][1][1]
		return (item[0],) + get_iter(subklass, path[1:])
	
        node = get_iter(self.klass, path)
	
	#print "on_get_iter", path, node
	return node

    def on_get_value(self, node, column):
	'''returns the value stored in a particular column for the node'''
	assert column == 0
	attr = node[-1]
	parent = self.class_from_node(node[:-1])
	attrdef = parent._attrdef[attr]
	#print "on_get_value", node, attrdef
	closing = ")"
	if attrdef[0] == Sequence:
	    closing = "*)"
	    
	if len(attrdef) == 3:
	    return attr + " (" + attrdef[1].__name__ + "::" + attrdef[2] + closing
	else:
	    return attr + " (" + attrdef[1].__name__ + closing

    def on_iter_next(self, node):
	'''returns the next node at this level of the tree'''
	attr = node[-1]
	parent = self.class_from_node(node[:-1])
	attrdef = parent._attrdef[attr]
	items = parent._attrdef.items()
	sentinel = 0
	for i in items:
	    if sentinel:
	        node = node[:-1] + (i[0],)
		#print "on_iter_next", node
		return node
	    elif i[0] == attr:
	        sentinel = 1 # Use next item
	#print "on_iter_next (None)"
        return None

    def on_iter_children(self, node):
	'''returns the first child of this node'''
	klass = self.class_from_node(node)
	if klass.__dict__.has_key("_attrdef"):
	    item = klass._attrdef.items()[0][0]
	    #print "on_iter_children", node, item
	    return node + (item,)
	else:
	    #print "on_iter_children (None)"
	    return None

    def on_iter_has_child(self, node):
	'''returns true if this node has children'''
	#return 0
	klass = self.class_from_node(node)
	#print "on_iter_has_child", node
	return klass.__dict__.has_key("_attrdef") and len(klass._attrdef) > 0

    def on_iter_n_children(self, node):
	'''returns the number of children of this node'''
	klass = self.class_from_node(node)
	if klass.__dict__.has_key("_attrdef"):
	    items = klass._attrdef.items()
	    #print "on_iter_n_children", len(items)
	    return len(items) - 1
	else:
	    #print "on_iter_n_children (None)"
	    return 0

    def on_iter_nth_child(self, node, n):
	'''returns the nth child of this node'''
	#print "on_iter_nth_child"
        if node == None:
	    #print 'result =', n, self.klass._attrdef.items()[0][0]
            return (self.klass._attrdef.items()[0][0],)
        klass = self.class_from_node(node)
	if klass.__dict__.has_key("_attrdef") and len(node) >= n:
	    item = klass._attrdef.items()[n][0]
	    #print "on_iter_nth_child", node, klass.__name__, item
	    #print 'result =', n, node, item
	    return node + (item,)
	else:
	    #print 'result =', n, None
	    return None

    def on_iter_parent(self, node):
	'''returns the parent of this node'''
	#print "on_iter_parent", node
	return node[:-1]

def main():
    args = sys.argv[1:]
    
    base_class = None
    try:
        base_class = eval(args[0])
    except NameError:
        print "Invalid class name (" + args[0] + ")"
        sys.exit(1)
    except IndexError:
	print "Use gbrowseUML.py <class>, now using class ModelElement"
	base_class = ModelElement

    window = gtk.Window()
    window.connect('destroy', lambda win: gtk.main_quit())
    window.set_title('gbrowseUML -- ' + base_class.__name__)
    window.set_default_size(250, 400)

    scrolled_window = gtk.ScrolledWindow()
    scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    window.add(scrolled_window)

    model = TreeModel(base_class)
    tree_view = gtk.TreeView(model)
    cell = gtk.CellRendererText()
    # the text in the column comes from column 0
    column = gtk.TreeViewColumn(base_class.__name__, cell, text=0)
    tree_view.append_column(column)

    scrolled_window.add(tree_view)
    window.show_all()

    gtk.main()

if __name__ == '__main__':
    main()
else:
    del main
