Fix #349 tab ordering when hiding/showing
This commit is contained in:
parent
88ca3bacd1
commit
cfadbec2cf
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue