diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index ca19048848e..2e568808b70 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -148,6 +148,7 @@ class view(osv.osv): required=True), } _defaults = { + 'mode': 'primary', 'priority': 16, } _order = "priority,name" @@ -215,7 +216,9 @@ class view(osv.osv): cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)') def _compute_defaults(self, cr, uid, values, context=None): - values.setdefault('mode', 'extension' if values.get('inherit_id') else 'primary') + if 'inherit_id' in values: + values.setdefault( + 'mode', 'extension' if values['inherit_id'] else 'primary') return values def create(self, cr, uid, values, context=None): @@ -301,7 +304,6 @@ class view(osv.osv): user = self.pool['res.users'].browse(cr, 1, uid, context=context) user_groups = frozenset(user.groups_id or ()) - check_view_ids = context and context.get('check_view_ids') or (0,) conditions = [['inherit_id', '=', view_id], ['model', '=', model]] if self.pool._init: # Module init currently in progress, only consider views from @@ -309,7 +311,7 @@ class view(osv.osv): conditions.extend([ '|', ['model_ids.module', 'in', tuple(self.pool._init_modules)], - ['id', 'in', check_view_ids], + ['id', 'in', context and context.get('check_view_ids') or (0,)], ]) view_ids = self.search(cr, uid, conditions, context=context) @@ -465,7 +467,7 @@ class view(osv.osv): if context is None: context = {} if root_id is None: root_id = source_id - sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, uid, source_id, model, context=context) + sql_inherit = self.pool['ir.ui.view'].get_inheriting_views_arch(cr, uid, source_id, model, context=context) for (specs, view_id) in sql_inherit: specs_tree = etree.fromstring(specs.encode('utf-8')) if context.get('inherit_branding'): @@ -488,7 +490,7 @@ class view(osv.osv): # if view_id is not a root view, climb back to the top. base = v = self.browse(cr, uid, view_id, context=context) - while v.inherit_id: + while v.mode != 'primary': v = v.inherit_id root_id = v.id @@ -498,7 +500,16 @@ class view(osv.osv): # read the view arch [view] = self.read(cr, uid, [root_id], fields=fields, context=context) - arch_tree = etree.fromstring(view['arch'].encode('utf-8')) + view_arch = etree.fromstring(view['arch'].encode('utf-8')) + if not v.inherit_id: + arch_tree = view_arch + else: + parent_view = self.read_combined( + cr, uid, v.inherit_id.id, fields=fields, context=context) + arch_tree = etree.fromstring(parent_view['arch']) + self.apply_inheritance_specs( + cr, uid, arch_tree, view_arch, parent_view['id'], context=context) + if context.get('inherit_branding'): arch_tree.attrib.update({ diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index 2ccf608e0b4..9da162a7e5c 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -1,5 +1,6 @@ # -*- encoding: utf-8 -*- from functools import partial +import itertools import unittest2 @@ -22,7 +23,7 @@ class ViewCase(common.TransactionCase): return self.Views.create(self.cr, self.uid, value, context=context) def assertTreesEqual(self, n1, n2, msg=None): - self.assertEqual(n1.tag, n2.tag) + self.assertEqual(n1.tag, n2.tag, msg) self.assertEqual((n1.text or '').strip(), (n2.text or '').strip(), msg) self.assertEqual((n1.tail or '').strip(), (n2.tail or '').strip(), msg) @@ -30,8 +31,8 @@ class ViewCase(common.TransactionCase): # equality (!?!?!?!) self.assertEqual(dict(n1.attrib), dict(n2.attrib), msg) - for c1, c2 in zip(n1, n2): - self.assertTreesEqual(c1, c2, msg) + for c1, c2 in itertools.izip_longest(n1, n2): + self.assertEqual(c1, c2, msg) class TestNodeLocator(common.TransactionCase): @@ -934,11 +935,123 @@ class TestDefaultView(ViewCase): class TestViewCombined(ViewCase): """ - Test fallback operations of View.read_combined: - * defaults mapping - * ? + * When asked for a view, instead of looking for the closest parent with + inherit_id=False look for mode=primary + * If root.inherit_id, resolve the arch for root.inherit_id (?using which + model?), then apply root's inheritance specs to it + * Apply inheriting views on top """ + def setUp(self): + super(TestViewCombined, self).setUp() + + self.a1 = self.create({ + 'model': 'a', + 'arch': '' + }) + self.a2 = self.create({ + 'model': 'a', + 'inherit_id': self.a1, + 'priority': 5, + 'arch': '' + }) + self.a3 = self.create({ + 'model': 'a', + 'inherit_id': self.a1, + 'arch': '' + }) + + self.b1 = self.create({ + 'model': 'b', + 'inherit_id': self.a3, + 'mode': 'primary', + 'arch': '' + }) + self.b2 = self.create({ + 'model': 'b', + 'inherit_id': self.b1, + 'arch': '' + }) + + self.c1 = self.create({ + 'model': 'c', + 'inherit_id': self.a1, + 'mode': 'primary', + 'arch': '' + }) + self.c2 = self.create({ + 'model': 'c', + 'inherit_id': self.c1, + 'priority': 5, + 'arch': '' + }) + self.c3 = self.create({ + 'model': 'c', + 'inherit_id': self.c2, + 'priority': 10, + 'arch': '' + }) + + self.d1 = self.create({ + 'model': 'd', + 'inherit_id': self.b1, + 'mode': 'primary', + 'arch': '' + }) + + def read_combined(self, id): + return self.Views.read_combined( + self.cr, self.uid, + id, ['arch'], + context={'check_view_ids': self.Views.search(self.cr, self.uid, [])} + ) + + def test_basic_read(self): + arch = self.read_combined(self.a1)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.a1(), + E.a3(), + E.a2(), + ), arch) + + def test_read_from_child(self): + arch = self.read_combined(self.a3)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.a1(), + E.a3(), + E.a2(), + ), arch) + + def test_cross_model_simple(self): + arch = self.read_combined(self.c2)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.a1(), + E.c3(), + E.c2(), + E.c1(), + E.a3(), + E.a2(), + ), arch) + + def test_cross_model_double(self): + arch = self.read_combined(self.d1)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.a1(), + E.d1(), + E.b2(), + E.b1(), + E.a3(), + E.a2(), + ), arch) + class TestXPathExtentions(common.BaseCase): def test_hasclass(self): tree = E.node(