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

View File

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

View File

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

View File

@ -1165,11 +1165,15 @@ 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): def describe_layout(self, count, parent, global_layout):
"""Describe our layout""" """Describe our layout"""
layout = {} layout = {}
layout['type'] = 'Terminal' 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): def create_layout(self, layout):
"""Apply our layout""" """Apply our layout"""

View File

@ -106,6 +106,7 @@ class Terminator(Borg):
def create_layout(self, layoutname): def create_layout(self, layoutname):
"""Create all the parts necessary to satisfy the specified layout""" """Create all the parts necessary to satisfy the specified layout"""
layout = None layout = None
objects = {}
layout = self.config.layout_get_config(layoutname) layout = self.config.layout_get_config(layoutname)
if not layout: if not layout:
@ -113,12 +114,45 @@ class Terminator(Borg):
err('layout %s not defined' % layout) err('layout %s not defined' % layout)
raise(KeyError) 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: for windef in layout:
if windef['type'] != 'Window': if layout[windef]['type'] != 'Window':
err('invalid layout format. %s' % layout) err('invalid layout format. %s' % layout)
raise(ValueError) raise(ValueError)
window, terminal = self.new_window() window, terminal = self.new_window()
window.create_layout(windef) window.create_layout(layout[windef])
def reconfigure(self): def reconfigure(self):
"""Update configuration for the whole application""" """Update configuration for the whole application"""
@ -230,9 +264,11 @@ class Terminator(Borg):
def describe_layout(self): def describe_layout(self):
"""Describe our current layout""" """Describe our current layout"""
layout = [] layout = {}
count = 0
for window in self.windows: for window in self.windows:
layout.append(window.describe_layout()) parent = ''
count = window.describe_layout(count, parent, layout)
return(layout) return(layout)

View File

@ -586,7 +586,7 @@ class Window(Container, gtk.Window):
err('incorrect number of children for Window: %s' % layout) err('incorrect number of children for Window: %s' % layout)
return return
child = children[0] child = children[children.keys()[0]]
terminal = self.get_children()[0] terminal = self.get_children()[0]
if child['type'] == 'VPaned': if child['type'] == 'VPaned':
self.split_axis(terminal, True) self.split_axis(terminal, True)