No need to revert a choice from the user.
[pysize.git] / ui / gtk / pysize_widget.py
blobd4d1ab9432d93beec58f971b27a2dcdec797a4f4
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 core.pysize_global_fs_cache import drop_caches
10 from core.pysize_fs_tree import pysize_tree
11 from ui.utils import min_size_to_consider
12 from ui.gtk.threaded_pysize_tree import threaded_pysize_tree
14 from ui.gtk.pysize_widget_draw import PysizeWidget_Draw
15 from ui.gtk.pysize_widget_menu import PysizeWidget_Menu
16 from ui.gtk.pysize_widget_mouse import PysizeWidget_Mouse
19 class PysizeWidget(gtk.DrawingArea, PysizeWidget_Draw,
20 PysizeWidget_Menu, PysizeWidget_Mouse):
21 __gsignals__ = {
22 'hover-changed':
23 (gobject.SIGNAL_RUN_LAST,
24 gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
25 'building-tree-state-changed':
26 (gobject.SIGNAL_RUN_LAST,
27 gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN,))
30 def __init__(self, options, path):
31 gtk.DrawingArea.__init__(self)
32 PysizeWidget_Draw.__init__(self, options, path)
33 PysizeWidget_Menu.__init__(self, options, path)
34 PysizeWidget_Mouse.__init__(self, options, path)
35 self.connect('realize', type(self)._realize)
36 self.connect('key-press-event', type(self)._key_press)
37 self.connect('configure-event', type(self)._configure)
38 self.set_flags(gtk.CAN_FOCUS)
39 self.options = options
40 self.selected_nodes = []
41 self.path = path
42 self.tree = pysize_tree(None)
43 self.tree_builder = threaded_pysize_tree()
44 self.tree_builder.completion.add_observer(self._new_tree_callback)
46 def _realize(self):
47 events = self.window.get_events()
48 events |= gtk.gdk.POINTER_MOTION_MASK
49 events |= gtk.gdk.POINTER_MOTION_HINT_MASK
50 events |= gtk.gdk.KEY_PRESS_MASK
51 events |= gtk.gdk.BUTTON_PRESS_MASK
52 events |= gtk.gdk.BUTTON_RELEASE_MASK
53 self.window.set_events(events)
55 def _key_press(self, event):
56 directions = {
57 gtk.keysyms.Left: self.tree.get_parent,
58 gtk.keysyms.Up: self.tree.get_previous_sibling,
59 gtk.keysyms.Right: self.tree.get_first_child,
60 gtk.keysyms.Down: self.tree.get_next_sibling
63 action = directions.get(event.keyval, None)
64 if action and self.cursor_node is not None:
65 new_selection = action(self.cursor_node)
66 if new_selection not in (None, self.tree.root):
67 self.queue_node_redraw(self.cursor_node)
68 self.queue_node_redraw(new_selection)
69 self.set_cursor_node(new_selection)
70 return action is not None
72 # Called when the threaded_pysize_tree built a new tree for us
73 def _new_tree_callback(self, tree):
74 if tree:
75 self.tree = tree
76 self.queue_draw()
77 gobject.idle_add(self.invalidate_tree)
78 emit_sig = lambda: self.emit('building-tree-state-changed', not tree)
79 gobject.idle_add(emit_sig)
80 if tree:
81 if self.options.min_size == 'auto':
82 height = self.get_parent().allocation.height - 2
83 else:
84 height = int(self._get_requested_height())
85 self.set_size_request(-1, height)
87 def refresh_tree(self):
88 drop_caches()
89 self.schedule_new_tree()
91 def min_size_requested(self):
92 return min_size_to_consider(self.options.min_size,
93 self.max_number_of_items())
95 def schedule_new_tree(self):
96 self.tree_builder.schedule(self.path, self.options.max_depth,
97 self.min_size_requested())
99 def _configure(self, event):
100 self.schedule_new_tree()
102 def invalidate_tree(self):
103 self.emit('hover-changed', None)
105 def parent_directory(self):
106 if len(self.path) > 1:
107 self.path = os.path.dirname(self.path)
108 self.schedule_new_tree()
110 def max_depth_changed(self, spin):
111 value = spin.get_value()
112 self.options.max_depth = value
113 self.schedule_new_tree()
115 def open(self):
116 action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
117 buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
118 gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)
119 dialog = gtk.FileChooserDialog(title='Select a directory',
120 action=action, buttons=buttons)
121 response = dialog.run()
122 if response == gtk.RESPONSE_ACCEPT:
123 self.path = dialog.get_filename()
124 self.schedule_new_tree()
125 dialog.destroy()