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>
23 assert gtk
.pygtk_version
>= (2, 8)
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
):
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'
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
)
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
):
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
):
95 self
.invalidate_tree()
96 history
.add_entry(tree
)
97 self
.emit('building-tree-state-changed', not tree
)
99 if self
.min_size
== 'auto':
100 height
= self
.get_parent().allocation
.height
- 2
102 height
= int(self
.get_requested_height())
103 self
.set_size_request(-1, height
)
105 def complete_reload(self
):
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()
114 def set_paths(self
, 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()
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()
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
)
156 def schedule_delete(self
, nodes
):
157 deletion
.schedule(nodes
)
158 self
.schedule_new_tree()