Skip to content

Commit 6086c21

Browse files
hbrunnalexis-via
authored andcommitted
[ADD] base_view_inheritance_extension
1 parent 235cf3e commit 6086c21

File tree

9 files changed

+288
-0
lines changed

9 files changed

+288
-0
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
2+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
3+
:alt: License: AGPL-3
4+
5+
=========================
6+
Extended view inheritance
7+
=========================
8+
9+
This module was written to make it simple to add custom operators for view inheritance.
10+
11+
Usage
12+
=====
13+
14+
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
15+
:alt: Try me on Runbot
16+
:target: https://runbot.odoo-community.org/runbot/149/8.0
17+
18+
Change a python dictionary (context for example)
19+
------------------------------------------------
20+
21+
.. code-block:: xml
22+
23+
<attribute name="$attribute" operation="python_dict" key="$key">
24+
$new_value
25+
</attribute>
26+
27+
Note that views are subject to evaluation of xmlids anyways, so if you need to refer to some xmlid, say ``%(xmlid)s``.
28+
29+
Move an element in the view
30+
---------------------------
31+
32+
.. code-block:: xml
33+
34+
<xpath expr="$xpath" position="move" target="$targetxpath" />
35+
36+
This can also be used to wrap some element into another, create the target element first, then move the node youwant to wrap there.
37+
38+
Known issues / Roadmap
39+
======================
40+
41+
* add ``<attribute operation="python_list_add">$value</attribute>``
42+
* add ``<attribute operation="python_list_remove">$index</attribute>``
43+
* add ``<attribute operation="json_dict" key="$key">$value</attribute>``
44+
* support ``<xpath expr="$xpath" position="move" target="xpath" target_position="position" />``
45+
* support an ``eval`` attribute for our new node types
46+
47+
Bug Tracker
48+
===========
49+
50+
Bugs are tracked on `GitHub Issues
51+
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
52+
check there if your issue has already been reported. If you spotted it first,
53+
help us smashing it by providing a detailed and welcomed feedback.
54+
55+
Credits
56+
=======
57+
58+
Images
59+
------
60+
61+
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
62+
63+
Contributors
64+
------------
65+
66+
* Holger Brunn <hbrunn@therp.nl>
67+
68+
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.
69+
70+
Maintainer
71+
----------
72+
73+
.. image:: https://odoo-community.org/logo.png
74+
:alt: Odoo Community Association
75+
:target: https://odoo-community.org
76+
77+
This module is maintained by the OCA.
78+
79+
OCA, or the Odoo Community Association, is a nonprofit organization whose
80+
mission is to support the collaborative development of Odoo features and
81+
promote its widespread use.
82+
83+
To contribute to this module, please visit https://odoo-community.org.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
from . import models
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
{
5+
"name": "Extended view inheritance",
6+
"version": "8.0.1.0.0",
7+
"author": "Therp BV,Odoo Community Association (OCA)",
8+
"license": "AGPL-3",
9+
"category": "Hidden/Dependency",
10+
"summary": "Adds more operators for view inheritance",
11+
"depends": [
12+
'base',
13+
],
14+
"demo": [
15+
"demo/ir_ui_view.xml",
16+
],
17+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<openerp>
3+
<data>
4+
<record id="view_partner_form" model="ir.ui.view">
5+
<field name="model">res.partner</field>
6+
<field name="inherit_id" ref="base.view_partner_form" />
7+
<field name="arch" type="xml">
8+
<xpath expr="." position="attributes">
9+
<attribute name="string">Partner form</attribute>
10+
</xpath>
11+
<field name="parent_id" position="attributes">
12+
<attribute name="context" operation="python_dict" key="default_name">'The company name'</attribute>
13+
<attribute name="context" operation="python_dict" key="default_company_id">context.get('company_id', context.get('company'))</attribute>
14+
</field>
15+
<notebook position="inside">
16+
<page string="A new page" name="my_new_page" />
17+
</notebook>
18+
<xpath expr="//field[@name='child_ids']" position="move" target="//page[@name='my_new_page']" />
19+
</field>
20+
</record>
21+
</data>
22+
</openerp>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
from . import ir_ui_view
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
from lxml import etree
5+
from openerp import api, models, tools
6+
7+
8+
class UnquoteObject(str):
9+
def __getattr__(self, name):
10+
return UnquoteObject('%s.%s' % (self, name))
11+
12+
def __repr__(self):
13+
return self
14+
15+
def __call__(self, *args, **kwargs):
16+
return UnquoteObject(
17+
'%s(%s)' % (
18+
self,
19+
','.join(
20+
[
21+
UnquoteObject(
22+
a if not isinstance(a, basestring)
23+
else "'%s'" % a
24+
)
25+
for a in args
26+
] +
27+
[
28+
'%s=%s' % (UnquoteObject(k), v)
29+
for (k, v) in kwargs.iteritems()
30+
]
31+
)
32+
)
33+
)
34+
35+
36+
class UnquoteEvalObjectContext(tools.misc.UnquoteEvalContext):
37+
def __missing__(self, key):
38+
return UnquoteObject(key)
39+
40+
41+
class IrUiView(models.Model):
42+
_inherit = 'ir.ui.view'
43+
44+
@api.model
45+
def apply_inheritance_specs(self, source, specs_tree, inherit_id):
46+
for specs, handled_by in self._iter_inheritance_specs(specs_tree):
47+
source = handled_by(source, specs, inherit_id)
48+
return source
49+
50+
@api.model
51+
def _iter_inheritance_specs(self, spec):
52+
if spec.tag == 'data':
53+
for child in spec:
54+
for node, handler in self._iter_inheritance_specs(child):
55+
yield node, handler
56+
return
57+
if spec.get('position') == 'attributes':
58+
for child in spec:
59+
node = etree.Element(spec.tag, **spec.attrib)
60+
node.insert(0, child)
61+
yield node, self._get_inheritance_handler_attributes(
62+
child
63+
)
64+
return
65+
yield spec, self._get_inheritance_handler(spec)
66+
67+
@api.model
68+
def _get_inheritance_handler(self, node):
69+
handler = super(IrUiView, self).apply_inheritance_specs
70+
if hasattr(
71+
self, 'inheritance_handler_%s' % node.tag
72+
):
73+
handler = getattr(
74+
self,
75+
'inheritance_handler_%s' % node.tag
76+
)
77+
return handler
78+
79+
@api.model
80+
def _get_inheritance_handler_attributes(self, node):
81+
handler = super(IrUiView, self).apply_inheritance_specs
82+
if hasattr(
83+
self, 'inheritance_handler_attributes_%s' % node.get('operation')
84+
):
85+
handler = getattr(
86+
self,
87+
'inheritance_handler_attributes_%s' % node.get('operation')
88+
)
89+
return handler
90+
91+
@api.model
92+
def inheritance_handler_attributes_python_dict(
93+
self, source, specs, inherit_id
94+
):
95+
"""Implement
96+
<$node position="attributes">
97+
<attribute name="$attribute" operation="python_dict" key="$key">
98+
$keyvalue
99+
</attribute>
100+
</$node>"""
101+
node = self.locate_node(source, specs)
102+
for attribute_node in specs:
103+
python_dict = tools.safe_eval(
104+
node.get(attribute_node.get('name')) or '{}',
105+
UnquoteEvalObjectContext()
106+
)
107+
python_dict[attribute_node.get('key')] = UnquoteObject(
108+
attribute_node.text
109+
)
110+
node.attrib[attribute_node.get('name')] = str(python_dict)
111+
return source
112+
113+
@api.model
114+
def inheritance_handler_xpath(self, source, specs, inherit_id):
115+
if not specs.get('position') == 'move':
116+
return super(IrUiView, self).apply_inheritance_specs(
117+
source, specs, inherit_id
118+
)
119+
node = self.locate_node(source, specs)
120+
target_node = self.locate_node(
121+
source, etree.Element(specs.tag, expr=specs.get('target'))
122+
)
123+
target_node.append(node)
124+
return source
9.23 KB
Loading
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
from . import test_base_view_inheritance_extension
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# -*- coding: utf-8 -*-
2+
# © 2016 Therp BV <http://therp.nl>
3+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4+
from lxml import etree
5+
from openerp.tests.common import TransactionCase
6+
7+
8+
class TestBaseViewInheritanceExtension(TransactionCase):
9+
def test_base_view_inheritance_extension(self):
10+
view_id = self.env.ref('base.view_partner_form').id
11+
fields_view_get = self.env['res.partner'].fields_view_get(
12+
view_id=view_id
13+
)
14+
view = etree.fromstring(fields_view_get['arch'])
15+
# verify normal attributes work
16+
self.assertEqual(view.xpath('//form')[0].get('string'), 'Partner form')
17+
# verify our extra context key worked
18+
self.assertTrue(
19+
'default_name' in
20+
view.xpath('//field[@name="parent_id"]')[0].get('context')
21+
)
22+
self.assertTrue(
23+
"context.get('company_id', context.get('company'))" in
24+
view.xpath('//field[@name="parent_id"]')[0].get('context')
25+
)
26+
# verify we moved the child_ids field
27+
self.assertEqual(
28+
view.xpath('//field[@name="child_ids"]')[0].getparent(),
29+
view.xpath('//page[@name="my_new_page"]')[0]
30+
)

0 commit comments

Comments
 (0)