Fix #349 tab ordering when hiding/showing

This commit is contained in:
Andrew Resch 2008-07-17 20:20:34 +00:00
parent 88ca3bacd1
commit cfadbec2cf
7 changed files with 151 additions and 74 deletions

View File

@ -8,6 +8,7 @@ Deluge 0.9.03 - "1.0.0_RC3" (In-Development)
GtkUI: GtkUI:
* Fix open folder * Fix open folder
* Fix #349 tab ordering when hiding/showing
Misc: Misc:
* Some changes for python 2.6 compatibility * Some changes for python 2.6 compatibility

View File

@ -42,6 +42,7 @@ from deluge.log import LOG as log
class DetailsTab(Tab): class DetailsTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self)
# Get the labels we need to update. # Get the labels we need to update.
# widgetname, modifier function, status keys # widgetname, modifier function, status keys
glade = component.get("MainWindow").main_glade glade = component.get("MainWindow").main_glade

View File

@ -94,6 +94,7 @@ class ColumnState:
class FilesTab(Tab): class FilesTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self)
glade = component.get("MainWindow").get_glade() glade = component.get("MainWindow").get_glade()
self._name = "Files" self._name = "Files"

View File

@ -37,6 +37,7 @@ from deluge.ui.gtkui.torrentdetails import Tab
class OptionsTab(Tab): class OptionsTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self)
glade = component.get("MainWindow").get_glade() glade = component.get("MainWindow").get_glade()
self._name = "Options" self._name = "Options"

View File

@ -56,6 +56,7 @@ class ColumnState:
class PeersTab(Tab): class PeersTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self)
glade = component.get("MainWindow").get_glade() glade = component.get("MainWindow").get_glade()
self._name = "Peers" self._name = "Peers"

View File

@ -59,6 +59,7 @@ def fspeed(value, max_value=-1):
class StatisticsTab(Tab): class StatisticsTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self)
# Get the labels we need to update. # Get the labels we need to update.
# widgetname, modifier function, status keys # widgetname, modifier function, status keys
glade = component.get("MainWindow").main_glade glade = component.get("MainWindow").main_glade

View File

@ -46,7 +46,9 @@ from deluge.log import LOG as log
class Tab: class Tab:
def __init__(self): def __init__(self):
pass self.is_visible = True
self.position = -1
self.weight = -1
def get_name(self): def get_name(self):
return self._name return self._name
@ -60,6 +62,7 @@ class Tab:
def get_tab_label(self): def get_tab_label(self):
parent = self._tab_label.get_parent() parent = self._tab_label.get_parent()
log.debug("parent: %s", parent)
if parent is not None: if parent is not None:
parent.remove(self._tab_label) parent.remove(self._tab_label)
@ -72,21 +75,14 @@ class TorrentDetails(component.Component):
glade = self.window.main_glade glade = self.window.main_glade
self.notebook = glade.get_widget("torrent_info") self.notebook = glade.get_widget("torrent_info")
# This is the menu item we'll attach the tabs checklist menu to # This is the menu item we'll attach the tabs checklist menu to
self.menu_tabs = glade.get_widget("menu_tabs") self.menu_tabs = glade.get_widget("menu_tabs")
self.notebook.connect("switch-page", self._on_switch_page) self.notebook.connect("switch-page", self._on_switch_page)
# Tab index is a list of tab names in the order which they presented
# to the user.
self.tab_index = []
# Tabs holds references to the Tab objects by their name # Tabs holds references to the Tab objects by their name
self.tabs = {} self.tabs = {}
# tab_name: (tab_object, position)
self.hidden_tabs = {}
# Add the default tabs # Add the default tabs
from statistics_tab import StatisticsTab from statistics_tab import StatisticsTab
@ -103,12 +99,13 @@ class TorrentDetails(component.Component):
"Options": OptionsTab "Options": OptionsTab
} }
# tab_name, visible
default_order = [ default_order = [
"Statistics", ("Statistics", True),
"Details", ("Details", True),
"Files", ("Files", True),
"Peers", ("Peers", True),
"Options" ("Options", True)
] ]
# Get the state from saved file # Get the state from saved file
@ -118,16 +115,15 @@ class TorrentDetails(component.Component):
if state == None: if state == None:
# Set the default order # Set the default order
state = default_order state = default_order
# Add the tabs in the order from the state # Add the tabs in the order from the state
for tab_name in state: for tab_name, visible in state:
self.add_tab(default_tabs[tab_name]()) self.add_tab(default_tabs[tab_name]())
if len(state) < len(default_order): # Hide any of the non-visible ones
# We have hidden tabs and need to add them to the hidden_tabs dict for tab_name, visible in state:
for i, tab_name in enumerate(default_order): if not visible:
if tab_name not in state: self.hide_tab(tab_name)
self.hidden_tabs[tab_name] = (default_tabs[tab_name](), i)
# Generate the checklist menu # Generate the checklist menu
self.generate_menu() self.generate_menu()
@ -139,7 +135,14 @@ class TorrentDetails(component.Component):
tab_object.get_child_widget(), tab_object.get_child_widget(),
tab_object.get_tab_label(), tab_object.get_tab_label(),
position) position)
self.tab_index.insert(pos, tab_object.get_name())
tab_object.position = pos
tab_object.weight = pos
# Regenerate positions if an insert occured
if position > -1:
self.regenerate_positions()
if generate_menu: if generate_menu:
self.generate_menu() self.generate_menu()
@ -147,48 +150,115 @@ class TorrentDetails(component.Component):
# If the notebook isn't visible, show it # If the notebook isn't visible, show it
self.visible(True) self.visible(True)
def regenerate_positions(self):
"""This will sync up the positions in the tab, with the position stored
in the tab object"""
for tab in self.tabs:
page_num = self.notebook.page_num(self.tabs[tab]._child_widget)
if page_num > -1:
self.tabs[tab].position = page_num
def remove_tab(self, tab_name): def remove_tab(self, tab_name):
"""Removes a tab by name.""" """Removes a tab by name."""
index = self.tab_index.index(tab_name) self.notebook.remove_page(self.tabs[tab_name].position)
self.notebook.remove_page(index)
del self.tabs[tab_name] del self.tabs[tab_name]
del self.tab_index[index] self.regenerate_positions()
self.generate_menu() self.generate_menu()
# If there are no tabs visible, then do not show the notebook # If there are no tabs visible, then do not show the notebook
if len(self.tabs) == 0: if len(self.tabs) == 0:
self.visible(False) self.visible(False)
def hide_all_tabs(self):
"""Hides all tabs"""
log.debug("n_pages: %s", self.notebook.get_n_pages())
for n in xrange(self.notebook.get_n_pages() - 1, -1, -1):
self.notebook.remove_page(n)
for tab in self.tabs:
self.tabs[tab].is_visible = False
log.debug("n_pages: %s", self.notebook.get_n_pages())
self.generate_menu()
def show_all_tabs(self):
"""Shows all tabs"""
for tab in self.tabs:
if not self.tabs[tab].is_visible:
self.notebook.insert_page(
self.tabs[tab].get_child_widget(),
self.tabs[tab].get_tab_label(),
self.tabs[tab].position)
self.tabs[tab].is_visible = True
self.generate_menu()
def hide_tab(self, tab_name):
"""Hides tab by name"""
self.notebook.remove_page(self.tabs[tab_name].position)
self.tabs[tab_name].is_visible = False
self.regenerate_positions()
self.generate_menu()
def show_tab(self, tab_name):
log.debug("%s\n%s\n%s", self.tabs[tab_name].get_child_widget(),
self.tabs[tab_name].get_tab_label(),
self.tabs[tab_name].position)
# Determine insert position based on weight
# weights is a list of visible tab names in weight order
weights = []
for tab in self.tabs:
if self.tabs[tab].is_visible:
weights.append((self.tabs[tab].weight, self.tabs[tab].get_name()))
weights.sort()
log.debug("weights: %s", weights)
position = self.tabs[tab_name].position
log.debug("weight of tab: %s", self.tabs[tab_name].weight)
for i, w in enumerate(weights):
if w[0] >= self.tabs[tab_name].weight:
position = self.tabs[w[1]].position
break
log.debug("position: %s", position)
self.notebook.insert_page(
self.tabs[tab_name].get_child_widget(),
self.tabs[tab_name].get_tab_label(),
position)
self.tabs[tab_name].is_visible = True
self.regenerate_positions()
self.generate_menu()
def generate_menu(self): def generate_menu(self):
"""Generates the checklist menu for all the tabs and attaches it""" """Generates the checklist menu for all the tabs and attaches it"""
menu = gtk.Menu() menu = gtk.Menu()
# Create 'All' menuitem and a separator # Create 'All' menuitem and a separator
menuitem = gtk.CheckMenuItem("All") menuitem = gtk.CheckMenuItem("All")
menuitem.connect("toggled", self._on_menuitem_toggled)
if len(self.hidden_tabs) > 0: all_tabs = True
menuitem.set_active(False) for key in self.tabs:
else: if not self.tabs[key].is_visible:
menuitem.set_active(True) all_tabs = False
break
menuitem.set_active(all_tabs)
menuitem.connect("toggled", self._on_menuitem_toggled)
menu.append(menuitem) menu.append(menuitem)
menuitem = gtk.SeparatorMenuItem() menuitem = gtk.SeparatorMenuItem()
menu.append(menuitem) menu.append(menuitem)
# Add all the tabs to the menu # Create a list in order of tabs to create menu
for tab in self.tab_index: menuitem_list = []
menuitem = gtk.CheckMenuItem(tab) for tab_name in self.tabs:
menuitem.connect("toggled", self._on_menuitem_toggled) menuitem_list.append((self.tabs[tab_name].weight, tab_name))
menuitem.set_active(True) menuitem_list.sort()
menu.append(menuitem)
# Add all hidden_tabs to the menu too for pos, name in menuitem_list:
for tab in self.hidden_tabs.keys(): menuitem = gtk.CheckMenuItem(name)
menuitem = gtk.CheckMenuItem(tab) menuitem.set_active(self.tabs[name].is_visible)
menuitem.connect("toggled", self._on_menuitem_toggled) menuitem.connect("toggled", self._on_menuitem_toggled)
menuitem.set_active(False) menu.append(menuitem)
# Try to keep position in sync
menu.insert(menuitem, self.hidden_tabs[tab][1] + 2)
self.menu_tabs.set_submenu(menu) self.menu_tabs.set_submenu(menu)
self.menu_tabs.show_all() self.menu_tabs.show_all()
@ -203,22 +273,15 @@ class TorrentDetails(component.Component):
def set_tab_visible(self, tab_name, visible): def set_tab_visible(self, tab_name, visible):
"""Sets the tab to visible""" """Sets the tab to visible"""
log.debug("set_tab_visible name: %s visible: %s", tab_name, visible) log.debug("set_tab_visible name: %s visible: %s", tab_name, visible)
if visible: if visible and not self.tabs[tab_name].is_visible:
# We need to show tab, make sure it's not already shown self.show_tab(tab_name)
if tab_name not in self.hidden_tabs.keys(): elif not visible and self.tabs[tab_name].is_visible:
return self.hide_tab(tab_name)
# Add the tab back to the notebook
self.add_tab(self.hidden_tabs[tab_name][0], self.hidden_tabs[tab_name][1], generate_menu=False)
del self.hidden_tabs[tab_name]
else:
# Check to see if tab is already hidden
if tab_name in self.hidden_tabs.keys():
return
# Remove the tab from the notebook and store it in hidden_tabs
self.hidden_tabs[tab_name] = (self.tabs[tab_name], self.tab_index.index(tab_name))
self.remove_tab(tab_name)
def stop(self): def stop(self):
self.clear()
def shutdown(self):
# Save the state of the tabs # Save the state of the tabs
for tab in self.tabs: for tab in self.tabs:
try: try:
@ -226,7 +289,6 @@ class TorrentDetails(component.Component):
except AttributeError: except AttributeError:
pass pass
self.clear()
# Save tabs state # Save tabs state
self.save_state() self.save_state()
@ -240,17 +302,26 @@ class TorrentDetails(component.Component):
page_num = self.notebook.get_current_page() page_num = self.notebook.get_current_page()
try: try:
# Get the tab name # Get the tab name
name = self.tab_index[page_num] name = None
for tab in self.tabs:
if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
name = tab
except IndexError: except IndexError:
return return
# Update the tab that is in view # Update the tab that is in view
self.tabs[name].update() if name:
self.tabs[name].update()
def clear(self): def clear(self):
# Get the tab name # Get the tab name
try: try:
name = self.tab_index[self.notebook.get_current_page()] page_num = self.notebook.get_current_page()
self.tabs[name].clear() name = None
for tab in self.tabs:
if self.tabs[tab].position == page_num and self.tabs[tab].is_visible:
name = tab
if name:
self.tabs[name].clear()
except Exception, e: except Exception, e:
log.debug("Unable to clear torrentdetails: %s", e) log.debug("Unable to clear torrentdetails: %s", e)
@ -262,16 +333,10 @@ class TorrentDetails(component.Component):
# Get the tab name # Get the tab name
name = widget.get_child().get_text() name = widget.get_child().get_text()
if name == "All": if name == "All":
if self.menu_tabs.get_submenu() is not None: if widget.get_active():
# Widget has been changed to active which means we need to self.show_all_tabs()
# show all the tabs. else:
for tab in self.menu_tabs.get_submenu().get_children(): self.hide_all_tabs()
if isinstance(tab, gtk.SeparatorMenuItem):
continue
if tab.get_child().get_text() == "All" or tab is gtk.SeparatorMenuItem:
continue
tab.set_active(widget.get_active())
return return
self.set_tab_visible(name, widget.get_active()) self.set_tab_visible(name, widget.get_active())
@ -279,8 +344,14 @@ class TorrentDetails(component.Component):
def save_state(self): def save_state(self):
"""We save the state, which is basically the tab_index list""" """We save the state, which is basically the tab_index list"""
filename = "tabs.state" filename = "tabs.state"
state = self.tab_index state = []
for tab in self.tabs:
state.append((self.tabs[tab].weight, self.tabs[tab].get_name(),
self.tabs[tab].is_visible))
# Sort by weight
state.sort()
state = [(n, v) for w, n, v in state]
# Get the config location for saving the state file # Get the config location for saving the state file
config_location = ConfigManager("gtkui.conf")["config_location"] config_location = ConfigManager("gtkui.conf")["config_location"]