source: deluge/ui/gtkui/torrentdetails.py@ d6fd69

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

Fix adding torrents

  • Property mode set to 100644
File size: 12.7 KB
Line 
1#
2# torrentdetails.py
3#
4# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
5#
6# Deluge is free software.
7#
8# You may redistribute it and/or modify it under the terms of the
9# GNU General Public License, as published by the Free Software
10# Foundation; either version 3 of the License, or (at your option)
11# any later version.
12#
13# deluge is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16# See the GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with deluge. If not, write to:
20# The Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor
22# Boston, MA 02110-1301, USA.
23#
24
25
26"""The torrent details component shows info about the selected torrent."""
27
28import gtk, gtk.glade
29import os
30import os.path
31import cPickle
32
33import deluge.component as component
34from deluge.ui.client import client
35from deluge.configmanager import ConfigManager
36import deluge.configmanager
37
38from deluge.log import LOG as log
39
40class Tab:
41 def __init__(self):
42 self.is_visible = True
43 self.position = -1
44 self.weight = -1
45
46 def get_name(self):
47 return self._name
48
49 def get_child_widget(self):
50 parent = self._child_widget.get_parent()
51 if parent is not None:
52 parent.remove(self._child_widget)
53
54 return self._child_widget
55
56 def get_tab_label(self):
57 parent = self._tab_label.get_parent()
58 log.debug("parent: %s", parent)
59 if parent is not None:
60 parent.remove(self._tab_label)
61
62 return self._tab_label
63
64class TorrentDetails(component.Component):
65 def __init__(self):
66 component.Component.__init__(self, "TorrentDetails", interval=2)
67 self.window = component.get("MainWindow")
68 glade = self.window.main_glade
69
70 self.notebook = glade.get_widget("torrent_info")
71
72 # This is the menu item we'll attach the tabs checklist menu to
73 self.menu_tabs = glade.get_widget("menu_tabs")
74
75 self.notebook.connect("switch-page", self._on_switch_page)
76
77 # Tabs holds references to the Tab objects by their name
78 self.tabs = {}
79
80 # Add the default tabs
81 from status_tab import StatusTab
82 from details_tab import DetailsTab
83 from files_tab import FilesTab
84 from peers_tab import PeersTab
85 from options_tab import OptionsTab
86
87 default_tabs = {
88 "Status": StatusTab,
89 "Details": DetailsTab,
90 "Files": FilesTab,
91 "Peers": PeersTab,
92 "Options": OptionsTab
93 }
94
95 # tab_name, visible
96 default_order = [
97 ("Status", True),
98 ("Details", True),
99 ("Files", True),
100 ("Peers", True),
101 ("Options", True)
102 ]
103
104 # Get the state from saved file
105 state = self.load_state()
106
107 if state:
108 for item in state:
109 if not isinstance(item, tuple):
110 log.debug("Old tabs.state, using default..")
111 state = None
112 break
113
114 # The state is a list of tab_names in the order they should appear
115 if state == None:
116 # Set the default order
117 state = default_order
118
119 # Add the tabs in the order from the state
120 for tab_name, visible in state:
121 # We need to rename the tab in the state for backwards compat
122 tab_name = tab_name.replace("Statistics", "Status")
123 self.add_tab(default_tabs[tab_name]())
124
125 # Hide any of the non-visible ones
126 for tab_name, visible in state:
127 if not visible:
128 self.hide_tab(tab_name)
129
130 # Generate the checklist menu
131 self.generate_menu()
132
133 def add_tab(self, tab_object, position=-1, generate_menu=True):
134 """Adds a tab object to the notebook."""
135 self.tabs[tab_object.get_name()] = tab_object
136 pos = self.notebook.insert_page(
137 tab_object.get_child_widget(),
138 tab_object.get_tab_label(),
139 position)
140
141 tab_object.position = pos
142 tab_object.weight = pos
143
144 # Regenerate positions if an insert occured
145 if position > -1:
146 self.regenerate_positions()
147
148 if generate_menu:
149 self.generate_menu()
150
151 if not self.notebook.get_property("visible"):
152 # If the notebook isn't visible, show it
153 self.visible(True)
154
155 def regenerate_positions(self):
156 """This will sync up the positions in the tab, with the position stored
157 in the tab object"""
158 for tab in self.tabs:
159 page_num = self.notebook.page_num(self.tabs[tab]._child_widget)
160 if page_num > -1:
161 self.tabs[tab].position = page_num
162
163 def remove_tab(self, tab_name):
164 """Removes a tab by name."""
165 self.notebook.remove_page(self.tabs[tab_name].position)
166 del self.tabs[tab_name]
167 self.regenerate_positions()
168 self.generate_menu()
169
170 # If there are no tabs visible, then do not show the notebook
171 if len(self.tabs) == 0:
172 self.visible(False)
173
174 def hide_all_tabs(self):
175 """Hides all tabs"""
176 log.debug("n_pages: %s", self.notebook.get_n_pages())
177 for n in xrange(self.notebook.get_n_pages() - 1, -1, -1):
178 self.notebook.remove_page(n)
179
180 for tab in self.tabs:
181 self.tabs[tab].is_visible = False
182 log.debug("n_pages: %s", self.notebook.get_n_pages())
183 self.generate_menu()
184 self.visible(False)
185
186 def show_all_tabs(self):
187 """Shows all tabs"""
188 for tab in self.tabs:
189 if not self.tabs[tab].is_visible:
190 self.notebook.insert_page(
191 self.tabs[tab].get_child_widget(),
192 self.tabs[tab].get_tab_label(),
193 self.tabs[tab].position)
194 self.tabs[tab].is_visible = True
195 self.generate_menu()
196 if not self.notebook.get_property("visible"):
197 # If the notebook isn't visible, show it
198 self.visible(True)
199
200 def hide_tab(self, tab_name):
201 """Hides tab by name"""
202 self.notebook.remove_page(self.tabs[tab_name].position)
203 self.tabs[tab_name].is_visible = False
204 self.regenerate_positions()
205 self.generate_menu()
206
207 def show_tab(self, tab_name):
208 log.debug("%s\n%s\n%s", self.tabs[tab_name].get_child_widget(),
209 self.tabs[tab_name].get_tab_label(),
210 self.tabs[tab_name].position)
211
212 # Determine insert position based on weight
213 # weights is a list of visible tab names in weight order
214 weights = []
215
216 for tab in self.tabs:
217 if self.tabs[tab].is_visible:
218 weights.append((self.tabs[tab].weight, self.tabs[tab].get_name()))
219
220 weights.sort()
221 log.debug("weights: %s", weights)
222 position = self.tabs[tab_name].position
223 log.debug("weight of tab: %s", self.tabs[tab_name].weight)
224 for i, w in enumerate(weights):
225 if w[0] >= self.tabs[tab_name].weight:
226 position = self.tabs[w[1]].position
227 break
228
229 log.debug("position: %s", position)
230 self.notebook.insert_page(
231 self.tabs[tab_name].get_child_widget(),
232 self.tabs[tab_name].get_tab_label(),
233 position)
234 self.tabs[tab_name].is_visible = True
235 self.regenerate_positions()
236 self.generate_menu()
237
238 def generate_menu(self):
239 """Generates the checklist menu for all the tabs and attaches it"""
240 menu = gtk.Menu()
241 # Create 'All' menuitem and a separator
242 menuitem = gtk.CheckMenuItem("All")
243
244 all_tabs = True
245 for key in self.tabs:
246 if not self.tabs[key].is_visible:
247 all_tabs = False
248 break
249 menuitem.set_active(all_tabs)
250 menuitem.connect("toggled", self._on_menuitem_toggled)
251
252 menu.append(menuitem)
253
254 menuitem = gtk.SeparatorMenuItem()
255 menu.append(menuitem)
256
257 # Create a list in order of tabs to create menu
258 menuitem_list = []
259 for tab_name in self.tabs:
260 menuitem_list.append((self.tabs[tab_name].weight, tab_name))
261 menuitem_list.sort()
262
263 for pos, name in menuitem_list:
264 menuitem = gtk.CheckMenuItem(name)
265 menuitem.set_active(self.tabs[name].is_visible)
266 menuitem.connect("toggled", self._on_menuitem_toggled)
267 menu.append(menuitem)
268
269 self.menu_tabs.set_submenu(menu)
270 self.menu_tabs.show_all()
271
272 def visible(self, visible):
273 if visible:
274 self.notebook.show()
275 else:
276 self.notebook.hide()
277 self.window.vpaned.set_position(-1)
278
279 def set_tab_visible(self, tab_name, visible):
280 """Sets the tab to visible"""
281 log.debug("set_tab_visible name: %s visible: %s", tab_name, visible)
282 if visible and not self.tabs[tab_name].is_visible:
283 self.show_tab(tab_name)
284 elif not visible and self.tabs[tab_name].is_visible:
285 self.hide_tab(tab_name)
286
287 def start(self):
288 for tab in self.tabs.values():
289 try:
290 tab.start()
291 except AttributeError:
292 pass
293
294 def stop(self):
295 self.clear()
296 for tab in self.tabs.values():
297 try:
298 tab.stop()
299 except AttributeError:
300 pass
301
302
303 def shutdown(self):
304 # Save the state of the tabs
305 for tab in self.tabs:
306 try:
307 self.tabs[tab].save_state()
308 except AttributeError:
309 pass
310
311 # Save tabs state
312 self.save_state()
313
314 def update(self, page_num=None):
315 if len(component.get("TorrentView").get_selected_torrents()) == 0:
316 # No torrents selected, so just clear
317 self.clear()
318
319 if self.notebook.get_property("visible"):
320 if page_num == None:
321 page_num = self.notebook.get_current_page()
322 try:
323 # Get the tab name
324 name = None
325 for tab in self.tabs:
326 if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
327 name = tab
328 except IndexError:
329 return
330 # Update the tab that is in view
331 if name:
332 self.tabs[name].update()
333
334 def clear(self):
335 # Get the tab name
336 try:
337 page_num = self.notebook.get_current_page()
338 name = None
339 for tab in self.tabs:
340 if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
341 name = tab
342 if name:
343 self.tabs[name].clear()
344 except Exception, e:
345 log.debug("Unable to clear torrentdetails: %s", e)
346
347 def _on_switch_page(self, notebook, page, page_num):
348 self.update(page_num)
349 client.force_call(False)
350
351 def _on_menuitem_toggled(self, widget):
352 # Get the tab name
353 name = widget.get_child().get_text()
354 if name == "All":
355 if widget.get_active():
356 self.show_all_tabs()
357 else:
358 self.hide_all_tabs()
359 return
360
361 self.set_tab_visible(name, widget.get_active())
362
363 def save_state(self):
364 """We save the state, which is basically the tab_index list"""
365 filename = "tabs.state"
366 state = []
367 for tab in self.tabs:
368 state.append((self.tabs[tab].weight, self.tabs[tab].get_name(),
369 self.tabs[tab].is_visible))
370 # Sort by weight
371 state.sort()
372 state = [(n, v) for w, n, v in state]
373
374 # Get the config location for saving the state file
375 config_location = deluge.configmanager.get_config_dir()
376
377 try:
378 log.debug("Saving TorrentDetails state file: %s", filename)
379 state_file = open(os.path.join(config_location, filename), "wb")
380 cPickle.dump(state, state_file)
381 state_file.close()
382 except IOError, e:
383 log.warning("Unable to save state file: %s", e)
384
385 def load_state(self):
386 filename = "tabs.state"
387 # Get the config location for loading the state file
388 config_location = deluge.configmanager.get_config_dir()
389 state = None
390
391 try:
392 log.debug("Loading TorrentDetails state file: %s", filename)
393 state_file = open(os.path.join(config_location, filename), "rb")
394 state = cPickle.load(state_file)
395 state_file.close()
396 except (EOFError, IOError), e:
397 log.warning("Unable to load state file: %s", e)
398
399 return state
Note: See TracBrowser for help on using the repository browser.