from cElementTree import iterparse
import sys
import qt

def handleprops(widget, elem):
    def geometry(prop):
        x = int(prop.findtext("rect/x"))
        y = int(prop.findtext("rect/y"))
        w = int(prop.findtext("rect/width"))
        h = int(prop.findtext("rect/height"))
        widget.setGeometry(qt.QRect(x, y, w, h))

    def text(prop):
        widget.setText(prop.findtext("string"))

    def name(prop):
        widget.setName(prop.findtext("cstring"))

    def caption(prop):
        widget.setCaption(prop.findtext("string"))
    
    properties = {
        "geometry": geometry,
        "text" : text,
        "name" : name,
        "caption": caption
        }

    for prop in elem.findall("property"):
        try:
            properties[prop.attrib["name"]](prop)
        except KeyError:
            print "unhandled property: %s" % (prop.attrib["name"], )
    

def parseUI(filename, subclass):
    def maketoplevel(wtype):
        subclass.__bases__ = (type(wtype()),)
        w = subclass()
        wtype.__init__(w)
        toplevel.append(w)
        return w
                              
        
    def addtolayout(w, elem):
        if len(layoutStack):
            if isinstance(w, qt.QWidget):
                layoutStack[-1].addWidget(w, int(elem.attrib["row"]),
                                          int(elem.attrib["column"]))
            else:
                layoutStack[-1].addItem(w, int(elem.attrib["row"]),
                                          int(elem.attrib["column"]))
        
    def newwidget(elem):
        if len(widgetStack) == 1:
            w = maketoplevel(getattr(qt, elem.attrib["class"]))
        else:
            w  = getattr(qt, elem.attrib["class"])(widgetStack[-1])
        widgetStack.append(w)
        addtolayout(w, elem)
        handleprops(w, elem)

        
    def newspacer(elem):
        w = int(elem.findtext("property/size/width"))
        h = int(elem.findtext("property/size/height"))
        orientation = 0
        policy = 0
        for p in elem.findall("property/enum"):
            if p.text == "Vertical":
                orientation = 1
            elif p.text == "Horizontal":
                pass
            else:
                policy = getattr(qt.QSizePolicy, p.text)
        if orientation:
            sp = qt.QSpacerItem(w, h, qt.QSizePolicy.Minimum, policy)
        else:
            sp = qt.QSpacerItem(w, h, policy, qt.QSizePolicy.Minimum)
        addtolayout(sp, elem)

        
    def newgrid(elem):
        rows = 0
        cols = 0
        for child in list(elem):
            try:
                i = int(child.attrib["row"])
                if i > rows:
                    rows = i
                i = int(child.attrib["column"])
                if i > cols:
                    cols = i
            except KeyError:
                pass
        layoutStack.append(qt.QGridLayout(widgetStack[-1], rows, cols,
                                          defaults["margin"], defaults["spacing"]))


    def getdefaults(elem):
        u = elem.findall("layoutdefaults")
        defaults.update(u.attrib)
    
    widgetStack = [None]
    layoutStack = []
    toplevel = []
    defaults = {"margin": 11,
               "spacing" : 6}
    actions = {
        ("UI", "start"): getdefaults,
        ("start", "widget"): newwidget,
        ("end", "widget"): lambda elem: widgetStack.pop(),
        ("start", "grid"): newgrid,
        ("end", "grid"): lambda elem: layoutStack.pop(),
        ("start", "spacer"): newspacer
        }
    for event, elem in iterparse(filename, events=("start", "end")):
        try:
            actions[(event, elem.tag)](elem)
        except KeyError:
            print "unsupported action (%s, %s)" % (event, elem.tag)
    return toplevel[0]
    

class BeBiBu(qt.QWidget):
    def closeEvent(self, e):
        print "in closeEvent!"
        e.accept()

if __name__ == "__main__":
    app = qt.QApplication(sys.argv)
    qt.QObject.connect(app, qt.SIGNAL("lastWindowClosed()"), app, qt.SLOT("quit()"))
    w = parseUI("test1.ui", BeBiBu)
    w.show()
    app.exec_loop()
