#!/usr/bin/env python
#
# $Id: NavigableTree.py,v 1.5 2001/11/03 11:05:22 doughellmann Exp $
#
# Copyright 2001 Doug Hellmann.
#
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Doug
# Hellmann not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
"""Tree data structure to be used with TreeNavigator widget.
"""
__rcs_info__ = {
#
# Creation Information
#
'module_name' : '$RCSfile: NavigableTree.py,v $',
'rcs_id' : '$Id: NavigableTree.py,v 1.5 2001/11/03 11:05:22 doughellmann Exp $',
'creator' : 'Doug Hellmann <doug@hellfly.net>',
'project' : 'PmwContribD',
'created' : 'Sat, 21-Apr-2001 12:31:04 EDT',
#
# Current Information
#
'author' : '$Author: doughellmann $',
'version' : '$Revision: 1.5 $',
'date' : '$Date: 2001/11/03 11:05:22 $',
}
#
# Import system modules
#
import Tkinter, Canvas
import Pmw
import sys, os, string, math
#
# Import Local modules
#
import AnimatedFolder, AnimatedFileIcon
#
# Module
#
class NavigableTree:
"""Tree data structure to be used with TreeNavigator widget.
"""
icon_padding = 4
def __init__(self, name, data=None, parent=None, children=[],
icon_type=AnimatedFolder.AnimatedFolder,
no_child_icon_type=AnimatedFileIcon.AnimatedFileIcon):
"""Create a NavigableTree, possibly with known children.
Arguments
name -- Name of the root node of the tree.
data -- Data associated with the root node of the tree.
parent -- Parent node, if any.
children=[] -- Child nodes, if any.
icon_type=AnimatedFolder.AnimatedFolder -- Class to
instantiate when an icon is needed to represent this node.
Should support AnimatedIcon interfaces.
no_child_icon_type=AnimatedFileIcon.AnimatedFileIcon --
Class to instantiate when an icon is needed to represent
this node and the node has no children. Should support
AnimatedIcon interfaces.
Attributes
data -- Any piece of data which should be attached to the
node. This is maintained by the data structure, but not used
directly. It is present to make the tree data structure
useful.
icon_type -- A subclass of the PmwContribD.AnimatedIcon
class, this attribute is used to create icons when the tree
is being displayed in a TreeNavigator.
name -- The name of the node. It is usually useful to have a
string displayed in the TreeNavigator to represent the
node. The default '__str__' method uses the name attribute.
"""
self.name = name
self.data = data
self._children = children
self._parent = parent
self.icon_type = icon_type
self.no_child_icon_type = no_child_icon_type
#print 'parent of "%s" is "%s"' % (name, parent)
return
def add_children(self, new_children=[]):
"""Add children to the existing children of the node.
Arguments
new_children=[] -- Sequence of child nodes.
"""
#self._children = tuple(self._children) + tuple(new_children)
self._children = self._children + list(new_children)
return
def children(self):
"""Returns the children for this node.
"""
l = list(self._children)
l.sort()
return l
def has_children(self):
"Returns boolean indicating whether this node has children."
return len(self._children)
def getpath(self):
"""Find this node's place in the tree.
Returns the path from the root of the tree containing
this node all the way down to this node.
"""
if self._parent:
return self._parent.getpath() + (self,)
else:
return (self,)
def create_icon(self, canvas, command=None, state=None):
"""Create the icon for this node.
Given a canvas, and possibly a command to call on ButtonPress,
create an icon for this node. Our icon should be the only
icon on the canvas (although it does not have to be the only
drawing).
Arguments
canvas -- Widget on which to draw.
command -- Callable object to be called on ButtonPress on
the icon.
state=None -- State the icon should be in to start.
"""
self.canvas = canvas
width=canvas.winfo_width()
if width > self.icon_padding:
width = width - self.icon_padding
height=canvas.winfo_height()
if height > self.icon_padding:
height = height - self.icon_padding
if self.children():
icon_type = self.icon_type
else:
icon_type = self.no_child_icon_type
self.icon = icon_type(canvas, name=self.name,
ulx=self.icon_padding,
uly=self.icon_padding,
width=width,
height=height,
command=command)
canvas.bind('<Configure>', self.resize_icon)
self.icon.set_state(state)
return self.icon
def resize_icon(self, event):
"""Change the size of the icon based on an event.
Usually resizes the icon for this node when the canvas to
which it is attached is redrawn.
"""
#width=event.width - (2*self.icon_padding)
#height = (width * 1.0) * (4.0/5.0)
height = event.height - (2*self.icon_padding)
width = height * 1.25
self.icon.set_geometry(width=width, height=height)
self.icon.redraw()
return
def __str__(self):
"""Return a string representation of ourself. (our name)
"""
return str(self.name)
def __cmp__(self, other):
"""Comparison method for sorting.
Compare names.
"""
if not other:
return 37
return cmp(self.name, other.name)
def create_from_tuples(data, parent=None):
"""Given a nested set of tuples, create a NavigableTree.
"""
t = NavigableTree(data[0], data=data[1], parent=parent)
c = []
for subt in data[2]:
c.append(create_from_tuples(subt, parent=t))
t.add_children(c)
return t
class NavigableFileTree(NavigableTree):
"NavigableTree which works on files in a directory."
def __init__(self,
name,
data=None,
parent=None,
children=[],
icon_type=AnimatedFolder.AnimatedFolder):
NavigableTree.__init__(self,
name,
data=data,
parent=parent,
children=children,
icon_type=icon_type)
self.full_path = node_seq_to_filename(self.getpath())
return
def children(self):
print 'getting children of %s' % self.full_path
child_names = os.listdir(self.full_path)
print 'got %d files' % len(child_names)
children = map(lambda x, s=self: create_from_directory(
os.path.join(s.full_path, x), parent=s
),
child_names)
return list(children)
def has_children(self):
if os.path.isdir(self.full_path):
return len(os.listdir(self.full_path))
else:
return 0
def create_from_directory(directory, data=None, parent=None,
directory_node_type=NavigableFileTree,
file_node_type=NavigableTree):
"""
Given a root directory, create a NavigableTree reflecting the
contents of the filesystem.
"""
basename=os.path.basename(directory)
if not basename:
basename = directory
if os.path.isdir(directory):
t =directory_node_type(basename, data=data, parent=parent)
else:
t = file_node_type(basename,
data=data,
parent=parent,
icon_type=AnimatedFileIcon.AnimatedFileIcon)
return t
def old_create_from_directory(directory, data=None, parent=None,
directory_node_type=NavigableTree,
file_node_type=NavigableTree):
"""
Given a root directory, create a NavigableTree reflecting the
contents of the filesystem.
"""
basename=os.path.basename(directory)
if not basename:
basename = directory
if os.path.isdir(directory):
t =directory_node_type(basename, data=data, parent=parent)
contents = os.listdir(directory)
c = []
for subt in contents:
subname=os.path.join(directory, subt)
c.append(create_from_directory(subname, data=data, parent=t,
directory_node_type=directory_node_type,
file_node_type=file_node_type))
t.add_children(c)
else:
t = file_node_type(basename,
data=data,
parent=parent,
icon_type=AnimatedFileIcon.AnimatedFileIcon)
return t
def node_seq_to_filename(node_seq):
"""
Given a sequence of NavigableTrees (as returned by NavigableTree.getpath()),
combine the node names into a filename.
"""
return apply(os.path.join, tuple(map(str, node_seq)))
|