Don't use the name 'item'. Nodes are nodes, fullpaths are fullpaths.
[pysize.git] / pysize / ui / gtk / pysize_widget.py
blob3b818a9870fb6865707f61be92af8f14f77f2ecf
1 import os
3 import pygtk
4 pygtk.require('2.0')
5 import gtk
6 assert gtk.pygtk_version >= (2, 8)
7 import gobject
9 from pysize.core.pysize_global_fs_cache import drop_caches
10 from pysize.core.pysize_fs_tree import pysize_tree
11 from pysize.core import history
12 from pysize.ui.utils import min_size_to_consider
13 from pysize.ui.gtk.threaded_pysize_tree import threaded_pysize_tree
15 from pysize.ui.gtk.pysize_widget_draw import PysizeWidget_Draw
16 from pysize.ui.gtk.pysize_widget_menu import PysizeWidget_Menu
17 from pysize.ui.gtk.pysize_widget_mouse import PysizeWidget_Mouse
20 class PysizeWidget(gtk.DrawingArea, PysizeWidget_Draw,
21 PysizeWidget_Menu, PysizeWidget_Mouse):
22 __gsignals__ = {
23 'hover-changed':
24 (gobject.SIGNAL_RUN_LAST,
25 gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
26 'building-tree-state-changed':
27 (gobject.SIGNAL_RUN_LAST,
28 gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN,))
31 def __init__(self, options, args):
32 gtk.DrawingArea.__init__(self)
33 PysizeWidget_Draw.__init__(self, options, args)
34 PysizeWidget_Menu.__init__(self, options, args)
35 PysizeWidget_Mouse.__init__(self, options, args)
36 self.connect('realize', type(self)._realize)
37 self.connect('key-press-event', type(self)._key_press)
38 self.connect('configure-event', type(self)._configure)
39 self.set_flags(gtk.CAN_FOCUS)
40 self.options = options
41 self.selected_nodes = []
42 self.paths = args
43 self.tree = pysize_tree(None)
44 self.tree_builder = threaded_pysize_tree()
45 self.tree_builder.completion.add_observer(self._new_tree_callback)
47 def _realize(self):
48 events = self.window.get_events()
49 events |= gtk.gdk.POINTER_MOTION_MASK
50 events |= gtk.gdk.POINTER_MOTION_HINT_MASK
51 events |= gtk.gdk.KEY_PRESS_MASK
52 events |= gtk.gdk.BUTTON_PRESS_MASK
53 events |= gtk.gdk.BUTTON_RELEASE_MASK
54 self.window.set_events(events)
56 def _key_press(self, event):
57 directions = {
58 gtk.keysyms.Left: self.tree.get_parent,
59 gtk.keysyms.Up: self.tree.get_previous_sibling,
60 gtk.keysyms.Right: self.tree.get_first_child,
61 gtk.keysyms.Down: self.tree.get_next_sibling
64 action = directions.get(event.keyval, None)
65 if action and self.cursor_node is not None:
66 new_selection = action(self.cursor_node)
67 if new_selection not in (None, self.tree.root):
68 self.queue_node_redraw(self.cursor_node)
69 self.queue_node_redraw(new_selection)
70 self.set_cursor_node(new_selection)
71 return action is not None
73 # Called when the threaded_pysize_tree built a new tree for us
74 def _new_tree_callback(self, tree):
75 if tree:
76 self.tree = tree
77 self.queue_draw()
78 self.invalidate_tree()
79 history.add_entry(tree)
80 self.emit('building-tree-state-changed', not tree)
81 if tree:
82 if self.options.min_size == 'auto':
83 height = self.get_parent().allocation.height - 2
84 else:
85 height = int(self._get_requested_height())
86 self.set_size_request(-1, height)
88 def refresh_tree(self):
89 drop_caches()
90 self.schedule_new_tree()
92 def min_size_requested(self):
93 return min_size_to_consider(self.options.min_size,
94 self.max_number_of_nodes())
96 def set_paths(self, paths):
97 if paths:
98 self.paths = paths
99 self.schedule_new_tree()
101 def schedule_new_tree(self):
102 self.tree_builder.schedule(self.paths, self.options.max_depth,
103 self.min_size_requested())
105 def _configure(self, event):
106 if self.options.min_size == 'auto':
107 self.schedule_new_tree()
109 def invalidate_tree(self):
110 self.emit('hover-changed', None)
112 def parent_directory(self):
113 self.set_paths([self.tree.root.get_dirname()])
115 def max_depth_changed(self, spin):
116 value = spin.get_value()
117 self.options.max_depth = value
118 self.schedule_new_tree()
120 def open(self):
121 action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
122 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
123 gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)
124 dialog = gtk.FileChooserDialog(title='Select a directory',
125 action=action, buttons=buttons)
126 response = dialog.run()
127 if response == gtk.RESPONSE_ACCEPT:
128 self.set_paths([dialog.get_filename()])
129 dialog.destroy()