terminator/terminatorlib/notebook.py

269 lines
8.4 KiB
Python
Raw Normal View History

#!/usr/bin/python
# Terminator by Chris Jones <cmsj@tenshu.net>
# GPL v2 only
"""notebook.py - classes for the notebook widget"""
import gobject
import gtk
from newterminator import Terminator
2009-11-23 15:17:33 +00:00
from config import Config
from factory import Factory
2009-11-23 15:17:33 +00:00
from container import Container
from editablelabel import EditableLabel
from translation import _
from util import err
class Notebook(Container, gtk.Notebook):
"""Class implementing a gtk.Notebook container"""
2009-11-23 15:17:33 +00:00
window = None
def __init__(self, window):
"""Class initialiser"""
if isinstance(window.get_child(), gtk.Notebook):
err('There is already a Notebook at the top of this window')
raise(ValueError)
Container.__init__(self)
gtk.Notebook.__init__(self)
self.terminator = Terminator()
2009-11-23 15:17:33 +00:00
self.window = window
gobject.type_register(Notebook)
self.register_signals(Notebook)
self.configure()
child = window.get_child()
window.remove(child)
window.add(self)
self.newtab(child)
2009-11-23 15:17:33 +00:00
self.show_all()
def configure(self):
"""Apply widget-wide settings"""
# FIXME: Should all of our widgets have this?
#self.connect('page-reordered', self.on_page_reordered)
self.set_property('homogeneous', not self.config['scroll_tabbar'])
self.set_scrollable(self.config['scroll_tabbar'])
pos = getattr(gtk, 'POS_%s' % self.config['tab_position'].upper())
self.set_tab_pos(pos)
self.set_show_tabs(not self.config['hide_tabbar'])
def split_axis(self, widget, vertical=True, sibling=None):
"""Default axis splitter. This should be implemented by subclasses"""
page_num = self.page_num(widget)
if page_num == -1:
err('Notebook::split_axis: %s not found in Notebook' % widget)
return
self.remove_page(page_num)
maker = Factory()
if vertical:
container = maker.make('vpaned')
else:
container = maker.make('hpaned')
if not sibling:
sibling = maker.make('terminal')
self.terminator.register_terminal(sibling)
sibling.spawn_child()
self.insert_page(container, None, page_num)
self.show_all()
container.add(widget)
container.add(sibling)
self.set_current_page(page_num)
self.show_all()
def add(self, widget):
"""Add a widget to the container"""
raise NotImplementedError('add')
def remove(self, widget):
"""Remove a widget from the container"""
page_num = self.page_num(widget)
if page_num == -1:
err('Notebook::remove: %s not found in Notebook' % widget)
return(False)
self.remove_page(page_num)
return(True)
def newtab(self, widget=None):
"""Add a new tab, optionally supplying a child widget"""
if not widget:
maker = Factory()
widget = maker.make('terminal')
self.terminator.register_terminal(widget)
widget.spawn_child()
signals = {'close-term': self.wrapcloseterm,
#'title-change': self.title.set_title,
'split-horiz': self.split_horiz,
'split-vert': self.split_vert,
'unzoom': self.unzoom}
maker = Factory()
if maker.isinstance(widget, 'Terminal'):
for signal in signals:
self.connect_child(widget, signal, signals[signal])
self.set_tab_reorderable(widget, True)
2009-11-23 15:17:33 +00:00
label = TabLabel(self.window.get_title(), self)
label.connect('close-clicked', self.closetab)
2009-11-23 15:17:33 +00:00
label.show_all()
widget.show_all()
self.append_page(widget, None)
2009-11-23 15:17:33 +00:00
self.set_tab_label(widget, label)
self.set_tab_label_packing(widget, not self.config['scroll_tabbar'],
not self.config['scroll_tabbar'],
gtk.PACK_START)
self.set_current_page(-1)
widget.grab_focus()
def wrapcloseterm(self, widget):
"""A child terminal has closed"""
if self.closeterm(widget):
if self.get_n_pages() == 1:
child = self.get_nth_page(0)
self.remove_page(0)
parent = self.get_parent()
parent.remove(self)
parent.add(child)
del(self)
def closetab(self, widget, label):
"""Close a tab"""
tabnum = None
try:
nb = widget.notebook
except AttributeError:
err('TabLabel::closetab: called on non-Notebook: %s' % widget)
return
for i in xrange(0, nb.get_n_pages()):
if label == nb.get_tab_label(nb.get_nth_page(i)):
tabnum = i
break
if not tabnum:
err('TabLabel::closetab: %s not in %s' % (label, nb))
return
maker = Factory()
child = nb.get_nth_page(tabnum)
if maker.isinstance(child, 'Terminal'):
child.close()
elif maker.isinstance(child, 'Container'):
#FIXME: Handle this case
dbg('Notebook::closetab: Container children not yet handled')
else:
err('Notebook::closetab: Unknown child type %s' % child)
nb.remove_page(tabnum)
del(label)
def resizeterm(self, widget, keyname):
"""Handle a keyboard event requesting a terminal resize"""
raise NotImplementedError('resizeterm')
def zoom(self, widget, fontscale = False):
"""Zoom a terminal"""
raise NotImplementedError('zoom')
def unzoom(self, widget):
"""Unzoom a terminal"""
raise NotImplementedError('unzoom')
2009-11-23 15:17:33 +00:00
class TabLabel(gtk.HBox):
"""Class implementing a label widget for Notebook tabs"""
notebook = None
terminator = None
config = None
label = None
icon = None
button = None
__gsignals__ = {
'close-clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
(gobject.TYPE_OBJECT,)),
}
2009-11-23 15:17:33 +00:00
def __init__(self, title, notebook):
"""Class initialiser"""
gtk.HBox.__init__(self)
self.__gobject_init__()
2009-11-23 15:17:33 +00:00
self.notebook = notebook
self.terminator = Terminator()
self.config = Config()
self.label = EditableLabel(title)
self.update_angle()
self.pack_start(self.label, True, True)
self.update_button()
self.show_all()
def update_button(self):
"""Update the state of our close button"""
if not self.config['close_button_on_tab']:
if self.button:
self.button.remove(self.icon)
self.remove(self.button)
del(self.button)
del(self.icon)
self.button = None
self.icon = None
return
if not self.button:
self.button = gtk.Button()
if not self.icon:
self.icon = gtk.Image()
self.icon.set_from_stock(gtk.STOCK_CLOSE,
gtk.ICON_SIZE_MENU)
self.button.set_relief(gtk.RELIEF_NONE)
self.button.set_focus_on_click(False)
# FIXME: Why on earth are we doing this twice?
self.button.set_relief(gtk.RELIEF_NONE)
self.button.add(self.icon)
self.button.connect('clicked', self.on_close)
self.button.set_name('terminator-tab-close-button')
self.button.connect('style-set', self.on_style_set)
if hasattr(self.button, 'set_tooltip_text'):
self.button.set_tooltip_text(_('Close Tab'))
self.pack_start(self.button, False, False)
self.show_all()
def update_angle(self):
"""Update the angle of a label"""
position = self.notebook.get_tab_pos()
if position == gtk.POS_LEFT:
self.label.set_angle(90)
elif position == gtk.POS_RIGHT:
self.label.set_angle(270)
else:
self.label.set_angle(0)
def on_style_set(self, widget, prevstyle):
"""Style changed, recalculate icon size"""
x, y = gtk.icon_size_lookup_for_settings(self.button.get_settings(),
gtk.ICON_SIZE_MENU)
self.button.set_size_request(x + 2, y + 2)
def on_close(self, widget):
"""The close button has been clicked. Destroy the tab"""
self.emit('close-clicked', self)
# vim: set expandtab ts=4 sw=4: