HomePage | RecentChanges

Showing revision 4

OpmlToTreeWidget

A simple program to read an OPML file and render it using Gene Cash's Tree widget (for TkInter?).

Notes :

How to use :

Here's the code

from __future__ import generators

from Tree import *
from Tkinter import *
from xml.dom.minidom import parse, parseString

def fUidGen() :
    """Generate Unique IDs. """
    x = 0
    yield x
    while 1 :
        x = x + 1
        yield x

fUid = fUidGen()

class TreeNode :
    """Phil's simple tree is built from these"""
    
    def __init__(self, text='') :
        self.text = text
        self.uid = fUid.next()
        self.tags = []
        self.children = []

    def addChild(self, tNode) :
        self.children.append(tNode)

    def noChildren(self) :
        return len(self.children)

    def getChild(self, i) :
        return self.children[i]
    
    def addTag(self, tag) :
        self.tags.append(tag)

    def addChildText(self, text) :
        node = TreeNode(text)
        self.addChild(node)

    def prettyPrint(self, l) :
        print "%s%s" % ('*' * l, self.text)
        for x in self.children :
            x.prettyPrint(l+1)

class TreeWalker :

    def treeSearch(self, node, uid) :
        """Find the node with this uid"""
        if uid == node.uid :
            return node
        else :
            for x in node.children :
                y = self.treeSearch(x, uid)
                if y != None :
                    return y
        return None


class OpmlToTreeNodes :
    """Mindlessly simplistic and brittle. Uses the minidom"""

    def __init__(self) :
        pass

    def parse(self, s) :
        self.dom = parseString(s)
        return self.dom
    

    def recurse(self, parent, tag) :
        node = TreeNode(tag.getAttribute('text'))
        for child in tag.childNodes :
            if child.nodeType != child.TEXT_NODE :
                self.recurse(node, child)
        parent.addChild(node)
                
    def toTreeNodes(self) :
        root = TreeNode('root')
        tag = self.dom.getElementsByTagName('body')[0]
        for child in tag.childNodes :
            if child.nodeType != child.TEXT_NODE :
                self.recurse(root, child)
        return root


    

if __name__ == '__main__': 
 
    # default routine to get contents of subtree
    # supply this for a different type of app
    # argument is the node object being expanded
    # should call add_node()
            
        
    def get_contents(node):
            """Callback which fills the widget Tree from Phil's TreeNode tree.
            Because this takes only one argument, we need to refer to global "tn"
            which is my Tree. Must be a better way of doing this but may need the
            widget to be rewritten"""
            
            pNode = TreeWalker().treeSearch(tn,node.id)
            if pNode != None : 
                for x in pNode.children :
                    node.widget.add_node(name=x.text, id=x.uid, flag=x.noChildren() > 0)

    root=Tk()
    root.title('Reading test.opml')
    f = open('test.opml')
    xml = f.read()
    f.close()
    o2t = OpmlToTreeNodes()
    o2t.parse(xml)
    tn = o2t.toTreeNodes()
    

    # create the control
    t=Tree(master=root,
           root_id=tn.uid,
           root_label=tn.text,
           get_contents_callback=get_contents,
           width=300)
    t.grid(row=0, column=0, sticky='nsew')

    # make expandable
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    # add scrollbars
    sb=Scrollbar(root)
    sb.grid(row=0, column=1, sticky='ns')
    t.configure(yscrollcommand=sb.set)
    sb.configure(command=t.yview)

    sb=Scrollbar(root, orient=HORIZONTAL)
    sb.grid(row=1, column=0, sticky='ew')
    t.configure(xscrollcommand=sb.set)
    sb.configure(command=t.xview)

    # must get focus so keys work for demo
    t.focus_set()

    # we could do without this, but it's nice and friendly to have
    Button(root, text='Quit', command=root.quit).grid(row=2, column=0,
                                                      columnspan=2)

    # expand out the root
    t.root.expand()
    
    root.mainloop()