Add layout save and load of active term for tabs, remember active term on switching tabs, plus more. Too inter-dependant to split into smaller commits.

This commit is contained in:
Stephen Boddy 2013-12-18 18:06:59 +01:00
parent 0272c78739
commit 581b6eeb92
4 changed files with 142 additions and 30 deletions

View File

@ -275,11 +275,14 @@ the %s will also close all terminals within it.') % (reqtype, reqtype))
if mytype == 'Notebook': if mytype == 'Notebook':
labels = [] labels = []
last_active_term = []
for tabnum in xrange(0, self.get_n_pages()): for tabnum in xrange(0, self.get_n_pages()):
page = self.get_nth_page(tabnum) page = self.get_nth_page(tabnum)
label = self.get_tab_label(page) label = self.get_tab_label(page)
labels.append(label.get_custom_label()) labels.append(label.get_custom_label())
last_active_term.append(self.last_active_term[self.get_nth_page(tabnum)])
layout['labels'] = labels layout['labels'] = labels
layout['last_active_term'] = last_active_term
layout['active_page'] = self.get_current_page() layout['active_page'] = self.get_current_page()
else: else:
if hasattr(self, 'last_active_term') and self.last_active_term is not None: if hasattr(self, 'last_active_term') and self.last_active_term is not None:

View File

@ -12,11 +12,14 @@ from factory import Factory
from container import Container from container import Container
from editablelabel import EditableLabel from editablelabel import EditableLabel
from translation import _ from translation import _
from util import err, dbg, enumerate_descendants from util import err, dbg, enumerate_descendants, make_uuid
class Notebook(Container, gtk.Notebook): class Notebook(Container, gtk.Notebook):
"""Class implementing a gtk.Notebook container""" """Class implementing a gtk.Notebook container"""
window = None window = None
last_active_term = None
pending_on_tab_switch = None
pending_on_tab_switch_args = None
def __init__(self, window): def __init__(self, window):
"""Class initialiser""" """Class initialiser"""
@ -30,12 +33,16 @@ class Notebook(Container, gtk.Notebook):
self.window = window self.window = window
gobject.type_register(Notebook) gobject.type_register(Notebook)
self.register_signals(Notebook) self.register_signals(Notebook)
self.connect('switch-page', self.deferred_on_tab_switch)
self.configure() self.configure()
child = window.get_child() child = window.get_child()
window.remove(child) window.remove(child)
window.add(self) window.add(self)
self.newtab(widget=child) self.newtab(widget=child)
if window.last_active_term:
self.set_last_active_term(window.last_active_term)
window.last_active_term = None
self.show_all() self.show_all()
@ -63,6 +70,7 @@ class Notebook(Container, gtk.Notebook):
style.xthickness = 0 style.xthickness = 0
style.ythickness = 0 style.ythickness = 0
self.modify_style(style) self.modify_style(style)
self.last_active_term = {}
def create_layout(self, layout): def create_layout(self, layout):
"""Apply layout configuration""" """Apply layout configuration"""
@ -117,10 +125,14 @@ class Notebook(Container, gtk.Notebook):
label = self.get_tab_label(page) label = self.get_tab_label(page)
label.set_custom_label(labeltext) label.set_custom_label(labeltext)
page.create_layout(children[child_key]) page.create_layout(children[child_key])
if layout.get('last_active_term', None):
self.last_active_term[page] = make_uuid(layout['last_active_term'][num])
num = num + 1 num = num + 1
if layout.has_key('active_page'): if layout.has_key('active_page'):
self.set_current_page(int(layout['active_page'])) # Need to do it later, or layout changes result
gobject.idle_add(self.set_current_page, int(layout['active_page']))
else: else:
self.set_current_page(0) self.set_current_page(0)
@ -167,12 +179,13 @@ class Notebook(Container, gtk.Notebook):
self.set_current_page(page_num) self.set_current_page(page_num)
self.show_all() self.show_all()
terminal.grab_focus()
while gtk.events_pending(): while gtk.events_pending():
gtk.main_iteration_do(False) gtk.main_iteration_do(False)
self.get_toplevel().set_pos_by_ratio = False self.get_toplevel().set_pos_by_ratio = False
gobject.idle_add(terminal.ensure_visible_and_focussed)
def add(self, widget, metadata=None): def add(self, widget, metadata=None):
"""Add a widget to the container""" """Add a widget to the container"""
dbg('adding a new tab') dbg('adding a new tab')
@ -268,15 +281,22 @@ class Notebook(Container, gtk.Notebook):
dbg('inserting page at position: %s' % tabpos) dbg('inserting page at position: %s' % tabpos)
self.insert_page(widget, None, tabpos) self.insert_page(widget, None, tabpos)
self.set_tab_label(widget, label) child_widgets = [widget]
self.set_tab_label_packing(widget, not self.config['scroll_tabbar'], child_widgets .extend(enumerate_descendants(widget))
not self.config['scroll_tabbar'], term_widget = None
gtk.PACK_START) for term_widget in child_widgets:
if maker.isinstance(term_widget, 'Terminal'):
self.set_last_active_term(term_widget.uuid)
self.set_tab_label(term_widget, label)
self.set_tab_label_packing(term_widget, not self.config['scroll_tabbar'],
not self.config['scroll_tabbar'],
gtk.PACK_START)
break
self.set_tab_reorderable(widget, True) self.set_tab_reorderable(widget, True)
self.set_current_page(tabpos) self.set_current_page(tabpos)
self.show_all() self.show_all()
if maker.isinstance(widget, 'Terminal'): if maker.isinstance(term_widget, 'Terminal'):
widget.grab_focus() widget.grab_focus()
def wrapcloseterm(self, widget): def wrapcloseterm(self, widget):
@ -311,6 +331,7 @@ class Notebook(Container, gtk.Notebook):
if maker.isinstance(child, 'Terminal'): if maker.isinstance(child, 'Terminal'):
dbg('Notebook::closetab: child is a single Terminal') dbg('Notebook::closetab: child is a single Terminal')
del nb.last_active_term[child]
child.close() child.close()
# FIXME: We only do this del and return here to avoid removing the # FIXME: We only do this del and return here to avoid removing the
# page below, which child.close() implicitly does # page below, which child.close() implicitly does
@ -318,9 +339,7 @@ class Notebook(Container, gtk.Notebook):
return return
elif maker.isinstance(child, 'Container'): elif maker.isinstance(child, 'Container'):
dbg('Notebook::closetab: child is a Container') dbg('Notebook::closetab: child is a Container')
dialog = self.construct_confirm_close(self.window, _('tab')) result = self.construct_confirm_close(self.window, _('tab'))
result = dialog.run()
dialog.destroy()
if result == gtk.RESPONSE_ACCEPT: if result == gtk.RESPONSE_ACCEPT:
containers = None containers = None
@ -340,9 +359,6 @@ class Notebook(Container, gtk.Notebook):
err('Notebook::closetab: child is unknown type %s' % child) err('Notebook::closetab: child is unknown type %s' % child)
return return
nb.remove_page(tabnum)
del(label)
def resizeterm(self, widget, keyname): def resizeterm(self, widget, keyname):
"""Handle a keyboard event requesting a terminal resize""" """Handle a keyboard event requesting a terminal resize"""
raise NotImplementedError('resizeterm') raise NotImplementedError('resizeterm')
@ -403,6 +419,65 @@ class Notebook(Container, gtk.Notebook):
terms = parent.get_visible_terminals() terms = parent.get_visible_terminals()
terms.keys()[-1].grab_focus() terms.keys()[-1].grab_focus()
def page_num_descendant(self, widget):
"""Find the tabnum of the tab containing a widget at any level"""
tabnum = self.page_num(widget)
dbg("widget is direct child if not equal -1 - tabnum: %d" % tabnum)
while tabnum == -1 and widget.get_parent():
widget = widget.get_parent()
tabnum = self.page_num(widget)
dbg("found tabnum containing widget: %d" % tabnum)
return tabnum
def set_last_active_term(self, uuid):
"""Set the last active term for uuid"""
widget = self.terminator.find_terminal_by_uuid(uuid.urn)
if not widget:
err("Cannot find terminal with uuid: %s, so cannot make it active" % (uuid.urn))
return
tabnum = self.page_num_descendant(widget)
if tabnum == -1:
err("No tabnum found for terminal with uuid: %s" % (uuid.urn))
return
nth_page = self.get_nth_page(tabnum)
self.last_active_term[nth_page] = uuid
def clean_last_active_term(self):
"""Clean up old entries in last_active_term"""
if self.terminator.doing_layout == True:
return
last_active_term = {}
for tabnum in xrange(0, self.get_n_pages()):
nth_page = self.get_nth_page(tabnum)
if nth_page in self.last_active_term:
last_active_term[nth_page] = self.last_active_term[nth_page]
self.last_active_term = last_active_term
def deferred_on_tab_switch(self, notebook, page, page_num, data=None):
"""Prime a single idle tab switch signal, using the most recent set of params"""
tabs_last_active_term = self.last_active_term.get(self.get_nth_page(page_num), None)
data = {'tabs_last_active_term':tabs_last_active_term}
self.pending_on_tab_switch_args = (notebook, page, page_num, data)
if self.pending_on_tab_switch == True:
return
gobject.idle_add(self.do_deferred_on_tab_switch)
self.pending_on_tab_switch = True
def do_deferred_on_tab_switch(self):
"""Perform the latest tab switch signal, and resetting the pending flag"""
self.on_tab_switch(*self.pending_on_tab_switch_args)
self.pending_on_tab_switch = False
self.pending_on_tab_switch_args = None
def on_tab_switch(self, notebook, page, page_num, data=None):
"""Do the real work for a tab switch"""
tabs_last_active_term = data['tabs_last_active_term']
if tabs_last_active_term:
term = self.terminator.find_terminal_by_uuid(tabs_last_active_term.urn)
gobject.idle_add(term.ensure_visible_and_focussed)
return True
class TabLabel(gtk.HBox): class TabLabel(gtk.HBox):
"""Class implementing a label widget for Notebook tabs""" """Class implementing a label widget for Notebook tabs"""
notebook = None notebook = None

View File

@ -1069,13 +1069,12 @@ class Terminal(gtk.VBox):
maker = Factory() maker = Factory()
if maker.isinstance(topchild, 'Notebook'): if maker.isinstance(topchild, 'Notebook'):
prevtmp = None # Find which page number this term is on
tmp = self.get_parent() tabnum = topchild.page_num_descendant(self)
while tmp != topchild: # If terms page number is not the current one, switch to it
prevtmp = tmp current_page = topchild.get_current_page()
tmp = tmp.get_parent() if tabnum != current_page:
page = topchild.page_num(prevtmp) topchild.set_current_page(tabnum)
topchild.set_current_page(page)
self.grab_focus() self.grab_focus()
@ -1091,7 +1090,9 @@ class Terminal(gtk.VBox):
if not self.terminator.doing_layout: if not self.terminator.doing_layout:
self.terminator.last_focused_term = self self.terminator.last_focused_term = self
if self.get_toplevel().is_child_notebook(): if self.get_toplevel().is_child_notebook():
# TODO: Will need some code for the tabs active terms to work notebook = self.get_toplevel().get_children()[0]
notebook.set_last_active_term(self.uuid)
notebook.clean_last_active_term()
self.get_toplevel().last_active_term = None self.get_toplevel().last_active_term = None
else: else:
self.get_toplevel().last_active_term = self.uuid self.get_toplevel().last_active_term = self.uuid

View File

@ -292,21 +292,54 @@ class Terminator(Borg):
def layout_done(self): def layout_done(self):
"""Layout operations have finished, record that fact""" """Layout operations have finished, record that fact"""
self.doing_layout = False self.doing_layout = False
maker = Factory()
window_last_active_term_mapping={} window_last_active_term_mapping = {}
for window in self.windows: for window in self.windows:
# TODO: Will need some code for the tabs active terms to work if window.is_child_notebook():
window_last_active_term_mapping[window]=copy.deepcopy(window.last_active_term) source = window.get_toplevel().get_children()[0]
else:
source = window
window_last_active_term_mapping[window] = copy.copy(source.last_active_term)
for terminal in self.terminals: for terminal in self.terminals:
if not terminal.pid: if not terminal.pid:
terminal.spawn_child() terminal.spawn_child()
for window in self.windows: for window in self.windows:
if window.last_active_term: if window.is_child_notebook():
# TODO: Will need some code for the tabs active terms to work # For windows with a notebook
term = self.find_terminal_by_uuid(window_last_active_term_mapping[window].urn) notebook = window.get_toplevel().get_children()[0]
term.ensure_visible_and_focussed() # Cycle through pages by number
for page in xrange(0, notebook.get_n_pages()):
# Try and get the entry in the previously saved mapping
mapping = window_last_active_term_mapping[window]
page_last_active_term = mapping.get(notebook.get_nth_page(page), None)
if page_last_active_term is None:
# Couldn't find entry, so we find the first child of type Terminal
children = notebook.get_nth_page(page).get_children()
for page_last_active_term in children:
if maker.isinstance(page_last_active_term, 'Terminal'):
page_last_active_term = page_last_active_term.uuid
break
else:
err('Should never reach here!')
page_last_active_term = None
if page_last_active_term is None:
# Bail on this tab as we're having no luck here, continue with the next
continue
# Set the notebook entry, then ensure Terminal is visible and focussed
urn = page_last_active_term.urn
notebook.last_active_term[notebook.get_nth_page(page)] = page_last_active_term
if urn:
term = self.find_terminal_by_uuid(urn)
if term:
term.ensure_visible_and_focussed()
else:
# For windows without a notebook ensure Terminal is visible and focussed
if window_last_active_term_mapping[window]:
term = self.find_terminal_by_uuid(window_last_active_term_mapping[window].urn)
term.ensure_visible_and_focussed()
for window in self.windows: for window in self.windows:
if window.uuid == self.last_active_window: if window.uuid == self.last_active_window: