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.

143 lines
5.5 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2017 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. class IrUiView(models.Model):
  7. _inherit = 'ir.ui.view'
  8. @api.multi
  9. def custom_column(self, diff):
  10. """Apply a change for a custom view. Create a new custom view or
  11. view override as necessary"""
  12. self.ensure_one()
  13. tree = etree.fromstring(self.read_combined(self.id)['arch'])
  14. customized_view = self.env.ref(
  15. self._custom_column_xmlid(diff), raise_if_not_found=False
  16. ) or self.browse([])
  17. if diff['operation'] == 'add':
  18. etree.SubElement(tree, 'field', {'name': diff['name']})
  19. elif diff['operation'] == 'remove':
  20. for element in tree:
  21. if element.attrib['name'] == diff['name'] and\
  22. element.tag == 'field':
  23. tree.remove(element)
  24. elif diff['operation'] == 'left':
  25. for element in tree:
  26. if element.attrib['name'] == diff['name'] and\
  27. element.tag == 'field' and\
  28. element.getprevious() is not None:
  29. element.getprevious().addprevious(element)
  30. break
  31. elif diff['operation'] == 'right':
  32. for element in tree:
  33. if element.attrib['name'] == diff['name'] and\
  34. element.tag == 'field' and\
  35. element.getnext() is not None:
  36. element.getnext().addnext(element)
  37. break
  38. elif diff['operation'] == 'reset':
  39. customized_view.unlink()
  40. return []
  41. elif diff['operation'] == 'to_user':
  42. diff['type'] = 'user'
  43. customized_view = self.env.ref(
  44. self._custom_column_xmlid(diff), raise_if_not_found=False
  45. ) or self.browse([])
  46. elif diff['operation'] == 'to_all':
  47. customized_view.unlink()
  48. diff['type'] = 'all'
  49. customized_view = self.env.ref(
  50. self._custom_column_xmlid(diff), raise_if_not_found=False
  51. ) or self.browse([])
  52. else:
  53. raise NotImplementedError(
  54. 'Unknown operation %s' % diff['operation']
  55. )
  56. replacement = etree.Element('tree', {'position': 'replace'})
  57. replacement.append(tree)
  58. arch = etree.tostring(replacement, pretty_print=True)
  59. if customized_view:
  60. customized_view.write({'arch': arch})
  61. else:
  62. customized_view = self._custom_column_create_view(diff, arch)
  63. return customized_view.id
  64. @api.multi
  65. def custom_column_desc(self):
  66. """Return metadata necessary for UI"""
  67. self.ensure_one()
  68. return {
  69. 'fields': self.env[self.model].fields_get(),
  70. 'type': bool(self.env.ref(
  71. self._custom_column_xmlid({'type': 'user'}),
  72. raise_if_not_found=False
  73. )) and 'user' or bool(self.env.ref(
  74. self._custom_column_xmlid({'type': 'all'}),
  75. raise_if_not_found=False
  76. )) and 'all' or 'user',
  77. }
  78. @api.multi
  79. def _custom_column_xmlid(self, diff, qualify=True):
  80. """Return an xmlid for the view of a type of customization"""
  81. self.ensure_one()
  82. customization_type = diff['type']
  83. return '%scustom_view_%d_%s%s' % (
  84. qualify and 'web_listview_custom_column.' or '',
  85. self.id,
  86. customization_type,
  87. '_%d' % self.env.uid if customization_type == 'user' else '',
  88. )
  89. @api.multi
  90. def _custom_column_create_view(self, diff, arch):
  91. """Actually create a view for customization"""
  92. self.ensure_one()
  93. values = self.copy_data(default={
  94. 'name': _('%s customized') % self.name,
  95. 'arch': arch,
  96. 'inherit_id': self.id,
  97. 'mode': 'extension',
  98. 'priority': 10000 + (diff['type'] == 'user' and 1 or 0),
  99. 'user_ids': [(4, self.env.uid)] if diff['type'] == 'user' else [],
  100. })[0]
  101. result = self.create(values)
  102. self.env['ir.model.data'].create({
  103. 'name': self._custom_column_xmlid(diff, qualify=False),
  104. 'module': 'web_listview_custom_column',
  105. 'model': self._name,
  106. 'res_id': result.id,
  107. 'noupdate': True,
  108. })
  109. return result
  110. @api.multi
  111. def _check_xml(self):
  112. """Don't validate our custom views, this will break in init mode"""
  113. if self.env.registry._init:
  114. self = self.filtered(
  115. lambda x: not x.xml_id or not x.xml_id.startswith(
  116. 'web_listview_custom_column.custom_view_'
  117. )
  118. )
  119. return super(IrUiView, self)._check_xml()
  120. _constraints = [(_check_xml, 'Invalid view definition', ['arch'])]
  121. @api.model
  122. def get_inheriting_views_arch(self, view_id, model):
  123. """Don't apply our view inheritance in init mode for the same reason"""
  124. return [
  125. (arch, view_id_)
  126. for arch, view_id_ in
  127. super(IrUiView, self).get_inheriting_views_arch(view_id, model)
  128. if (not self.env.registry._init or tools.config['test_enable']) or
  129. not self.sudo().browse(view_id_).xml_id or
  130. not self.sudo().browse(view_id_).xml_id.startswith(
  131. 'web_listview_custom_column.custom_view_'
  132. )
  133. ]