Add help for each value to selection and multiselection
issue9649 review320021002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Add help for each value to selection and multiselection
|
||||
* Use safe_join in SharedDataMiddlewareIndex (issue10068)
|
||||
* Use menu name for window opened from menu
|
||||
* Add trigonometric functions to sqlite backend
|
||||
|
||||
@@ -446,7 +446,7 @@ A binary field. It will be represented in Python by a ``bytes`` instance.
|
||||
Selection
|
||||
---------
|
||||
|
||||
.. class:: Selection(selection, string[, sort[, selection_change_with[, translate[, \**options]]]])
|
||||
.. class:: Selection(selection, string[, sort[, selection_change_with[, translate[, help_selection[, \**options]]]]])
|
||||
|
||||
A string field with limited values to choose from.
|
||||
|
||||
@@ -494,6 +494,10 @@ A string field with limited values to choose from.
|
||||
If true, the human-readable values will be translated. Default value is
|
||||
``True``.
|
||||
|
||||
.. attribute:: Selection.help_selection
|
||||
|
||||
A dictionary mapping the selection value with its help string.
|
||||
|
||||
Instance methods:
|
||||
|
||||
.. method:: Selection.translated([name])
|
||||
@@ -506,7 +510,7 @@ Instance methods:
|
||||
MultiSelection
|
||||
--------------
|
||||
|
||||
.. class:: MultiSelection(selection, string[, sort[, translate[, \**options]]])
|
||||
.. class:: MultiSelection(selection, string[, sort[, translate[, help_selection[, \**options]]]])
|
||||
|
||||
A list field with limited values to choose from.
|
||||
|
||||
@@ -526,6 +530,10 @@ A list field with limited values to choose from.
|
||||
|
||||
Same as :attr:`Selection.translate_selection`
|
||||
|
||||
.. attribute:: MultiSelection.help_selection
|
||||
|
||||
Same as :attr:`Selection.help_selection`
|
||||
|
||||
Instance methods:
|
||||
|
||||
.. method:: MultiSelection.translated([name])
|
||||
@@ -536,7 +544,7 @@ Instance methods:
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. class:: Reference(string[, selection[, sort[, selection_change_with[, translated[,search_order[, search_context[, \**options]]]]]]])
|
||||
.. class:: Reference(string[, selection[, sort[, selection_change_with[, translate[, help_selection[,search_order[, search_context[, \**options]]]]]]]])
|
||||
|
||||
A field that refers to a record of a model. It will be represented in Python by
|
||||
a ``str`` instance like this::
|
||||
@@ -563,6 +571,10 @@ But a ``tuple`` can be used to search or set value.
|
||||
|
||||
Same as :attr:`Selection.translate_selection`.
|
||||
|
||||
.. attribute:: Reference.help_selection
|
||||
|
||||
Same as :attr:`Selection.help_selection`.
|
||||
|
||||
.. attribute:: Reference.datetime_field
|
||||
|
||||
Same as :attr:`Many2One.datetime_field`
|
||||
|
||||
@@ -167,6 +167,11 @@ List of attributes shared by many form elements:
|
||||
* ``symbol``: Only on numerical fields, the name of field which provides
|
||||
the symbol to display.
|
||||
|
||||
.. _common-attributes-help_field:
|
||||
|
||||
* ``help_field``: The name of Dict field mapping the Selection value with
|
||||
its help string.
|
||||
|
||||
form
|
||||
^^^^
|
||||
|
||||
@@ -289,6 +294,8 @@ Display a field of the object with the value of the current record.
|
||||
|
||||
* ``symbol``: see in common-attributes-symbol_.
|
||||
|
||||
* ``help_field``: see in common-attributes-help_field_.
|
||||
|
||||
image
|
||||
^^^^^
|
||||
|
||||
@@ -609,6 +616,8 @@ field
|
||||
|
||||
* ``symbol``: see in common-attributes-symbol_.
|
||||
|
||||
* ``help_field``: see in common-attributes-help_field_.
|
||||
|
||||
prefix or suffix
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -108,9 +108,18 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.message" id="msg_dict_schema_selection_sorted_help">
|
||||
<field name="text">If the selection must be sorted on label.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dict_schema_help_selection">
|
||||
<field name="text">Help Selection</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dict_schema_help_selection_help">
|
||||
<field name="text">The key followed by the help text separated by a ":", one per line.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dict_schema_selection_json">
|
||||
<field name="text">Selection JSON</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dict_schema_help_selection_json">
|
||||
<field name="text">Help Selection JSON</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_sequence">
|
||||
<field name="text">Sequence</field>
|
||||
</record>
|
||||
@@ -199,6 +208,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<record model="ir.message" id="msg_dict_schema_invalid_selection">
|
||||
<field name="text">Invalid selection in schema "%(schema)s".</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_dict_schema_invalid_help_selection">
|
||||
<field name="text">Invalid help selection in schema "%(schema)s".</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_recursion_error">
|
||||
<field name="text">Recursion error: Record "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
</record>
|
||||
|
||||
@@ -105,6 +105,7 @@ attlist.field &= [a:defaultValue = "1"] attribute completion { "0" | "1" }?
|
||||
attlist.field &= attribute string { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute factor { text }?
|
||||
attlist.field &= attribute filename { text }?
|
||||
attlist.field &= attribute help_field { text }?
|
||||
attlist.field &=
|
||||
[a:defaultValue = "0"] attribute toolbar { "0" | "1" }?
|
||||
attlist.field &= attribute symbol { text }?
|
||||
|
||||
@@ -465,6 +465,14 @@
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help_field</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
|
||||
@@ -63,6 +63,7 @@ attlist.field &= [a:defaultValue = "1"] attribute completion { "0" | "1" }?
|
||||
attlist.field &= attribute string { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute factor { text }?
|
||||
attlist.field &= attribute filename { text }?
|
||||
attlist.field &= attribute help_field { text }?
|
||||
attlist.field &= attribute view_ids { text }?
|
||||
attlist.field &= attribute symbol { text }?
|
||||
prefix = element prefix { attlist.affix, empty }
|
||||
|
||||
@@ -248,6 +248,14 @@
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help_field</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
|
||||
@@ -63,6 +63,13 @@ class DictSchemaMixin(object):
|
||||
'invisible': ~Eval('type_').in_(['selection', 'multiselection']),
|
||||
}, depends=['type_'],
|
||||
help=lazy_gettext('ir.msg_dict_schema_selection_sorted_help'))
|
||||
help_selection = fields.Text(
|
||||
lazy_gettext('ir.msg_dict_schema_help_selection'), translate=True,
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_'],
|
||||
help=lazy_gettext('is.msg_dict_schema_help_selection_help'))
|
||||
selection_json = fields.Function(fields.Char(
|
||||
lazy_gettext('ir.msg_dict_schema_selection_json'),
|
||||
states={
|
||||
@@ -70,6 +77,13 @@ class DictSchemaMixin(object):
|
||||
['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_']), 'get_selection_json')
|
||||
help_selection_json = fields.Function(fields.Char(
|
||||
lazy_gettext('ir.msg_dict_schema_help_selection_json'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(
|
||||
['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_']), 'get_selection_json')
|
||||
_relation_fields_cache = Cache('_dict_schema_mixin.get_relation_fields')
|
||||
|
||||
@classmethod
|
||||
@@ -119,15 +133,17 @@ class DictSchemaMixin(object):
|
||||
for schema in schemas:
|
||||
if schema.type_ not in {'selection', 'multiselection'}:
|
||||
continue
|
||||
try:
|
||||
dict(json.loads(schema.get_selection_json()))
|
||||
except Exception:
|
||||
raise SelectionError(
|
||||
gettext('ir.msg_dict_schema_invalid_selection',
|
||||
schema=schema.rec_name))
|
||||
for name in ['selection', 'help_selection']:
|
||||
try:
|
||||
dict(json.loads(schema.get_selection_json(name + '_json')))
|
||||
except Exception:
|
||||
raise SelectionError(
|
||||
gettext('ir.msg_dict_schema_invalid_%s' % name,
|
||||
schema=schema.rec_name))
|
||||
|
||||
def get_selection_json(self, name=None):
|
||||
db_selection = self.selection or ''
|
||||
def get_selection_json(self, name):
|
||||
field = name[:-len('_json')]
|
||||
db_selection = getattr(self, field) or ''
|
||||
selection = [[w.strip() for w in v.split(':', 1)]
|
||||
for v in db_selection.splitlines() if v]
|
||||
return json.dumps(selection, separators=(',', ':'))
|
||||
@@ -154,6 +170,8 @@ class DictSchemaMixin(object):
|
||||
english_key.selection_json))
|
||||
selection.update(dict(json.loads(record.selection_json)))
|
||||
new_key['selection'] = list(selection.items())
|
||||
new_key['help_selection'] = dict(
|
||||
json.loads(record.help_selection_json))
|
||||
new_key['sort'] = record.selection_sorted
|
||||
elif record.type_ in ('float', 'numeric'):
|
||||
new_key['digits'] = (16, record.digits)
|
||||
|
||||
@@ -21,9 +21,9 @@ class MultiSelection(SelectionMixin, Field):
|
||||
_py_type = list
|
||||
|
||||
def __init__(self, selection, string='', sort=True, translate=True,
|
||||
help='', required=False, readonly=False, domain=None, states=None,
|
||||
select=False, on_change=None, on_change_with=None, depends=None,
|
||||
context=None, loading='eager'):
|
||||
help='', help_selection=None, required=False, readonly=False,
|
||||
domain=None, states=None, select=False, on_change=None,
|
||||
on_change_with=None, depends=None, context=None, loading='eager'):
|
||||
"""
|
||||
:param selection: A list or a function name that returns a list.
|
||||
The list must be a list of tuples. First member is the value
|
||||
@@ -41,6 +41,7 @@ class MultiSelection(SelectionMixin, Field):
|
||||
self.selection_change_with = set()
|
||||
self.sort = sort
|
||||
self.translate_selection = translate
|
||||
self.help_selection = help_selection
|
||||
__init__.__doc__ += Field.__init__.__doc__
|
||||
|
||||
def set_rpc(self, model):
|
||||
|
||||
@@ -24,10 +24,10 @@ class Reference(SelectionMixin, Field):
|
||||
|
||||
def __init__(self, string='', selection=None, sort=True,
|
||||
selection_change_with=None, translate=True, search_order=None,
|
||||
search_context=None, help='', required=False, readonly=False,
|
||||
domain=None, states=None, select=False, on_change=None,
|
||||
on_change_with=None, depends=None, context=None, loading='lazy',
|
||||
datetime_field=None):
|
||||
search_context=None, help='', help_selection=None, required=False,
|
||||
readonly=False, domain=None, states=None, select=False,
|
||||
on_change=None, on_change_with=None, depends=None, context=None,
|
||||
loading='lazy', datetime_field=None):
|
||||
'''
|
||||
:param selection: A list or a function name that returns a list.
|
||||
The list must be a list of tuples. First member is an internal name
|
||||
@@ -57,6 +57,7 @@ class Reference(SelectionMixin, Field):
|
||||
self.selection_change_with |= set(selection_change_with)
|
||||
self.sort = sort
|
||||
self.translate_selection = translate
|
||||
self.help_selection = help_selection
|
||||
self.__search_order = None
|
||||
self.search_order = search_order
|
||||
self.__search_context = None
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import warnings
|
||||
from itertools import chain
|
||||
|
||||
from sql.conditionals import Case
|
||||
|
||||
@@ -40,19 +41,33 @@ class SelectionMixin(Field):
|
||||
selection = self.selection.copy()
|
||||
else:
|
||||
selection = self.selection
|
||||
if self.help_selection:
|
||||
help_selection = {}
|
||||
for key, source in self.help_selection.items():
|
||||
if not isinstance(source, LazyString):
|
||||
source = Translation.get_source(
|
||||
name, 'selection', language, source) or source
|
||||
help_selection[key] = str(source)
|
||||
else:
|
||||
help_selection = None
|
||||
definition['selection'] = selection
|
||||
definition['selection_change_with'] = list(self.selection_change_with)
|
||||
definition['sort'] = self.sort
|
||||
definition['help_selection'] = help_selection
|
||||
return definition
|
||||
|
||||
def definition_translations(self, model, language):
|
||||
name = '%s,%s' % (model.__name__, self.name)
|
||||
selection = []
|
||||
sources = []
|
||||
if not isinstance(self.selection, str) and self.translate_selection:
|
||||
for key, source in self.selection:
|
||||
if not isinstance(source, LazyString):
|
||||
selection.append(
|
||||
(name, 'selection', language, source))
|
||||
sources.append(self.selection)
|
||||
if self.help_selection:
|
||||
sources.append(self.help_selection.items())
|
||||
for key, source in chain(*sources):
|
||||
if not isinstance(source, LazyString):
|
||||
selection.append(
|
||||
(name, 'selection', language, source))
|
||||
return super().definition_translations(model, language) + selection
|
||||
|
||||
|
||||
@@ -66,9 +81,9 @@ class Selection(SelectionMixin, Field):
|
||||
|
||||
def __init__(self, selection, string='', sort=True,
|
||||
selection_change_with=None, translate=True, help='',
|
||||
required=False, readonly=False, domain=None, states=None,
|
||||
select=False, on_change=None, on_change_with=None, depends=None,
|
||||
context=None, loading='eager'):
|
||||
help_selection=None, required=False, readonly=False, domain=None,
|
||||
states=None, select=False, on_change=None, on_change_with=None,
|
||||
depends=None, context=None, loading='eager'):
|
||||
'''
|
||||
:param selection: A list or a function name that returns a list.
|
||||
The list must be a list of tuples. First member is the value
|
||||
@@ -91,6 +106,7 @@ class Selection(SelectionMixin, Field):
|
||||
self.selection_change_with |= set(selection_change_with)
|
||||
self.sort = sort
|
||||
self.translate_selection = translate
|
||||
self.help_selection = help_selection
|
||||
__init__.__doc__ += Field.__init__.__doc__
|
||||
|
||||
def set_rpc(self, model):
|
||||
|
||||
Reference in New Issue
Block a user