#
##############################################################################
-from osv import fields,osv
+import logging
from lxml import etree
-from tools import graph
-from tools.safe_eval import safe_eval as eval
-import tools
import os
-import logging
+
+from openerp import tools
+from openerp.osv import fields,osv
+from openerp.tools import graph
+from openerp.tools.safe_eval import safe_eval as eval
+from openerp.tools.view_validation import valid_view
_logger = logging.getLogger(__name__)
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_ui_view_custom_user_id_ref_id\'')
if not cr.fetchone():
cr.execute('CREATE INDEX ir_ui_view_custom_user_id_ref_id ON ir_ui_view_custom (user_id, ref_id)')
-view_custom()
class view(osv.osv):
_name = 'ir.ui.view'
+
+ def _type_field(self, cr, uid, ids, name, args, context=None):
+ result = {}
+ for record in self.browse(cr, uid, ids, context):
+ # Get the type from the inherited view if any.
+ if record.inherit_id:
+ result[record.id] = record.inherit_id.type
+ else:
+ result[record.id] = etree.fromstring(record.arch.encode('utf8')).tag
+ return result
+
_columns = {
- 'name': fields.char('View Name',size=64, required=True),
+ 'name': fields.char('View Name', required=True),
'model': fields.char('Object', size=64, required=True, select=True),
'priority': fields.integer('Sequence', required=True),
- 'type': fields.selection((
+ 'type': fields.function(_type_field, type='selection', selection=[
('tree','Tree'),
('form','Form'),
('mdx','mdx'),
('diagram','Diagram'),
('gantt', 'Gantt'),
('kanban', 'Kanban'),
- ('search','Search')), 'View Type', required=True, select=True),
+ ('search','Search')], string='View Type', required=True, select=True, store=True),
'arch': fields.text('View Architecture', required=True),
'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade', select=True),
'field_parent': fields.char('Child Field',size=64),
'xml_id': fields.function(osv.osv.get_xml_id, type='char', size=128, string="External ID",
help="ID of the view defined in xml file"),
+ 'groups_id': fields.many2many('res.groups', 'ir_ui_view_group_rel', 'view_id', 'group_id',
+ string='Groups', help="If this field is empty, the view applies to all users. Otherwise, the view applies to the users of those groups only."),
}
_defaults = {
'arch': '<?xml version="1.0"?>\n<tree string="My view">\n\t<field name="name"/>\n</tree>',
- 'priority': 16
+ 'priority': 16,
+ 'type': 'tree',
}
_order = "priority,name"
# Holds the RNG schema
- _relaxng_validator = None
+ _relaxng_validator = None
+
+ def create(self, cr, uid, values, context=None):
+ if 'type' in values:
+ _logger.warning("Setting the `type` field is deprecated in the `ir.ui.view` model.")
+ if not values.get('name'):
+ if values.get('inherit_id'):
+ inferred_type = self.browse(cr, uid, values['inherit_id'], context).type
+ else:
+ inferred_type = etree.fromstring(values['arch'].encode('utf8')).tag
+ values['name'] = "%s %s" % (values['model'], inferred_type)
+ return super(osv.osv, self).create(cr, uid, values, context)
def _relaxng(self):
if not self._relaxng_validator:
finally:
frng.close()
return self._relaxng_validator
-
-
+
def _check_render_view(self, cr, uid, view, context=None):
"""Verify that the given view's hierarchy is valid for rendering, along with all the changes applied by
its inherited views, by rendering it using ``fields_view_get()``.
@param browse_record view: view to validate
- @return: True if the view hierarchy was rendered without any error, False if an error occurred.
+ @return: the rendered definition (arch) of the view, always utf-8 bytestring (legacy convention)
+ if no error occurred, else False.
"""
try:
- self.pool.get(view.model).fields_view_get(cr, uid, view_id=view.id, view_type=view.type, context=context)
- return True
+ fvg = self.pool.get(view.model).fields_view_get(cr, uid, view_id=view.id, view_type=view.type, context=context)
+ return fvg['arch']
except:
_logger.exception("Can't render view %s for model: %s", view.xml_id, view.model)
return False
def _check_xml(self, cr, uid, ids, context=None):
for view in self.browse(cr, uid, ids, context):
+ # Sanity check: the view should not break anything upon rendering!
+ view_arch_utf8 = self._check_render_view(cr, uid, view, context=context)
+ # always utf-8 bytestring - legacy convention
+ if not view_arch_utf8: return False
+
# RNG-based validation is not possible anymore with 7.0 forms
- # TODO 7.0: provide alternative assertion-based validation!
- view_docs = [etree.fromstring(view.arch.encode('utf8'))]
+ # TODO 7.0: provide alternative assertion-based validation of view_arch_utf8
+ view_docs = [etree.fromstring(view_arch_utf8)]
if view_docs[0].tag == 'data':
# A <data> element is a wrapper for multiple root nodes
view_docs = view_docs[0]
for error in validator.error_log:
_logger.error(tools.ustr(error))
return False
-
- # Second sanity check: the view should not break anything upon rendering!
- if not self._check_render_view(cr, uid, view, context=context):
- return False
+ if not valid_view(view_arch):
+ return False
return True
_constraints = [
super(view, self)._auto_init(cr, context)
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_ui_view_model_type_inherit_id\'')
if not cr.fetchone():
- cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, type, inherit_id)')
+ cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)')
def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None):
"""Retrieves the architecture of views that inherit from the given view, from the sets of
:rtype: list of tuples
:return: [(view_arch,view_id), ...]
"""
+ user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
if self.pool._init:
# Module init currently in progress, only consider views from modules whose code was already loaded
- query = """SELECT v.arch, v.id FROM ir_ui_view v LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id)
+ query = """SELECT v.id FROM ir_ui_view v LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id)
WHERE v.inherit_id=%s AND v.model=%s AND md.module in %s
ORDER BY priority"""
query_params = (view_id, model, tuple(self.pool._init_modules))
else:
# Modules fully loaded, consider all views
- query = """SELECT v.arch, v.id FROM ir_ui_view v
+ query = """SELECT v.id FROM ir_ui_view v
WHERE v.inherit_id=%s AND v.model=%s
ORDER BY priority"""
query_params = (view_id, model)
cr.execute(query, query_params)
- return cr.fetchall()
+ view_ids = [v[0] for v in cr.fetchall()]
+ # filter views based on user groups
+ return [(view.arch, view.id)
+ for view in self.browse(cr, 1, view_ids, context)
+ if not (view.groups_id and user_groups.isdisjoint(view.groups_id))]
def write(self, cr, uid, ids, vals, context=None):
if not isinstance(ids, (list, tuple)):
ids = [ids]
- result = super(view, self).write(cr, uid, ids, vals, context)
# drop the corresponding view customizations (used for dashboards for example), otherwise
# not all users would see the updated views
if custom_view_ids:
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
- return result
+ return super(view, self).write(cr, uid, ids, vals, context)
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None):
nodes=[]
if label:
for lbl in eval(label):
if t.has_key(tools.ustr(lbl)) and tools.ustr(t[lbl])=='False':
- label_string = label_string + ' '
+ label_string += ' '
else:
label_string = label_string + " " + tools.ustr(t[lbl])
labels[str(t['id'])] = (a['id'],label_string)
'label' : labels,
'blank_nodes': blank_nodes,
'node_parent_field': _Model_Field,}
-view()
class view_sc(osv.osv):
_name = 'ir.ui.view_sc'
_order = 'sequence,name'
_defaults = {
- 'resource': lambda *a: 'ir.ui.menu',
+ 'resource': 'ir.ui.menu',
'user_id': lambda obj, cr, uid, context: uid,
}
_sql_constraints = [
('shortcut_unique', 'unique(res_id, resource, user_id)', 'Shortcut for this menu already exists!'),
]
-view_sc()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: