[REF] move apply_inheritance_specs to ir.ui.view

also moved raise_view_error utility function

bzr revid: xmo@openerp.com-20130423105856-558rl6ankd4g3qb0
This commit is contained in:
Xavier Morel 2013-04-23 12:58:56 +02:00
parent b0f2d3044a
commit e996f92e6c
2 changed files with 84 additions and 79 deletions

View File

@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import copy
import logging
from lxml import etree
@ -255,6 +256,86 @@ class view(osv.osv):
cr, uid, id, model, exclude_base=True, context=None):
yield info
def raise_view_error(self, cr, uid, model, error_msg, view_id, child_view_id, context=None):
view, child_view = self.browse(cr, uid, [view_id, child_view_id], context)
error_msg = error_msg % {'parent_xml_id': view.xml_id}
raise AttributeError("View definition error for inherited view '%s' on model '%s': %s"
% (child_view.xml_id, model, error_msg))
def apply_inheritance_specs(self, cr, uid, model, root_view_id, source, descendant_id, specs_arch, context=None):
""" Apply an inheriting view (a descendant of the base view)
Apply to a source architecture all the spec nodes (i.e. nodes
describing where and what changes to apply to some parent
architecture) given by an inheriting view.
:param source: a parent architecture to modify
:param descendant_id: the database id of the descendant
:param specs_arch: a modifying architecture in an inheriting view
:return: a modified source where the specs are applied
"""
if isinstance(specs_arch, unicode):
specs_arch = specs_arch.encode('utf-8')
specs_tree = etree.fromstring(specs_arch)
# Queue of specification nodes (i.e. nodes describing where and
# changes to apply to some parent architecture).
specs = [specs_tree]
while len(specs):
spec = specs.pop(0)
if isinstance(spec, SKIPPED_ELEMENT_TYPES):
continue
if spec.tag == 'data':
specs += [ c for c in specs_tree ]
continue
node = self.locate_node(source, spec)
if node is not None:
pos = spec.get('position', 'inside')
if pos == 'replace':
if node.getparent() is None:
source = copy.deepcopy(spec[0])
else:
for child in spec:
node.addprevious(child)
node.getparent().remove(node)
elif pos == 'attributes':
for child in spec.getiterator('attribute'):
attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
if attribute[1]:
node.set(attribute[0], attribute[1])
else:
del(node.attrib[attribute[0]])
else:
sib = node.getnext()
for child in spec:
if pos == 'inside':
node.append(child)
elif pos == 'after':
if sib is None:
node.addnext(child)
node = child
else:
sib.addprevious(child)
elif pos == 'before':
node.addprevious(child)
else:
self.raise_view_error(cr, uid, model, "Invalid position value: '%s'" % pos, root_view_id, descendant_id, context=context)
else:
attrs = ''.join([
' %s="%s"' % (attr, spec.get(attr))
for attr in spec.attrib
if attr != 'position'
])
tag = "<%s%s>" % (spec.tag, attrs)
if spec.get('version') and spec.get('version') != source.get('version'):
self.raise_view_error(cr, uid, model, "Mismatching view API version for element '%s': %r vs %r in parent view '%%(parent_xml_id)s'" % \
(tag, spec.get('version'), source.get('version')), root_view_id, descendant_id, context=context)
self.raise_view_error(cr, uid, model, "Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, root_view_id, descendant_id, context=context)
return source
def write(self, cr, uid, ids, vals, context=None):
if not isinstance(ids, (list, tuple)):
ids = [ids]

View File

@ -2062,83 +2062,6 @@ class BaseModel(object):
return s.encode('utf8')
return s
def raise_view_error(cr, uid, model, error_msg, view_id, child_view_id, context=None):
view, child_view = self.pool.get('ir.ui.view').browse(cr, uid, [view_id, child_view_id], context)
error_msg = error_msg % {'parent_xml_id': view.xml_id}
raise AttributeError("View definition error for inherited view '%s' on model '%s': %s"
% (child_view.xml_id, model, error_msg))
def apply_inheritance_specs(cr, uid, model, root_view_id, source, descendant_id, specs_arch, context=None):
""" Apply an inheriting view (a descendant of the base view)
Apply to a source architecture all the spec nodes (i.e. nodes
describing where and what changes to apply to some parent
architecture) given by an inheriting view.
:param source: a parent architecture to modify
:param descendant_id: the database id of the descendant
:param specs_arch: a modifying architecture in an inheriting view
:return: a modified source where the specs are applied
"""
specs_tree = etree.fromstring(encode(specs_arch))
# Queue of specification nodes (i.e. nodes describing where and
# changes to apply to some parent architecture).
specs = [specs_tree]
while len(specs):
spec = specs.pop(0)
if isinstance(spec, SKIPPED_ELEMENT_TYPES):
continue
if spec.tag == 'data':
specs += [ c for c in specs_tree ]
continue
node = View.locate_node(source, spec)
if node is not None:
pos = spec.get('position', 'inside')
if pos == 'replace':
if node.getparent() is None:
source = copy.deepcopy(spec[0])
else:
for child in spec:
node.addprevious(child)
node.getparent().remove(node)
elif pos == 'attributes':
for child in spec.getiterator('attribute'):
attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
if attribute[1]:
node.set(attribute[0], attribute[1])
else:
del(node.attrib[attribute[0]])
else:
sib = node.getnext()
for child in spec:
if pos == 'inside':
node.append(child)
elif pos == 'after':
if sib is None:
node.addnext(child)
node = child
else:
sib.addprevious(child)
elif pos == 'before':
node.addprevious(child)
else:
raise_view_error(cr, uid, model, "Invalid position value: '%s'" % pos, root_view_id, descendant_id, context=context)
else:
attrs = ''.join([
' %s="%s"' % (attr, spec.get(attr))
for attr in spec.attrib
if attr != 'position'
])
tag = "<%s%s>" % (spec.tag, attrs)
if spec.get('version') and spec.get('version') != source.get('version'):
raise_view_error(cr, uid, model, "Mismatching view API version for element '%s': %r vs %r in parent view '%%(parent_xml_id)s'" % \
(tag, spec.get('version'), source.get('version')), root_view_id, descendant_id, context=context)
raise_view_error(cr, uid, model, "Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, root_view_id, descendant_id, context=context)
return source
def apply_view_inheritance(cr, user, source, inherit_id):
""" Apply all the (directly and indirectly) inheriting views.
@ -2149,10 +2072,11 @@ class BaseModel(object):
are applied
"""
View = self.pool['ir.ui.view']
return reduce(
lambda s, descendant: apply_inheritance_specs(
lambda s, descendant: View.apply_inheritance_specs(
cr, user, self._name, inherit_id, s, *descendant, context=context),
self.pool['ir.ui.view'].iter(cr, user, inherit_id, self._name, exclude_base=True, context=context),
View.iter(cr, user, inherit_id, self._name, exclude_base=True, context=context),
source)
result = {'type': view_type, 'model': self._name}