You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.5 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2016 Therp BV <http://therp.nl>
  3. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
  4. from lxml import etree
  5. from odoo import api, models, tools
  6. class UnquoteObject(str):
  7. def __getattr__(self, name):
  8. return UnquoteObject('%s.%s' % (self, name))
  9. def __repr__(self):
  10. return self
  11. def __call__(self, *args, **kwargs):
  12. return UnquoteObject(
  13. '%s(%s)' % (
  14. self,
  15. ','.join(
  16. [
  17. UnquoteObject(
  18. a if not isinstance(a, basestring)
  19. else "'%s'" % a
  20. )
  21. for a in args
  22. ] +
  23. [
  24. '%s=%s' % (UnquoteObject(k), v)
  25. for (k, v) in kwargs.iteritems()
  26. ]
  27. )
  28. )
  29. )
  30. class UnquoteEvalObjectContext(tools.misc.UnquoteEvalContext):
  31. def __missing__(self, key):
  32. return UnquoteObject(key)
  33. class IrUiView(models.Model):
  34. _inherit = 'ir.ui.view'
  35. @api.model
  36. def apply_inheritance_specs(self, source, specs_tree, inherit_id):
  37. for specs, handled_by in self._iter_inheritance_specs(specs_tree):
  38. source = handled_by(source, specs, inherit_id)
  39. return source
  40. @api.model
  41. def _iter_inheritance_specs(self, spec):
  42. if spec.tag == 'data':
  43. for child in spec:
  44. for node, handler in self._iter_inheritance_specs(child):
  45. yield node, handler
  46. return
  47. if spec.get('position') == 'attributes':
  48. if all(not c.get('operation') for c in spec):
  49. yield spec, self._get_inheritance_handler(spec)
  50. return
  51. for child in spec:
  52. node = etree.Element(spec.tag, **spec.attrib)
  53. node.insert(0, child)
  54. yield node, self._get_inheritance_handler_attributes(
  55. child
  56. )
  57. return
  58. yield spec, self._get_inheritance_handler(spec)
  59. @api.model
  60. def _get_inheritance_handler(self, node):
  61. handler = super(IrUiView, self).apply_inheritance_specs
  62. if hasattr(
  63. self, 'inheritance_handler_%s' % node.tag
  64. ):
  65. handler = getattr(
  66. self,
  67. 'inheritance_handler_%s' % node.tag
  68. )
  69. return handler
  70. @api.model
  71. def _get_inheritance_handler_attributes(self, node):
  72. handler = super(IrUiView, self).apply_inheritance_specs
  73. if hasattr(
  74. self, 'inheritance_handler_attributes_%s' % node.get('operation')
  75. ):
  76. handler = getattr(
  77. self,
  78. 'inheritance_handler_attributes_%s' % node.get('operation')
  79. )
  80. return handler
  81. @api.model
  82. def inheritance_handler_attributes_python_dict(
  83. self, source, specs, inherit_id
  84. ):
  85. """Implement
  86. <$node position="attributes">
  87. <attribute name="$attribute" operation="python_dict" key="$key">
  88. $keyvalue
  89. </attribute>
  90. </$node>"""
  91. node = self.locate_node(source, specs)
  92. for attribute_node in specs:
  93. python_dict = tools.safe_eval(
  94. node.get(attribute_node.get('name')) or '{}',
  95. UnquoteEvalObjectContext(),
  96. nocopy=True
  97. )
  98. python_dict[attribute_node.get('key')] = UnquoteObject(
  99. attribute_node.text
  100. )
  101. node.attrib[attribute_node.get('name')] = str(python_dict)
  102. return source
  103. @api.model
  104. def inheritance_handler_xpath(self, source, specs, inherit_id):
  105. if not specs.get('position') == 'move':
  106. return super(IrUiView, self).apply_inheritance_specs(
  107. source, specs, inherit_id
  108. )
  109. node = self.locate_node(source, specs)
  110. target_node = self.locate_node(
  111. source, etree.Element(specs.tag, expr=specs.get('target'))
  112. )
  113. target_node.append(node)
  114. return source
  115. @api.model
  116. def inheritance_handler_attributes_list_add(
  117. self, source, specs, inherit_id
  118. ):
  119. """Implement
  120. <$node position="attributes">
  121. <attribute name="$attribute" operation="list_add">
  122. $new_value
  123. </attribute>
  124. </$node>"""
  125. node = self.locate_node(source, specs)
  126. for attribute_node in specs:
  127. attribute_name = attribute_node.get('name')
  128. old_value = node.get(attribute_name) or ''
  129. new_value = old_value + ',' + attribute_node.text
  130. node.attrib[attribute_name] = new_value
  131. return source
  132. @api.model
  133. def inheritance_handler_attributes_list_remove(
  134. self, source, specs, inherit_id
  135. ):
  136. """Implement
  137. <$node position="attributes">
  138. <attribute name="$attribute" operation="list_remove">
  139. $value_to_remove
  140. </attribute>
  141. </$node>"""
  142. node = self.locate_node(source, specs)
  143. for attribute_node in specs:
  144. attribute_name = attribute_node.get('name')
  145. old_values = (node.get(attribute_name) or '').split(',')
  146. remove_values = attribute_node.text.split(',')
  147. new_values = [x for x in old_values if x not in remove_values]
  148. node.attrib[attribute_name] = ','.join(filter(None, new_values))
  149. return source