"Fossies" - the Fresh Open Source Software Archive 
Member "pysize-0.2/pysize/ui/curses/ui_curses.py" (11 Mar 2007, 7499 Bytes) of package /linux/privat/old/pysize-0.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ui_curses.py" see the
Fossies "Dox" file reference documentation.
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
5 #
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
10 #
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14 #
15 # See the COPYING file for license information.
16 #
17 # Copyright (c) 2006, 2007 Guillaume Chazarain <guichaz@yahoo.fr>
18
19 import curses
20 import sys
21 import time
22
23 from pysize.ui.utils import human_unit, short_string, update_progress
24 from pysize.ui.utils import sanitize_string, UINotAvailableException
25 from pysize.ui.char_matrix import CharMatrix, MASK, SELECTED
26 from pysize.core.pysize_fs_tree import pysize_tree
27 from pysize.core.compute_size import size_observable
28
29 class _CursesApp(object):
30 """The curses UI."""
31 def __init__(self, win, options, args):
32 self.window = win
33 self.options = options
34 self.max_depth = options.max_depth
35 if options.min_size != 'auto':
36 raise Exception, 'curses UI supports only --min-size=auto'
37 self._set_paths(args)
38 self._init_curses()
39 self.last_star = 0
40 self.last_star_time = time.time()
41 size_observable.add_observer(self.draw_star)
42
43 def draw_star(self):
44 progress = update_progress()
45 if progress:
46 self.status_win.insch(0, self.width - 1, progress, curses.A_REVERSE)
47 self.status_win.refresh()
48
49 def _init_curses(self):
50 curses.use_default_colors()
51 curses.start_color()
52 curses.curs_set(0)
53
54 def dots(*positions):
55 return sum(map(lambda n: 1<<n, positions))
56
57 self.MATRIX_TO_CURSES = {
58 dots(): ' ',
59 dots(3, 4, 5): curses.ACS_HLINE,
60 dots(1, 4, 7): curses.ACS_VLINE,
61 dots(1, 3, 4, 5, 7): curses.ACS_PLUS,
62 dots(4, 5, 7): curses.ACS_ULCORNER,
63 dots(3, 4, 7): curses.ACS_URCORNER,
64 dots(1, 4, 5): curses.ACS_LLCORNER,
65 dots(1, 3, 4): curses.ACS_LRCORNER,
66 dots(3, 4, 5, 7): curses.ACS_TTEE,
67 dots(1, 3, 4, 5): curses.ACS_BTEE,
68 dots(1, 4, 5, 7): curses.ACS_LTEE,
69 dots(1, 3, 4, 7): curses.ACS_RTEE
70 }
71
72 try:
73 self.status_win = curses.newwin(0, 0)
74 self.panel = curses.newwin(0, 0)
75 self._resize()
76 except curses.error:
77 print 'Cannot create windows'
78 sys.exit(1)
79
80 def _resize(self):
81 """Called when the terminal size changes."""
82 self.height, self.width = self.window.getmaxyx()
83 self.height -= 1 # Status bar
84 self.need_tree = True
85 self.status_win.resize(1, self.width)
86 self.status_win.mvwin(self.height, 0)
87 self.panel.resize(self.height, self.width)
88 self._set_paths(self.paths)
89 self._refresh()
90
91 def _redraw(self):
92 self.window.refresh()
93 if self.need_tree:
94 # -1 accounts for the last horizontal line
95 self.tree = pysize_tree(self.paths, self.max_depth,
96 2.0 / (self.height - 1), self.options)
97 self.need_tree = False
98 if not self.tree.root:
99 return
100 self.panel.erase()
101
102 self._draw_matrix(CharMatrix(self.width, self.height, self.tree,
103 self.selected_node))
104
105 self.panel.refresh()
106 self.status_win.erase()
107 self.status_win.hline(0, 0, ord(' ') | curses.A_REVERSE, self.width)
108 status_line = sanitize_string(self.tree.root.get_name()) + ' '
109 status_line += human_unit(self.tree.root.size)
110 END = ' - Pysize'
111 if len(status_line) + len(END) >= self.width:
112 status_line = short_string(status_line, self.width - 2)
113 else:
114 status_line += END
115 self.status_win.addstr(status_line, curses.A_REVERSE)
116 self.status_win.refresh()
117
118 def _refresh(self):
119 while True:
120 try:
121 self._redraw()
122 break
123 except curses.error, e:
124 print e
125 time.sleep(1)
126
127 def _set_paths(self, paths):
128 self.selected_node = None
129 self.selection = None
130 self.paths = paths
131 self.need_tree = True
132
133 def _next_step(self):
134 self._set_paths([self.selected_node.get_dirname()])
135
136 def _select(self, function):
137 if not self.selected_node:
138 if self.tree.root.children:
139 self.selected_node = self.tree.root.children[0]
140 else:
141 # Forcing browsing to the left
142 self._set_paths([self.tree.root.get_dirname()])
143 return
144 selected = function(self.selected_node)
145 if not selected:
146 if function == self.tree.get_first_child and \
147 self.selected_node.is_dir():
148 # Browsing to the right
149 self._next_step()
150 return
151 self.selected_node = selected
152 if self.selected_node == self.tree.root:
153 # Browsing to the left
154 self._set_paths([self.tree.root.get_dirname()])
155
156 def _selected(self):
157 if self.selected_node:
158 self._set_paths(self.selected_node.get_fullpaths())
159
160 def run(self):
161 """The main dispatcher."""
162 key_bindings = {
163 ord('q'): lambda:
164 sys.exit(0),
165
166 curses.KEY_RESIZE: lambda:
167 self._resize(),
168
169 curses.KEY_DOWN: lambda:
170 self._select(self.tree.get_next_sibling),
171
172 curses.KEY_UP: lambda:
173 self._select(self.tree.get_previous_sibling),
174
175 curses.KEY_LEFT: lambda:
176 self._select(self.tree.get_parent),
177
178 curses.KEY_RIGHT: lambda:
179 self._select(self.tree.get_first_child),
180
181 ord('\n'): lambda:
182 self._selected()
183 }
184
185 while True:
186 self._refresh()
187 c = self.window.getch()
188 action = key_bindings.get(c, lambda: None)
189 action()
190
191 def _draw_matrix(self, matrix):
192 for y, line in enumerate(matrix.matrix):
193 for x, char in enumerate(line):
194 if isinstance(char, int):
195 selected = (char & SELECTED) != 0
196 char &= MASK
197 char = self.MATRIX_TO_CURSES[char]
198 if selected:
199 char |= curses.A_REVERSE
200 self.panel.insch(y, x, char)
201 else:
202 try:
203 char = char.encode('UTF-8')
204 except UnicodeDecodeError:
205 pass
206 self.panel.insstr(y, x, char)
207
208 def _run_curses(win, options, args):
209 args = args or ['.']
210 app = _CursesApp(win, options, args)
211 app.run()
212
213 def run(options, args):
214 if sys.stdin.isatty() and sys.stdout.isatty():
215 curses.wrapper(_run_curses, options, args)
216 else:
217 raise UINotAvailableException