diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index c31320eb63e..ef202c534ae 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -21,6 +21,7 @@ import copy import logging +import itertools from lxml import etree import os @@ -164,6 +165,35 @@ class view(osv.osv): if not cr.fetchone(): cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)') + def read_combined(self, cr, uid, view_id, fields=None, model=None, context=None): + """ + Reads the specified view and returns it after applying all inheriting + views upon it (essentially reads the "currently final" view) + + Returns `False` if the provided id is not a valid view, or if `False` + is provided as an id. + + The `arch` of the view is always read (regardless of its presence in + `fields`), and is returned as an lxml tree + + :param list(str) fields: same as in BaseModel.read() + :param str model: + """ + if fields and 'arch' not in fields: + fields = list(itertools.chain(['arch'], fields)) + if not view_id: return False + views = self.read(cr, uid, [view_id], fields=fields, context=context) + if not views: return False + + base_arch = views[0]['arch'] + base_arch = base_arch.encode('utf-8') if isinstance(base_arch, unicode) else base_arch + return dict(views[0], arch=reduce( + lambda current_arch, descendant: self.apply_inheritance_specs( + cr, uid, model, view_id, current_arch, *descendant, context=context), + self.iter(cr, uid, view_id, model, exclude_base=True, context=context), + etree.fromstring(base_arch) + )) + def locate_node(self, arch, spec): """ Locate a node in a source (parent) architecture. @@ -246,7 +276,7 @@ class view(osv.osv): `exclude_base` is `False`, the default) """ if not exclude_base: - [base] = self.browse(cr, uid, [view_id], context=context) + base = self.browse(cr, uid, view_id, context=context) yield base.id, base.arch for arch, id in self.get_inheriting_views_arch( @@ -259,8 +289,8 @@ class view(osv.osv): def get_root_ancestor(self, cr, uid, view_id=None, model=None, view_type=None, context=None): """ - Fetches the root of the view tree specified by the id or (type, model) - parameters. + Fetches the id of the root of the view tree specified by the id or + (type, model) parameters. If view_id is specified, view_type and model aren't needed (and the other way around) @@ -268,7 +298,7 @@ class view(osv.osv): :param view_id: id of view to search the root ancestor of :param str model: model to use the view for :param str view_type: expected view type - :return: + :return: id of the root view for the tree """ assert view_id or (model and view_type),\ "caller must provide either a view_id or a model and a view_type"\ @@ -291,11 +321,7 @@ class view(osv.osv): while view.inherit_id: view = view.inherit_id - views = self.read(cr, uid, [view.id],[ - 'arch', 'name', 'field_parent', - 'id', 'type', 'inherit_id', 'model' - ], context=context) - return views[0] + return view.id def raise_view_error(self, cr, uid, model, error_msg, view_id, child_view_id, context=None): diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 15091e9383b..2ec9025b297 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -2054,26 +2054,6 @@ class BaseModel(object): context = {} View = self.pool['ir.ui.view'] - def encode(s): - if isinstance(s, unicode): - return s.encode('utf8') - return s - - def apply_view_inheritance(cr, user, source, inherit_id): - """ Apply all the (directly and indirectly) inheriting views. - - :param source: a parent architecture to modify (with parent - modifications already applied) - :param inherit_id: the database view_id of the parent view - :return: a modified source where all the modifying architecture - are applied - """ - return reduce( - lambda s, descendant: View.apply_inheritance_specs( - cr, user, self._name, inherit_id, s, *descendant, context=context), - View.iter(cr, user, inherit_id, self._name, exclude_base=True, context=context), - source) - result = {'type': view_type, 'model': self._name} view_ref = context.get(view_type + '_view_ref') @@ -2085,12 +2065,14 @@ class BaseModel(object): if view_ref_res: view_id = view_ref_res[0] - root_view = View.get_root_ancestor( + root_view_id = View.get_root_ancestor( cr, user, view_id, self._name, view_type, context=context) + root_view = View.read_combined(cr, user, root_view_id, fields=[ + 'id', 'name', 'field_parent', 'type', 'model' + ], model=self._name, context=context) if root_view: - source = etree.fromstring(encode(root_view['arch'])) result.update( - arch=apply_view_inheritance(cr, user, source, root_view['id']), + arch=root_view['arch'], type=root_view['type'], view_id=root_view['id'], name=root_view['name'], diff --git a/openerp/tests/test_views.py b/openerp/tests/test_views.py index ba85b25f782..a7cb126fbdf 100644 --- a/openerp/tests/test_views.py +++ b/openerp/tests/test_views.py @@ -163,22 +163,22 @@ class TestViewInheritance(common.TransactionCase): def test_find_root(self): A_id = self.ids['A'] - root = self.View.get_root_ancestor(self.cr, self.uid, view_id=A_id) - self.assertEqual(root['id'], A_id, + root_id = self.View.get_root_ancestor(self.cr, self.uid, view_id=A_id) + self.assertEqual(root_id, A_id, "when given a root view, operation should be id") - root = self.View.get_root_ancestor( + root_id = self.View.get_root_ancestor( self.cr, self.uid, view_id=self.ids['A11']) - self.assertEqual(root['id'], A_id) + self.assertEqual(root_id, A_id) - root = self.View.get_root_ancestor( + root_id = self.View.get_root_ancestor( self.cr, self.uid, view_id=self.ids['A221']) - self.assertEqual(root['id'], A_id) + self.assertEqual(root_id, A_id) # search by model - root = self.View.get_root_ancestor( + root_id = self.View.get_root_ancestor( self.cr, self.uid, model=self.model, view_type='form') - self.assertEqual(root['id'], A_id) + self.assertEqual(root_id, A_id) def test_no_root(self): root = self.View.get_root_ancestor(