changeset 36c90d8bd0f7 in tryton:default
details: https://hg.tryton.org/tryton?cmd=changeset;node=36c90d8bd0f7
description:
        Add link button

        issue9051
        review280841002
diffstat:

 CHANGELOG                                                 |    1 +
 tryton/gui/window/board.py                                |    1 +
 tryton/gui/window/view_board/view_board.py                |    3 +
 tryton/gui/window/view_form/model/record.py               |    2 +
 tryton/gui/window/view_form/view/form.py                  |    7 +-
 tryton/gui/window/view_form/view/form_gtk/state_widget.py |  112 ++++++++++++++
 6 files changed, 125 insertions(+), 1 deletions(-)

diffs (210 lines):

diff -r f6f4d5759eaa -r 36c90d8bd0f7 CHANGELOG
--- a/CHANGELOG Sun Apr 12 23:21:08 2020 +0200
+++ b/CHANGELOG Mon Apr 13 12:21:55 2020 +0200
@@ -1,3 +1,4 @@
+* Support link button on form
 * Add URL for the current export
 * Add option to export listed records
 * Retire App Menu
diff -r f6f4d5759eaa -r 36c90d8bd0f7 tryton/gui/window/board.py
--- a/tryton/gui/window/board.py        Sun Apr 12 23:21:08 2020 +0200
+++ b/tryton/gui/window/board.py        Mon Apr 13 12:21:55 2020 +0200
@@ -40,6 +40,7 @@
             self.name = name
 
         self.create_tabcontent()
+        self.board.reload()
 
     def get_toolbars(self):
         return {}
diff -r f6f4d5759eaa -r 36c90d8bd0f7 tryton/gui/window/view_board/view_board.py
--- a/tryton/gui/window/view_board/view_board.py        Sun Apr 12 23:21:08 
2020 +0200
+++ b/tryton/gui/window/view_board/view_board.py        Mon Apr 13 12:21:55 
2020 +0200
@@ -38,6 +38,7 @@
     def __init__(self, xml, context=None):
         self.context = context
         self.actions = []
+        self.state_widgets = []
         self.xml_parser(self, None, {}).parse(xml)
         self.widget.show_all()
         self._active_changed(None)
@@ -48,6 +49,8 @@
     def reload(self):
         for action in self.actions:
             action.display()
+        for state_widget in self.state_widgets:
+            state_widget.state_set(None)
 
     def _active_changed(self, event_action, *args):
         for action in self.actions:
diff -r f6f4d5759eaa -r 36c90d8bd0f7 tryton/gui/window/view_form/model/record.py
--- a/tryton/gui/window/view_form/model/record.py       Sun Apr 12 23:21:08 
2020 +0200
+++ b/tryton/gui/window/view_form/model/record.py       Mon Apr 13 12:21:55 
2020 +0200
@@ -30,6 +30,7 @@
         self._timestamp = None
         self.resources = None
         self.button_clicks = {}
+        self.links_counts = {}
         self.next = {}  # Used in Group list
         self.value = {}
         self.autocompletion = {}
@@ -292,6 +293,7 @@
         self.modified_fields.clear()
         self._timestamp = None
         self.button_clicks.clear()
+        self.links_counts.clear()
 
     def get_timestamp(self):
         result = {self.model_name + ',' + str(self.id): self._timestamp}
diff -r f6f4d5759eaa -r 36c90d8bd0f7 tryton/gui/window/view_form/view/form.py
--- a/tryton/gui/window/view_form/view/form.py  Sun Apr 12 23:21:08 2020 +0200
+++ b/tryton/gui/window/view_form/view/form.py  Mon Apr 13 12:21:55 2020 +0200
@@ -34,7 +34,7 @@
 from .form_gtk.multiselection import MultiSelection
 from .form_gtk.pyson import PYSON
 from .form_gtk.state_widget import (Label, VBox, Image, Frame, ScrolledWindow,
-    Notebook, Expander)
+    Notebook, Expander, Link)
 
 _ = gettext.gettext
 
@@ -258,6 +258,11 @@
         self.view.state_widgets.append(button)
         self.container.add(button, attributes)
 
+    def _parse_link(self, node, attributes):
+        link = Link(attrs=attributes)
+        self.view.state_widgets.append(link)
+        self.container.add(link, attributes)
+
     def _parse_image(self, node, attributes):
         image = Image(attrs=attributes)
         self.view.state_widgets.append(image)
diff -r f6f4d5759eaa -r 36c90d8bd0f7 
tryton/gui/window/view_form/view/form_gtk/state_widget.py
--- a/tryton/gui/window/view_form/view/form_gtk/state_widget.py Sun Apr 12 
23:21:08 2020 +0200
+++ b/tryton/gui/window/view_form/view/form_gtk/state_widget.py Mon Apr 13 
12:21:55 2020 +0200
@@ -1,8 +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.
+import functools
+
 from gi.repository import Gtk
 
 import tryton.common as common
+from tryton.action import Action
+from tryton.config import CONFIG
+from tryton.pyson import PYSONDecoder
 
 
 class StateMixin(object):
@@ -104,3 +109,110 @@
         if not label:
             label = None
         super(Expander, self).__init__(label=label, attrs=attrs)
+
+
+class Link(StateMixin, Gtk.Button):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.set_relief(Gtk.ReliefStyle.NONE)
+        self.set_can_focus(False)
+        if self.attrs.get('icon'):
+            self.set_always_show_image(True)
+            self.set_image(common.IconFactory.get_image(
+                    self.attrs['icon'], Gtk.IconSize.LARGE_TOOLBAR))
+            self.set_image_position(Gtk.PositionType.TOP)
+        self._current = None
+
+    @property
+    def action_id(self):
+        return int(self.attrs['id'])
+
+    def state_set(self, record):
+        super().state_set(record)
+        if not self.get_visible():
+            return
+        if CONFIG['client.modepda']:
+            self.hide()
+            return
+        if record:
+            data = {
+                'model': record.model_name,
+                'id': record.id,
+                'ids': [record.id],
+                }
+            context = record.get_context()
+            pyson_ctx = {
+                'active_model': record.model_name,
+                'active_id': record.id,
+                'active_ids': [record.id],
+                }
+            self._current = record.id
+        else:
+            data = {}
+            context = {}
+            pyson_ctx = {}
+            self._current = None
+        pyson_ctx['context'] = context
+        try:
+            self.disconnect_by_func(self.__class__.clicked)
+        except TypeError:
+            pass
+        self.connect('clicked', self.__class__.clicked, [data, context])
+        action = common.RPCExecute(
+            'model', 'ir.action', 'get_action_value', self.action_id,
+            context=context)
+        self.set_label(action['rec_name'])
+
+        decoder = PYSONDecoder(pyson_ctx)
+        domain = decoder.decode(action['pyson_domain'])
+        if action.get('pyson_search_value'):
+            domain = [domain, decoder.decode(action['pyson_search_value'])]
+        tab_domains = [(n, decoder.decode(d))
+            for n, d, c in action['domains'] if c]
+        if tab_domains:
+            label = ('%s\n' % action['rec_name']) + '\n'.join(
+                '%s (%%d)' % n for n, _ in tab_domains)
+        else:
+            label = '%s (%%d)' % action['rec_name']
+        if record and self.action_id in record.links_counts:
+            counter = record.links_counts[self.action_id]
+            self._set_label_counter(label, counter)
+        else:
+            counter = [0] * (len(tab_domains) or 1)
+            if record:
+                record.links_counts[self.action_id] = counter
+            if tab_domains:
+                for i, (_, tab_domain) in enumerate(tab_domains):
+                    common.RPCExecute(
+                        'model', action['res_model'], 'search_count',
+                        ['AND', domain, tab_domain], context=context,
+                        callback=functools.partial(
+                            self._set_count, idx=i, current=self._current,
+                            counter=counter, label=label))
+            else:
+                common.RPCExecute(
+                    'model', action['res_model'], 'search_count', domain,
+                    context=context, callback=functools.partial(
+                        self._set_count, current=self._current,
+                        counter=counter, label=label))
+
+    def _set_count(self, value, idx=0, current=None, counter=None, label=''):
+        if current != self._current:
+            return
+        try:
+            counter[idx] = value()
+        except common.RPCException:
+            pass
+        self._set_label_counter(label, counter)
+
+    def _set_label_counter(self, label, counter):
+        self.set_label(label % tuple(counter))
+        if self.attrs.get('empty') == 'hide':
+            if any(counter):
+                self.show()
+            else:
+                self.hide()
+
+    def clicked(self, data):
+        Action.execute(self.action_id, *data, keyword=True)

Reply via email to