[ADD] use of explicit primary mode in read_combined
authorXavier Morel <xmo@openerp.com>
Tue, 27 May 2014 09:46:58 +0000 (11:46 +0200)
committerXavier Morel <xmo@openerp.com>
Tue, 27 May 2014 09:57:02 +0000 (11:57 +0200)
openerp/addons/base/ir/ir_ui_view.py
openerp/addons/base/tests/test_views.py

index ca19048..2e56880 100644 (file)
@@ -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({
index 2ccf608..9da162a 100644 (file)
@@ -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': '<qweb><a1/></qweb>'
+        })
+        self.a2 = self.create({
+            'model': 'a',
+            'inherit_id': self.a1,
+            'priority': 5,
+            'arch': '<xpath expr="//a1" position="after"><a2/></xpath>'
+        })
+        self.a3 = self.create({
+            'model': 'a',
+            'inherit_id': self.a1,
+            'arch': '<xpath expr="//a1" position="after"><a3/></xpath>'
+        })
+
+        self.b1 = self.create({
+            'model': 'b',
+            'inherit_id': self.a3,
+            'mode': 'primary',
+            'arch': '<xpath expr="//a1" position="after"><b1/></xpath>'
+        })
+        self.b2 = self.create({
+            'model': 'b',
+            'inherit_id': self.b1,
+            'arch': '<xpath expr="//a1" position="after"><b2/></xpath>'
+        })
+
+        self.c1 = self.create({
+            'model': 'c',
+            'inherit_id': self.a1,
+            'mode': 'primary',
+            'arch': '<xpath expr="//a1" position="after"><c1/></xpath>'
+        })
+        self.c2 = self.create({
+            'model': 'c',
+            'inherit_id': self.c1,
+            'priority': 5,
+            'arch': '<xpath expr="//a1" position="after"><c2/></xpath>'
+        })
+        self.c3 = self.create({
+            'model': 'c',
+            'inherit_id': self.c2,
+            'priority': 10,
+            'arch': '<xpath expr="//a1" position="after"><c3/></xpath>'
+        })
+
+        self.d1 = self.create({
+            'model': 'd',
+            'inherit_id': self.b1,
+            'mode': 'primary',
+            'arch': '<xpath expr="//a1" position="after"><d1/></xpath>'
+        })
+
+    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(