untangle inheritance and postprocessing
bzr revid: al@openerp.com-20130629213516-pqcl6oz1g3o5tpgn
This commit is contained in:
parent
ca98a61a3d
commit
932efea388
|
@ -57,19 +57,6 @@ class view_custom(osv.osv):
|
||||||
class view(osv.osv):
|
class view(osv.osv):
|
||||||
_name = 'ir.ui.view'
|
_name = 'ir.ui.view'
|
||||||
|
|
||||||
class NoViewError(Exception): pass
|
|
||||||
class NoDefaultError(NoViewError): pass
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def _arch_get(self, cr, uid, ids, name, arg, context=None):
|
def _arch_get(self, cr, uid, ids, name, arg, context=None):
|
||||||
"""
|
"""
|
||||||
For each id being read, return arch_db or the content of arch_file
|
For each id being read, return arch_db or the content of arch_file
|
||||||
|
@ -130,17 +117,6 @@ class view(osv.osv):
|
||||||
# Holds the RNG schema
|
# Holds the RNG schema
|
||||||
_relaxng_validator = None
|
_relaxng_validator = None
|
||||||
|
|
||||||
def create(self, cr, uid, values, context=None):
|
|
||||||
if 'type' not in values:
|
|
||||||
if values.get('inherit_id'):
|
|
||||||
values['type'] = self.browse(cr, uid, values['inherit_id'], context).type
|
|
||||||
else:
|
|
||||||
values['type'] = etree.fromstring(values['arch']).tag
|
|
||||||
|
|
||||||
if not values.get('name'):
|
|
||||||
values['name'] = "%s %s" % (values['model'], values['type'])
|
|
||||||
return super(view, self).create(cr, uid, values, context)
|
|
||||||
|
|
||||||
def _relaxng(self):
|
def _relaxng(self):
|
||||||
if not self._relaxng_validator:
|
if not self._relaxng_validator:
|
||||||
frng = tools.file_open(os.path.join('base','rng','view.rng'))
|
frng = tools.file_open(os.path.join('base','rng','view.rng'))
|
||||||
|
@ -157,7 +133,7 @@ class view(osv.osv):
|
||||||
for view in self.browse(cr, uid, ids, context):
|
for view in self.browse(cr, uid, ids, context):
|
||||||
# Sanity check: the view should not break anything upon rendering!
|
# Sanity check: the view should not break anything upon rendering!
|
||||||
try:
|
try:
|
||||||
fvg = self.read_combined(cr, uid, view.id, view.type, view.model, context=context)
|
fvg = self.read_combined(cr, uid, view.id, None, context=context)
|
||||||
view_arch_utf8 = fvg['arch']
|
view_arch_utf8 = fvg['arch']
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
_logger.exception(e)
|
_logger.exception(e)
|
||||||
|
@ -179,15 +155,8 @@ class view(osv.osv):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _check_model(self, cr, uid, ids, context=None):
|
|
||||||
for view in self.browse(cr, uid, ids, context):
|
|
||||||
if view.model and view.model not in self.pool:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
_constraints = [
|
_constraints = [
|
||||||
(_check_xml, 'Invalid XML for View Architecture!', ['arch'])
|
(_check_xml, 'Invalid XML for View Architecture!', ['arch'])
|
||||||
#(_check_model, 'The model name does not exist.', ['model']),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def _auto_init(self, cr, context=None):
|
def _auto_init(self, cr, context=None):
|
||||||
|
@ -196,107 +165,85 @@ class view(osv.osv):
|
||||||
if not cr.fetchone():
|
if not cr.fetchone():
|
||||||
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)')
|
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)')
|
||||||
|
|
||||||
def read_combined(self, cr, uid, view_id, view_type, model,
|
def create(self, cr, uid, values, context=None):
|
||||||
fields=None, fallback=None, context=None):
|
if 'type' not in values:
|
||||||
|
if values.get('inherit_id'):
|
||||||
|
values['type'] = self.browse(cr, uid, values['inherit_id'], context).type
|
||||||
|
else:
|
||||||
|
values['type'] = etree.fromstring(values['arch']).tag
|
||||||
|
|
||||||
|
if not values.get('name'):
|
||||||
|
values['name'] = "%s %s" % (values['model'], values['type'])
|
||||||
|
return super(view, self).create(cr, uid, values, context)
|
||||||
|
|
||||||
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
|
if not isinstance(ids, (list, tuple)):
|
||||||
|
ids = [ids]
|
||||||
|
|
||||||
|
# drop the corresponding view customizations (used for dashboards for example), otherwise
|
||||||
|
# not all users would see the updated views
|
||||||
|
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
|
||||||
|
if custom_view_ids:
|
||||||
|
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
||||||
|
|
||||||
|
return super(view, self).write(cr, uid, ids, vals, context)
|
||||||
|
|
||||||
|
# default view selection
|
||||||
|
|
||||||
|
def default_view(self, cr, uid, model, view_type, context=None):
|
||||||
|
""" Fetches the default view for the provided (model, view_type) pair:
|
||||||
|
view with no parent (inherit_id=Fase) with the lowest priority.
|
||||||
|
|
||||||
|
:param str model:
|
||||||
|
:param int view_type:
|
||||||
|
:return: id of the default view of False if none found
|
||||||
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
Utility function stringing together all method calls necessary to get
|
ids = self.search(cr, uid, [
|
||||||
a full, final view:
|
['model', '=', model],
|
||||||
|
['type', '=', view_type],
|
||||||
|
['inherit_id', '=', False],
|
||||||
|
], limit=1, order='priority', context=context)
|
||||||
|
if not ids:
|
||||||
|
return False
|
||||||
|
return ids[0]
|
||||||
|
|
||||||
* Gets the default view if no view_id is provided
|
# inheritance
|
||||||
* Gets the top of the view tree if a sub-view is requested
|
|
||||||
* Applies all inherited archs on the root view
|
|
||||||
* Applies post-processing
|
|
||||||
* Returns the view with all requested fields
|
|
||||||
|
|
||||||
.. note:: ``arch`` is always added to the fields list even if not
|
def get_inheriting_views_arch(self, cr, uid, view_id, context=None):
|
||||||
requested (similar to ``id``)
|
"""Retrieves the architecture of views that inherit from the given view, from the sets of
|
||||||
|
views that should currently be used in the system. During the module upgrade phase it
|
||||||
|
may happen that a view is present in the database but the fields it relies on are not
|
||||||
|
fully loaded yet. This method only considers views that belong to modules whose code
|
||||||
|
is already loaded. Custom views defined directly in the database are loaded only
|
||||||
|
after the module initialization phase is completely finished.
|
||||||
|
|
||||||
If no view is available (no view_id or invalid view_id provided, or
|
:param int view_id: id of the view whose inheriting views should be retrieved
|
||||||
no view stored for (model, view_type)) a view record will be fetched
|
:param str model: model identifier of the view's related model (for double-checking)
|
||||||
from the ``defaults`` mapping?
|
:rtype: list of tuples
|
||||||
|
:return: [(view_arch,view_id), ...]
|
||||||
:param fallback: a mapping of {view_type: view_dict}, if no view can
|
|
||||||
be found (read) will be used to provide a default
|
|
||||||
before post-processing
|
|
||||||
:type fallback: mapping
|
|
||||||
"""
|
"""
|
||||||
if context is None: context = {}
|
user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
|
||||||
|
|
||||||
def clean_anotations(arch, parent_info=None):
|
conditions = [['inherit_id', '=', view_id]]
|
||||||
for child in arch:
|
if self.pool._init:
|
||||||
if child.tag == 't' or child.tag == 'field':
|
# Module init currently in progress, only consider views from
|
||||||
# can not anote t and field while cleaning
|
# modules whose code is already loaded
|
||||||
continue
|
conditions.extend([
|
||||||
|
['model_ids.model', '=', 'ir.ui.view'],
|
||||||
|
['model_ids.module', 'in', tuple(self.pool._init_modules)],
|
||||||
|
])
|
||||||
|
view_ids = self.search(cr, uid, conditions, context=context)
|
||||||
|
|
||||||
child_text = "".join([etree.tostring(x) for x in child])
|
# filter views based on user groups
|
||||||
if child.attrib.get('data-edit-model'):
|
return [(view.arch, view.id)
|
||||||
if child_text.find('data-edit-model') != -1 or child_text.find('<t ') != -1:
|
for view in self.browse(cr, 1, view_ids, context)
|
||||||
# enclosed tag, move present tag to childs
|
if not (view.groups_id and user_groups.isdisjoint(view.groups_id))]
|
||||||
parent_info = {
|
|
||||||
'model': child.attrib.get('data-edit-model'),
|
|
||||||
'view_id': child.attrib.get('data-edit-view-id'),
|
|
||||||
'xpath': child.attrib.get('data-edit-xpath')+'/'+child.tag,
|
|
||||||
}
|
|
||||||
child.attrib.pop('data-edit-model')
|
|
||||||
child.attrib.pop('data-edit-view-id')
|
|
||||||
child.attrib.pop('data-edit-xpath')
|
|
||||||
child = clean_anotations(child, parent_info)
|
|
||||||
else:
|
|
||||||
# tagged node, no enclosed, can keep, don't care if had parent_info
|
|
||||||
continue
|
|
||||||
|
|
||||||
else:
|
def raise_view_error(self, cr, uid, view_id, message, context=None):
|
||||||
if child_text.find('data-edit-model') != -1 or child_text.find('<t ') != -1:
|
view = self.browse(cr, uid, [view_id], context)
|
||||||
# has other nodes to clean
|
message = "Inherit error: %s view_id: %s, xml_id: %s, model: %s, parent_view: %s" % (message, view_id, view.xml_id, view.model, view.inherit_id)
|
||||||
if parent_info:
|
raise AttributeError(message)
|
||||||
# update xpath
|
|
||||||
parent_info.update({'xpath': parent_info.get('xpath')+'/'+child.tag})
|
|
||||||
child = clean_anotations(child, parent_info)
|
|
||||||
elif parent_info:
|
|
||||||
# put tag from parent, no enclose, higher
|
|
||||||
child.attrib.update({
|
|
||||||
'data-edit-model': parent_info.get('model'),
|
|
||||||
'data-edit-view-id': parent_info.get('view_id'),
|
|
||||||
'data-edit-xpath': parent_info.get('xpath'),
|
|
||||||
})
|
|
||||||
|
|
||||||
return arch
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not view_id:
|
|
||||||
view_id = self.default_view(cr, uid, model, view_type, context=context)
|
|
||||||
root_id = self.root_ancestor(cr, uid, view_id, context=context)
|
|
||||||
|
|
||||||
if fields:
|
|
||||||
needed_fields = ['arch', 'model']
|
|
||||||
fields = list(itertools.chain(
|
|
||||||
[field for field in needed_fields if field not in fields],
|
|
||||||
fields))
|
|
||||||
|
|
||||||
[view] = self.read(cr, uid, [root_id], fields=fields, context=context)
|
|
||||||
|
|
||||||
arch_tree = etree.fromstring(
|
|
||||||
view['arch'].encode('utf-8') if isinstance(view['arch'], unicode)
|
|
||||||
else view['arch'])
|
|
||||||
|
|
||||||
descendants = self.iter(
|
|
||||||
cr, uid, view['id'], model, exclude_base=True, context=context)
|
|
||||||
arch = self.apply_inherited_archs(
|
|
||||||
cr, uid, arch_tree, descendants,
|
|
||||||
model, view['id'], context=context)
|
|
||||||
arch = self.add_root_tags(arch, model, view['id'])
|
|
||||||
|
|
||||||
except self.NoViewError:
|
|
||||||
# defaultdict is "empty" until first __getattr__
|
|
||||||
if fallback is None: raise
|
|
||||||
view = fallback[view_type]
|
|
||||||
arch = view['arch']
|
|
||||||
if isinstance(arch, basestring):
|
|
||||||
arch = etree.fromstring(
|
|
||||||
arch.encode('utf-8') if isinstance(arch, unicode) else arch)
|
|
||||||
|
|
||||||
arch = clean_anotations(arch)
|
|
||||||
return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
|
|
||||||
|
|
||||||
def locate_node(self, arch, spec):
|
def locate_node(self, arch, spec):
|
||||||
""" Locate a node in a source (parent) architecture.
|
""" Locate a node in a source (parent) architecture.
|
||||||
|
@ -335,144 +282,7 @@ class view(osv.osv):
|
||||||
return node
|
return node
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None):
|
def apply_inheritance_specs(self, cr, uid, source, specs_arch, inherit_id, context=None):
|
||||||
"""Retrieves the architecture of views that inherit from the given view, from the sets of
|
|
||||||
views that should currently be used in the system. During the module upgrade phase it
|
|
||||||
may happen that a view is present in the database but the fields it relies on are not
|
|
||||||
fully loaded yet. This method only considers views that belong to modules whose code
|
|
||||||
is already loaded. Custom views defined directly in the database are loaded only
|
|
||||||
after the module initialization phase is completely finished.
|
|
||||||
|
|
||||||
:param int view_id: id of the view whose inheriting views should be retrieved
|
|
||||||
:param str model: model identifier of the view's related model (for double-checking)
|
|
||||||
:rtype: list of tuples
|
|
||||||
:return: [(view_arch,view_id), ...]
|
|
||||||
"""
|
|
||||||
user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
|
|
||||||
|
|
||||||
conditions = [['inherit_id', '=', view_id], ['model', '=', model]]
|
|
||||||
if self.pool._init:
|
|
||||||
# Module init currently in progress, only consider views from
|
|
||||||
# modules whose code is already loaded
|
|
||||||
conditions.extend([
|
|
||||||
['model_ids.model', '=', 'ir.ui.view'],
|
|
||||||
['model_ids.module', 'in', tuple(self.pool._init_modules)],
|
|
||||||
])
|
|
||||||
view_ids = self.search(cr, uid, conditions, context=context)
|
|
||||||
|
|
||||||
# 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 add_root_tags(self, arch_tree, model, view_id):
|
|
||||||
for child in arch_tree:
|
|
||||||
if child.tag == 'data' or child.tag == 'xpath':
|
|
||||||
child = self.add_root_tags(child, model, view_id)
|
|
||||||
else:
|
|
||||||
child.attrib.update({
|
|
||||||
'data-edit-model': model or 'undefined',
|
|
||||||
'data-edit-view-id': str(view_id),
|
|
||||||
'data-edit-xpath': '/'
|
|
||||||
})
|
|
||||||
return arch_tree
|
|
||||||
|
|
||||||
def iter(self, cr, uid, view_id, model, exclude_base=False, context=None):
|
|
||||||
""" iterates on all of ``view_id``'s descendants tree depth-first.
|
|
||||||
|
|
||||||
If ``exclude_base`` is ``False``, also yields ``view_id`` itself. It is
|
|
||||||
``False`` by default to match the behavior of etree's Element.iter.
|
|
||||||
|
|
||||||
:param int view_id: database id of the root view
|
|
||||||
:param str model: name of the view's related model (for filtering)
|
|
||||||
:param bool exclude_base: whether ``view_id`` should be excluded
|
|
||||||
from the iteration
|
|
||||||
:return: iterator of (database_id, arch_string) pairs for all
|
|
||||||
descendants of ``view_id`` (including ``view_id`` itself if
|
|
||||||
``exclude_base`` is ``False``, the default)
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not exclude_base:
|
|
||||||
base = self.browse(cr, uid, view_id, context=context)
|
|
||||||
# should we do add_root_tags this one as well ?
|
|
||||||
yield base.id, base.arch
|
|
||||||
|
|
||||||
for arch, id in self.get_inheriting_views_arch(
|
|
||||||
cr, uid, view_id, model, context=context):
|
|
||||||
arch = self.add_root_tags(etree.fromstring(arch), model, view_id)
|
|
||||||
yield id, etree.tostring(arch)
|
|
||||||
for info in self.iter(
|
|
||||||
cr, uid, id, model, exclude_base=True, context=None):
|
|
||||||
yield info
|
|
||||||
|
|
||||||
def default_view(self, cr, uid, model, view_type, context=None):
|
|
||||||
""" Fetches the default view for the provided (model, view_type) pair:
|
|
||||||
view with no parent (inherit_id=Fase) with the lowest priority.
|
|
||||||
|
|
||||||
:param str model:
|
|
||||||
:param int view_type:
|
|
||||||
:return: id of the default view for the (model, view_type) pair
|
|
||||||
:rtype: int
|
|
||||||
"""
|
|
||||||
ids = self.search(cr, uid, [
|
|
||||||
['model', '=', model],
|
|
||||||
['type', '=', view_type],
|
|
||||||
['inherit_id', '=', False],
|
|
||||||
], limit=1, order='priority', context=context)
|
|
||||||
if not ids:
|
|
||||||
raise self.NoDefaultError(
|
|
||||||
_("No default view of type %s for model %s") % (
|
|
||||||
view_type, model))
|
|
||||||
return ids[0]
|
|
||||||
|
|
||||||
def root_ancestor(self, cr, uid, view_id, context=None):
|
|
||||||
"""
|
|
||||||
Fetches the id of the root of the view tree of which view_id is part
|
|
||||||
|
|
||||||
If view_id is specified, view_type and model aren't needed (and the
|
|
||||||
other way around)
|
|
||||||
|
|
||||||
:param view_id: id of view to search the root ancestor of
|
|
||||||
:return: id of the root view for the tree
|
|
||||||
"""
|
|
||||||
view = self.browse(cr, uid, view_id, context=context)
|
|
||||||
if not view.exists():
|
|
||||||
raise self.NoViewError(
|
|
||||||
_("No view for id %s, root ancestor not available") % view_id)
|
|
||||||
|
|
||||||
# Search for a root (i.e. without any parent) view.
|
|
||||||
while view.inherit_id:
|
|
||||||
view = view.inherit_id
|
|
||||||
|
|
||||||
return view.id
|
|
||||||
|
|
||||||
def apply_inherited_archs(self, cr, uid, source, descendants,
|
|
||||||
model, source_view_id, context=None):
|
|
||||||
""" Applies descendants to the ``source`` view, returns the result of
|
|
||||||
the application.
|
|
||||||
|
|
||||||
:param Element source: source arch to apply descendant on
|
|
||||||
:param descendants: iterable of (id, arch_string) pairs of all
|
|
||||||
descendants in the view tree, depth-first,
|
|
||||||
excluding the base view
|
|
||||||
:type descendants: iter((int, str))
|
|
||||||
:return: new architecture etree produced by applying all descendants
|
|
||||||
on ``source``
|
|
||||||
:rtype: Element
|
|
||||||
"""
|
|
||||||
return reduce(
|
|
||||||
lambda current_arch, descendant: self.apply_inheritance_specs(
|
|
||||||
cr, uid, model, source_view_id, current_arch,
|
|
||||||
*descendant, context=context),
|
|
||||||
descendants, source)
|
|
||||||
|
|
||||||
def raise_view_error(self, cr, uid, model, error_msg, view_id, child_view_id, context=None):
|
|
||||||
view, child_view = self.browse(cr, uid, [view_id, child_view_id], context)
|
|
||||||
error_msg = error_msg % {'parent_xml_id': view.xml_id}
|
|
||||||
raise AttributeError("View definition error for inherited view '%s' on model '%s': %s"
|
|
||||||
% (child_view.xml_id, model, error_msg))
|
|
||||||
|
|
||||||
def apply_inheritance_specs(self, cr, uid, model, root_view_id, source, descendant_id, specs_arch, context=None):
|
|
||||||
""" Apply an inheriting view (a descendant of the base view)
|
""" Apply an inheriting view (a descendant of the base view)
|
||||||
|
|
||||||
Apply to a source architecture all the spec nodes (i.e. nodes
|
Apply to a source architecture all the spec nodes (i.e. nodes
|
||||||
|
@ -530,7 +340,7 @@ class view(osv.osv):
|
||||||
elif pos == 'before':
|
elif pos == 'before':
|
||||||
node.addprevious(child)
|
node.addprevious(child)
|
||||||
else:
|
else:
|
||||||
self.raise_view_error(cr, uid, model, "Invalid position value: '%s'" % pos, root_view_id, descendant_id, context=context)
|
self.raise_view_error(cr, uid, "Invalid position value: '%s'" % pos, inherit_id, context=context)
|
||||||
else:
|
else:
|
||||||
attrs = ''.join([
|
attrs = ''.join([
|
||||||
' %s="%s"' % (attr, spec.get(attr))
|
' %s="%s"' % (attr, spec.get(attr))
|
||||||
|
@ -538,94 +348,69 @@ class view(osv.osv):
|
||||||
if attr != 'position'
|
if attr != 'position'
|
||||||
])
|
])
|
||||||
tag = "<%s%s>" % (spec.tag, attrs)
|
tag = "<%s%s>" % (spec.tag, attrs)
|
||||||
if spec.get('version') and spec.get('version') != source.get('version'):
|
self.raise_view_error(cr, uid, "Element '%s' not found in parent view " % tag, inherit_id, context=context)
|
||||||
self.raise_view_error(cr, uid, model, "Mismatching view API version for element '%s': %r vs %r in parent view '%%(parent_xml_id)s'" % \
|
|
||||||
(tag, spec.get('version'), source.get('version')), root_view_id, descendant_id, context=context)
|
|
||||||
self.raise_view_error(cr, uid, model, "Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, root_view_id, descendant_id, context=context)
|
|
||||||
|
|
||||||
return source
|
return source
|
||||||
|
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def add_root_tags(self, arch_tree, model, view_id):
|
||||||
if not isinstance(ids, (list, tuple)):
|
for child in arch_tree:
|
||||||
ids = [ids]
|
if child.tag == 'data' or child.tag == 'xpath':
|
||||||
|
child = self.add_root_tags(child, model, view_id)
|
||||||
# drop the corresponding view customizations (used for dashboards for example), otherwise
|
|
||||||
# not all users would see the updated views
|
|
||||||
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
|
|
||||||
if custom_view_ids:
|
|
||||||
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
|
||||||
|
|
||||||
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=[]
|
|
||||||
nodes_name=[]
|
|
||||||
transitions=[]
|
|
||||||
start=[]
|
|
||||||
tres={}
|
|
||||||
labels={}
|
|
||||||
no_ancester=[]
|
|
||||||
blank_nodes = []
|
|
||||||
|
|
||||||
_Model_Obj = self.pool[model]
|
|
||||||
_Node_Obj = self.pool[node_obj]
|
|
||||||
_Arrow_Obj = self.pool[conn_obj]
|
|
||||||
|
|
||||||
for model_key,model_value in _Model_Obj._columns.items():
|
|
||||||
if model_value._type=='one2many':
|
|
||||||
if model_value._obj==node_obj:
|
|
||||||
_Node_Field=model_key
|
|
||||||
_Model_Field=model_value._fields_id
|
|
||||||
flag=False
|
|
||||||
for node_key,node_value in _Node_Obj._columns.items():
|
|
||||||
if node_value._type=='one2many':
|
|
||||||
if node_value._obj==conn_obj:
|
|
||||||
if src_node in _Arrow_Obj._columns and flag:
|
|
||||||
_Source_Field=node_key
|
|
||||||
if des_node in _Arrow_Obj._columns and not flag:
|
|
||||||
_Destination_Field=node_key
|
|
||||||
flag = True
|
|
||||||
|
|
||||||
datas = _Model_Obj.read(cr, uid, id, [],context)
|
|
||||||
for a in _Node_Obj.read(cr,uid,datas[_Node_Field],[]):
|
|
||||||
if a[_Source_Field] or a[_Destination_Field]:
|
|
||||||
nodes_name.append((a['id'],a['name']))
|
|
||||||
nodes.append(a['id'])
|
|
||||||
else:
|
else:
|
||||||
blank_nodes.append({'id': a['id'],'name':a['name']})
|
child.attrib.update({
|
||||||
|
'data-edit-model': model or 'undefined',
|
||||||
|
'data-edit-view-id': str(view_id),
|
||||||
|
'data-edit-xpath': '/'
|
||||||
|
})
|
||||||
|
return arch_tree
|
||||||
|
|
||||||
if a.has_key('flow_start') and a['flow_start']:
|
def apply_view_inheritance(self, cr, uid, source, inherit_id, context=None):
|
||||||
start.append(a['id'])
|
""" Apply all the (directly and indirectly) inheriting views.
|
||||||
else:
|
|
||||||
if not a[_Source_Field]:
|
|
||||||
no_ancester.append(a['id'])
|
|
||||||
for t in _Arrow_Obj.read(cr,uid, a[_Destination_Field],[]):
|
|
||||||
transitions.append((a['id'], t[des_node][0]))
|
|
||||||
tres[str(t['id'])] = (a['id'],t[des_node][0])
|
|
||||||
label_string = ""
|
|
||||||
if label:
|
|
||||||
for lbl in eval(label):
|
|
||||||
if t.has_key(tools.ustr(lbl)) and tools.ustr(t[lbl])=='False':
|
|
||||||
label_string += ' '
|
|
||||||
else:
|
|
||||||
label_string = label_string + " " + tools.ustr(t[lbl])
|
|
||||||
labels[str(t['id'])] = (a['id'],label_string)
|
|
||||||
g = graph(nodes, transitions, no_ancester)
|
|
||||||
g.process(start)
|
|
||||||
g.scale(*scale)
|
|
||||||
result = g.result_get()
|
|
||||||
results = {}
|
|
||||||
for node in nodes_name:
|
|
||||||
results[str(node[0])] = result[node[0]]
|
|
||||||
results[str(node[0])]['name'] = node[1]
|
|
||||||
return {'nodes': results,
|
|
||||||
'transitions': tres,
|
|
||||||
'label' : labels,
|
|
||||||
'blank_nodes': blank_nodes,
|
|
||||||
'node_parent_field': _Model_Field,}
|
|
||||||
|
|
||||||
# this really needs to be refixtored
|
:param source: a parent architecture to modify (with parent modifications already applied)
|
||||||
def __view_look_dom(self, cr, user, model, node, view_id, in_tree_view, model_fields, context=None):
|
:param inherit_id: the database view_id of the parent view
|
||||||
|
:return: a modified source where all the modifying architecture are applied
|
||||||
|
"""
|
||||||
|
sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, uid, inherit_id)
|
||||||
|
for (view_arch, view_id) in sql_inherit:
|
||||||
|
source = self.apply_inheritance_specs(cr, uid, source, view_arch, view_id, context=context)
|
||||||
|
source = self.apply_view_inheritance(cr, uid, source, view_id, context=context)
|
||||||
|
return source
|
||||||
|
|
||||||
|
def read_combined(self, cr, uid, view_id, fields=None, context=None):
|
||||||
|
"""
|
||||||
|
Utility function to get a view combined with its inherited views.
|
||||||
|
|
||||||
|
* Gets the top of the view tree if a sub-view is requested
|
||||||
|
* Applies all inherited archs on the root view
|
||||||
|
* Returns the view with all requested fields
|
||||||
|
.. note:: ``arch`` is always added to the fields list even if not
|
||||||
|
requested (similar to ``id``)
|
||||||
|
"""
|
||||||
|
if context is None: context = {}
|
||||||
|
|
||||||
|
# if view_id is not a root view, climb back to the top.
|
||||||
|
v = self.browse(cr, uid, view_id, context=context)
|
||||||
|
while v.inherit_id:
|
||||||
|
v = v.inherit_id
|
||||||
|
root_id = v.id
|
||||||
|
|
||||||
|
# arch and model fields are always returned
|
||||||
|
if fields:
|
||||||
|
fields = list(set(fields) | set(['arch', 'model']))
|
||||||
|
|
||||||
|
# read the view arch
|
||||||
|
[view] = self.read(cr, uid, [root_id], fields=fields, context=context)
|
||||||
|
arch_tree = etree.fromstring( view['arch'].encode('utf-8') if isinstance(view['arch'], unicode) else view['arch'])
|
||||||
|
|
||||||
|
# and apply inheritance
|
||||||
|
arch = self.apply_view_inheritance(cr, uid, arch_tree, root_id, context=context)
|
||||||
|
|
||||||
|
return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
|
||||||
|
|
||||||
|
# post processing
|
||||||
|
|
||||||
|
def postprocess(self, cr, user, model, node, view_id, in_tree_view, model_fields, context=None):
|
||||||
"""Return the description of the fields in the node.
|
"""Return the description of the fields in the node.
|
||||||
|
|
||||||
In a normal call to this method, node is a complete view architecture
|
In a normal call to this method, node is a complete view architecture
|
||||||
|
@ -692,7 +477,7 @@ class view(osv.osv):
|
||||||
new_xml = etree.fromstring(encode(xml))
|
new_xml = etree.fromstring(encode(xml))
|
||||||
ctx = context.copy()
|
ctx = context.copy()
|
||||||
ctx['base_model_name'] = model
|
ctx['base_model_name'] = model
|
||||||
xarch, xfields = self.__view_look_dom_arch(cr, user, node.get('object'), new_xml, view_id, ctx)
|
xarch, xfields = self.postprocess_and_fields(cr, user, node.get('object'), new_xml, view_id, ctx)
|
||||||
views['form'] = {
|
views['form'] = {
|
||||||
'arch': xarch,
|
'arch': xarch,
|
||||||
'fields': xfields
|
'fields': xfields
|
||||||
|
@ -719,7 +504,7 @@ class view(osv.osv):
|
||||||
node.remove(f)
|
node.remove(f)
|
||||||
ctx = context.copy()
|
ctx = context.copy()
|
||||||
ctx['base_model_name'] = Model
|
ctx['base_model_name'] = Model
|
||||||
xarch, xfields = self.__view_look_dom_arch(cr, user, column._obj or None, f, view_id, ctx)
|
xarch, xfields = self.postprocess_and_fields(cr, user, column._obj or None, f, view_id, ctx)
|
||||||
views[str(f.tag)] = {
|
views[str(f.tag)] = {
|
||||||
'arch': xarch,
|
'arch': xarch,
|
||||||
'fields': xfields
|
'fields': xfields
|
||||||
|
@ -803,7 +588,7 @@ class view(osv.osv):
|
||||||
|
|
||||||
for f in node:
|
for f in node:
|
||||||
if children or (node.tag == 'field' and f.tag in ('filter','separator')):
|
if children or (node.tag == 'field' and f.tag in ('filter','separator')):
|
||||||
fields.update(self.__view_look_dom(cr, user, model, f, view_id, in_tree_view, model_fields, context))
|
fields.update(self.postprocess(cr, user, model, f, view_id, in_tree_view, model_fields, context))
|
||||||
|
|
||||||
orm.transfer_modifiers_to_node(modifiers, node)
|
orm.transfer_modifiers_to_node(modifiers, node)
|
||||||
return fields
|
return fields
|
||||||
|
@ -833,11 +618,11 @@ class view(osv.osv):
|
||||||
button.set('readonly', str(int(not can_click)))
|
button.set('readonly', str(int(not can_click)))
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def __view_look_dom_arch(self, cr, user, model, node, view_id, context=None):
|
def postprocess_and_fields(self, cr, user, model, node, view_id, context=None):
|
||||||
""" Return an architecture and a description of all the fields.
|
""" Return an architecture and a description of all the fields.
|
||||||
|
|
||||||
The field description combines the result of fields_get() and
|
The field description combines the result of fields_get() and
|
||||||
__view_look_dom().
|
postprocess().
|
||||||
|
|
||||||
:param node: the architecture as as an etree
|
:param node: the architecture as as an etree
|
||||||
:return: a tuple (arch, fields) where arch is the given node as a
|
:return: a tuple (arch, fields) where arch is the given node as a
|
||||||
|
@ -860,7 +645,7 @@ class view(osv.osv):
|
||||||
elif Model:
|
elif Model:
|
||||||
fields = Model.fields_get(cr, user, None, context)
|
fields = Model.fields_get(cr, user, None, context)
|
||||||
|
|
||||||
fields_def = self.__view_look_dom(cr, user, model, node, view_id, False, fields, context=context)
|
fields_def = self.postprocess(cr, user, model, node, view_id, False, fields, context=context)
|
||||||
node = self._disable_workflow_buttons(cr, user, model, node)
|
node = self._disable_workflow_buttons(cr, user, model, node)
|
||||||
if node.tag in ('kanban', 'tree', 'form', 'gantt'):
|
if node.tag in ('kanban', 'tree', 'form', 'gantt'):
|
||||||
for action, operation in (('create', 'create'), ('delete', 'unlink'), ('edit', 'write')):
|
for action, operation in (('create', 'create'), ('delete', 'unlink'), ('edit', 'write')):
|
||||||
|
@ -887,7 +672,49 @@ class view(osv.osv):
|
||||||
raise orm.except_orm('View error', msg)
|
raise orm.except_orm('View error', msg)
|
||||||
return arch, fields
|
return arch, fields
|
||||||
|
|
||||||
def _get_arch(self, cr, uid, id_, context=None):
|
# view used as templates
|
||||||
|
|
||||||
|
def clean_anotations(arch, parent_info=None):
|
||||||
|
for child in arch:
|
||||||
|
if child.tag == 't' or child.tag == 'field':
|
||||||
|
# can not anote t and field while cleaning
|
||||||
|
continue
|
||||||
|
|
||||||
|
child_text = "".join([etree.tostring(x) for x in child])
|
||||||
|
if child.attrib.get('data-edit-model'):
|
||||||
|
if child_text.find('data-edit-model') != -1 or child_text.find('<t ') != -1:
|
||||||
|
# enclosed tag, move present tag to childs
|
||||||
|
parent_info = {
|
||||||
|
'model': child.attrib.get('data-edit-model'),
|
||||||
|
'view_id': child.attrib.get('data-edit-view-id'),
|
||||||
|
'xpath': child.attrib.get('data-edit-xpath')+'/'+child.tag,
|
||||||
|
}
|
||||||
|
child.attrib.pop('data-edit-model')
|
||||||
|
child.attrib.pop('data-edit-view-id')
|
||||||
|
child.attrib.pop('data-edit-xpath')
|
||||||
|
child = clean_anotations(child, parent_info)
|
||||||
|
else:
|
||||||
|
# tagged node, no enclosed, can keep, don't care if had parent_info
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
if child_text.find('data-edit-model') != -1 or child_text.find('<t ') != -1:
|
||||||
|
# has other nodes to clean
|
||||||
|
if parent_info:
|
||||||
|
# update xpath
|
||||||
|
parent_info.update({'xpath': parent_info.get('xpath')+'/'+child.tag})
|
||||||
|
child = clean_anotations(child, parent_info)
|
||||||
|
elif parent_info:
|
||||||
|
# put tag from parent, no enclose, higher
|
||||||
|
child.attrib.update({
|
||||||
|
'data-edit-model': parent_info.get('model'),
|
||||||
|
'data-edit-view-id': parent_info.get('view_id'),
|
||||||
|
'data-edit-xpath': parent_info.get('xpath'),
|
||||||
|
})
|
||||||
|
|
||||||
|
return arch
|
||||||
|
|
||||||
|
def read_template(self, cr, uid, id_, context=None):
|
||||||
from pprint import pprint as pp
|
from pprint import pprint as pp
|
||||||
pp(id_)
|
pp(id_)
|
||||||
try:
|
try:
|
||||||
|
@ -921,7 +748,7 @@ class view(osv.osv):
|
||||||
|
|
||||||
def render(self, cr, uid, id_or_xml_id, values, context=None):
|
def render(self, cr, uid, id_or_xml_id, values, context=None):
|
||||||
def loader(name):
|
def loader(name):
|
||||||
arch = self._get_arch(cr, uid, name, context=context)
|
arch = self.read_template(cr, uid, name, context=context)
|
||||||
# parse arch
|
# parse arch
|
||||||
# on the root tag of arch add the attribute t-name="<name>"
|
# on the root tag of arch add the attribute t-name="<name>"
|
||||||
arch = u'<?xml version="1.0" encoding="utf-8"?><tpl><t t-name="{0}">{1}</t></tpl>'.format(name, arch)
|
arch = u'<?xml version="1.0" encoding="utf-8"?><tpl><t t-name="{0}">{1}</t></tpl>'.format(name, arch)
|
||||||
|
@ -929,6 +756,75 @@ class view(osv.osv):
|
||||||
engine = qweb.QWebXml(loader)
|
engine = qweb.QWebXml(loader)
|
||||||
return engine.render(id_or_xml_id, values)
|
return engine.render(id_or_xml_id, values)
|
||||||
|
|
||||||
|
# maybe used to print the workflow ?
|
||||||
|
|
||||||
|
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None):
|
||||||
|
nodes=[]
|
||||||
|
nodes_name=[]
|
||||||
|
transitions=[]
|
||||||
|
start=[]
|
||||||
|
tres={}
|
||||||
|
labels={}
|
||||||
|
no_ancester=[]
|
||||||
|
blank_nodes = []
|
||||||
|
|
||||||
|
_Model_Obj = self.pool[model]
|
||||||
|
_Node_Obj = self.pool[node_obj]
|
||||||
|
_Arrow_Obj = self.pool[conn_obj]
|
||||||
|
|
||||||
|
for model_key,model_value in _Model_Obj._columns.items():
|
||||||
|
if model_value._type=='one2many':
|
||||||
|
if model_value._obj==node_obj:
|
||||||
|
_Node_Field=model_key
|
||||||
|
_Model_Field=model_value._fields_id
|
||||||
|
flag=False
|
||||||
|
for node_key,node_value in _Node_Obj._columns.items():
|
||||||
|
if node_value._type=='one2many':
|
||||||
|
if node_value._obj==conn_obj:
|
||||||
|
if src_node in _Arrow_Obj._columns and flag:
|
||||||
|
_Source_Field=node_key
|
||||||
|
if des_node in _Arrow_Obj._columns and not flag:
|
||||||
|
_Destination_Field=node_key
|
||||||
|
flag = True
|
||||||
|
|
||||||
|
datas = _Model_Obj.read(cr, uid, id, [],context)
|
||||||
|
for a in _Node_Obj.read(cr,uid,datas[_Node_Field],[]):
|
||||||
|
if a[_Source_Field] or a[_Destination_Field]:
|
||||||
|
nodes_name.append((a['id'],a['name']))
|
||||||
|
nodes.append(a['id'])
|
||||||
|
else:
|
||||||
|
blank_nodes.append({'id': a['id'],'name':a['name']})
|
||||||
|
|
||||||
|
if a.has_key('flow_start') and a['flow_start']:
|
||||||
|
start.append(a['id'])
|
||||||
|
else:
|
||||||
|
if not a[_Source_Field]:
|
||||||
|
no_ancester.append(a['id'])
|
||||||
|
for t in _Arrow_Obj.read(cr,uid, a[_Destination_Field],[]):
|
||||||
|
transitions.append((a['id'], t[des_node][0]))
|
||||||
|
tres[str(t['id'])] = (a['id'],t[des_node][0])
|
||||||
|
label_string = ""
|
||||||
|
if label:
|
||||||
|
for lbl in eval(label):
|
||||||
|
if t.has_key(tools.ustr(lbl)) and tools.ustr(t[lbl])=='False':
|
||||||
|
label_string += ' '
|
||||||
|
else:
|
||||||
|
label_string = label_string + " " + tools.ustr(t[lbl])
|
||||||
|
labels[str(t['id'])] = (a['id'],label_string)
|
||||||
|
g = graph(nodes, transitions, no_ancester)
|
||||||
|
g.process(start)
|
||||||
|
g.scale(*scale)
|
||||||
|
result = g.result_get()
|
||||||
|
results = {}
|
||||||
|
for node in nodes_name:
|
||||||
|
results[str(node[0])] = result[node[0]]
|
||||||
|
results[str(node[0])]['name'] = node[1]
|
||||||
|
return {'nodes': results,
|
||||||
|
'transitions': tres,
|
||||||
|
'label' : labels,
|
||||||
|
'blank_nodes': blank_nodes,
|
||||||
|
'node_parent_field': _Model_Field,}
|
||||||
|
|
||||||
class view_sc(osv.osv):
|
class view_sc(osv.osv):
|
||||||
_name = 'ir.ui.view_sc'
|
_name = 'ir.ui.view_sc'
|
||||||
_columns = {
|
_columns = {
|
||||||
|
|
|
@ -634,27 +634,6 @@ class MetaModel(type):
|
||||||
if not self._custom:
|
if not self._custom:
|
||||||
self.module_to_models.setdefault(self._module, []).append(self)
|
self.module_to_models.setdefault(self._module, []).append(self)
|
||||||
|
|
||||||
class FallbackViewMapping(collections.defaultdict):
|
|
||||||
def __init__(self, cr, uid, model, context=None):
|
|
||||||
super(FallbackViewMapping, self).__init__()
|
|
||||||
self.cr = cr
|
|
||||||
self.uid = uid
|
|
||||||
self.model = model
|
|
||||||
self.context = context
|
|
||||||
|
|
||||||
def __missing__(self, view_type):
|
|
||||||
try:
|
|
||||||
arch = getattr(self.model, '_get_default_%s_view' % view_type)(
|
|
||||||
self.cr, self.uid, self.context)
|
|
||||||
except AttributeError:
|
|
||||||
raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
|
|
||||||
return {
|
|
||||||
'id': 0,
|
|
||||||
'type': view_type,
|
|
||||||
'name': 'default',
|
|
||||||
'field_parent': False,
|
|
||||||
'arch': arch,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Definition of log access columns, automatically added to models if
|
# Definition of log access columns, automatically added to models if
|
||||||
# self._log_access is True
|
# self._log_access is True
|
||||||
|
@ -1796,15 +1775,12 @@ class BaseModel(object):
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
||||||
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||||
"""
|
"""
|
||||||
Get the detailed composition of the requested view like fields, model, view architecture
|
Get the detailed composition of the requested view like fields, model, view architecture
|
||||||
|
|
||||||
:param cr: database cursor
|
|
||||||
:param user: current user id
|
|
||||||
:param view_id: id of the view or None
|
:param view_id: id of the view or None
|
||||||
:param view_type: type of the view to return if view_id is None ('form', tree', ...)
|
:param view_type: type of the view to return if view_id is None ('form', tree', ...)
|
||||||
:param context: context arguments, like lang, time zone
|
|
||||||
:param toolbar: true to include contextual actions
|
:param toolbar: true to include contextual actions
|
||||||
:param submenu: deprecated
|
:param submenu: deprecated
|
||||||
:return: dictionary describing the composition of the requested view (including inherited views and extensions)
|
:return: dictionary describing the composition of the requested view (including inherited views and extensions)
|
||||||
|
@ -1812,69 +1788,72 @@ class BaseModel(object):
|
||||||
* if the inherited view has unknown position to work with other than 'before', 'after', 'inside', 'replace'
|
* if the inherited view has unknown position to work with other than 'before', 'after', 'inside', 'replace'
|
||||||
* if some tag other than 'position' is found in parent view
|
* if some tag other than 'position' is found in parent view
|
||||||
:raise Invalid ArchitectureError: if there is view type other than form, tree, calendar, search etc defined on the structure
|
:raise Invalid ArchitectureError: if there is view type other than form, tree, calendar, search etc defined on the structure
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
View = self.pool['ir.ui.view']
|
View = self.pool['ir.ui.view']
|
||||||
|
|
||||||
view_ref = context.get(view_type + '_view_ref')
|
|
||||||
|
|
||||||
if view_ref and not view_id and '.' in view_ref:
|
|
||||||
module, view_ref = view_ref.split('.', 1)
|
|
||||||
cr.execute("SELECT res_id FROM ir_model_data WHERE model='ir.ui.view' AND module=%s AND name=%s", (module, view_ref))
|
|
||||||
view_ref_res = cr.fetchone()
|
|
||||||
if view_ref_res:
|
|
||||||
view_id = view_ref_res[0]
|
|
||||||
|
|
||||||
root_view = View.read_combined(
|
|
||||||
cr, user, view_id, view_type, self._name, fields=[
|
|
||||||
'id', 'name', 'field_parent', 'type', 'model', 'arch'
|
|
||||||
], fallback=FallbackViewMapping(cr, user, self, context=context),
|
|
||||||
context=context)
|
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
'model': self._name,
|
'model': self._name,
|
||||||
'arch': root_view['arch'],
|
'field_parent': False,
|
||||||
'type': root_view['type'],
|
|
||||||
'view_id': root_view['id'],
|
|
||||||
'name': root_view['name'],
|
|
||||||
'field_parent': root_view['field_parent'] or False
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# try to find a view_id if none provided
|
||||||
|
if not view_id:
|
||||||
|
# <view_type>_view_ref in context can be used to overrride the default view
|
||||||
|
view_ref = context.get(view_type + '_view_ref')
|
||||||
|
if view_ref and '.' in view_ref:
|
||||||
|
module, view_ref = view_ref.split('.', 1)
|
||||||
|
cr.execute("SELECT res_id FROM ir_model_data WHERE model='ir.ui.view' AND module=%s AND name=%s", (module, view_ref))
|
||||||
|
view_ref_res = cr.fetchone()
|
||||||
|
if view_ref_res:
|
||||||
|
view_id = view_ref_res[0]
|
||||||
|
else:
|
||||||
|
# otherwise try to find the lowest priority matching ir.ui.view
|
||||||
|
view_id = View.default_view(cr, uid, self._name, view_type, context=context)
|
||||||
|
|
||||||
|
if view_id:
|
||||||
|
# read the view with inherited views applied
|
||||||
|
root_view = View.read_combined(cr, uid, view_id, fields=['id', 'name', 'field_parent', 'type', 'model', 'arch'], context=context)
|
||||||
|
result['arch'] = root_view['arch']
|
||||||
|
result['name'] = root_view['name']
|
||||||
|
result['type'] = root_view['type']
|
||||||
|
result['view_id'] = root_view['id']
|
||||||
|
result['field_parent'] = root_view['field_parent']
|
||||||
|
else:
|
||||||
|
# fallback on default views methods if no ir.ui.view could be found
|
||||||
|
try:
|
||||||
|
get_func = getattr(self, '_get_default_%s_view' % view_type)
|
||||||
|
arch_etree = get_func(self.cr, self.uid, self.context)
|
||||||
|
result['arch'] = etree.tostring(arch_etree, encoding='utf-8')
|
||||||
|
result['type'] = view_type
|
||||||
|
result['name'] = 'default'
|
||||||
|
except AttributeError:
|
||||||
|
raise except_orm(_('Invalid Architecture!'), _("No default view of type '%s' could be found !") % view_type)
|
||||||
|
|
||||||
|
# Apply post processing, groups and modifiers etc...
|
||||||
ctx = context
|
ctx = context
|
||||||
if root_view.get('model') != self._name:
|
if root_view.get('model') != self._name:
|
||||||
ctx = dict(context, base_model_name=root_view.get('model'))
|
ctx = dict(context, base_model_name=root_view.get('model'))
|
||||||
xarch, xfields = View._view__view_look_dom_arch(
|
xarch, xfields = View.postprocess_and_fields( cr, uid, self._name, etree.fromstring(result['arch']), result['view_id'], context=ctx)
|
||||||
cr, user, self._name, etree.fromstring(result['arch']),
|
|
||||||
result['view_id'], context=ctx)
|
|
||||||
result['arch'] = xarch
|
result['arch'] = xarch
|
||||||
result['fields'] = xfields
|
result['fields'] = xfields
|
||||||
|
|
||||||
|
# Add related action information if aksed
|
||||||
if toolbar:
|
if toolbar:
|
||||||
|
toclean = ('report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml', 'report_sxw_content_data', 'report_rml_content_data')
|
||||||
def clean(x):
|
def clean(x):
|
||||||
x = x[2]
|
x = x[2]
|
||||||
for key in ('report_sxw_content', 'report_rml_content',
|
for key in toclean:
|
||||||
'report_sxw', 'report_rml',
|
|
||||||
'report_sxw_content_data', 'report_rml_content_data'):
|
|
||||||
if key in x:
|
if key in x:
|
||||||
del x[key]
|
del x[key]
|
||||||
return x
|
return x
|
||||||
ir_values_obj = self.pool.get('ir.values')
|
ir_values_obj = self.pool.get('ir.values')
|
||||||
resprint = ir_values_obj.get(cr, user, 'action',
|
resprint = ir_values_obj.get(cr, uid, 'action', 'client_print_multi', [(self._name, False)], False, context)
|
||||||
'client_print_multi', [(self._name, False)], False,
|
resaction = ir_values_obj.get(cr, uid, 'action', 'client_action_multi', [(self._name, False)], False, context)
|
||||||
context)
|
resrelate = ir_values_obj.get(cr, uid, 'action', 'client_action_relate', [(self._name, False)], False, context)
|
||||||
resaction = ir_values_obj.get(cr, user, 'action',
|
resaction = [clean(action) for action in resaction if view_type == 'tree' or not action[2].get('multi')]
|
||||||
'client_action_multi', [(self._name, False)], False,
|
resprint = [clean(print_) for print_ in resprint if view_type == 'tree' or not print_[2].get('multi')]
|
||||||
context)
|
|
||||||
|
|
||||||
resrelate = ir_values_obj.get(cr, user, 'action',
|
|
||||||
'client_action_relate', [(self._name, False)], False,
|
|
||||||
context)
|
|
||||||
resaction = [clean(action) for action in resaction
|
|
||||||
if view_type == 'tree' or not action[2].get('multi')]
|
|
||||||
resprint = [clean(print_) for print_ in resprint
|
|
||||||
if view_type == 'tree' or not print_[2].get('multi')]
|
|
||||||
#When multi="True" set it will display only in More of the list view
|
#When multi="True" set it will display only in More of the list view
|
||||||
resrelate = [clean(action) for action in resrelate
|
resrelate = [clean(action) for action in resrelate
|
||||||
if (action[2].get('multi') and view_type == 'tree') or (not action[2].get('multi') and view_type == 'form')]
|
if (action[2].get('multi') and view_type == 'tree') or (not action[2].get('multi') and view_type == 'form')]
|
||||||
|
@ -1890,7 +1869,7 @@ class BaseModel(object):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _view_look_dom_arch(self, cr, uid, node, view_id, context=None):
|
def _view_look_dom_arch(self, cr, uid, node, view_id, context=None):
|
||||||
return self['ir.ui.view']._view__view_look_dom_arch(
|
return self['ir.ui.view'].postprocess_and_fields(
|
||||||
cr, uid, self._name, node, view_id, context=context)
|
cr, uid, self._name, node, view_id, context=context)
|
||||||
|
|
||||||
def search_count(self, cr, user, args, context=None):
|
def search_count(self, cr, user, args, context=None):
|
||||||
|
@ -3045,31 +3024,6 @@ class BaseModel(object):
|
||||||
self._columns[field_name].required = True
|
self._columns[field_name].required = True
|
||||||
self._columns[field_name].ondelete = "cascade"
|
self._columns[field_name].ondelete = "cascade"
|
||||||
|
|
||||||
#def __getattr__(self, name):
|
|
||||||
# """
|
|
||||||
# Proxies attribute accesses to the `inherits` parent so we can call methods defined on the inherited parent
|
|
||||||
# (though inherits doesn't use Python inheritance).
|
|
||||||
# Handles translating between local ids and remote ids.
|
|
||||||
# Known issue: doesn't work correctly when using python's own super(), don't involve inherit-based inheritance
|
|
||||||
# when you have inherits.
|
|
||||||
# """
|
|
||||||
# for model, field in self._inherits.iteritems():
|
|
||||||
# proxy = self.pool.get(model)
|
|
||||||
# if hasattr(proxy, name):
|
|
||||||
# attribute = getattr(proxy, name)
|
|
||||||
# if not hasattr(attribute, '__call__'):
|
|
||||||
# return attribute
|
|
||||||
# break
|
|
||||||
# else:
|
|
||||||
# return super(orm, self).__getattr__(name)
|
|
||||||
|
|
||||||
# def _proxy(cr, uid, ids, *args, **kwargs):
|
|
||||||
# objects = self.browse(cr, uid, ids, kwargs.get('context', None))
|
|
||||||
# lst = [obj[field].id for obj in objects if obj[field]]
|
|
||||||
# return getattr(proxy, name)(cr, uid, lst, *args, **kwargs)
|
|
||||||
|
|
||||||
# return _proxy
|
|
||||||
|
|
||||||
|
|
||||||
def fields_get(self, cr, user, allfields=None, context=None, write_access=True):
|
def fields_get(self, cr, user, allfields=None, context=None, write_access=True):
|
||||||
""" Return the definition of each field.
|
""" Return the definition of each field.
|
||||||
|
@ -4911,6 +4865,32 @@ class BaseModel(object):
|
||||||
""" stuff to do right after the registry is built """
|
""" stuff to do right after the registry is built """
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
#def __getattr__(self, name):
|
||||||
|
# """
|
||||||
|
# Proxies attribute accesses to the `inherits` parent so we can call methods defined on the inherited parent
|
||||||
|
# (though inherits doesn't use Python inheritance).
|
||||||
|
# Handles translating between local ids and remote ids.
|
||||||
|
# Known issue: doesn't work correctly when using python's own super(), don't involve inherit-based inheritance
|
||||||
|
# when you have inherits.
|
||||||
|
# """
|
||||||
|
# for model, field in self._inherits.iteritems():
|
||||||
|
# proxy = self.pool.get(model)
|
||||||
|
# if hasattr(proxy, name):
|
||||||
|
# attribute = getattr(proxy, name)
|
||||||
|
# if not hasattr(attribute, '__call__'):
|
||||||
|
# return attribute
|
||||||
|
# break
|
||||||
|
# else:
|
||||||
|
# return super(orm, self).__getattr__(name)
|
||||||
|
|
||||||
|
# def _proxy(cr, uid, ids, *args, **kwargs):
|
||||||
|
# objects = self.browse(cr, uid, ids, kwargs.get('context', None))
|
||||||
|
# lst = [obj[field].id for obj in objects if obj[field]]
|
||||||
|
# return getattr(proxy, name)(cr, uid, lst, *args, **kwargs)
|
||||||
|
|
||||||
|
# return _proxy
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name.startswith('signal_'):
|
if name.startswith('signal_'):
|
||||||
signal_name = name[len('signal_'):]
|
signal_name = name[len('signal_'):]
|
||||||
|
@ -4976,12 +4956,12 @@ def itemgetter_tuple(items):
|
||||||
if len(items) == 1:
|
if len(items) == 1:
|
||||||
return lambda gettable: (gettable[items[0]],)
|
return lambda gettable: (gettable[items[0]],)
|
||||||
return operator.itemgetter(*items)
|
return operator.itemgetter(*items)
|
||||||
|
|
||||||
class ImportWarning(Warning):
|
class ImportWarning(Warning):
|
||||||
""" Used to send warnings upwards the stack during the import process
|
""" Used to send warnings upwards the stack during the import process
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def convert_pgerror_23502(model, fields, info, e):
|
def convert_pgerror_23502(model, fields, info, e):
|
||||||
m = re.match(r'^null value in column "(?P<field>\w+)" violates '
|
m = re.match(r'^null value in column "(?P<field>\w+)" violates '
|
||||||
r'not-null constraint\n',
|
r'not-null constraint\n',
|
||||||
|
@ -4997,6 +4977,7 @@ def convert_pgerror_23502(model, fields, info, e):
|
||||||
'message': message,
|
'message': message,
|
||||||
'field': field_name,
|
'field': field_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
def convert_pgerror_23505(model, fields, info, e):
|
def convert_pgerror_23505(model, fields, info, e):
|
||||||
m = re.match(r'^duplicate key (?P<field>\w+) violates unique constraint',
|
m = re.match(r'^duplicate key (?P<field>\w+) violates unique constraint',
|
||||||
str(e))
|
str(e))
|
||||||
|
|
Loading…
Reference in New Issue