#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 lxml import etree try: import hashlib except ImportError: hashlib = None import md5 import copy from trytond.model import Model from trytond.tools import safe_eval from trytond.pyson import PYSONEncoder, CONTEXT from trytond.transaction import Transaction from trytond.cache import Cache 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: if element2.tag != 'xpath': continue element = _find(tree_src, element2) if element is not None: pos = element2.get('position', 'inside') if pos == 'replace': parent = element.getparent() enext = element.getnext() if enext is not None: for child in element2: index = parent.index(enext) 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() enext = element.getnext() if enext is not None: for child in element2: index = parent.index(enext) 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. """ __modules_list = None # Cache for the modules list sorted by dependency @staticmethod def _reset_modules_list(): ModelView.__modules_list = None def _get_modules_list(self): from trytond.modules import create_graph, get_module_list if ModelView.__modules_list: return ModelView.__modules_list graph = create_graph(get_module_list())[0] ModelView.__modules_list = [x.name for x in graph] + [None] return ModelView.__modules_list _modules_list = property(fget=_get_modules_list) def __init__(self): super(ModelView, self).__init__() self._rpc['fields_view_get'] = False @Cache('modelview.fields_view_get') def fields_view_get(self, view_id=None, view_type='form', toolbar=False, hexmd5=None): ''' Return a view definition. :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 toolbar: if True the result will contain a toolbar key with keyword action definitions for the view :param hexmd5: if filled, the function will return True if the result has the same md5 :return: a dictionary with keys: - model: the model name - arch: the xml description of the view - fields: a dictionary with the definition of each field in the view - toolbar: a dictionary with the keyword action definitions - md5: the check sum of the dictionary without this checksum ''' result = {'model': self._name} test = True model = True sql_res = False inherit_view_id = False cursor = Transaction().cursor 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( result['view_id'])['arch'] view_id = inherit_view_id # get all views which inherit from (ie modify) this view cursor.execute('SELECT arch, domain, module 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() raise_p = False while True: try: sql_inherit.sort(lambda x, y: \ cmp(self._modules_list.index(x[2] or None), self._modules_list.index(y[2] or None))) break except ValueError: if raise_p: raise # There is perhaps a new module in the directory ModelView._reset_modules_list() raise_p = True for arch, domain, _ in sql_inherit: if domain: if not safe_eval(domain, {'context': Transaction().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() xml = '''''' \ '''
''' % (self._description,) for i in res: if i in ('create_uid', 'create_date', 'write_uid', 'write_date', 'id', 'rec_name'): continue if res[i]['type'] not in ('one2many', 'many2many'): xml += '