Add the very barest of support for tabs.

This commit is contained in:
Chris Jones 2009-11-21 22:28:39 -06:00
parent b6703153a1
commit 9cbc6f1282
3 changed files with 46 additions and 135 deletions

View File

@ -1,86 +1,47 @@
#!/usr/bin/python #!/usr/bin/python
# Terminator by Chris Jones <cmsj@tenshu.net> # Terminator by Chris Jones <cmsj@tenshu.net>
# GPL v2 only # GPL v2 only
"""container.py - classes necessary to contain Terminal widgets""" """notebook.py - classes for the notebook widget"""
import gobject import gobject
import gtk import gtk
from config import Config from container import Container
from util import dbg, err from newterminator import Terminator
from translation import _ from terminal import Terminal
from util import err
# pylint: disable-msg=R0921 class Notebook(Container, gtk.Notebook):
class Container(object): """Class implementing a gtk.Notebook container"""
"""Base class for Terminator Containers"""
terminator = None def __init__(self, window):
immutable = None
children = None
config = None
signals = None
cnxids = None
def __init__(self):
"""Class initialiser""" """Class initialiser"""
self.children = [] if isinstance(window.get_child(), gtk.Notebook):
self.signals = [] err('There is already a Notebook at the top of this window')
self.cnxids = {} raise(ValueError)
self.config = Config()
def register_signals(self, widget): Container.__init__(self)
"""Register gobject signals in a way that avoids multiple inheritance""" gtk.Notebook.__init__(self)
existing = gobject.signal_list_names(widget) self.terminator = Terminator()
for signal in self.signals: gobject.type_register(Notebook)
if signal['name'] in existing: self.register_signals(Notebook)
dbg('Container:: skipping signal %s for %s, already exists' % ( self.configure()
signal['name'], widget))
else:
dbg('Container:: registering signal for %s on %s' %
(signal['name'], widget))
try:
gobject.signal_new(signal['name'],
widget,
signal['flags'],
signal['return_type'],
signal['param_types'])
except RuntimeError:
err('Container:: registering signal for %s on %s failed' %
(signal['name'], widget))
def connect_child(self, widget, signal, handler, data=None): child = window.get_child()
"""Register the requested signal and record its connection ID""" window.remove(child)
if not self.cnxids.has_key(widget): window.add(self)
self.cnxids[widget] = [] self.newtab(child)
self.show_all()
if data is not None: def configure(self):
self.cnxids[widget].append(widget.connect(signal, handler, data)) """Apply widget-wide settings"""
dbg('Container::connect_child: connecting %s(%s) for %s::%s' % #self.connect('page-reordered', self.on_page_reordered)
(handler.__name__, data, widget.__class__.__name__, signal)) self.set_property('homogeneous', not self.config['scroll_tabbar'])
else: self.set_scrollable(self.config['scroll_tabbar'])
self.cnxids[widget].append(widget.connect(signal, handler))
dbg('Container::connect_child: registering %s to handle %s::%s' %
(handler.__name__, widget.__class__.__name__, signal))
def disconnect_child(self, widget): pos = getattr(gtk, 'POS_%s' % self.config['tab_position'].upper())
"""De-register the signals for a child""" self.set_tab_pos(pos)
if self.cnxids.has_key(widget): self.set_show_tabs(not self.config['hide_tabbar'])
for cnxid in self.cnxids[widget]:
# FIXME: Look up the IDs to print a useful debugging message
widget.disconnect(cnxid)
del(self.cnxids[widget])
def get_offspring(self):
"""Return a list of child widgets, if any"""
return(self.children)
def split_horiz(self, widget):
"""Split this container horizontally"""
return(self.split_axis(widget, True))
def split_vert(self, widget):
"""Split this container vertically"""
return(self.split_axis(widget, False))
def split_axis(self, widget, vertical=True, sibling=None): def split_axis(self, widget, vertical=True, sibling=None):
"""Default axis splitter. This should be implemented by subclasses""" """Default axis splitter. This should be implemented by subclasses"""
@ -94,40 +55,21 @@ class Container(object):
"""Remove a widget from the container""" """Remove a widget from the container"""
raise NotImplementedError('remove') raise NotImplementedError('remove')
def closeterm(self, widget): def newtab(self, widget=None):
"""Handle the closure of a terminal""" """Add a new tab, optionally supplying a child widget"""
try: if not widget:
if self.get_property('term_zoomed'): widget = Terminal()
# We're zoomed, so unzoom and then start closing again self.terminator.register_terminal(widget)
dbg('Container::closeterm: terminal zoomed, unzooming') widget.spawn_child()
self.unzoom(widget)
widget.close()
return(True)
except TypeError:
pass
if not self.remove(widget): self.set_tab_reorderable(widget, True)
return(False) self.append_page(widget, None)
widget.grab_focus()
self.terminator.deregister_terminal(widget)
self.terminator.group_hoover()
return(True)
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')
def toggle_zoom(self, widget, fontscale = False):
"""Toggle the existing zoom state"""
try:
if self.get_property('term_zoomed'):
self.unzoom(widget)
else:
self.zoom(widget, fontscale)
except TypeError:
err('Container::toggle_zoom: %s is unable to handle zooming, for \
%s' % (self, widget))
def zoom(self, widget, fontscale = False): def zoom(self, widget, fontscale = False):
"""Zoom a terminal""" """Zoom a terminal"""
raise NotImplementedError('zoom') raise NotImplementedError('zoom')
@ -136,37 +78,4 @@ class Container(object):
"""Unzoom a terminal""" """Unzoom a terminal"""
raise NotImplementedError('unzoom') raise NotImplementedError('unzoom')
def construct_confirm_close(self, window, type):
"""Create a confirmation dialog for closing things"""
dialog = gtk.Dialog(_('Close?'), window, gtk.DIALOG_MODAL)
dialog.set_has_separator(False)
dialog.set_resizable(False)
cancel = dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
close_all = dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT)
label = close_all.get_children()[0].get_children()[0].get_children()[1].set_label(_('Close _Terminals'))
primary = gtk.Label(_('<big><b>Close multiple temrinals?</b></big>'))
primary.set_use_markup(True)
primary.set_alignment(0, 0.5)
secondary = gtk.Label(_('This %s has several terminals open. Closing the \
%s will also close all terminals within it.') % (type, type))
secondary.set_line_wrap(True)
labels = gtk.VBox()
labels.pack_start(primary, False, False, 6)
labels.pack_start(secondary, False, False, 6)
image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING,
gtk.ICON_SIZE_DIALOG)
image.set_alignment(0.5, 0)
box = gtk.HBox()
box.pack_start(image, False, False, 6)
box.pack_start(labels, False, False, 6)
dialog.vbox.pack_start(box, False, False, 12)
dialog.show_all()
return(dialog)
# vim: set expandtab ts=4 sw=4: # vim: set expandtab ts=4 sw=4:

View File

@ -464,7 +464,7 @@ class Terminal(gtk.VBox):
if mapping == "hide_window": if mapping == "hide_window":
return(False) return(False)
if mapping and mapping not in ['close_window', 'full_screen']: if mapping and mapping not in ['close_window', 'full_screen', 'new_tab']:
dbg('Terminal::on_keypress: lookup found: %r' % mapping) dbg('Terminal::on_keypress: lookup found: %r' % mapping)
# handle the case where user has re-bound copy to ctrl+<key> # handle the case where user has re-bound copy to ctrl+<key>
# we only copy if there is a selection otherwise let it fall through # we only copy if there is a selection otherwise let it fall through
@ -963,9 +963,6 @@ class Terminal(gtk.VBox):
def key_close_term(self): def key_close_term(self):
self.close() self.close()
def key_new_tab(self):
self.terminator.newtab(self)
def key_resize_up(self): def key_resize_up(self):
self.emit('resize-term', 'up') self.emit('resize-term', 'up')

View File

@ -12,6 +12,7 @@ from util import dbg, err
from translation import _ from translation import _
from version import APP_NAME from version import APP_NAME
from container import Container from container import Container
from notebook import Notebook
from newterminator import Terminator from newterminator import Terminator
from terminal import Terminal from terminal import Terminal
from paned import HPaned, VPaned from paned import HPaned, VPaned
@ -115,6 +116,10 @@ class Window(Container, gtk.Window):
gtk.gdk.Event(gtk.gdk.DELETE)): gtk.gdk.Event(gtk.gdk.DELETE)):
self.on_destroy_event(window, self.on_destroy_event(window,
gtk.gdk.Event(gtk.gdk.DESTROY)) gtk.gdk.Event(gtk.gdk.DESTROY))
elif mapping == 'new_tab':
if not isinstance(self.get_child(), Notebook):
notebook = Notebook(self)
self.get_child().newtab()
else: else:
return(False) return(False)
return(True) return(True)