Rework layout config to flatten and build up trees

This commit is contained in:
Chris Jones 2010-02-02 00:39:41 +00:00
parent 9ac5f913fa
commit 1aadbae30b
6 changed files with 95 additions and 38 deletions

View File

@ -206,7 +206,16 @@ DEFAULTS = {
},
},
'layouts': {
'default': "{'type': 'Window', 'children': [{'type': 'Terminal'}]}",
'default': {
'window0': {
'type': 'Window',
'parent': ''
},
'child1': {
'type': 'Terminal',
'parent': 'window0'
}
}
},
'plugins': {
},
@ -381,7 +390,7 @@ class ConfigBase(Borg):
if self.layouts is None:
self.layouts = {}
for layout in DEFAULTS['layouts']:
self.layouts[layout] = eval(DEFAULTS['layouts'][layout])
self.layouts[layout] = copy(DEFAULTS['layouts'][layout])
def defaults_to_configspec(self):
"""Convert our tree of default values into a ConfigObj validation
@ -433,6 +442,15 @@ class ConfigBase(Borg):
configspecdata['profiles'] = {}
configspecdata['profiles']['__many__'] = section
section = {}
section['type'] = 'string'
section['parent'] = 'string'
section['profile'] = 'string(default=default)'
section['command'] = 'string(default="")'
configspecdata['layouts'] = {}
configspecdata['layouts']['__many__'] = {}
configspecdata['layouts']['__many__']['__many__'] = section
configspec = ConfigObj(configspecdata)
if DEBUG == True:
configspec.write(open('/tmp/terminator_configspec_debug.txt', 'w'))
@ -460,9 +478,11 @@ class ConfigBase(Borg):
err('ConfigBase::load: config format is not valid')
for (section_list, key, _other) in flatten_errors(parser, result):
if key is not None:
print('[%s]: %s is invalid' % (','.join(section_list), key))
err('[%s]: %s is invalid' % (','.join(section_list), key))
else:
print ('[%s] missing' % ','.join(section_list))
err('[%s] missing' % ','.join(section_list))
else:
dbg('config validated successfully')
for section_name in self.sections:
dbg('ConfigBase::load: Processing section: %s' % section_name)
@ -471,6 +491,7 @@ class ConfigBase(Borg):
for profile in parser[section_name]:
dbg('ConfigBase::load: Processing profile: %s' % profile)
if not section.has_key(section_name):
# FIXME: Should this be outside the loop?
section[profile] = copy(DEFAULTS['profiles']['default'])
section[profile].update(parser[section_name][profile])
elif section_name == 'plugins':
@ -479,17 +500,10 @@ class ConfigBase(Borg):
part))
section[part] = parser[section_name][part]
elif section_name == 'layouts':
for part in parser[section_name]:
for layout 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))
layout))
section[layout] = parser[section_name][layout]
else:
try:
section.update(parser[section_name])
@ -519,13 +533,7 @@ class ConfigBase(Borg):
parser['layouts'] = {}
for layout in self.layouts:
dbg('ConfigBase::save: Processing layout: %s' % layout)
if layout == 'default' and \
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['layouts'][layout] = self.layouts[layout]
parser['plugins'] = {}
for plugin in self.plugins:

View File

@ -190,7 +190,7 @@ the %s will also close all terminals within it.') % (reqtype, reqtype))
return(terminals)
def describe_layout(self):
def describe_layout(self, count, parent, global_layout):
"""Describe our current layout"""
layout = {}
maker = Factory()
@ -200,11 +200,16 @@ the %s will also close all terminals within it.') % (reqtype, reqtype))
return({})
layout['type'] = mytype
layout['children'] = []
for child in self.get_children():
layout['children'].append(child.describe_layout())
layout['parent'] = parent
name = 'child%d' % count
count = count + 1
return(layout)
global_layout[name] = layout
for child in self.get_children():
count = child.describe_layout(count, name, global_layout)
return(count)
def create_layout(self, layout):
"""Apply settings for our layout"""

View File

@ -190,8 +190,9 @@ class Paned(Container):
err('incorrect number of children for Paned: %s' % layout)
return
for num in xrange(0, 2):
child = children[num]
num = 0
for child_key in children:
child = children[child_key]
if child['type'] == 'Terminal':
continue
elif child['type'] == 'VPaned':
@ -208,9 +209,12 @@ class Paned(Container):
self.split_axis(terminal, False)
else:
err('unknown child type: %s' % child['type'])
num = num + 1
self.get_child1().create_layout(children[0])
self.get_child2().create_layout(children[1])
keys = children.keys()
keys.sort()
self.get_child1().create_layout(children[keys[0]])
self.get_child2().create_layout(children[keys[1]])
class HPaned(Paned, gtk.HPaned):
"""Merge gtk.HPaned into our base Paned Container"""

View File

@ -1165,11 +1165,15 @@ for %s (%s)' % (name, urlplugin.__class__.__name__))
window = util.get_top_window(self)
window.set_urgency_hint(True)
def describe_layout(self):
def describe_layout(self, count, parent, global_layout):
"""Describe our layout"""
layout = {}
layout['type'] = 'Terminal'
return(layout)
layout['parent'] = parent
name = 'terminal%d' % count
count = count + 1
global_layout[name] = layout
return(count)
def create_layout(self, layout):
"""Apply our layout"""

View File

@ -106,6 +106,7 @@ class Terminator(Borg):
def create_layout(self, layoutname):
"""Create all the parts necessary to satisfy the specified layout"""
layout = None
objects = {}
layout = self.config.layout_get_config(layoutname)
if not layout:
@ -113,12 +114,45 @@ class Terminator(Borg):
err('layout %s not defined' % layout)
raise(KeyError)
# Wind the flat objects into a hierarchy
hierarchy = {}
count = 0
# Loop over the layout until we have consumed it, or hit 1000 loops.
# This is a stupid artificial limit, but it's safe.
while len(layout) > 0 and count < 1000:
count = count + 1
if count == 1000:
err('hit maximum loop boundary. THIS IS VERY LIKELY A BUG')
for obj in layout.keys():
if layout[obj]['type'].lower() == 'window':
hierarchy[obj] = {}
hierarchy[obj]['type'] = 'Window'
hierarchy[obj]['children'] = {}
objects[obj] = hierarchy[obj]
del(layout[obj])
else:
# Now examine children to see if their parents exist yet
if not layout[obj].has_key('parent'):
err('Invalid object: %s' % obj)
del(layout[obj])
continue
if objects.has_key(layout[obj]['parent']):
# Our parent has been created
childobj = {}
childobj['type'] = layout[obj]['type']
childobj['children'] = {}
objects[layout[obj]['parent']]['children'][obj] = childobj
objects[obj] = childobj
del(layout[obj])
layout = hierarchy
for windef in layout:
if windef['type'] != 'Window':
if layout[windef]['type'] != 'Window':
err('invalid layout format. %s' % layout)
raise(ValueError)
window, terminal = self.new_window()
window.create_layout(windef)
window.create_layout(layout[windef])
def reconfigure(self):
"""Update configuration for the whole application"""
@ -230,9 +264,11 @@ class Terminator(Borg):
def describe_layout(self):
"""Describe our current layout"""
layout = []
layout = {}
count = 0
for window in self.windows:
layout.append(window.describe_layout())
parent = ''
count = window.describe_layout(count, parent, layout)
return(layout)

View File

@ -581,12 +581,12 @@ class Window(Container, gtk.Window):
err('layout describes no children: %s' % layout)
return
children = layout['children']
if len(children) != 1:
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]
child = children[children.keys()[0]]
terminal = self.get_children()[0]
if child['type'] == 'VPaned':
self.split_axis(terminal, True)