changeset bdbd86d9c69a in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=bdbd86d9c69a
description:
        Add help for each value to selection and multiselection

        issue9649
        review320021002
diffstat:

 CHANGELOG                              |   1 +
 doc/ref/models/fields.rst              |  18 +++++++++++++++---
 doc/topics/views/index.rst             |   9 +++++++++
 trytond/ir/message.xml                 |  12 ++++++++++++
 trytond/ir/ui/form.rnc                 |   1 +
 trytond/ir/ui/form.rng                 |   8 ++++++++
 trytond/ir/ui/tree.rnc                 |   1 +
 trytond/ir/ui/tree.rng                 |   8 ++++++++
 trytond/model/dictschema.py            |  34 ++++++++++++++++++++++++++--------
 trytond/model/fields/multiselection.py |   7 ++++---
 trytond/model/fields/reference.py      |   9 +++++----
 trytond/model/fields/selection.py      |  30 +++++++++++++++++++++++-------
 12 files changed, 113 insertions(+), 25 deletions(-)

diffs (380 lines):

diff -r 42deab7e7838 -r bdbd86d9c69a CHANGELOG
--- a/CHANGELOG Sat Feb 13 11:15:16 2021 +0100
+++ b/CHANGELOG Sun Feb 14 14:28:55 2021 +0100
@@ -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
diff -r 42deab7e7838 -r bdbd86d9c69a doc/ref/models/fields.rst
--- a/doc/ref/models/fields.rst Sat Feb 13 11:15:16 2021 +0100
+++ b/doc/ref/models/fields.rst Sun Feb 14 14:28:55 2021 +0100
@@ -446,7 +446,7 @@
 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 @@
     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 @@
 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 @@
 
     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 @@
 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 @@
 
     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`
diff -r 42deab7e7838 -r bdbd86d9c69a doc/topics/views/index.rst
--- a/doc/topics/views/index.rst        Sat Feb 13 11:15:16 2021 +0100
+++ b/doc/topics/views/index.rst        Sun Feb 14 14:28:55 2021 +0100
@@ -167,6 +167,11 @@
     * ``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 @@
 
     * ``symbol``: see in common-attributes-symbol_.
 
+    * ``help_field``: see in common-attributes-help_field_.
+
 image
 ^^^^^
 
@@ -609,6 +616,8 @@
 
     * ``symbol``: see in common-attributes-symbol_.
 
+    * ``help_field``: see in common-attributes-help_field_.
+
 prefix or suffix
 ^^^^^^^^^^^^^^^^
 
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/ir/message.xml
--- a/trytond/ir/message.xml    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/ir/message.xml    Sun Feb 14 14:28:55 2021 +0100
@@ -108,9 +108,18 @@
         <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 @@
         <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>
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/ir/ui/form.rnc
--- a/trytond/ir/ui/form.rnc    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/ir/ui/form.rnc    Sun Feb 14 14:28:55 2021 +0100
@@ -105,6 +105,7 @@
 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 }?
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/ir/ui/form.rng
--- a/trytond/ir/ui/form.rng    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/ir/ui/form.rng    Sun Feb 14 14:28:55 2021 +0100
@@ -467,6 +467,14 @@
   </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">
         <name ns="">toolbar</name>
         <choice>
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/ir/ui/tree.rnc
--- a/trytond/ir/ui/tree.rnc    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/ir/ui/tree.rnc    Sun Feb 14 14:28:55 2021 +0100
@@ -63,6 +63,7 @@
 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 }
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/ir/ui/tree.rng
--- a/trytond/ir/ui/tree.rng    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/ir/ui/tree.rng    Sun Feb 14 14:28:55 2021 +0100
@@ -251,6 +251,14 @@
   <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>
         <name ns="">view_ids</name>
         <text/>
       </attribute>
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/model/dictschema.py
--- a/trytond/model/dictschema.py       Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/model/dictschema.py       Sun Feb 14 14:28:55 2021 +0100
@@ -63,6 +63,13 @@
             '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 @@
                     ['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 @@
         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 @@
                             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)
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/model/fields/multiselection.py
--- a/trytond/model/fields/multiselection.py    Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/model/fields/multiselection.py    Sun Feb 14 14:28:55 2021 +0100
@@ -21,9 +21,9 @@
     _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 @@
         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):
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/model/fields/reference.py
--- a/trytond/model/fields/reference.py Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/model/fields/reference.py Sun Feb 14 14:28:55 2021 +0100
@@ -24,10 +24,10 @@
 
     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 @@
             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
diff -r 42deab7e7838 -r bdbd86d9c69a trytond/model/fields/selection.py
--- a/trytond/model/fields/selection.py Sat Feb 13 11:15:16 2021 +0100
+++ b/trytond/model/fields/selection.py Sun Feb 14 14:28:55 2021 +0100
@@ -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 @@
             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 @@
 
     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 @@
             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):

Reply via email to