| OLD | NEW | 
 | (Empty) | 
|    1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. |  | 
|    2 # See LICENSE for details. |  | 
|    3  |  | 
|    4 """ |  | 
|    5 What I want it to look like: |  | 
|    6  |  | 
|    7 +- One |  | 
|    8 | \- Two |  | 
|    9 | |- Three |  | 
|   10 | |- Four |  | 
|   11 | +- Five |  | 
|   12 | | \- Six |  | 
|   13 | |- Seven |  | 
|   14 +- Eight |  | 
|   15 | \- Nine |  | 
|   16 """ |  | 
|   17  |  | 
|   18 import os |  | 
|   19 from Tkinter import * |  | 
|   20  |  | 
|   21 class Node: |  | 
|   22     def __init__(self): |  | 
|   23         """ |  | 
|   24         Do whatever you want here. |  | 
|   25         """ |  | 
|   26         self.item=None |  | 
|   27     def getName(self): |  | 
|   28         """ |  | 
|   29         Return the name of this node in the tree. |  | 
|   30         """ |  | 
|   31         pass |  | 
|   32     def isExpandable(self): |  | 
|   33         """ |  | 
|   34         Return true if this node is expandable. |  | 
|   35         """ |  | 
|   36         return len(self.getSubNodes())>0 |  | 
|   37     def getSubNodes(self): |  | 
|   38         """ |  | 
|   39         Return the sub nodes of this node. |  | 
|   40         """ |  | 
|   41         return [] |  | 
|   42     def gotDoubleClick(self): |  | 
|   43         """ |  | 
|   44         Called when we are double clicked. |  | 
|   45         """ |  | 
|   46         pass |  | 
|   47     def updateMe(self): |  | 
|   48         """ |  | 
|   49         Call me when something about me changes, so that my representation |  | 
|   50         changes. |  | 
|   51         """ |  | 
|   52         if self.item: |  | 
|   53             self.item.update() |  | 
|   54  |  | 
|   55 class FileNode(Node): |  | 
|   56     def __init__(self,name): |  | 
|   57         Node.__init__(self) |  | 
|   58         self.name=name |  | 
|   59     def getName(self): |  | 
|   60         return os.path.basename(self.name) |  | 
|   61     def isExpandable(self): |  | 
|   62         return os.path.isdir(self.name) |  | 
|   63     def getSubNodes(self): |  | 
|   64         names=map(lambda x,n=self.name:os.path.join(n,x),os.listdir(self.name)) |  | 
|   65         return map(FileNode,names) |  | 
|   66  |  | 
|   67 class TreeItem: |  | 
|   68     def __init__(self,widget,parent,node): |  | 
|   69         self.widget=widget |  | 
|   70         self.node=node |  | 
|   71         node.item=self |  | 
|   72         if self.node.isExpandable(): |  | 
|   73             self.expand=0 |  | 
|   74         else: |  | 
|   75             self.expand=None |  | 
|   76         self.parent=parent |  | 
|   77         if parent: |  | 
|   78             self.level=self.parent.level+1 |  | 
|   79         else: |  | 
|   80             self.level=0 |  | 
|   81         self.first=0 # gets set in Tree.expand() |  | 
|   82         self.subitems=[] |  | 
|   83     def __del__(self): |  | 
|   84         del self.node |  | 
|   85         del self.widget |  | 
|   86     def __repr__(self): |  | 
|   87         return "<Item for Node %s at level %s>"%(self.node.getName(),self.level) |  | 
|   88     def render(self): |  | 
|   89         """ |  | 
|   90         Override in a subclass. |  | 
|   91         """ |  | 
|   92         raise NotImplementedError |  | 
|   93     def update(self): |  | 
|   94         self.widget.update(self) |  | 
|   95  |  | 
|   96 class ListboxTreeItem(TreeItem): |  | 
|   97     def render(self): |  | 
|   98         start=self.level*"|    " |  | 
|   99         if self.expand==None and not self.first: |  | 
|  100             start=start+"|" |  | 
|  101         elif self.expand==0: |  | 
|  102             start=start+"L" |  | 
|  103         elif self.expand==1: |  | 
|  104             start=start+"+" |  | 
|  105         else: |  | 
|  106             start=start+"\\" |  | 
|  107         r=[start+"- "+self.node.getName()] |  | 
|  108         if self.expand: |  | 
|  109             for i in self.subitems: |  | 
|  110                 r.extend(i.render()) |  | 
|  111         return r |  | 
|  112  |  | 
|  113 class ListboxTree: |  | 
|  114     def __init__(self,parent=None,**options): |  | 
|  115         self.box=apply(Listbox,[parent],options) |  | 
|  116         self.box.bind("<Double-1>",self.flip) |  | 
|  117         self.roots=[] |  | 
|  118         self.items=[] |  | 
|  119     def pack(self,*args,**kw): |  | 
|  120         """ |  | 
|  121         for packing. |  | 
|  122         """ |  | 
|  123         apply(self.box.pack,args,kw) |  | 
|  124     def grid(self,*args,**kw): |  | 
|  125         """ |  | 
|  126         for gridding. |  | 
|  127         """ |  | 
|  128         apply(self.box.grid,args,kw) |  | 
|  129     def yview(self,*args,**kw): |  | 
|  130         """ |  | 
|  131         for scrolling. |  | 
|  132         """ |  | 
|  133         apply(self.box.yview,args,kw) |  | 
|  134     def addRoot(self,node): |  | 
|  135         r=ListboxTreeItem(self,None,node) |  | 
|  136         self.roots.append(r) |  | 
|  137         self.items.append(r) |  | 
|  138         self.box.insert(END,r.render()[0]) |  | 
|  139         return r |  | 
|  140     def curselection(self): |  | 
|  141         c=self.box.curselection() |  | 
|  142         if not c: return |  | 
|  143         return self.items[int(c[0])] |  | 
|  144     def flip(self,*foo): |  | 
|  145         if not self.box.curselection(): return |  | 
|  146         item=self.items[int(self.box.curselection()[0])] |  | 
|  147         if item.expand==None: return |  | 
|  148         if not item.expand: |  | 
|  149             self.expand(item) |  | 
|  150         else: |  | 
|  151             self.close(item) |  | 
|  152         item.node.gotDoubleClick() |  | 
|  153     def expand(self,item): |  | 
|  154         if item.expand or item.expand==None: return |  | 
|  155         item.expand=1 |  | 
|  156         item.subitems=map(lambda x,i=item,s=self:ListboxTreeItem(s,i,x),item.nod
     e.getSubNodes()) |  | 
|  157         if item.subitems: |  | 
|  158             item.subitems[0].first=1 |  | 
|  159         i=self.items.index(item) |  | 
|  160         self.items,after=self.items[:i+1],self.items[i+1:] |  | 
|  161         self.items=self.items+item.subitems+after |  | 
|  162         c=self.items.index(item) |  | 
|  163         self.box.delete(c) |  | 
|  164         r=item.render() |  | 
|  165         for i in r: |  | 
|  166             self.box.insert(c,i) |  | 
|  167             c=c+1 |  | 
|  168     def close(self,item): |  | 
|  169         if not item.expand: return |  | 
|  170         item.expand=0 |  | 
|  171         length=len(item.subitems) |  | 
|  172         for i in item.subitems: |  | 
|  173             self.close(i) |  | 
|  174         c=self.items.index(item) |  | 
|  175         del self.items[c+1:c+1+length] |  | 
|  176         for i in range(length+1): |  | 
|  177             self.box.delete(c) |  | 
|  178         self.box.insert(c,item.render()[0]) |  | 
|  179     def remove(self,item): |  | 
|  180         if item.expand: |  | 
|  181             self.close(item) |  | 
|  182         c=self.items.index(item) |  | 
|  183         del self.items[c] |  | 
|  184         if item.parent: |  | 
|  185             item.parent.subitems.remove(item) |  | 
|  186         self.box.delete(c) |  | 
|  187     def update(self,item): |  | 
|  188         if item.expand==None: |  | 
|  189             c=self.items.index(item) |  | 
|  190             self.box.delete(c) |  | 
|  191             self.box.insert(c,item.render()[0]) |  | 
|  192         elif item.expand: |  | 
|  193             self.close(item) |  | 
|  194             self.expand(item) |  | 
|  195  |  | 
|  196 if __name__=="__main__": |  | 
|  197     tk=Tk() |  | 
|  198     s=Scrollbar() |  | 
|  199     t=ListboxTree(tk,yscrollcommand=s.set) |  | 
|  200     t.pack(side=LEFT,fill=BOTH) |  | 
|  201     s.config(command=t.yview) |  | 
|  202     s.pack(side=RIGHT,fill=Y) |  | 
|  203     t.addRoot(FileNode("C:/")) |  | 
|  204     #mainloop() |  | 
| OLD | NEW |