# tree widget demo showing how to subclass a node for special behaviour
#
# 16-OCT-01 CEC created
# 10-FEB-02 CEC updated with new ins_bef(), ins_aft(), ins_chld()
#               menu items

import os
import Tree
from Tkinter import *

class MyNodes(Tree.Node):
    def __init__(self, *args, **kw_args):
        # call superclass
        apply(Tree.Node.__init__, (self,)+args, kw_args)
        # bind right-click
        self.widget.tag_bind(self.symbol, '<3>', self.popup_menu)
        self.widget.tag_bind(self.label, '<3>', self.popup_menu)

    # pop up menu on right click
    def popup_menu(self, event):
        menu=Menu(self.widget, tearoff=0)
        menu.add_command(label='Cut', command=self.cut)
        if cut_obj:
            menu.add_command(label='Paste', command=self.paste)
        else:
            menu.add_command(label='Paste', command=self.paste,
                             state='disabled')
        menu.add_command(label='Insert Before', command=self.ins_bef)
        menu.add_command(label='Insert After', command=self.ins_aft)
        menu.add_command(label='Insert Child', command=self.ins_chld)
        menu.tk_popup(event.x_root, event.y_root)

    # cut'n'paste
    def cut(self):
        global cut_id, cut_name, cut_label, cut_expanded_icon, \
               cut_collapsed_icon, cut_expandable_flag, cut_obj

        cut_obj=1
        cut_id=self.id
        cut_expanded_icon=self.expanded_icon
        cut_collapsed_icon=self.collapsed_icon
        cut_expandable_flag=self.expandable_flag
        cut_name=self.get_label()
        self.delete()

    def paste(self):
        if self == self.widget.root:
            self.insert_children(
                self.widget.add_list(name=cut_name,
                                     id=cut_id,
                                     flag=cut_expandable_flag,
                                     expanded_icon=cut_expanded_icon,
                                     collapsed_icon=cut_collapsed_icon))
        else:
            self.insert_before(
                self.widget.add_list(name=cut_name,
                                     id=cut_id,
                                     flag=cut_expandable_flag,
                                     expanded_icon=cut_expanded_icon,
                                     collapsed_icon=cut_collapsed_icon))
        cut_obj=None

    def ins_bef(self):
        n=self.widget.add_list(name='Inserted before '+self.get_label())
        self.insert_before(n)

    def ins_aft(self):
        n=self.widget.add_list(name='Inserted after '+self.get_label())
        self.insert_after(n)

    def ins_chld(self):
        n=self.widget.add_list(name='Inserted as child of '+self.get_label())
        self.insert_children(n)

def getfiles(node):
    path=apply(os.path.join, node.full_id())
    for filename in os.listdir(path):
        full=os.path.join(path, filename)
        name=filename
        folder=0
        if os.path.isdir(full):
            # it's a directory
            folder=1
        elif not os.path.isfile(full):
            # but it's not a file
            name=name+' (special)'
        if os.path.islink(full):
            # it's a link
            name=name+' (link to '+os.readlink(full)+')'
        t.add_node(name=name, id=filename, flag=folder)

cut_obj=None
root=Tk()
root.title(os.path.basename(sys.argv[0]))

# create the control
t=Tree.Tree(master=root,
            root_id=os.sep,
            root_label=os.sep,
            get_contents_callback=getfiles,
            width=300,
            node_class=MyNodes)
t.grid(row=0, column=0, sticky='nsew')

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

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)

t.focus_set()
t.root.expand()

root.mainloop()
