From 3d91b2dfa2bf02bb2c307ad0353d1e5021025318 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:30:42 +0200 Subject: [PATCH 01/12] [REM] unused stack_result parameter --- addons/website/models/ir_ui_view.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 9d89665c56f..f4b6a600177 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -26,11 +26,9 @@ class view(osv.osv): # Returns all views (called and inherited) related to a view # Used by translation mechanism, SEO and optional templates - def _views_get(self, cr, uid, view, options=True, context=None, root=True, stack_result=None): + def _views_get(self, cr, uid, view, options=True, context=None, root=True): if not context: context = {} - if not stack_result: - stack_result = [] def view_obj(view): if isinstance(view, basestring): @@ -59,7 +57,7 @@ class view(osv.osv): except ValueError: continue if call_view not in result: - result += self._views_get(cr, uid, call_view, options=options, context=context, stack_result=result) + result += self._views_get(cr, uid, call_view, options=options, context=context) todo = view.inherit_children_ids if options: @@ -67,7 +65,7 @@ class view(osv.osv): # Keep options in a determinitic order whatever their enabled disabled status todo.sort(lambda x,y:cmp(x.id,y.id)) for child_view in todo: - for r in self._views_get(cr, uid, child_view, options=bool(child_view.inherit_id), context=context, root=False, stack_result=result): + for r in self._views_get(cr, uid, child_view, options=bool(child_view.inherit_id), context=context, root=False): if r not in result: result.append(r) return result From ad33728043c574f5f3fa6799873fc3aa52db4738 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:31:22 +0200 Subject: [PATCH 02/12] [IMP] use sorted + key instead of sort + cmp --- addons/website/models/ir_ui_view.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index f4b6a600177..26ca5eebfc6 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -63,8 +63,7 @@ class view(osv.osv): if options: todo += filter(lambda x: not x.inherit_id, view.inherited_option_ids) # Keep options in a determinitic order whatever their enabled disabled status - todo.sort(lambda x,y:cmp(x.id,y.id)) - for child_view in todo: + for child_view in sorted(todo, key=lambda v: v.id): for r in self._views_get(cr, uid, child_view, options=bool(child_view.inherit_id), context=context, root=False): if r not in result: result.append(r) From 85c466611a0c213d1ed2c6675fec24a7fb61157b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:31:44 +0200 Subject: [PATCH 03/12] [IMP] don't pointlessly recreate view_obj every time _views_get is called, better use of pool & data APIs --- addons/website/models/ir_ui_view.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 26ca5eebfc6..1c5736c0cff 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -24,23 +24,26 @@ class view(osv.osv): 'page': False, } + + def _view_obj(self, cr, uid, view_id, context=None): + if isinstance(view_id, basestring): + return self.pool['ir.model.data'].xmlid_to_object( + cr, uid, view_id, raise_if_not_found=True, context=context + ) + elif isinstance(view_id, (int, long)): + return self.browse(cr, uid, view_id, context=context) + + # assume it's already a view object (WTF?) + return view_id + # Returns all views (called and inherited) related to a view # Used by translation mechanism, SEO and optional templates - def _views_get(self, cr, uid, view, options=True, context=None, root=True): + def _views_get(self, cr, uid, view_id, options=True, context=None, root=True): if not context: context = {} - def view_obj(view): - if isinstance(view, basestring): - mod_obj = self.pool.get("ir.model.data") - m, n = view.split('.') - view = mod_obj.get_object(cr, uid, m, n, context=context) - elif isinstance(view, (int, long)): - view = self.pool.get("ir.ui.view").browse(cr, uid, view, context=context) - return view - try: - view = view_obj(view) + view = self._view_obj(cr, uid, view_id, context=context) except ValueError: # Shall we log that ? return [] @@ -53,7 +56,7 @@ class view(osv.osv): node = etree.fromstring(view.arch) for child in node.xpath("//t[@t-call]"): try: - call_view = view_obj(child.get('t-call')) + call_view = self._view_obj(cr, uid, child.get('t-call'), context=context) except ValueError: continue if call_view not in result: From 4e3864c1fbacefff6c2c277d01b73f5f581a733d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:32:18 +0200 Subject: [PATCH 04/12] [IMP] no need to ensure an actual context if the method does not use it just forwarding the context object does not count as using it, if callees want a context they can ensure they've got one on their own --- addons/website/models/ir_ui_view.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 1c5736c0cff..3ee663a78ef 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -39,9 +39,6 @@ class view(osv.osv): # Returns all views (called and inherited) related to a view # Used by translation mechanism, SEO and optional templates def _views_get(self, cr, uid, view_id, options=True, context=None, root=True): - if not context: - context = {} - try: view = self._view_obj(cr, uid, view_id, context=context) except ValueError: From b5cce44dd2f8e5ea4a6b51ad93fb748ac25a2084 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:33:12 +0200 Subject: [PATCH 05/12] [IMP] use sets to check for groups/ACL rco notes that group tests are generally intersections, if the user has *any* group set on the object he can see/use it. This change is a literal translation of the original semantics, which may be wrong. --- addons/website/controllers/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index ab024e18197..5317b37fa2e 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -218,14 +218,14 @@ class Website(openerp.addons.web.controllers.main.Home): request.cr, request.uid, 'website', 'theme') user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, request.context) - group_ids = [g.id for g in user.groups_id] + user_groups = set(user.groups_id) - view = request.registry.get("ir.ui.view") + view = request.registry["ir.ui.view"] views = view._views_get(request.cr, request.uid, xml_id, context=request.context) done = {} result = [] for v in views: - if v.groups_id and [g for g in v.groups_id if g.id not in group_ids]: + if not user_groups.issuperset(v.groups_id): continue if v.inherit_option_id and v.inherit_option_id.id != view_theme_id or not optional: if v.inherit_option_id.id not in done: From da4441246ec1e8ac3bc450e0563b2d7086eb8da0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:33:37 +0200 Subject: [PATCH 06/12] [IMP] use set to collect inherit_id and inherit_option_id Also add a few comments to note understanding of code --- addons/website/models/ir_ui_view.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 3ee663a78ef..0bb0fd62e4f 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -39,6 +39,12 @@ class view(osv.osv): # Returns all views (called and inherited) related to a view # Used by translation mechanism, SEO and optional templates def _views_get(self, cr, uid, view_id, options=True, context=None, root=True): + """ For a given view ``view_id``, should return: + + * the view itself + * all views inheriting from it, enabled or not + * all views called from it (via t-call) + """ try: view = self._view_obj(cr, uid, view_id, context=context) except ValueError: @@ -53,18 +59,23 @@ class view(osv.osv): node = etree.fromstring(view.arch) for child in node.xpath("//t[@t-call]"): try: - call_view = self._view_obj(cr, uid, child.get('t-call'), context=context) + called_view = self._view_obj(cr, uid, child.get('t-call'), context=context) except ValueError: continue - if call_view not in result: - result += self._views_get(cr, uid, call_view, options=options, context=context) + if called_view not in result: + result += self._views_get(cr, uid, called_view, options=options, context=context) - todo = view.inherit_children_ids + todo = set(view.inherit_children_ids) if options: - todo += filter(lambda x: not x.inherit_id, view.inherited_option_ids) - # Keep options in a determinitic order whatever their enabled disabled status + todo.update(view.inherited_option_ids) + + # Keep options in a deterministic order regardless of their applicability for child_view in sorted(todo, key=lambda v: v.id): - for r in self._views_get(cr, uid, child_view, options=bool(child_view.inherit_id), context=context, root=False): + for r in self._views_get( + cr, uid, child_view, + # only return optional grandchildren if this child is enabled + options=bool(child_view.inherit_id), + context=context, root=False): if r not in result: result.append(r) return result From 80c7b6defcecccbd761056f0fe56e2bd2903e3a5 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:34:14 +0200 Subject: [PATCH 07/12] [IMP] dict(int: True) -> set(int) --- addons/website/controllers/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 5317b37fa2e..db9c4bda1e9 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -222,7 +222,7 @@ class Website(openerp.addons.web.controllers.main.Home): view = request.registry["ir.ui.view"] views = view._views_get(request.cr, request.uid, xml_id, context=request.context) - done = {} + done = set() result = [] for v in views: if not user_groups.issuperset(v.groups_id): @@ -237,7 +237,7 @@ class Website(openerp.addons.web.controllers.main.Home): 'header': True, 'active': False }) - done[v.inherit_option_id.id] = True + done.add(v.inherit_option_id.id) result.append({ 'name': v.name, 'id': v.id, From d67161b64910a1f1f06239e31d397b1e3b37b295 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:34:49 +0200 Subject: [PATCH 08/12] [IMP] renamed some stuff for clarity --- addons/website/controllers/main.py | 10 +++++++--- addons/website/models/ir_ui_view.py | 11 ++++++----- addons/website/static/src/js/website.ace.js | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index db9c4bda1e9..19828afdc83 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -212,7 +212,11 @@ class Website(openerp.addons.web.controllers.main.Home): return True @http.route('/website/customize_template_get', type='json', auth='user', website=True) - def customize_template_get(self, xml_id, optional=True): + def customize_template_get(self, xml_id, full=False): + """ Lists the templates customizing ``xml_id``. By default, only + returns optional templates (which can be toggled on and off), if + ``full=True`` returns all templates customizing ``xml_id`` + """ imd = request.registry['ir.model.data'] view_model, view_theme_id = imd.get_object_reference( request.cr, request.uid, 'website', 'theme') @@ -227,7 +231,7 @@ class Website(openerp.addons.web.controllers.main.Home): for v in views: if not user_groups.issuperset(v.groups_id): continue - if v.inherit_option_id and v.inherit_option_id.id != view_theme_id or not optional: + if full or v.inherit_option_id and v.inherit_option_id.id != view_theme_id: if v.inherit_option_id.id not in done: result.append({ 'name': v.inherit_option_id.name, @@ -244,7 +248,7 @@ class Website(openerp.addons.web.controllers.main.Home): 'xml_id': v.xml_id, 'inherit_id': v.inherit_id.id, 'header': False, - 'active': (v.inherit_id.id == v.inherit_option_id.id) or (not optional and v.inherit_id.id) + 'active': (v.inherit_id.id == v.inherit_option_id.id) or (full and v.inherit_id.id) }) return result diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 0bb0fd62e4f..f422dae7b20 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -43,6 +43,7 @@ class view(osv.osv): * the view itself * all views inheriting from it, enabled or not + - but not the optional children of a non-enabled child * all views called from it (via t-call) """ try: @@ -65,16 +66,16 @@ class view(osv.osv): if called_view not in result: result += self._views_get(cr, uid, called_view, options=options, context=context) - todo = set(view.inherit_children_ids) + extensions = set(view.inherit_children_ids) if options: - todo.update(view.inherited_option_ids) + extensions.update(view.inherited_option_ids) # Keep options in a deterministic order regardless of their applicability - for child_view in sorted(todo, key=lambda v: v.id): + for extension in sorted(extensions, key=lambda v: v.id): for r in self._views_get( - cr, uid, child_view, + cr, uid, extension, # only return optional grandchildren if this child is enabled - options=bool(child_view.inherit_id), + options=bool(extension.inherit_id), context=context, root=False): if r not in result: result.append(r) diff --git a/addons/website/static/src/js/website.ace.js b/addons/website/static/src/js/website.ace.js index a8af74bb52d..27e5cd60e62 100644 --- a/addons/website/static/src/js/website.ace.js +++ b/addons/website/static/src/js/website.ace.js @@ -97,7 +97,7 @@ var viewId = $(document.documentElement).data('view-xmlid'); openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': viewId, - 'optional': false, + 'full': true, }).then(function (views) { self.loadViews.call(self, views); self.open.call(self); From d82ffb87289547c8f9013d3f8bebadfe17e16374 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:49:26 +0200 Subject: [PATCH 09/12] [ADD] application field & check during inheriting views read --- openerp/addons/base/ir/ir_ui_view.py | 15 ++++++- openerp/addons/base/tests/test_views.py | 59 ++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index 2e568808b70..d006b02705c 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -146,9 +146,18 @@ class view(osv.osv): [('primary', "Base view"), ('extension', "Extension View")], string="View inheritance mode", required=True), + + 'application': fields.selection([ + ('always', "Always applied"), + ('enabled', "Optional, enabled"), + ('disabled', "Optional, disabled"), + ], required=True, string="If this view is inherited, whether it can be" + " toggled off, and whether it is currently" + " enabled"), } _defaults = { 'mode': 'primary', + 'application': 'always', 'priority': 16, } _order = "priority,name" @@ -304,7 +313,11 @@ class view(osv.osv): user = self.pool['res.users'].browse(cr, 1, uid, context=context) user_groups = frozenset(user.groups_id or ()) - conditions = [['inherit_id', '=', view_id], ['model', '=', model]] + conditions = [ + ['inherit_id', '=', view_id], + ['model', '=', model], + ['application', 'in', ['always', 'enabled']], + ] if self.pool._init: # Module init currently in progress, only consider views from # modules whose code is already loaded diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index 9da162a7e5c..a098b9438ac 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -22,6 +22,13 @@ class ViewCase(common.TransactionCase): def create(self, value, context=None): return self.Views.create(self.cr, self.uid, value, context=context) + 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 assertTreesEqual(self, n1, n2, msg=None): self.assertEqual(n1.tag, n2.tag, msg) self.assertEqual((n1.text or '').strip(), (n2.text or '').strip(), msg) @@ -629,6 +636,7 @@ class test_views(ViewCase): """Insert view into database via a query to passtrough validation""" kw.pop('id', None) kw.setdefault('mode', 'extension' if kw.get('inherit_id') else 'primary') + kw.setdefault('application', 'always') keys = sorted(kw.keys()) fields = ','.join('"%s"' % (k.replace('"', r'\"'),) for k in keys) @@ -999,13 +1007,6 @@ class TestViewCombined(ViewCase): '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( @@ -1052,6 +1053,50 @@ class TestViewCombined(ViewCase): E.a2(), ), arch) +class TestOptionalViews(ViewCase): + """ + Tests ability to enable/disable inherited views, formerly known as + inherit_option_id + """ + + def setUp(self): + super(TestOptionalViews, self).setUp() + self.v0 = self.create({ + 'model': 'a', + 'arch': '', + }) + self.v1 = self.create({ + 'model': 'a', + 'inherit_id': self.v0, + 'application': 'always', + 'arch': '', + }) + self.v2 = self.create({ + 'model': 'a', + 'inherit_id': self.v0, + 'application': 'enabled', + 'arch': '', + }) + self.v3 = self.create({ + 'model': 'a', + 'inherit_id': self.v0, + 'application': 'disabled', + 'arch': '' + }) + + def test_applied(self): + """ mandatory and enabled views should be applied + """ + arch = self.read_combined(self.v0)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.base(), + E.v1(), + E.v2(), + ) + ) + class TestXPathExtentions(common.BaseCase): def test_hasclass(self): tree = E.node( From e2f41d09ba7a5f2e6b0fa8efa1624e257824c992 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:52:57 +0200 Subject: [PATCH 10/12] [IMP] prevent changing a view from application: always to application: disabled not sure that's actually useful, and can still go always -> enabled -> disabled... --- openerp/addons/base/ir/ir_ui_view.py | 8 +++++ openerp/addons/base/tests/test_views.py | 44 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index d006b02705c..de997b2cf36 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -258,6 +258,14 @@ class view(osv.osv): if custom_view_ids: self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids) + if vals.get('application') == 'disabled': + from_always = self.search( + cr, uid, [('id', 'in', ids), ('application', '=', 'always')], context=context) + if from_always: + raise ValueError( + "Can't disable views %s marked as always applied" % ( + ', '.join(map(str, from_always)))) + self.read_template.clear_cache(self) ret = super(view, self).write( cr, uid, ids, diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index a098b9438ac..db9b475ddbe 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -1069,18 +1069,21 @@ class TestOptionalViews(ViewCase): 'model': 'a', 'inherit_id': self.v0, 'application': 'always', + 'priority': 10, 'arch': '', }) self.v2 = self.create({ 'model': 'a', 'inherit_id': self.v0, 'application': 'enabled', + 'priority': 9, 'arch': '', }) self.v3 = self.create({ 'model': 'a', 'inherit_id': self.v0, 'application': 'disabled', + 'priority': 8, 'arch': '' }) @@ -1097,6 +1100,47 @@ class TestOptionalViews(ViewCase): ) ) + def test_applied_state_toggle(self): + """ Change application states of v2 and v3, check that the results + are as expected + """ + self.browse(self.v2).write({'application': 'disabled'}) + arch = self.read_combined(self.v0)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.base(), + E.v1(), + ) + ) + + self.browse(self.v3).write({'application': 'enabled'}) + arch = self.read_combined(self.v0)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.base(), + E.v1(), + E.v3(), + ) + ) + + self.browse(self.v2).write({'application': 'enabled'}) + arch = self.read_combined(self.v0)['arch'] + self.assertEqual( + ET.fromstring(arch), + E.qweb( + E.base(), + E.v1(), + E.v2(), + E.v3(), + ) + ) + + def test_mandatory_no_disabled(self): + with self.assertRaises(Exception): + self.browse(self.v1).write({'application': 'disabled'}) + class TestXPathExtentions(common.BaseCase): def test_hasclass(self): tree = E.node( From e06f5b414b47270c1b30dfe49a5f2d7621d54714 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 27 May 2014 11:54:01 +0200 Subject: [PATCH 11/12] [IMP] inherit_option_id -> application --- addons/website/controllers/main.py | 54 ++++++++----------- addons/website/models/ir_ui_view.py | 12 ++--- .../website/static/src/js/website.editor.js | 10 +++- addons/website/views/themes.xml | 24 ++++----- addons/website/views/website_templates.xml | 8 +-- .../views/website_blog_templates.xml | 24 ++++----- addons/website_crm/views/website_crm.xml | 4 +- .../views/website_crm_partner_assign.xml | 2 +- .../views/website_customer.xml | 4 +- addons/website_event/views/website_event.xml | 12 ++--- .../views/website_event_sale.xml | 2 +- .../views/website_event.xml | 6 +-- addons/website_hr/views/website_hr.xml | 2 +- .../views/templates.xml | 4 +- .../views/website_membership.xml | 4 +- .../website_quote/views/website_quotation.xml | 6 +-- addons/website_sale/views/templates.xml | 22 ++++---- openerp/addons/base/ir/ir_ui_view.py | 15 ++++++ openerp/import_xml.rng | 9 +++- openerp/tools/convert.py | 9 ++-- 20 files changed, 126 insertions(+), 107 deletions(-) diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 19828afdc83..39f3067720f 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -158,22 +158,25 @@ class Website(openerp.addons.web.controllers.main.Home): @http.route('/website/theme_change', type='http', auth="user", website=True) def theme_change(self, theme_id=False, **kwargs): imd = request.registry['ir.model.data'] - view = request.registry['ir.ui.view'] + Views = request.registry['ir.ui.view'] - view_model, view_option_id = imd.get_object_reference( + _, theme_template_id = imd.get_object_reference( request.cr, request.uid, 'website', 'theme') - views = view.search( - request.cr, request.uid, [('inherit_id', '=', view_option_id)], - context=request.context) - view.write(request.cr, request.uid, views, {'inherit_id': False}, - context=request.context) + views = Views.search(request.cr, request.uid, [ + ('inherit_id', '=', theme_template_id), + ('application', '=', 'enabled'), + ], context=request.context) + Views.write(request.cr, request.uid, views, { + 'application': 'disabled', + }, context=request.context) if theme_id: module, xml_id = theme_id.split('.') - view_model, view_id = imd.get_object_reference( + _, view_id = imd.get_object_reference( request.cr, request.uid, module, xml_id) - view.write(request.cr, request.uid, [view_id], - {'inherit_id': view_option_id}, context=request.context) + Views.write(request.cr, request.uid, [view_id], { + 'application': 'enabled' + }, context=request.context) return request.render('website.themes', {'theme_changed': True}) @@ -197,20 +200,6 @@ class Website(openerp.addons.web.controllers.main.Home): module_obj.button_immediate_upgrade(request.cr, request.uid, module_ids, context=request.context) return request.redirect(redirect) - @http.route('/website/customize_template_toggle', type='json', auth='user', website=True) - def customize_template_set(self, view_id): - view_obj = request.registry.get("ir.ui.view") - view = view_obj.browse(request.cr, request.uid, int(view_id), - context=request.context) - if view.inherit_id: - value = False - else: - value = view.inherit_option_id and view.inherit_option_id.id or False - view_obj.write(request.cr, request.uid, [view_id], { - 'inherit_id': value - }, context=request.context) - return True - @http.route('/website/customize_template_get', type='json', auth='user', website=True) def customize_template_get(self, xml_id, full=False): """ Lists the templates customizing ``xml_id``. By default, only @@ -221,34 +210,35 @@ class Website(openerp.addons.web.controllers.main.Home): view_model, view_theme_id = imd.get_object_reference( request.cr, request.uid, 'website', 'theme') - user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, request.context) + user = request.registry['res.users']\ + .browse(request.cr, request.uid, request.uid, request.context) user_groups = set(user.groups_id) - view = request.registry["ir.ui.view"] - views = view._views_get(request.cr, request.uid, xml_id, context=request.context) + views = request.registry["ir.ui.view"]\ + ._views_get(request.cr, request.uid, xml_id, context=request.context) done = set() result = [] for v in views: if not user_groups.issuperset(v.groups_id): continue - if full or v.inherit_option_id and v.inherit_option_id.id != view_theme_id: - if v.inherit_option_id.id not in done: + if full or (v.application != 'always' and v.inherit_id.id != view_theme_id): + if v.inherit_id not in done: result.append({ - 'name': v.inherit_option_id.name, + 'name': v.inherit_id.name, 'id': v.id, 'xml_id': v.xml_id, 'inherit_id': v.inherit_id.id, 'header': True, 'active': False }) - done.add(v.inherit_option_id.id) + done.add(v.inherit_id) result.append({ 'name': v.name, 'id': v.id, 'xml_id': v.xml_id, 'inherit_id': v.inherit_id.id, 'header': False, - 'active': (v.inherit_id.id == v.inherit_option_id.id) or (full and v.inherit_id.id) + 'active': v.application in ('always', 'enabled'), }) return result diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index f422dae7b20..398bbb6a87b 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -13,8 +13,6 @@ from openerp.osv import osv, fields class view(osv.osv): _inherit = "ir.ui.view" _columns = { - 'inherit_option_id': fields.many2one('ir.ui.view','Optional Inheritancy'), - 'inherited_option_ids': fields.one2many('ir.ui.view','inherit_option_id','Optional Inheritancies'), 'page': fields.boolean("Whether this view is a web page template (complete)"), 'website_meta_title': fields.char("Website meta title", size=70, translate=True), 'website_meta_description': fields.text("Website meta description", size=160, translate=True), @@ -66,16 +64,18 @@ class view(osv.osv): if called_view not in result: result += self._views_get(cr, uid, called_view, options=options, context=context) - extensions = set(view.inherit_children_ids) - if options: - extensions.update(view.inherited_option_ids) + extensions = view.inherit_children_ids + if not options: + # only active children + extensions = (v for v in view.inherit_children_ids + if v.application in ('always', 'enabled')) # Keep options in a deterministic order regardless of their applicability for extension in sorted(extensions, key=lambda v: v.id): for r in self._views_get( cr, uid, extension, # only return optional grandchildren if this child is enabled - options=bool(extension.inherit_id), + options=extension.application in ('always', 'enabled'), context=context, root=False): if r not in result: result.append(r) diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index 595df04a088..fcb957cafda 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -470,8 +470,14 @@ }); menu.on('click', 'a[data-action!=ace]', function (event) { var view_id = $(event.currentTarget).data('view-id'); - openerp.jsonRpc('/website/customize_template_toggle', 'call', { - 'view_id': view_id + return openerp.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'ir.ui.view', + method: 'toggle', + args: [], + kwargs: { + ids: [parseInt(view_id, 10)], + context: website.get_context() + } }).then( function() { window.location.reload(); }); diff --git a/addons/website/views/themes.xml b/addons/website/views/themes.xml index 82f5105adcd..a2408133207 100644 --- a/addons/website/views/themes.xml +++ b/addons/website/views/themes.xml @@ -203,82 +203,82 @@ All Default Themes --> -