Add modelview

This commit is contained in:
Cédric Krier committed 2009-01-29 20:34:26 +01:00
1 parent 5218c3545f
commit b137a42676
3 files changed
+371 -339

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from model import *
from modelview import *
+368
View File
@@ -0,0 +1,368 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from trytond.model import Model
from trytond.tools import Cache
from lxml import etree
import md5
import copy
def _find(tree, element):
if element.tag == 'xpath':
res = tree.xpath(element.get('expr'))
if res:
return res[0]
return None
def _inherit_apply(src, inherit):
tree_src = etree.fromstring(src)
tree_inherit = etree.fromstring(inherit)
root_inherit = tree_inherit.getroottree().getroot()
for element2 in root_inherit:
element = _find(tree_src, element2)
if element is not None:
pos = element2.get('position', 'inside')
if pos == 'replace':
parent = element.getparent()
next = element.getnext()
if next is not None:
for child in element2:
index = parent.index(next)
parent.insert(index, child)
else:
parent.extend(element2.getchildren())
parent.remove(element)
elif pos == 'replace_attributes':
child = element2.getchildren()[0]
for attr in child.attrib:
element.set(attr, child.get(attr))
elif pos == 'inside':
element.extend(element2.getchildren())
elif pos == 'after':
parent = element.getparent()
next = element.getnext()
if next is not None:
for child in element2:
index = parent.index(next)
parent.insert(index, child)
else:
parent.extend(element2.getchildren())
elif pos == 'before':
parent = element.getparent()
for child in element2:
index = parent.index(element)
parent.insert(index, child)
else:
raise AttributeError('Unknown position ' \
'in inherited view %s!' % pos)
else:
raise AttributeError(
'Couldn\'t find tag (%s: %s) in parent view!' % \
(element2.tag, element2.get('expr')))
return etree.tostring(tree_src, encoding='utf-8')
class ModelView(Model):
"""
Define a model with views in Tryton.
"""
def __init__(self):
super(ModelView, self).__init__()
self._rpc_allowed += [
'fields_view_get',
]
def fields_view_get(self, cursor, user, view_id=None, view_type='form',
context=None, toolbar=False, hexmd5=None):
'''
Return a view definition
:param cursor: the database cursor
:param user: the user id
:param view_id: the id of the view, if None the first one will be used
:param view_type: the type of the view if view_id is None
:param context: the context
:param toolbar: if True the result will contain a toolbar key with
keyword action definitions for the view
:param hexmd5: if fill, the function will return True if the result
have the same md5
:return: a dictionnary with keys:
- model: the model name
- arch: the xml description of the view
- fields: a dictionnary with the definition of each fields
in the view
- toolbar: a dictionnary with the keyword action definitions
- md5: the check sum of the dictionnary without this checksum
'''
if context is None:
context = {}
result = {'model': self._name}
test = True
model = True
sql_res = False
inherit_view_id = False
while test:
if view_id:
where = (model and (" and model='%s'" % (self._name,))) or ''
cursor.execute('SELECT arch, field_childs, id, type, ' \
'inherit, model ' \
'FROM ir_ui_view WHERE id = %s ' + where, (view_id,))
else:
cursor.execute('SELECT arch, field_childs, id, type, ' \
'inherit, model ' \
'FROM ir_ui_view ' \
'WHERE model = %s AND type = %s' \
'ORDER BY inherit DESC, priority ASC, id ASC',
(self._name, view_type))
sql_res = cursor.fetchone()
if not sql_res:
break
test = sql_res[4]
if test:
inherit_view_id = sql_res[2]
view_id = test or sql_res[2]
model = False
# if a view was found
if sql_res:
result['type'] = sql_res[3]
result['view_id'] = view_id
result['arch'] = sql_res[0]
result['field_childs'] = sql_res[1] or False
# Check if view is not from an inherited model
if sql_res[5] != self._name:
inherit_obj = self.pool.get(sql_res[5])
result['arch'] = inherit_obj.fields_view_get(cursor, user,
result['view_id'], context=context)['arch']
view_id = inherit_view_id
# get all views which inherit from (ie modify) this view
cursor.execute('SELECT arch, domain, id FROM ir_ui_view ' \
'WHERE (inherit = %s AND model = %s) OR ' \
' (id = %s AND inherit IS NOT NULL) '
'ORDER BY priority ASC, id ASC',
(view_id, self._name, view_id))
sql_inherit = cursor.fetchall()
for (arch, domain, view_id) in sql_inherit:
if domain:
if not eval(domain, {'context': context}):
continue
if not arch or not arch.strip():
continue
result['arch'] = _inherit_apply(result['arch'], arch)
# otherwise, build some kind of default view
else:
if view_type == 'form':
res = self.fields_get(cursor, user, context=context)
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<form string="%s">''' % (self._description,)
for i in res:
if i in ('create_uid', 'create_date',
'write_uid', 'write_date', 'id'):
continue
if res[i]['type'] not in ('one2many', 'many2many'):
xml += '<label name="%s"/>' % (i,)
xml += '<field name="%s"/>' % (i,)
if res[i]['type'] == 'text':
xml += "<newline/>"
xml += "</form>"
elif view_type == 'tree':
field = 'id'
if self._rec_name in self._columns:
field = self._rec_name
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<tree string="%s"><field name="%s"/></tree>''' \
% (self._description, field)
elif view_type == 'calendar':
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<calendar string="%s" date_start="%s">''' \
'''<field name="%s"/></calendar>''' \
% (self._description, self._date_name, self._rec_name)
else:
xml = ''
result['type'] = view_type
result['arch'] = xml
result['field_childs'] = False
result['view_id'] = 0
# Update arch and compute fields from arch
parser = etree.XMLParser(remove_blank_text=True)
tree = etree.fromstring(result['arch'], parser)
xarch, xfields = self._view_look_dom_arch(cursor, user, tree,
result['type'], context=context)
result['arch'] = xarch
result['fields'] = xfields
# Add toolbar
if toolbar:
action_obj = self.pool.get('ir.action.keyword')
prints = action_obj.get_keyword(cursor, user, 'form_print',
(self._name, 0), context=context)
actions = action_obj.get_keyword(cursor, user, 'form_action',
(self._name, 0), context=context)
relates = action_obj.get_keyword(cursor, user, 'form_relate',
(self._name, 0), context=context)
result['toolbar'] = {
'print': prints,
'action': actions,
'relate': relates,
}
# Compute md5
result['md5'] = md5.new(str(result)).hexdigest()
if hexmd5 == result['md5']:
return True
return result
fields_view_get = Cache('orm.fields_view_get')(fields_view_get)
def view_header_get(self, cursor, user, value, view_type='form',
context=None):
"""
Overload this method if you need a window title
which depends on the context
:param cursor: the database cursor
:param user: the user id
:param value: the default header string
:param view_type: the type of the view
:param context: the context
:return: the header string of the view
"""
return value
def _view_look_dom_arch(self, cursor, user, tree, type, context=None):
fields_width = {}
tree_root = tree.getroottree().getroot()
if type == 'tree':
viewtreewidth_obj = self.pool.get('ir.ui.view_tree_width')
viewtreewidth_ids = viewtreewidth_obj.search(cursor, user, [
('model', '=', self._name),
('user', '=', user),
], context=context)
for viewtreewidth in viewtreewidth_obj.browse(cursor, user,
viewtreewidth_ids, context=context):
if viewtreewidth.width > 0:
fields_width[viewtreewidth.field] = viewtreewidth.width
fields_def = self.__view_look_dom(cursor, user, tree_root, type,
fields_width=fields_width, context=context)
for field_name in fields_def.keys():
if field_name in self._columns:
field = self._columns[field_name]
elif field_name in self._inherit_fields:
field = self._inherit_fields[field_name][2]
else:
continue
for depend in field.depends:
fields_def.setdefault(depend, {'name': depend})
if ('active' in self._columns) or ('active' in self._inherit_fields):
fields_def.setdefault('active', {'name': 'active', 'select': "2"})
arch = etree.tostring(tree, encoding='utf-8', pretty_print=False)
fields2 = self.fields_get(cursor, user, fields_def.keys(), context)
for field in fields_def:
if field in fields2:
fields2[field].update(fields_def[field])
return arch, fields2
def __view_look_dom(self, cursor, user, element, type, fields_width=None,
context=None):
translation_obj = self.pool.get('ir.translation')
if fields_width is None:
fields_width = {}
if context is None:
context = {}
result = False
fields_attrs = {}
childs = True
if element.tag in ('field', 'label', 'separator', 'group'):
for attr in ('name', 'icon'):
if element.get(attr):
attrs = {}
try:
if element.get(attr) in self._columns:
relation = self._columns[element.get(attr)]._obj
else:
relation = self._inherit_fields[element.get(attr)][2]._obj
except:
relation = False
if relation and element.tag == 'field':
childs = False
views = {}
for field in element:
if field.tag in ('form', 'tree', 'graph'):
field2 = copy.copy(field)
def _translate_field(field):
if field.get('string'):
trans = translation_obj._get_source(
cursor, self._name, 'view',
context['language'],
field.get('string'))
if trans:
field.set('string', trans)
if field.get('sum'):
trans = translation_obj._get_source(
cursor, self._name, 'view',
context['language'],
field.get('sum'))
if trans:
field.set('sum', trans)
for field_child in field:
_translate_field(field_child)
if 'language' in context:
_translate_field(field2)
relation_obj = self.pool.get(relation)
if hasattr(relation_obj, '_view_look_dom_arch'):
xarch, xfields = \
relation_obj._view_look_dom_arch(
cursor, user,
field2, field.tag,
context=context)
views[field.tag] = {
'arch': xarch,
'fields': xfields
}
element.remove(field)
attrs = {'views': views}
fields_attrs[element.get(attr)] = attrs
if element.get('name') in fields_width:
element.set('width', str(fields_width[element.get('name')]))
# translate view
if ('language' in context) and not result:
for attr in ('string', 'sum', 'confirm', 'help'):
if element.get(attr):
trans = translation_obj._get_source(cursor,
self._name, 'view', context['language'],
element.get(attr))
if trans:
element.set(attr, trans)
# Set header string
if element.tag in ('form', 'tree', 'graph'):
element.set('string', self.view_header_get(cursor, user,
element.get('string') or '', view_type=element.tag,
context=context))
if element.tag == 'tree' and element.get('sequence'):
fields_attrs.setdefault(element.get('sequence'), {})
if childs:
for field in element:
fields_attrs.update(self.__view_look_dom(cursor, user, field,
type, fields_width=fields_width, context=context))
return fields_attrs
+2 -339
View File
@@ -1,15 +1,13 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
# -*- coding: utf-8 -*-
from trytond.model import Model
from trytond.model import ModelView
from trytond.netsvc import LocalService
import fields
from trytond.tools import Cache
import md5
import time
import traceback
import datetime
from lxml import etree
import copy
from trytond.sql_db import table_handler
from decimal import Decimal
@@ -283,7 +281,7 @@ class EvalEnvironment(dict):
def __nonzero__(self):
return bool(self.record)
class ORM(Model):
class ORM(ModelView):
"""
Object relationnal mapping to postgresql module
. Hierarchical structure
@@ -445,7 +443,6 @@ class ORM(Model):
'write',
'create',
'delete',
'fields_view_get',
'search',
'name_get',
'name_search',
@@ -1541,340 +1538,6 @@ class ORM(Model):
wf_service.trg_create(user, self._name, id_new, cursor, context=context)
return id_new
def view_header_get(self, cursor, user, value, view_type='form',
context=None):
"""
Overload this method if you need a window title
which depends on the context
"""
return False
def __view_look_dom(self, cursor, user, element, type, fields_width=None,
context=None):
translation_obj = self.pool.get('ir.translation')
if fields_width is None:
fields_width = {}
if context is None:
context = {}
result = False
fields_attrs = {}
childs = True
if element.tag in ('field', 'label', 'separator', 'group'):
for attr in ('name', 'icon'):
if element.get(attr):
attrs = {}
try:
if element.get(attr) in self._columns:
relation = self._columns[element.get(attr)]._obj
else:
relation = self._inherit_fields[element.get(attr)][2]._obj
except:
relation = False
if relation and element.tag == 'field':
childs = False
views = {}
for field in element:
if field.tag in ('form', 'tree', 'graph'):
field2 = copy.copy(field)
def _translate_field(field):
if field.get('string'):
trans = translation_obj._get_source(
cursor, self._name, 'view',
context['language'],
field.get('string'))
if trans:
field.set('string', trans)
if field.get('sum'):
trans = translation_obj._get_source(
cursor, self._name, 'view',
context['language'],
field.get('sum'))
if trans:
field.set('sum', trans)
for field_child in field:
_translate_field(field_child)
if 'language' in context:
_translate_field(field2)
xarch, xfields = self.pool.get(relation
)._view_look_dom_arch(cursor, user,
field2, field.tag,
context=context)
views[field.tag] = {
'arch': xarch,
'fields': xfields
}
element.remove(field)
attrs = {'views': views}
fields_attrs[element.get(attr)] = attrs
if element.get('name') in fields_width:
element.set('width', str(fields_width[element.get('name')]))
# translate view
if ('language' in context) and not result:
for attr in ('string', 'sum', 'confirm', 'help'):
if element.get(attr):
trans = translation_obj._get_source(cursor,
self._name, 'view', context['language'],
element.get(attr))
if trans:
element.set(attr, trans)
if element.tag in ('form', 'tree', 'graph'):
value = ''
if element.get('string'):
value = element.get('string')
result = self.view_header_get(cursor, user, value, element.tag,
context)
if result:
element.set('string', result)
if element.tag == 'tree' and element.get('sequence'):
fields_attrs.setdefault(element.get('sequence'), {})
if childs:
for field in element:
fields_attrs.update(self.__view_look_dom(cursor, user, field,
type, fields_width=fields_width, context=context))
return fields_attrs
def _view_look_dom_arch(self, cursor, user, tree, type, context=None):
fields_width = {}
tree_root = tree.getroottree().getroot()
if type == 'tree':
viewtreewidth_obj = self.pool.get('ir.ui.view_tree_width')
viewtreewidth_ids = viewtreewidth_obj.search(cursor, user, [
('model', '=', self._name),
('user', '=', user),
], context=context)
for viewtreewidth in viewtreewidth_obj.browse(cursor, user,
viewtreewidth_ids, context=context):
if viewtreewidth.width > 0:
fields_width[viewtreewidth.field] = viewtreewidth.width
fields_def = self.__view_look_dom(cursor, user, tree_root, type,
fields_width=fields_width, context=context)
for field_name in fields_def.keys():
if field_name in self._columns:
field = self._columns[field_name]
elif field_name in self._inherit_fields:
field = self._inherit_fields[field_name][2]
else:
continue
for depend in field.depends:
fields_def.setdefault(depend, {'name': depend})
if ('active' in self._columns) or ('active' in self._inherit_fields):
fields_def.setdefault('active', {'name': 'active', 'select': "2"})
arch = etree.tostring(tree, encoding='utf-8', pretty_print=False)
fields2 = self.fields_get(cursor, user, fields_def.keys(), context)
for field in fields_def:
if field in fields2:
fields2[field].update(fields_def[field])
return arch, fields2
def fields_view_get(self, cursor, user, view_id=None, view_type='form',
context=None, toolbar=False, hexmd5=None):
'''
Return a dict with keys:
- arch: the xml description of the view.
- fields: a dict with the definition of each fields.
- toolbar: if toolbar is True, a dict with 'print', 'action', 'relate'
keyword action defintion for the view.
- md5: the check sum of the above dict that will be used for caching.
view_id can specify the id of the view, if empty the system
will select the first view
view_type specify the type of the view if view_id is empty
If hexmd5 is fill, the function will return True if the view have the same
md5 or the dict.
'''
if context is None:
context = {}
def _inherit_apply(src, inherit):
def _find(tree, element):
if element.tag == 'xpath':
res = tree.xpath(element.get('expr'))
if res:
return res[0]
return None
tree_src = etree.fromstring(src)
tree_inherit = etree.fromstring(inherit)
root_inherit = tree_inherit.getroottree().getroot()
for element2 in root_inherit:
element = _find(tree_src, element2)
if element is not None:
pos = element2.get('position', 'inside')
if pos == 'replace':
parent = element.getparent()
next = element.getnext()
if next is not None:
for child in element2:
index = parent.index(next)
parent.insert(index, child)
else:
parent.extend(element2.getchildren())
parent.remove(element)
elif pos == 'replace_attributes':
child = element2.getchildren()[0]
for attr in child.attrib:
element.set(attr, child.get(attr))
elif pos == 'inside':
element.extend(element2.getchildren())
elif pos == 'after':
parent = element.getparent()
next = element.getnext()
if next is not None:
for child in element2:
index = parent.index(next)
parent.insert(index, child)
else:
parent.extend(element2.getchildren())
elif pos == 'before':
parent = element.getparent()
for child in element2:
index = parent.index(element)
parent.insert(index, child)
else:
raise AttributeError('Unknown position ' \
'in inherited view %s!' % pos)
else:
raise AttributeError(
'Couldn\'t find tag (%s: %s) in parent view!' % \
(element2.tag, element2.get('expr')))
return etree.tostring(tree_src, encoding='utf-8')
result = {'type': view_type, 'model': self._name}
test = True
model = True
sql_res = False
inherit_view_id = False
while test:
if view_id:
where = (model and (" and model='%s'" % (self._name,))) or ''
cursor.execute('SELECT arch, field_childs, id, type, ' \
'inherit, model ' \
'FROM ir_ui_view WHERE id = %s ' + where, (view_id,))
else:
cursor.execute('SELECT arch, field_childs, id, type, ' \
'inherit, model ' \
'FROM ir_ui_view ' \
'WHERE model = %s AND type = %s' \
'ORDER BY inherit DESC, priority ASC, id ASC',
(self._name, view_type))
sql_res = cursor.fetchone()
if not sql_res:
break
test = sql_res[4]
if test:
inherit_view_id = sql_res[2]
view_id = test or sql_res[2]
model = False
# if a view was found
if sql_res:
result['type'] = sql_res[3]
result['view_id'] = view_id
result['arch'] = sql_res[0]
if sql_res[5] != self._name:
inherit_obj = self.pool.get(sql_res[5])
result['arch'] = inherit_obj.fields_view_get(cursor, user,
result['view_id'], context=context)['arch']
view_id = inherit_view_id
def _inherit_apply_rec(result, inherit_id):
# get all views which inherit from (ie modify) this view
cursor.execute('SELECT arch, domain, id FROM ir_ui_view ' \
'WHERE (inherit = %s AND model = %s) OR ' \
' (id = %s AND inherit IS NOT NULL) '
'ORDER BY priority ASC, id ASC',
(inherit_id, self._name, inherit_id))
sql_inherit = cursor.fetchall()
for (arch, domain, view_id) in sql_inherit:
if domain:
if not eval(domain, {'context': context}):
continue
if not arch or not arch.strip():
continue
result = _inherit_apply(result, arch)
#result = _inherit_apply_rec(result, view_id)
return result
result['arch'] = _inherit_apply_rec(result['arch'], view_id)
result['field_childs'] = sql_res[1] or False
# otherwise, build some kind of default view
else:
if view_type == 'form':
res = self.fields_get(cursor, user, context=context)
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<form string="%s">''' % (self._description,)
for i in res:
if i in ('create_uid', 'create_date',
'write_uid', 'write_date', 'id'):
continue
if res[i]['type'] not in ('one2many', 'many2many'):
xml += '<label name="%s"/>' % (i,)
xml += '<field name="%s"/>' % (i,)
if res[i]['type'] == 'text':
xml += "<newline/>"
xml += "</form>"
elif view_type == 'tree':
field = 'id'
if self._rec_name in self._columns:
field = self._rec_name
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<tree string="%s"><field name="%s"/></tree>''' \
% (self._description, field)
elif view_type == 'calendar':
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<calendar string="%s" date_start="%s">''' \
'''<field name="%s"/></calendar>''' \
% (self._description, self._date_name, self._rec_name)
else:
xml = ''
result['type'] = view_type
result['arch'] = xml
result['field_childs'] = False
result['view_id'] = 0
parser = etree.XMLParser(remove_blank_text=True)
tree = etree.fromstring(result['arch'], parser)
xarch, xfields = self._view_look_dom_arch(cursor, user, tree,
result['type'], context=context)
result['arch'] = xarch
result['fields'] = xfields
if toolbar:
action_obj = self.pool.get('ir.action.keyword')
prints = action_obj.get_keyword(cursor, user, 'form_print',
(self._name, 0), context=context)
actions = action_obj.get_keyword(cursor, user, 'form_action',
(self._name, 0), context=context)
relates = action_obj.get_keyword(cursor, user, 'form_relate',
(self._name, 0), context=context)
result['toolbar'] = {
'print': prints,
'action': actions,
'relate': relates,
}
result['md5'] = md5.new(str(result)).hexdigest()
if hexmd5 == result['md5']:
return True
return result
fields_view_get = Cache('orm.fields_view_get')(fields_view_get)
def _where_calc(self, cursor, user, args, active_test=True, context=None):
if context is None:
context = {}