[MERGE] orm: use directly lxml.etree to generate default views.
bzr revid: vmt@openerp.com-20111004092828-79hhaiwgw4dltimd
This commit is contained in:
commit
8dc80c7c7c
|
@ -44,6 +44,7 @@
|
||||||
import calendar
|
import calendar
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import operator
|
import operator
|
||||||
import pickle
|
import pickle
|
||||||
|
@ -1727,13 +1728,69 @@ class BaseModel(object):
|
||||||
raise except_orm('View error', msg)
|
raise except_orm('View error', msg)
|
||||||
return arch, fields
|
return arch, fields
|
||||||
|
|
||||||
def __get_default_calendar_view(self):
|
def _get_default_form_view(self, cr, user, context=None):
|
||||||
"""Generate a default calendar view (For internal use only).
|
""" Generates a default single-line form view using all fields
|
||||||
"""
|
of the current model except the m2m and o2m ones.
|
||||||
# TODO could return an etree instead of a string
|
|
||||||
|
|
||||||
arch = ('<?xml version="1.0" encoding="utf-8"?>\n'
|
:param cr: database cursor
|
||||||
'<calendar string="%s"') % (self._description)
|
:param int user: user id
|
||||||
|
:param dict context: connection context
|
||||||
|
:returns: a form view as an lxml document
|
||||||
|
:rtype: etree._Element
|
||||||
|
"""
|
||||||
|
view = etree.Element('form', string=self._description)
|
||||||
|
# TODO it seems fields_get can be replaced by _all_columns (no need for translation)
|
||||||
|
for field, descriptor in self.fields_get(cr, user, context=context).iteritems():
|
||||||
|
if descriptor['type'] in ('one2many', 'many2many'):
|
||||||
|
continue
|
||||||
|
etree.SubElement(view, 'field', name=field)
|
||||||
|
if descriptor['type'] == 'text':
|
||||||
|
etree.SubElement(view, 'newline')
|
||||||
|
return view
|
||||||
|
|
||||||
|
def _get_default_tree_view(self, cr, user, context=None):
|
||||||
|
""" Generates a single-field tree view, using _rec_name if
|
||||||
|
it's one of the columns or the first column it finds otherwise
|
||||||
|
|
||||||
|
:param cr: database cursor
|
||||||
|
:param int user: user id
|
||||||
|
:param dict context: connection context
|
||||||
|
:returns: a tree view as an lxml document
|
||||||
|
:rtype: etree._Element
|
||||||
|
"""
|
||||||
|
_rec_name = self._rec_name
|
||||||
|
if _rec_name not in self._columns:
|
||||||
|
_rec_name = self._columns.keys()[0]
|
||||||
|
|
||||||
|
view = etree.Element('tree', string=self._description)
|
||||||
|
etree.SubElement(view, 'field', name=_rec_name)
|
||||||
|
return view
|
||||||
|
|
||||||
|
def _get_default_calendar_view(self, cr, user, context=None):
|
||||||
|
""" Generates a default calendar view by trying to infer
|
||||||
|
calendar fields from a number of pre-set attribute names
|
||||||
|
|
||||||
|
:param cr: database cursor
|
||||||
|
:param int user: user id
|
||||||
|
:param dict context: connection context
|
||||||
|
:returns: a calendar view
|
||||||
|
:rtype: etree._Element
|
||||||
|
"""
|
||||||
|
def set_first_of(seq, in_, to):
|
||||||
|
"""Sets the first value of ``seq`` also found in ``in_`` to
|
||||||
|
the ``to`` attribute of the view being closed over.
|
||||||
|
|
||||||
|
Returns whether it's found a suitable value (and set it on
|
||||||
|
the attribute) or not
|
||||||
|
"""
|
||||||
|
for item in seq:
|
||||||
|
if item in in_:
|
||||||
|
view.set(to, item)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
view = etree.Element('calendar', string=self._description)
|
||||||
|
etree.SubElement(view, 'field', name=self._rec_name)
|
||||||
|
|
||||||
if (self._date_name not in self._columns):
|
if (self._date_name not in self._columns):
|
||||||
date_found = False
|
date_found = False
|
||||||
|
@ -1745,61 +1802,52 @@ class BaseModel(object):
|
||||||
|
|
||||||
if not date_found:
|
if not date_found:
|
||||||
raise except_orm(_('Invalid Object Architecture!'), _("Insufficient fields for Calendar View!"))
|
raise except_orm(_('Invalid Object Architecture!'), _("Insufficient fields for Calendar View!"))
|
||||||
|
view.set('date_start', self._date_name)
|
||||||
|
|
||||||
if self._date_name:
|
set_first_of(["user_id", "partner_id", "x_user_id", "x_partner_id"],
|
||||||
arch += ' date_start="%s"' % (self._date_name)
|
self._columns, 'color')
|
||||||
|
|
||||||
for color in ["user_id", "partner_id", "x_user_id", "x_partner_id"]:
|
if not set_first_of(["date_stop", "date_end", "x_date_stop", "x_date_end"],
|
||||||
if color in self._columns:
|
self._columns, 'date_stop'):
|
||||||
arch += ' color="' + color + '"'
|
if not set_first_of(["date_delay", "planned_hours", "x_date_delay", "x_planned_hours"],
|
||||||
break
|
self._columns, 'date_delay'):
|
||||||
|
raise except_orm(
|
||||||
|
_('Invalid Object Architecture!'),
|
||||||
|
_("Insufficient fields to generate a Calendar View for %s, missing a date_stop or a date_delay" % (self._name)))
|
||||||
|
|
||||||
dt_stop_flag = False
|
return view
|
||||||
|
|
||||||
for dt_stop in ["date_stop", "date_end", "x_date_stop", "x_date_end"]:
|
def _get_default_search_view(self, cr, uid, context=None):
|
||||||
if dt_stop in self._columns:
|
"""
|
||||||
arch += ' date_stop="' + dt_stop + '"'
|
:param cr: database cursor
|
||||||
dt_stop_flag = True
|
:param int user: user id
|
||||||
break
|
:param dict context: connection context
|
||||||
|
:returns: an lxml document of the view
|
||||||
if not dt_stop_flag:
|
:rtype: etree._Element
|
||||||
for dt_delay in ["date_delay", "planned_hours", "x_date_delay", "x_planned_hours"]:
|
"""
|
||||||
if dt_delay in self._columns:
|
|
||||||
arch += ' date_delay="' + dt_delay + '"'
|
|
||||||
break
|
|
||||||
|
|
||||||
arch += ('>\n'
|
|
||||||
' <field name="%s"/>\n'
|
|
||||||
'</calendar>') % (self._rec_name)
|
|
||||||
|
|
||||||
return arch
|
|
||||||
|
|
||||||
def __get_default_search_view(self, cr, uid, context=None):
|
|
||||||
form_view = self.fields_view_get(cr, uid, False, 'form', context=context)
|
form_view = self.fields_view_get(cr, uid, False, 'form', context=context)
|
||||||
tree_view = self.fields_view_get(cr, uid, False, 'tree', context=context)
|
tree_view = self.fields_view_get(cr, uid, False, 'tree', context=context)
|
||||||
|
|
||||||
fields_to_search = set()
|
|
||||||
# TODO it seems _all_columns could be used instead of fields_get (no need for translated fields info)
|
# TODO it seems _all_columns could be used instead of fields_get (no need for translated fields info)
|
||||||
fields = self.fields_get(cr, uid, context=context)
|
fields = self.fields_get(cr, uid, context=context)
|
||||||
for field in fields:
|
fields_to_search = set(
|
||||||
if fields[field].get('select'):
|
field for field, descriptor in fields.iteritems()
|
||||||
fields_to_search.add(field)
|
if descriptor.get('select'))
|
||||||
|
|
||||||
for view in (form_view, tree_view):
|
for view in (form_view, tree_view):
|
||||||
view_root = etree.fromstring(view['arch'])
|
view_root = etree.fromstring(view['arch'])
|
||||||
# Only care about select=1 in xpath below, because select=2 is covered
|
# Only care about select=1 in xpath below, because select=2 is covered
|
||||||
# by the custom advanced search in clients
|
# by the custom advanced search in clients
|
||||||
fields_to_search = fields_to_search.union(view_root.xpath("//field[@select=1]/@name"))
|
fields_to_search.update(view_root.xpath("//field[@select=1]/@name"))
|
||||||
|
|
||||||
tree_view_root = view_root # as provided by loop above
|
tree_view_root = view_root # as provided by loop above
|
||||||
search_view = etree.Element("search", attrib={'string': tree_view_root.get("string", "")})
|
search_view = etree.Element("search", string=tree_view_root.get("string", ""))
|
||||||
field_group = etree.Element("group")
|
|
||||||
search_view.append(field_group)
|
|
||||||
|
|
||||||
|
field_group = etree.SubElement(search_view, "group")
|
||||||
for field_name in fields_to_search:
|
for field_name in fields_to_search:
|
||||||
field_group.append(etree.Element("field", attrib={'name': field_name}))
|
etree.SubElement(field_group, "field", name=field_name)
|
||||||
|
|
||||||
#TODO tostring can be removed as fromstring is call directly after...
|
return search_view
|
||||||
return etree.tostring(search_view, encoding="utf-8").replace('\t', '')
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# if view_id, view_type is not required
|
# if view_id, view_type is not required
|
||||||
|
@ -1990,50 +2038,27 @@ class BaseModel(object):
|
||||||
|
|
||||||
# if a view was found
|
# if a view was found
|
||||||
if sql_res:
|
if sql_res:
|
||||||
result['type'] = sql_res['type']
|
|
||||||
result['view_id'] = sql_res['id']
|
|
||||||
|
|
||||||
source = etree.fromstring(encode(sql_res['arch']))
|
source = etree.fromstring(encode(sql_res['arch']))
|
||||||
result['arch'] = apply_view_inheritance(cr, user, source, result['view_id'])
|
result.update(
|
||||||
|
arch=apply_view_inheritance(cr, user, source, sql_res['id']),
|
||||||
result['name'] = sql_res['name']
|
type=sql_res['type'],
|
||||||
result['field_parent'] = sql_res['field_parent'] or False
|
view_id=sql_res['id'],
|
||||||
|
name=sql_res['name'],
|
||||||
|
field_parent=sql_res['field_parent'] or False)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# otherwise, build some kind of default view
|
# otherwise, build some kind of default view
|
||||||
if view_type == 'form':
|
try:
|
||||||
# TODO it seems fields_get can be replaced by _all_columns (no need for translation)
|
view = getattr(self, '_get_default_%s_view' % view_type)(
|
||||||
res = self.fields_get(cr, user, context=context)
|
cr, user, context)
|
||||||
xml = '<?xml version="1.0" encoding="utf-8"?> ' \
|
except AttributeError:
|
||||||
'<form string="%s">' % (self._description,)
|
|
||||||
for x in res:
|
|
||||||
if res[x]['type'] not in ('one2many', 'many2many'):
|
|
||||||
xml += '<field name="%s"/>' % (x,)
|
|
||||||
if res[x]['type'] == 'text':
|
|
||||||
xml += "<newline/>"
|
|
||||||
xml += "</form>"
|
|
||||||
|
|
||||||
elif view_type == 'tree':
|
|
||||||
_rec_name = self._rec_name
|
|
||||||
if _rec_name not in self._columns:
|
|
||||||
_rec_name = self._columns.keys()[0]
|
|
||||||
xml = '<?xml version="1.0" encoding="utf-8"?>' \
|
|
||||||
'<tree string="%s"><field name="%s"/></tree>' \
|
|
||||||
% (self._description, _rec_name)
|
|
||||||
|
|
||||||
elif view_type == 'calendar':
|
|
||||||
xml = self.__get_default_calendar_view()
|
|
||||||
|
|
||||||
elif view_type == 'search':
|
|
||||||
xml = self.__get_default_search_view(cr, user, context)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# what happens here, graph case?
|
# what happens here, graph case?
|
||||||
raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
|
raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
|
||||||
result['arch'] = etree.fromstring(encode(xml))
|
|
||||||
result['name'] = 'default'
|
result.update(
|
||||||
result['field_parent'] = False
|
arch=view,
|
||||||
result['view_id'] = 0
|
name='default',
|
||||||
|
field_parent=False,
|
||||||
|
view_id=0)
|
||||||
|
|
||||||
if parent_view_model != self._name:
|
if parent_view_model != self._name:
|
||||||
ctx = context.copy()
|
ctx = context.copy()
|
||||||
|
@ -2064,14 +2089,13 @@ class BaseModel(object):
|
||||||
resrelate = ir_values_obj.get(cr, user, 'action',
|
resrelate = ir_values_obj.get(cr, user, 'action',
|
||||||
'client_action_relate', [(self._name, False)], False,
|
'client_action_relate', [(self._name, False)], False,
|
||||||
context)
|
context)
|
||||||
resprint = map(clean, resprint)
|
resaction = [clean(action) for action in resaction
|
||||||
resaction = map(clean, resaction)
|
if view_type == 'tree' or not action[2].get('multi')]
|
||||||
if view_type != 'tree':
|
resprint = [clean(print_) for print_ in resprint
|
||||||
resaction = filter(lambda x: not x.get('multi'), resaction)
|
if view_type == 'tree' or not print_[2].get('multi')]
|
||||||
resprint = filter(lambda x: not x.get('multi'), resprint)
|
|
||||||
resrelate = map(lambda x: x[2], resrelate)
|
resrelate = map(lambda x: x[2], resrelate)
|
||||||
|
|
||||||
for x in resprint + resaction + resrelate:
|
for x in itertools.chain(resprint, resaction, resrelate):
|
||||||
x['string'] = x['name']
|
x['string'] = x['name']
|
||||||
|
|
||||||
result['toolbar'] = {
|
result['toolbar'] = {
|
||||||
|
|
Loading…
Reference in New Issue