changeset 65aff6f1a7e9 in tryton:default
details: https://hg.tryton.org/tryton?cmd=changeset;node=65aff6f1a7e9
description:
        Improve note button

        * Add resources method to ModelStorage
        * Support badge on icon
        * Display unread and total of notes
        * Add two extra colors for icon

        issue8122
        review70561002
diffstat:

 CHANGELOG                                    |   3 +
 tryton/common/common.py                      |  31 +++++++--
 tryton/config.py                             |   2 +-
 tryton/gui/window/form.py                    |  91 ++++++++++++----------------
 tryton/gui/window/view_form/model/record.py  |  36 ++--------
 tryton/gui/window/view_form/screen/screen.py |  33 ++-------
 6 files changed, 82 insertions(+), 114 deletions(-)

diffs (325 lines):

diff -r 71de92ba03b6 -r 65aff6f1a7e9 CHANGELOG
--- a/CHANGELOG Fri Mar 22 11:57:42 2019 +0100
+++ b/CHANGELOG Fri Mar 22 12:16:36 2019 +0100
@@ -1,3 +1,6 @@
+* Display unread and total of notes
+* Support badge on icon
+* Use resources method
 * Replace Arrow by Image
 * Remove Fast Tabbing option
 * Remove usage of focus_chain
diff -r 71de92ba03b6 -r 65aff6f1a7e9 tryton/common/common.py
--- a/tryton/common/common.py   Fri Mar 22 11:57:42 2019 +0100
+++ b/tryton/common/common.py   Fri Mar 22 12:16:36 2019 +0100
@@ -111,10 +111,12 @@
             cls._tryton_icons.remove((icon['id'], icon['name']))
             del cls._name2id[icon['name']]
 
+    colors = CONFIG['icon.colors'].split(',')
+
     @classmethod
-    def get_pixbuf(cls, iconname, size=16, color=None):
+    def get_pixbuf(cls, iconname, size=16, color=None, badge=None):
         cls.register_icon(iconname)
-        if iconname not in cls._pixbufs[size]:
+        if iconname not in cls._pixbufs[(size, badge)]:
             if iconname in cls._icons:
                 data = cls._icons[iconname]
             elif iconname in cls._local_icons:
@@ -124,12 +126,24 @@
             else:
                 logger.error("Unknown icon %s" % iconname)
                 return
-            if color is None:
-                color = CONFIG['icon.color']
+            if not color:
+                color = cls.colors[0]
             try:
                 ET.register_namespace('', 'http://www.w3.org/2000/svg')
                 root = ET.fromstring(data)
                 root.attrib['fill'] = color
+                if badge:
+                    if not isinstance(badge, str):
+                        try:
+                            badge = cls.colors[badge]
+                        except IndexError:
+                            badge = color
+                    ET.SubElement(root, 'circle', {
+                            'cx': '20',
+                            'cy': '4',
+                            'r': '4',
+                            'fill': badge,
+                            })
                 data = ET.tostring(root)
             except ET.ParseError:
                 pass
@@ -141,12 +155,13 @@
                 Gtk.IconSize.DND: 12,
                 Gtk.IconSize.DIALOG: 48,
                 }.get(size, size)
-            cls._pixbufs[size][iconname] = data2pixbuf(data, width, height)
-        return cls._pixbufs[size][iconname]
+            pixbuf = data2pixbuf(data, width, height)
+            cls._pixbufs[(size, badge)][iconname] = pixbuf
+        return cls._pixbufs[(size, badge)][iconname]
 
     @classmethod
-    def get_image(cls, iconname, size=16, color=None):
-        pixbuf = cls.get_pixbuf(iconname, size, color)
+    def get_image(cls, iconname, size=16, color=None, badge=None):
+        pixbuf = cls.get_pixbuf(iconname, size, color, badge)
         image = Gtk.Image()
         image.set_from_pixbuf(pixbuf)
         return image
diff -r 71de92ba03b6 -r 65aff6f1a7e9 tryton/config.py
--- a/tryton/config.py  Fri Mar 22 11:57:42 2019 +0100
+++ b/tryton/config.py  Fri Mar 22 12:16:36 2019 +0100
@@ -55,7 +55,7 @@
             'client.limit': 1000,
             'client.check_version': True,
             'client.bus_timeout': 10 * 60,
-            'icon.color': '#3465a4',
+            'icon.colors': '#3465a4,#555753,#cc0000',
             'image.max_size': 10 ** 6,
             'bug.url': 'https://bugs.tryton.org/',
             'download.url': 'https://downloads.tryton.org/',
diff -r 71de92ba03b6 -r 65aff6f1a7e9 tryton/gui/window/form.py
--- a/tryton/gui/window/form.py Fri Mar 22 11:57:42 2019 +0100
+++ b/tryton/gui/window/form.py Fri Mar 22 12:16:36 2019 +0100
@@ -53,9 +53,9 @@
         self.screen.signal_connect(self, 'record-modified',
             lambda *a: GLib.idle_add(self._record_modified, *a))
         self.screen.signal_connect(self, 'record-saved', self._record_saved)
-        self.screen.signal_connect(self, 'attachment-count',
-                self._attachment_count)
-        self.screen.signal_connect(self, 'unread-note', self._unread_note)
+        self.screen.signal_connect(
+            self, 'resources',
+            lambda screen, resources: self.update_resources(resources))
 
         if res_id not in (None, False):
             if isinstance(res_id, int):
@@ -105,7 +105,7 @@
     def sig_attach(self, widget=None):
         def window(widget):
             return Attachment(
-                record, lambda: self.update_attachment_count(reload=True))
+                record, lambda: self.refresh_resources(reload=True))
 
         def add_file(widget):
             filenames = common.file_selection(_("Select"), multi=True)
@@ -139,61 +139,48 @@
         menu.connect('deactivate', self._popup_menu_hide, button)
         self.action_popup(button)
 
-    def update_attachment_count(self, reload=False):
-        record = self.screen.current_record
-        if record:
-            attachment_count = record.get_attachment_count(reload=reload)
-        else:
-            attachment_count = 0
-        self._attachment_count(None, attachment_count)
-
-    def _attachment_count(self, widget, signal_data):
-        label = _('Attachment(%d)') % signal_data
-        self.buttons['attach'].set_label(label)
-        if signal_data:
-            # FIXME
-            icon = 'tryton-attach'
-        else:
-            icon = 'tryton-attach'
-        image = common.IconFactory.get_image(icon, Gtk.IconSize.LARGE_TOOLBAR)
-        image.show()
-        self.buttons['attach'].set_icon_widget(image)
-        record = self.screen.current_record
-        self.buttons['attach'].props.sensitive = bool(
-            record.id >= 0 if record else False)
-
     def sig_note(self, widget=None):
         record = self.screen.current_record
         if not record or record.id < 0:
             return
         Note(record,
-            lambda: self.update_unread_note(reload=True))
+            lambda: self.refresh_resources(reload=True))
 
-    def update_unread_note(self, reload=False):
+    def refresh_resources(self, reload=False):
         record = self.screen.current_record
-        if record:
-            unread = record.get_unread_note(reload=reload)
-        else:
-            unread = 0
-        self._unread_note(None, unread)
+        self.update_resources(
+            record.get_resources(reload=reload) if record else None)
+
+    def update_resources(self, resources):
+        if not resources:
+            resources = {}
+        record = self.screen.current_record
+        sensitive = record.id >= 0 if record else False
 
-    def _unread_note(self, widget, signal_data):
-        label = _('Note(%d)') % signal_data
-        self.buttons['note'].set_label(label)
-        if signal_data:
-            # FIXME
-            icon = 'tryton-note'
+        def update(name, label, icon, badge):
+            button = self.buttons[name]
+            button.set_label(label)
+            image = common.IconFactory.get_image(
+                icon, Gtk.IconSize.LARGE_TOOLBAR, badge=badge)
+            image.show()
+            button.set_icon_widget(image)
+            button.props.sensitive = sensitive
+
+        attachment_count = resources.get('attachment_count', 0)
+        badge = 1 if attachment_count else None
+        label = _("Attachment (%s)") % attachment_count
+        update('attach', label, 'tryton-attach', badge)
+
+        note_count = resources.get('note_count', 0)
+        note_unread = resources.get('note_unread', 0)
+        if note_unread:
+            badge = 2
+        elif note_count:
+            badge = 1
         else:
-            icon = 'tryton-note'
-        image = common.IconFactory.get_image(icon, Gtk.IconSize.LARGE_TOOLBAR)
-        image.show()
-        self.buttons['note'].set_icon_widget(image)
-        record = self.screen.current_record
-        if not record or record.id < 0:
-            sensitive = False
-        else:
-            sensitive = True
-        self.buttons['note'].props.sensitive = sensitive
+            badge = None
+        label = _("Note (%d/%d)") % (note_unread, note_count)
+        update('note', label, 'tryton-note', badge)
 
     def sig_switch(self, widget=None):
         if not self.modified_save():
@@ -498,7 +485,7 @@
 
     def _record_saved(self, screen, signal_data):
         self.activate_save()
-        self.update_attachment_count()
+        self.refresh_resources()
 
     def modified_save(self):
         self.screen.save_tree_state()
@@ -711,7 +698,7 @@
         if not record or record.id < 0:
             return
         win_attach = Attachment(record,
-            lambda: self.update_attachment_count(reload=True))
+            lambda: self.refresh_resources(reload=True))
         if info == 0:
             if selection.get_uris():
                 for uri in selection.get_uris():
diff -r 71de92ba03b6 -r 65aff6f1a7e9 tryton/gui/window/view_form/model/record.py
--- a/tryton/gui/window/view_form/model/record.py       Fri Mar 22 11:57:42 
2019 +0100
+++ b/tryton/gui/window/view_form/model/record.py       Fri Mar 22 12:16:36 
2019 +0100
@@ -28,8 +28,7 @@
         self.state_attrs = {}
         self.modified_fields = {}
         self._timestamp = None
-        self.attachment_count = -1
-        self.unread_note = -1
+        self.resources = None
         self.button_clicks = {}
         self.next = {}  # Used in Group list
         self.value = {}
@@ -602,34 +601,15 @@
             if context:
                 value.context = self.expr_eval(context)
 
-    def get_attachment_count(self, reload=False):
-        if self.id < 0:
-            return 0
-        if self.attachment_count < 0 or reload:
+    def get_resources(self, reload=False):
+        if self.id >= 0 and (not self.resources or reload):
             try:
-                self.attachment_count = RPCExecute('model', 'ir.attachment',
-                    'search_count', [
-                        ('resource', '=',
-                            '%s,%s' % (self.model_name, self.id)),
-                        ], context=self.get_context())
+                self.resources = RPCExecute(
+                    'model', self.model_name, 'resources', self.id,
+                    context=self.get_context())
             except RPCException:
-                return 0
-        return self.attachment_count
-
-    def get_unread_note(self, reload=False):
-        if self.id < 0:
-            return 0
-        if self.unread_note < 0 or reload:
-            try:
-                self.unread_note = RPCExecute('model', 'ir.note',
-                    'search_count', [
-                        ('resource', '=',
-                            '%s,%s' % (self.model_name, self.id)),
-                        ('unread', '=', True),
-                        ], context=self.get_context())
-            except RPCException:
-                return 0
-        return self.unread_note
+                pass
+        return self.resources
 
     def get_button_clicks(self, name):
         if self.id < 0:
diff -r 71de92ba03b6 -r 65aff6f1a7e9 
tryton/gui/window/view_form/screen/screen.py
--- a/tryton/gui/window/view_form/screen/screen.py      Fri Mar 22 11:57:42 
2019 +0100
+++ b/tryton/gui/window/view_form/screen/screen.py      Fri Mar 22 12:16:36 
2019 +0100
@@ -436,35 +436,18 @@
             pos = 0
         self.signal('record-message', (pos, len(self.group) + self.offset,
             self.search_count, record and record.id))
-        attachment_count = 0
-        if record and record.attachment_count > 0:
-            attachment_count = record.attachment_count
-        self.signal('attachment-count', attachment_count)
-        unread_note = 0
-        if record and record.unread_note > 0:
-            unread_note = record.unread_note
-        self.signal('unread-note', unread_note)
-        # update attachment-count after 1 second
-        GLib.timeout_add(1000, self.update_attachment, record)
-        GLib.timeout_add(1000, self.update_note, record)
+        self.signal('resources', record.resources if record else None)
+        # update resources after 1 second
+        GLib.timeout_add(1000, self._update_resources, record)
         return True
 
     current_record = property(__get_current_record, __set_current_record)
 
-    def update_attachment(self, record):
-        if record != self.current_record:
-            return False
-        if record and self.signal_connected('attachment-count'):
-            attachment_count = record.get_attachment_count()
-            self.signal('attachment-count', attachment_count)
-        return False
-
-    def update_note(self, record):
-        if record != self.current_record:
-            return False
-        if record and self.signal_connected('unread-note'):
-            unread_note = record.get_unread_note()
-            self.signal('unread-note', unread_note)
+    def _update_resources(self, record):
+        if (record
+                and record == self.current_record
+                and self.signal_connected('resources')):
+            self.signal('resources', record.get_resources())
         return False
 
     def destroy(self):

Reply via email to