source: deluge/ui/gtkui/filtertreeview.py@ d54266

2.0.x develop extjs4-port
Last change on this file since d54266 was d54266, checked in by Andrew Resch <andrewresch@gmail.com>, 16 years ago

Fix some deprecation warnings and imports

  • Property mode set to 100644
File size: 12.0 KB
Line 
1#
2# filtertreeview.py
3#
4# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
5# Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
6#
7# Deluge is free software.
8#
9# You may redistribute it and/or modify it under the terms of the
10# GNU General Public License, as published by the Free Software
11# Foundation; either version 3 of the License, or (at your option)
12# any later version.
13#
14# deluge is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17# See the GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with deluge. If not, write to:
21# The Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor
23# Boston, MA 02110-1301, USA.
24#
25
26
27import gtk
28import gtk.glade
29import pkg_resources
30
31import deluge.component as component
32import deluge.common
33from deluge.ui.tracker_icons import TrackerIcons
34from deluge.log import LOG as log
35from deluge.ui.client import client
36from deluge.configmanager import ConfigManager
37
38STATE_PIX = {
39 "All": "all",
40 "Downloading": "downloading",
41 "Seeding": "seeding",
42 "Paused": "inactive",
43 "Checking": "checking",
44 "Queued": "queued",
45 "Error": "alert",
46 "Active": "active"
47 }
48
49
50TRANSLATE = {
51 "state": "States",
52 "tracker_host": "Trackers",
53 "label": "Labels"
54}
55
56FILTER_COLUMN = 5
57
58def _t(text):
59 if text in TRANSLATE:
60 text = TRANSLATE[text]
61 return _(text)
62
63
64#sidebar-treeview
65class FilterTreeView(component.Component):
66 def __init__(self):
67 component.Component.__init__(self, "FilterTreeView", interval=2)
68 self.window = component.get("MainWindow")
69 glade = self.window.main_glade
70 self.hpaned = glade.get_widget("hpaned")
71 self.scrolled = glade.get_widget("scrolledwindow_sidebar")
72 self.sidebar = component.get("SideBar")
73 self.config = ConfigManager("gtkui.conf")
74 self.tracker_icons = TrackerIcons()
75
76 self.label_view = gtk.TreeView()
77 self.sidebar.add_tab(self.label_view, "filters", _("Filters"))
78
79 #set filter to all when hidden:
80 self.sidebar.notebook.connect("hide", self._on_hide)
81
82 #menu
83 glade_menu = gtk.glade.XML(pkg_resources.resource_filename("deluge.ui.gtkui",
84 "glade/filtertree_menu.glade"))
85 self.menu = glade_menu.get_widget("filtertree_menu")
86 glade_menu.signal_autoconnect({
87 "select_all": self.on_select_all,
88 "pause_all": self.on_pause_all,
89 "resume_all": self.on_resume_all
90 })
91
92 self.default_menu_items = self.menu.get_children()
93
94 # Create the liststore
95 #cat, value, label, count, pixmap, visible
96 self.treestore = gtk.TreeStore(str, str, str, int, gtk.gdk.Pixbuf, bool)
97
98 # Create the column
99 column = gtk.TreeViewColumn(_("Filters"))
100 column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
101 render = gtk.CellRendererPixbuf()
102 self.renderpix = render
103 column.pack_start(render, expand=False)
104 column.add_attribute(render, 'pixbuf', 4)
105 render = gtk.CellRendererText()
106 column.pack_start(render, expand=False)
107 column.set_cell_data_func(render, self.render_cell_data,None)
108
109 self.label_view.append_column(column)
110
111 #style:
112 self.label_view.set_show_expanders(True)
113 self.label_view.set_headers_visible(False)
114 self.label_view.set_level_indentation(-35)
115
116 self.label_view.set_model(self.treestore)
117 self.label_view.get_selection().connect("changed", self.on_selection_changed)
118 self.create_model_filter()
119
120 #init.....
121 self.label_view.connect("button-press-event", self.on_button_press_event)
122
123 #colors using current theme.
124 style = self.window.window.get_style()
125 self.colour_background = style.bg[gtk.STATE_NORMAL]
126 self.colour_foreground = style.fg[gtk.STATE_NORMAL]
127
128 def start(self):
129 #add Cat nodes:
130 self.cat_nodes = {}
131 self.filters = {}
132
133 #initial order of state filter:
134 self.cat_nodes["state"] = self.treestore.append(None, ["cat", "state", _("State"), 0, None, False])
135 self.update_row("state", "All" , 0)
136 self.update_row("state", "Downloading" , 0)
137 self.update_row("state", "Seeding" , 0)
138 self.update_row("state", "Active" , 0)
139 self.update_row("state", "Paused" , 0)
140 self.update_row("state", "Queued" , 0)
141
142 # We set to this expand the rows on start-up
143 self.expand_rows = True
144
145 self.selected_path = None
146
147 def stop(self):
148 self.treestore.clear()
149
150 def create_model_filter(self):
151 self.model_filter = self.treestore.filter_new()
152 self.model_filter.set_visible_column(FILTER_COLUMN)
153 self.label_view.set_model(self.model_filter)
154
155 def cb_update_filter_tree(self, filter_items):
156 #create missing cat_nodes
157 for cat in filter_items:
158 if not cat in self.cat_nodes:
159 self.cat_nodes[cat] = self.treestore.append(None, ["cat", cat, _t(cat), 0, None, False])
160
161 #update rows
162 visible_filters = []
163 for cat,filters in filter_items.iteritems():
164 for value, count in filters:
165 self.update_row(cat, value , count)
166 visible_filters.append((cat, value))
167
168 # hide root-categories not returned by core-part of the plugin.
169 for cat in self.cat_nodes:
170 if cat in filter_items:
171 self.treestore.set_value(self.cat_nodes[cat], FILTER_COLUMN, True)
172 else:
173 self.treestore.set_value(self.cat_nodes[cat], FILTER_COLUMN, False)
174
175 # hide items not returned by core-plugin.
176 for f in self.filters:
177 if not f in visible_filters:
178 self.treestore.set_value(self.filters[f], FILTER_COLUMN, False)
179
180 if self.expand_rows:
181 self.label_view.expand_all()
182 self.expand_rows = False
183
184 if not self.selected_path:
185 self.select_default_filter()
186
187 def update_row(self, cat, value , count):
188 if (cat, value) in self.filters:
189 row = self.filters[(cat, value)]
190 self.treestore.set_value(row, 3, count)
191 else:
192 pix = self.get_pixmap(cat, value)
193 label = value
194 if cat == "state":
195 label = _(value)
196 row = self.treestore.append(self.cat_nodes[cat],[cat, value, label, count , pix, True])
197 self.filters[(cat, value)] = row
198
199 if cat == "tracker_host" or cat == "label":
200 self.tracker_icons.get_async(value, lambda filename: self.set_row_image(cat, value, filename))
201
202 self.treestore.set_value(row, FILTER_COLUMN, True)
203 return row
204
205 def render_cell_data(self, column, cell, model, row, data):
206 "cell renderer"
207 cat = model.get_value(row, 0)
208 value = model.get_value(row, 1)
209 label = model.get_value(row, 2)
210 count = model.get_value(row, 3)
211 pix = model.get_value(row, 4)
212
213 if label == "" and cat == "label":
214 label = _("no label")
215
216 if pix:
217 self.renderpix.set_property("visible", True)
218 else:
219 self.renderpix.set_property("visible", False)
220
221 if cat == "cat":
222 txt = label
223 cell.set_property("cell-background-gdk", self.colour_background)
224 cell.set_property("foreground-gdk", self.colour_foreground)
225 else:
226 txt = "%s (%s)" % (label, count)
227 cell.set_property("cell-background", None)
228 cell.set_property("foreground", None)
229
230 cell.set_property('text', txt)
231
232 def get_pixmap(self, cat, value):
233 if cat == "state":
234 pix = STATE_PIX.get(value, "dht")
235 return gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap("%s16.png" % pix))
236
237 return None
238
239 def set_row_image(self, cat, value, filename):
240 pix = None
241 try: #assume we could get trashed images here..
242 pix = gtk.gdk.pixbuf_new_from_file_at_size(filename, 16, 16)
243 except Exception, e:
244 log.debug(e)
245
246 if not pix:
247 pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16)
248 pix.fill(0x00000000)
249 row = self.filters[(cat, value)]
250 self.treestore.set_value(row, 4, pix)
251 return False
252
253
254 def on_selection_changed(self, selection):
255 try:
256 (model, row) = self.label_view.get_selection().get_selected()
257 if not row:
258 log.debug("nothing selected")
259 return
260
261 cat = model.get_value(row, 0)
262 value = model.get_value(row, 1)
263
264 filter_dict = {cat: [value]}
265 if value == "All" or cat == "cat":
266 filter_dict = {}
267
268 component.get("TorrentView").set_filter(filter_dict)
269
270 self.selected_path = model.get_path(row)
271
272 except Exception, e:
273 log.debug(e)
274 # paths is likely None .. so lets return None
275 return None
276
277 def update(self):
278 try:
279 hide_cat = []
280 if not self.config["sidebar_show_trackers"]:
281 hide_cat = ["tracker_host"]
282 client.core.get_filter_tree(self.config["sidebar_show_zero"], hide_cat).addCallback(self.cb_update_filter_tree)
283 except Exception, e:
284 log.debug(e)
285
286
287 ### Callbacks ###
288 def on_button_press_event(self, widget, event):
289 """This is a callback for showing the right-click context menu.
290 NOT YET!
291 """
292 x, y = event.get_coords()
293 path = self.label_view.get_path_at_pos(int(x), int(y))
294 if not path:
295 return
296 path = path[0]
297 cat = self.model_filter[path][0]
298
299 if event.button == 1:
300 # Prevent selecting a category label
301 if cat == "cat":
302 if self.label_view.row_expanded(path):
303 self.label_view.collapse_row(path)
304 else:
305 self.label_view.expand_row(path, False)
306 if not self.selected_path:
307 self.select_default_filter()
308 else:
309 self.label_view.get_selection().select_path(self.selected_path)
310 return True
311
312 elif event.button == 3:
313 #assign current cat, value to self:
314 x, y = event.get_coords()
315 path = self.label_view.get_path_at_pos(int(x), int(y))
316 if not path:
317 return
318 row = self.model_filter.get_iter(path[0])
319 self.cat = self.model_filter.get_value(row, 0)
320 self.value = self.model_filter.get_value(row, 1)
321 self.count = self.model_filter.get_value(row, 3)
322
323 #Show the pop-up menu
324 self.set_menu_sensitivity()
325 self.menu.hide()
326 self.menu.popup(None, None, None, event.button, event.time)
327 self.menu.show()
328
329 if cat == "cat":
330 # Do not select the row
331 return True
332
333 def set_menu_sensitivity(self):
334 #select-all/pause/resume
335 sensitive = (self.cat != "cat" and self.count <> 0)
336 for item in self.default_menu_items:
337 item.set_sensitive(sensitive)
338
339 def select_all(self):
340 "for use in popup menu"
341 component.get("TorrentView").treeview.get_selection().select_all()
342
343 def on_select_all(self, event):
344 self.select_all()
345
346 def on_pause_all(self, event):
347 self.select_all()
348 func = getattr(component.get("MenuBar"), "on_menuitem_%s_activate" % "pause")
349 func(event)
350
351 def on_resume_all(self, event):
352 self.select_all()
353 func = getattr(component.get("MenuBar"), "on_menuitem_%s_activate" % "resume")
354 func(event)
355
356 def _on_hide(self, *args):
357 self.select_default_filter()
358
359 def select_default_filter(self):
360 row = self.filters[("state", "All")]
361 path = self.treestore.get_path(row)
362 self.label_view.get_selection().select_path(path)
Note: See TracBrowser for help on using the repository browser.