When the tree is changed, reset what we know about the selected nodes.
[pysize.git] / core / pysize_fs_node.py
blobf65661720db5910fb04e909c7c160203eba44637
1 import os
2 import stat
4 from core import chdir_browsing
5 from core import compute_size
7 class _pysize_node:
8 """The parent class of all displayed nodes, as these nodes are displayed on
9 screen, there should be few instances."""
10 def __init__(self, parent, basename):
11 self.rectangle = (0, 0, 0, 0)
12 self.parent = parent
13 if basename:
14 self.basename = basename
15 self.size = compute_size.slow(basename)
17 def compute_height(self):
18 return 0
20 def compute_depth(self):
21 depth = 0
22 node = self
23 while node:
24 node = node.parent
25 depth += 1
26 return depth
28 def minimum_real_size(self):
29 res = self.size
30 for child in self.get_children():
31 child_min_real_size = child.minimum_real_size()
32 if child_min_real_size >= 0 and child_min_real_size < res:
33 res = child_min_real_size
34 return res
36 def is_dir(self):
37 return False
39 def is_real(self):
40 """Does the node correspond to a path that actually exists?"""
41 return True
43 def get_children(self):
44 """Return the children for a directory."""
45 return []
47 def get_fullpath(self):
48 """Return the fullpath of the node, using its parent node."""
49 fullpath = self.basename
50 parent = self.parent
51 while parent:
52 fullpath = os.path.join(parent.basename, fullpath)
53 parent = parent.parent
54 return fullpath
56 def get_name(self):
57 """Return the name that should be displayed for this node."""
58 return self.basename
60 def __iter__(self):
61 """The iterator is a depth first traversal."""
62 yield self
63 for child in self.get_children():
64 for node in child:
65 yield node
67 def contains_point(self, p):
68 """Is the point p in the graphical representation of this node?"""
69 (x0, x1, y0, y1) = self.rectangle
70 return x0 < p.x and p.x < x1 and y0 < p.y and p.y < y1
72 class _pysize_node_remaining(_pysize_node):
73 """The sum of a directory's children that are too small to be drawn."""
74 def __init__(self, parent, size):
75 _pysize_node.__init__(self, parent, None)
76 self.basename = '..///..'
77 self.size = size
79 def is_real(self):
80 """This node does not actually exists, it is an aggregate."""
81 return False
83 def minimum_real_size(self):
84 return -1
86 class _pysize_node_dir(_pysize_node):
87 """A directory"""
88 def __init__(self, parent, basename, max_depth, min_size):
89 _pysize_node.__init__(self, parent, basename)
90 self.children = []
91 if max_depth != 0:
92 children_size = 0
93 remaining_size = 0
94 previous_cwd = chdir_browsing.init(basename)
95 try:
96 for child in os.listdir('.'):
97 node = create_node(self, child, max_depth - 1, min_size)
98 if node.is_real():
99 self.children.append(node)
100 children_size += node.size
101 else:
102 remaining_size += node.size
103 finally:
104 chdir_browsing.finalize(previous_cwd)
105 self.children.sort(key=lambda t: t.size, reverse=True)
106 self.size = max(children_size, self.size)
107 if remaining_size > min_size:
108 rem = _pysize_node_remaining(self, remaining_size)
109 self.children.append(rem)
111 def compute_height(self):
112 if self.children:
113 children_height = max([c.compute_height() for c in self.children])
114 return children_height + 1
115 return 0
117 def is_dir(self):
118 return True
120 def get_children(self):
121 return self.children
123 def get_name(self):
124 return self.basename + '/'
126 class _pysize_node_file(_pysize_node):
127 """A file"""
128 def __init__(self, parent, basename):
129 _pysize_node.__init__(self, parent, basename)
131 class _pysize_node_hardlink(_pysize_node_file):
132 """A hardlink, the canonical one, or a link"""
133 def __init__(self, parent, basename):
134 _pysize_node_file.__init__(self, parent, basename)
136 def create_node(parent, basename, max_depth, min_size):
137 """Return a pysize_node for parent/basename traversing up to max_depth
138 levels and only taking into account elements bigger than min_size."""
139 if not basename:
140 return _pysize_node_remaining(parent, 0)
141 size = compute_size.slow(basename)
142 if size < min_size:
143 node = _pysize_node_remaining(parent, size)
144 else:
145 st = os.lstat(basename)
146 if stat.S_ISDIR(st.st_mode):
147 node = _pysize_node_dir(parent, basename, max_depth, min_size)
148 elif st.st_nlink > 1:
149 node = _pysize_node_hardlink(parent, basename)
150 else:
151 node = _pysize_node_file(parent, basename)
152 return node