source: deluge/ui/gtkui/torrentdetails.py@ 911d958

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

Fix hiding bottom pane when no tabs are enabled upon restart

  • Property mode set to 100644
File size: 12.9 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 show = False
208 for name, tab in self.tabs.iteritems():
209 show = show or tab.is_visible
210
211 self.visible(show)
212
213 def show_tab(self, tab_name):
214 log.debug("%s\n%s\n%s", self.tabs[tab_name].get_child_widget(),
215 self.tabs[tab_name].get_tab_label(),
216 self.tabs[tab_name].position)
217
218 # Determine insert position based on weight
219 # weights is a list of visible tab names in weight order
220 weights = []
221
222 for tab in self.tabs:
223 if self.tabs[tab].is_visible:
224 weights.append((self.tabs[tab].weight, self.tabs[tab].get_name()))
225
226 weights.sort()
227 log.debug("weights: %s", weights)
228 position = self.tabs[tab_name].position
229 log.debug("weight of tab: %s", self.tabs[tab_name].weight)
230 for i, w in enumerate(weights):
231 if w[0] >= self.tabs[tab_name].weight:
232 position = self.tabs[w[1]].position
233 break
234
235 log.debug("position: %s", position)
236 self.notebook.insert_page(
237 self.tabs[tab_name].get_child_widget(),
238 self.tabs[tab_name].get_tab_label(),
239 position)
240 self.tabs[tab_name].is_visible = True
241 self.regenerate_positions()
242 self.generate_menu()
243 self.visible(True)
244
245 def generate_menu(self):
246 """Generates the checklist menu for all the tabs and attaches it"""
247 menu = gtk.Menu()
248 # Create 'All' menuitem and a separator
249 menuitem = gtk.CheckMenuItem("All")
250
251 all_tabs = True
252 for key in self.tabs:
253 if not self.tabs[key].is_visible:
254 all_tabs = False
255 break
256 menuitem.set_active(all_tabs)
257 menuitem.connect("toggled", self._on_menuitem_toggled)
258
259 menu.append(menuitem)
260
261 menuitem = gtk.SeparatorMenuItem()
262 menu.append(menuitem)
263
264 # Create a list in order of tabs to create menu
265 menuitem_list = []
266 for tab_name in self.tabs:
267 menuitem_list.append((self.tabs[tab_name].weight, tab_name))
268 menuitem_list.sort()
269
270 for pos, name in menuitem_list:
271 menuitem = gtk.CheckMenuItem(name)
272 menuitem.set_active(self.tabs[name].is_visible)
273 menuitem.connect("toggled", self._on_menuitem_toggled)
274 menu.append(menuitem)
275
276 self.menu_tabs.set_submenu(menu)
277 self.menu_tabs.show_all()
278
279 def visible(self, visible):
280 if visible:
281 self.notebook.show()
282 else:
283 self.notebook.hide()
284 self.window.vpaned.set_position(-1)
285
286 def set_tab_visible(self, tab_name, visible):
287 """Sets the tab to visible"""
288 log.debug("set_tab_visible name: %s visible: %s", tab_name, visible)
289 if visible and not self.tabs[tab_name].is_visible:
290 self.show_tab(tab_name)
291 elif not visible and self.tabs[tab_name].is_visible:
292 self.hide_tab(tab_name)
293
294 def start(self):
295 for tab in self.tabs.values():
296 try:
297 tab.start()
298 except AttributeError:
299 pass
300
301 def stop(self):
302 self.clear()
303 for tab in self.tabs.values():
304 try:
305 tab.stop()
306 except AttributeError:
307 pass
308
309
310 def shutdown(self):
311 # Save the state of the tabs
312 for tab in self.tabs:
313 try:
314 self.tabs[tab].save_state()
315 except AttributeError:
316 pass
317
318 # Save tabs state
319 self.save_state()
320
321 def update(self, page_num=None):
322 if len(component.get("TorrentView").get_selected_torrents()) == 0:
323 # No torrents selected, so just clear
324 self.clear()
325
326 if self.notebook.get_property("visible"):
327 if page_num == None:
328 page_num = self.notebook.get_current_page()
329 try:
330 # Get the tab name
331 name = None
332 for tab in self.tabs:
333 if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
334 name = tab
335 except IndexError:
336 return
337 # Update the tab that is in view
338 if name:
339 self.tabs[name].update()
340
341 def clear(self):
342 # Get the tab name
343 try:
344 page_num = self.notebook.get_current_page()
345 name = None
346 for tab in self.tabs:
347 if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
348 name = tab
349 if name:
350 self.tabs[name].clear()
351 except Exception, e:
352 log.debug("Unable to clear torrentdetails: %s", e)
353
354 def _on_switch_page(self, notebook, page, page_num):
355 self.update(page_num)
356 client.force_call(False)
357
358 def _on_menuitem_toggled(self, widget):
359 # Get the tab name
360 name = widget.get_child().get_text()
361 if name == "All":
362 if widget.get_active():
363 self.show_all_tabs()
364 else:
365 self.hide_all_tabs()
366 return
367
368 self.set_tab_visible(name, widget.get_active())
369
370 def save_state(self):
371 """We save the state, which is basically the tab_index list"""
372 filename = "tabs.state"
373 state = []
374 for tab in self.tabs:
375 state.append((self.tabs[tab].weight, self.tabs[tab].get_name(),
376 self.tabs[tab].is_visible))
377 # Sort by weight
378 state.sort()
379 state = [(n, v) for w, n, v in state]
380
381 # Get the config location for saving the state file
382 config_location = deluge.configmanager.get_config_dir()
383
384 try:
385 log.debug("Saving TorrentDetails state file: %s", filename)
386 state_file = open(os.path.join(config_location, filename), "wb")
387 cPickle.dump(state, state_file)
388 state_file.close()
389 except IOError, e:
390 log.warning("Unable to save state file: %s", e)
391
392 def load_state(self):
393 filename = "tabs.state"
394 # Get the config location for loading the state file
395 config_location = deluge.configmanager.get_config_dir()
396 state = None
397
398 try:
399 log.debug("Loading TorrentDetails state file: %s", filename)
400 state_file = open(os.path.join(config_location, filename), "rb")
401 state = cPickle.load(state_file)
402 state_file.close()
403 except (EOFError, IOError), e:
404 log.warning("Unable to load state file: %s", e)
405
406 return state
Note: See TracBrowser for help on using the repository browser.