First run at layout loading, creating, enumerating and saving. It sucks and works poorly at the moment, but here it is
This commit is contained in:
parent
5392585893
commit
678057a0d3
|
@ -43,7 +43,7 @@ import terminatorlib.optionparse
|
||||||
from terminatorlib.terminator import Terminator
|
from terminatorlib.terminator import Terminator
|
||||||
from terminatorlib.factory import Factory
|
from terminatorlib.factory import Factory
|
||||||
from terminatorlib.version import APP_NAME, APP_VERSION
|
from terminatorlib.version import APP_NAME, APP_VERSION
|
||||||
from terminatorlib.util import dbg
|
from terminatorlib.util import dbg, err
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION))
|
dbg ("%s starting up, version %s" % (APP_NAME, APP_VERSION))
|
||||||
|
@ -54,6 +54,10 @@ if __name__ == '__main__':
|
||||||
TERMINATOR = Terminator()
|
TERMINATOR = Terminator()
|
||||||
TERMINATOR.origcwd = ORIGCWD
|
TERMINATOR.origcwd = ORIGCWD
|
||||||
TERMINATOR.reconfigure()
|
TERMINATOR.reconfigure()
|
||||||
|
try:
|
||||||
|
TERMINATOR.create_layout(OPTIONS.layout)
|
||||||
|
except (KeyError,ValueError), ex:
|
||||||
|
err('layout creation failed, creating a window ("%s")' % ex)
|
||||||
TERMINATOR.new_window()
|
TERMINATOR.new_window()
|
||||||
|
|
||||||
if OPTIONS.debug > 2:
|
if OPTIONS.debug > 2:
|
||||||
|
|
|
@ -206,7 +206,7 @@ DEFAULTS = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'layouts': {
|
'layouts': {
|
||||||
'default': {'type': 'Terminal'}
|
'default': "{'type': 'Window', 'children': [{'type': 'Terminal'}]}",
|
||||||
},
|
},
|
||||||
'plugins': {
|
'plugins': {
|
||||||
},
|
},
|
||||||
|
@ -266,9 +266,9 @@ class Config(object):
|
||||||
"""List all configured profiles"""
|
"""List all configured profiles"""
|
||||||
return(self.base.profiles.keys())
|
return(self.base.profiles.keys())
|
||||||
|
|
||||||
def add_layout(self, layout):
|
def add_layout(self, name, layout):
|
||||||
"""Add a new layout"""
|
"""Add a new layout"""
|
||||||
return(self.base.add_layout(layout))
|
return(self.base.add_layout(name, layout))
|
||||||
|
|
||||||
def del_layout(self, layout):
|
def del_layout(self, layout):
|
||||||
"""Delete a layout"""
|
"""Delete a layout"""
|
||||||
|
@ -335,6 +335,14 @@ class Config(object):
|
||||||
"""Set a whole config tree for a given plugin"""
|
"""Set a whole config tree for a given plugin"""
|
||||||
return(self.base.set_plugin(plugin, tree))
|
return(self.base.set_plugin(plugin, tree))
|
||||||
|
|
||||||
|
def layout_get_config(self, layout):
|
||||||
|
"""Return a layout"""
|
||||||
|
return(self.base.get_layout(layout))
|
||||||
|
|
||||||
|
def layout_set_config(self, layout, tree):
|
||||||
|
"""Set a layout"""
|
||||||
|
return(self.base.set_layout(layout, tree))
|
||||||
|
|
||||||
class ConfigBase(Borg):
|
class ConfigBase(Borg):
|
||||||
"""Class to provide access to our user configuration"""
|
"""Class to provide access to our user configuration"""
|
||||||
loaded = None
|
loaded = None
|
||||||
|
@ -371,7 +379,9 @@ class ConfigBase(Borg):
|
||||||
if self.plugins is None:
|
if self.plugins is None:
|
||||||
self.plugins = {}
|
self.plugins = {}
|
||||||
if self.layouts is None:
|
if self.layouts is None:
|
||||||
self.layouts = copy(DEFAULTS['layouts'])
|
self.layouts = {}
|
||||||
|
for layout in DEFAULTS['layouts']:
|
||||||
|
self.layouts[layout] = eval(DEFAULTS['layouts'][layout])
|
||||||
|
|
||||||
def defaults_to_configspec(self):
|
def defaults_to_configspec(self):
|
||||||
"""Convert our tree of default values into a ConfigObj validation
|
"""Convert our tree of default values into a ConfigObj validation
|
||||||
|
@ -463,11 +473,23 @@ class ConfigBase(Borg):
|
||||||
if not section.has_key(section_name):
|
if not section.has_key(section_name):
|
||||||
section[profile] = copy(DEFAULTS['profiles']['default'])
|
section[profile] = copy(DEFAULTS['profiles']['default'])
|
||||||
section[profile].update(parser[section_name][profile])
|
section[profile].update(parser[section_name][profile])
|
||||||
elif section_name == ['layouts', 'plugins']:
|
elif section_name == 'plugins':
|
||||||
for part in parser[section_name]:
|
for part in parser[section_name]:
|
||||||
dbg('ConfigBase::load: Processing %s: %s' % (section_name,
|
dbg('ConfigBase::load: Processing %s: %s' % (section_name,
|
||||||
part))
|
part))
|
||||||
section[part] = parser[section_name][part]
|
section[part] = parser[section_name][part]
|
||||||
|
elif section_name == 'layouts':
|
||||||
|
for part in parser[section_name]:
|
||||||
|
dbg('ConfigBase::load: Processing %s: %s' % (section_name,
|
||||||
|
part))
|
||||||
|
try:
|
||||||
|
windows = []
|
||||||
|
for window in parser[section_name][part]:
|
||||||
|
windows.append(eval(window))
|
||||||
|
section[part] = windows
|
||||||
|
except Exception, ex:
|
||||||
|
err('Unable to parse layout: %s (%s: %s)' % (part, ex,
|
||||||
|
window))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
section.update(parser[section_name])
|
section.update(parser[section_name])
|
||||||
|
@ -497,8 +519,13 @@ class ConfigBase(Borg):
|
||||||
parser['layouts'] = {}
|
parser['layouts'] = {}
|
||||||
for layout in self.layouts:
|
for layout in self.layouts:
|
||||||
dbg('ConfigBase::save: Processing layout: %s' % layout)
|
dbg('ConfigBase::save: Processing layout: %s' % layout)
|
||||||
parser['layouts'][layout] = dict_diff(
|
if layout == 'default' and \
|
||||||
DEFAULTS['layouts']['default'], self.layouts[layout])
|
str(self.layouts[layout]) == DEFAULTS['layouts']['default']:
|
||||||
|
continue;
|
||||||
|
parser['layouts'][layout] = []
|
||||||
|
# FIXME: This look seems pointless and broken
|
||||||
|
for window in self.layouts[layout]:
|
||||||
|
parser['layouts'][layout].append(str(self.layouts[layout]))
|
||||||
|
|
||||||
parser['plugins'] = {}
|
parser['plugins'] = {}
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
|
@ -568,10 +595,21 @@ class ConfigBase(Borg):
|
||||||
self.profiles[profile] = copy(DEFAULTS['profiles']['default'])
|
self.profiles[profile] = copy(DEFAULTS['profiles']['default'])
|
||||||
return(True)
|
return(True)
|
||||||
|
|
||||||
def add_layout(self, layout):
|
def add_layout(self, name, layout):
|
||||||
"""Add a new layout"""
|
"""Add a new layout"""
|
||||||
if layout in self.layouts:
|
if name in self.layouts:
|
||||||
return(False)
|
return(False)
|
||||||
self.layouts[layout] = {'type': 'Terminal'}
|
self.layouts[name] = layout
|
||||||
return(True)
|
return(True)
|
||||||
|
|
||||||
|
def get_layout(self, layout):
|
||||||
|
"""Return a layout"""
|
||||||
|
if self.layouts.has_key(layout):
|
||||||
|
return(self.layouts[layout])
|
||||||
|
else:
|
||||||
|
err('layout does not exist: %s' % layout)
|
||||||
|
|
||||||
|
def set_layout(self, layout, tree):
|
||||||
|
"""Set a layout"""
|
||||||
|
self.layouts[layout] = tree
|
||||||
|
|
||||||
|
|
|
@ -190,4 +190,24 @@ the %s will also close all terminals within it.') % (reqtype, reqtype))
|
||||||
|
|
||||||
return(terminals)
|
return(terminals)
|
||||||
|
|
||||||
|
def describe_layout(self):
|
||||||
|
"""Describe our current layout"""
|
||||||
|
layout = {}
|
||||||
|
maker = Factory()
|
||||||
|
mytype = maker.type(self)
|
||||||
|
if not mytype:
|
||||||
|
err('unable to detemine own type. %s' % self)
|
||||||
|
return({})
|
||||||
|
|
||||||
|
layout['type'] = mytype
|
||||||
|
layout['children'] = []
|
||||||
|
for child in self.get_children():
|
||||||
|
layout['children'].append(child.describe_layout())
|
||||||
|
|
||||||
|
return(layout)
|
||||||
|
|
||||||
|
def create_layout(self, layout):
|
||||||
|
"""Apply settings for our layout"""
|
||||||
|
raise NotImplementedError('create_layout')
|
||||||
|
|
||||||
# vim: set expandtab ts=4 sw=4:
|
# vim: set expandtab ts=4 sw=4:
|
||||||
|
|
|
@ -26,6 +26,14 @@ from util import dbg, err
|
||||||
# pylint: disable-msg=W0613
|
# pylint: disable-msg=W0613
|
||||||
class Factory(Borg):
|
class Factory(Borg):
|
||||||
"""Definition of a class that makes other classes"""
|
"""Definition of a class that makes other classes"""
|
||||||
|
types = {'Terminal': 'terminal',
|
||||||
|
'VPaned': 'paned',
|
||||||
|
'HPaned': 'paned',
|
||||||
|
'Paned': 'paned',
|
||||||
|
'Notebook': 'notebook',
|
||||||
|
'Container': 'container',
|
||||||
|
'Window': 'window'}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Class initialiser"""
|
"""Class initialiser"""
|
||||||
Borg.__init__(self, self.__class__.__name__)
|
Borg.__init__(self, self.__class__.__name__)
|
||||||
|
@ -37,28 +45,31 @@ class Factory(Borg):
|
||||||
|
|
||||||
def isinstance(self, product, classtype):
|
def isinstance(self, product, classtype):
|
||||||
"""Check if a given product is a particular type of object"""
|
"""Check if a given product is a particular type of object"""
|
||||||
types = {'Terminal': 'terminal',
|
if classtype in self.types.keys():
|
||||||
'VPaned': 'paned',
|
|
||||||
'HPaned': 'paned',
|
|
||||||
'Paned': 'paned',
|
|
||||||
'Notebook': 'notebook',
|
|
||||||
'Container': 'container',
|
|
||||||
'Window': 'window'}
|
|
||||||
if classtype in types.keys():
|
|
||||||
# This is quite ugly, but we're importing from the current
|
# This is quite ugly, but we're importing from the current
|
||||||
# directory if that makes sense, otherwise falling back to
|
# directory if that makes sense, otherwise falling back to
|
||||||
# terminatorlib. Someone with real Python skills should fix
|
# terminatorlib. Someone with real Python skills should fix
|
||||||
# this to be less insane.
|
# this to be less insane.
|
||||||
try:
|
try:
|
||||||
module = __import__(types[classtype], None, None, [''])
|
module = __import__(self.types[classtype], None, None, [''])
|
||||||
except ImportError:
|
except ImportError:
|
||||||
module = __import__('terminatorlib.%s' % types[classtype],
|
module = __import__('terminatorlib.%s' % self.types[classtype],
|
||||||
None, None, [''])
|
None, None, [''])
|
||||||
return(isinstance(product, getattr(module, classtype)))
|
return(isinstance(product, getattr(module, classtype)))
|
||||||
else:
|
else:
|
||||||
err('Factory::isinstance: unknown class type: %s' % classtype)
|
err('Factory::isinstance: unknown class type: %s' % classtype)
|
||||||
return(False)
|
return(False)
|
||||||
|
|
||||||
|
def type(self, product):
|
||||||
|
"""Determine the type of an object we've previously created"""
|
||||||
|
for atype in self.types:
|
||||||
|
# Skip over generic types
|
||||||
|
if atype in ['Container', 'Paned']:
|
||||||
|
continue
|
||||||
|
if self.isinstance(product, atype):
|
||||||
|
return(atype)
|
||||||
|
return(None)
|
||||||
|
|
||||||
def make(self, product, **kwargs):
|
def make(self, product, **kwargs):
|
||||||
"""Make the requested product"""
|
"""Make the requested product"""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -67,6 +67,7 @@ command to execute inside the terminal, and its arguments')
|
||||||
dest='working_directory', help='Set the working directory')
|
dest='working_directory', help='Set the working directory')
|
||||||
parser.add_option('-r', '--role', dest='role', help='Set a custom \
|
parser.add_option('-r', '--role', dest='role', help='Set a custom \
|
||||||
WM_WINDOW_ROLE property on the window')
|
WM_WINDOW_ROLE property on the window')
|
||||||
|
parser.add_option('-l', '--layout', dest='layout', help='Select a layout')
|
||||||
for item in ['--sm-client-id', '--sm-config-prefix', '--screen', '-n',
|
for item in ['--sm-client-id', '--sm-config-prefix', '--screen', '-n',
|
||||||
'--no-gconf', '-p', '--profile' ]:
|
'--no-gconf', '-p', '--profile' ]:
|
||||||
parser.add_option(item, dest='dummy', action='store',
|
parser.add_option(item, dest='dummy', action='store',
|
||||||
|
|
|
@ -178,6 +178,40 @@ class Paned(Container):
|
||||||
# This is not a key we can handle
|
# This is not a key we can handle
|
||||||
self.emit('resize-term', keyname)
|
self.emit('resize-term', keyname)
|
||||||
|
|
||||||
|
def create_layout(self, layout):
|
||||||
|
"""Apply layout configuration"""
|
||||||
|
if not layout.has_key('children'):
|
||||||
|
err('layout specifies no children: %s' % layout)
|
||||||
|
return
|
||||||
|
|
||||||
|
children = layout['children']
|
||||||
|
if len(children) != 2:
|
||||||
|
# Paned widgets can only have two children
|
||||||
|
err('incorrect number of children for Paned: %s' % layout)
|
||||||
|
return
|
||||||
|
|
||||||
|
for num in xrange(0, 2):
|
||||||
|
child = children[num]
|
||||||
|
if child['type'] == 'Terminal':
|
||||||
|
continue
|
||||||
|
elif child['type'] == 'VPaned':
|
||||||
|
if num == 0:
|
||||||
|
terminal = self.get_child1()
|
||||||
|
else:
|
||||||
|
terminal = self.get_child2()
|
||||||
|
self.split_axis(terminal, True)
|
||||||
|
elif child['type'] == 'HPaned':
|
||||||
|
if num == 0:
|
||||||
|
terminal = self.get_child1()
|
||||||
|
else:
|
||||||
|
terminal = self.get_child2()
|
||||||
|
self.split_axis(terminal, False)
|
||||||
|
else:
|
||||||
|
err('unknown child type: %s' % child['type'])
|
||||||
|
|
||||||
|
self.get_child1().create_layout(children[0])
|
||||||
|
self.get_child2().create_layout(children[1])
|
||||||
|
|
||||||
class HPaned(Paned, gtk.HPaned):
|
class HPaned(Paned, gtk.HPaned):
|
||||||
"""Merge gtk.HPaned into our base Paned Container"""
|
"""Merge gtk.HPaned into our base Paned Container"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -662,21 +662,23 @@ class PrefsEditor:
|
||||||
|
|
||||||
def on_layoutaddbutton_clicked(self, _button):
|
def on_layoutaddbutton_clicked(self, _button):
|
||||||
"""Add a new layout to the list"""
|
"""Add a new layout to the list"""
|
||||||
|
terminator = Terminator()
|
||||||
|
current_layout = terminator.describe_layout()
|
||||||
guiget = self.builder.get_object
|
guiget = self.builder.get_object
|
||||||
|
|
||||||
treeview = guiget('layoutlist')
|
treeview = guiget('layoutlist')
|
||||||
model = treeview.get_model()
|
model = treeview.get_model()
|
||||||
values = [ r[0] for r in model ]
|
values = [ r[0] for r in model ]
|
||||||
|
|
||||||
newlayout = _('New Layout')
|
name = _('New Layout')
|
||||||
if newlayout in values:
|
if name in values:
|
||||||
i = 1
|
i = 1
|
||||||
while newlayout in values:
|
while name in values:
|
||||||
i = i + 1
|
i = i + 1
|
||||||
newlayout = '%s %d' % (_('New Layout'), i)
|
name = '%s %d' % (_('New Layout'), i)
|
||||||
|
|
||||||
if self.config.add_layout(newlayout):
|
if self.config.add_layout(name, current_layout):
|
||||||
model.append([newlayout, True])
|
model.append([name, True])
|
||||||
|
|
||||||
def on_layoutremovebutton_clicked(self, _button):
|
def on_layoutremovebutton_clicked(self, _button):
|
||||||
"""Remove a layout from the list"""
|
"""Remove a layout from the list"""
|
||||||
|
|
|
@ -1159,6 +1159,16 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
|
||||||
window = util.get_top_window(self)
|
window = util.get_top_window(self)
|
||||||
window.set_urgency_hint(True)
|
window.set_urgency_hint(True)
|
||||||
|
|
||||||
|
def describe_layout(self):
|
||||||
|
"""Describe our layout"""
|
||||||
|
layout = {}
|
||||||
|
layout['type'] = 'Terminal'
|
||||||
|
return(layout)
|
||||||
|
|
||||||
|
def create_layout(self, layout):
|
||||||
|
"""Apply our layout"""
|
||||||
|
print "Terminal::create_layout: Unimplemented. %s" % layout
|
||||||
|
|
||||||
# There now begins a great list of keyboard event handlers
|
# There now begins a great list of keyboard event handlers
|
||||||
def key_zoom_in(self):
|
def key_zoom_in(self):
|
||||||
self.zoom_in()
|
self.zoom_in()
|
||||||
|
|
|
@ -103,6 +103,23 @@ class Terminator(Borg):
|
||||||
|
|
||||||
return(window, terminal)
|
return(window, terminal)
|
||||||
|
|
||||||
|
def create_layout(self, layoutname):
|
||||||
|
"""Create all the parts necessary to satisfy the specified layout"""
|
||||||
|
layout = None
|
||||||
|
|
||||||
|
layout = self.config.layout_get_config(layoutname)
|
||||||
|
if not layout:
|
||||||
|
# User specified a non-existent layout. default to one Terminal
|
||||||
|
err('layout %s not defined' % layout)
|
||||||
|
raise(KeyError)
|
||||||
|
|
||||||
|
for windef in layout:
|
||||||
|
if windef['type'] != 'Window':
|
||||||
|
err('invalid layout format. %s' % layout)
|
||||||
|
raise(ValueError)
|
||||||
|
window, terminal = self.new_window()
|
||||||
|
window.create_layout(windef)
|
||||||
|
|
||||||
def reconfigure(self):
|
def reconfigure(self):
|
||||||
"""Update configuration for the whole application"""
|
"""Update configuration for the whole application"""
|
||||||
|
|
||||||
|
@ -210,4 +227,13 @@ class Terminator(Borg):
|
||||||
for terminal in self.terminals:
|
for terminal in self.terminals:
|
||||||
terminal.titlebar.update(widget)
|
terminal.titlebar.update(widget)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def describe_layout(self):
|
||||||
|
"""Describe our current layout"""
|
||||||
|
layout = []
|
||||||
|
for window in self.windows:
|
||||||
|
layout.append(window.describe_layout())
|
||||||
|
|
||||||
|
return(layout)
|
||||||
|
|
||||||
# vim: set expandtab ts=4 sw=4:
|
# vim: set expandtab ts=4 sw=4:
|
||||||
|
|
|
@ -575,6 +575,33 @@ class Window(Container, gtk.Window):
|
||||||
if next is not None:
|
if next is not None:
|
||||||
terminals[next].grab_focus()
|
terminals[next].grab_focus()
|
||||||
|
|
||||||
|
def create_layout(self, layout):
|
||||||
|
"""Apply any config items from our layout"""
|
||||||
|
if not layout.has_key('children'):
|
||||||
|
err('layout describes no children: %s' % layout)
|
||||||
|
return
|
||||||
|
children = layout['children']
|
||||||
|
if len(children) != 1:
|
||||||
|
# We're a Window, we can only have one child
|
||||||
|
err('incorrect number of children for Window: %s' % layout)
|
||||||
|
return
|
||||||
|
|
||||||
|
child = children[0]
|
||||||
|
terminal = self.get_children()[0]
|
||||||
|
if child['type'] == 'VPaned':
|
||||||
|
self.split_axis(terminal, True)
|
||||||
|
elif child['type'] == 'HPaned':
|
||||||
|
self.split_axis(terminal, False)
|
||||||
|
elif child['type'] == 'Notebook':
|
||||||
|
self.tab_new()
|
||||||
|
elif child['type'] == 'Terminal':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
err('unknown child type: %s' % child['type'])
|
||||||
|
return
|
||||||
|
|
||||||
|
self.get_children()[0].create_layout(child)
|
||||||
|
|
||||||
class WindowTitle(object):
|
class WindowTitle(object):
|
||||||
"""Class to handle the setting of the window title"""
|
"""Class to handle the setting of the window title"""
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue