Detect unsuccessful attempts at running an uninstalled pysize
[pysize.git] / pysize / ui / gtk / pysize_widget.py
blob0689ba896b07edddeddc3035f1cc4c0869a8b708
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.
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.
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.
15 # See the COPYING file for license information.
17 # Copyright (c) 2006, 2007, 2008 Guillaume Chazarain <guichaz@gmail.com>
19 import os
20 import pygtk
21 pygtk.require('2.0')
22 import gtk
23 assert gtk.pygtk_version >= (2, 8)
24 import gobject
26 from pysize.core.pysize_global_fs_cache import drop_caches
27 from pysize.core.pysize_fs_tree import pysize_tree
28 from pysize.core import history
29 from pysize.core import deletion
30 from pysize.ui.gtk.threaded_pysize_tree import threaded_pysize_tree
32 from pysize.ui.gtk.pysize_widget_draw import PysizeWidget_Draw
33 from pysize.ui.gtk.pysize_widget_menu import PysizeWidget_Menu
34 from pysize.ui.gtk.pysize_widget_mouse import PysizeWidget_Mouse
37 class PysizeWidget(gtk.DrawingArea, PysizeWidget_Draw,
38 PysizeWidget_Menu, PysizeWidget_Mouse):
39 __gsignals__ = {
40 'hover-changed':
41 (gobject.SIGNAL_RUN_LAST,
42 gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
43 'building-tree-state-changed':
44 (gobject.SIGNAL_RUN_LAST,
45 gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN,))
48 def __init__(self, options, args):
49 gtk.DrawingArea.__init__(self)
50 PysizeWidget_Draw.__init__(self, options, args)
51 PysizeWidget_Menu.__init__(self, options, args)
52 PysizeWidget_Mouse.__init__(self, options, args)
53 self.connect('realize', type(self)._realize)
54 self.connect('key-press-event', type(self)._key_press)
55 self.connect('configure-event', type(self)._configure)
56 self.set_flags(gtk.CAN_FOCUS)
57 self.options = options
58 self.min_size = 'auto'
59 self.paths = args
60 self.tree = pysize_tree([], 0, 0, self.options)
61 self.tree_builder = threaded_pysize_tree()
62 self.tree_builder.completion.add_observer(self._new_tree_callback)
64 def _realize(self):
65 events = self.window.get_events()
66 events |= gtk.gdk.POINTER_MOTION_MASK
67 events |= gtk.gdk.POINTER_MOTION_HINT_MASK
68 events |= gtk.gdk.KEY_PRESS_MASK
69 events |= gtk.gdk.BUTTON_PRESS_MASK
70 events |= gtk.gdk.BUTTON_RELEASE_MASK
71 self.window.set_events(events)
73 def _key_press(self, event):
74 directions = {
75 gtk.keysyms.Left: self.tree.get_parent,
76 gtk.keysyms.Up: self.tree.get_previous_sibling,
77 gtk.keysyms.Right: self.tree.get_first_child,
78 gtk.keysyms.Down: self.tree.get_next_sibling
81 action = directions.get(event.keyval, None)
82 if action and self.cursor_node is not None:
83 new_selection = action(self.cursor_node)
84 if new_selection not in (None, self.tree.root):
85 self.queue_node_redraw(self.cursor_node)
86 self.queue_node_redraw(new_selection)
87 self.set_cursor_node(new_selection)
88 return action is not None
90 # Called when the threaded_pysize_tree built a new tree for us
91 def _new_tree_callback(self, tree):
92 if tree:
93 self.tree = tree
94 self.queue_draw()
95 self.invalidate_tree()
96 history.add_entry(tree)
97 self.emit('building-tree-state-changed', not tree)
98 if tree:
99 if self.min_size == 'auto':
100 height = self.get_parent().allocation.height - 2
101 else:
102 height = int(self.get_requested_height())
103 self.set_size_request(-1, height)
105 def complete_reload(self):
106 drop_caches()
107 self.schedule_new_tree()
109 def min_size_requested(self):
110 if self.min_size == 'auto':
111 return 1.0 / self.max_number_of_nodes()
112 return self.min_size
114 def set_paths(self, paths):
115 if paths:
116 self.paths = paths
117 self.min_size = 'auto'
118 self.schedule_new_tree()
120 def schedule_new_tree(self):
121 self.tree_builder.schedule(self.paths, self.options.max_depth,
122 self.min_size_requested(), self.options)
124 def _configure(self, event):
125 if self.min_size == 'auto':
126 self.schedule_new_tree()
127 else:
128 for node in self.tree.root:
129 node.rectangle = None
131 def invalidate_tree(self):
132 self.emit('hover-changed', None)
133 self.selected_nodes = set()
135 def parent_directory(self):
136 self.set_paths([self.tree.root.get_dirname()])
138 def max_depth_changed(self, spin):
139 value = spin.get_value()
140 self.options.max_depth = value
141 self.schedule_new_tree()
143 def open(self):
144 action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER
145 buttons = gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
146 gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT
147 dialog = gtk.FileChooserDialog(title='Select a directory',
148 action=action, buttons=buttons)
149 dialog.set_select_multiple(True)
150 response = dialog.run()
151 if response == gtk.RESPONSE_ACCEPT:
152 paths = map(os.path.realpath, dialog.get_filenames())
153 self.set_paths(paths)
154 dialog.destroy()
156 def schedule_delete(self, nodes):
157 deletion.schedule(nodes)
158 self.schedule_new_tree()