diff --git a/CHANGELOG b/CHANGELOG index 15a33d9e6c..f006e0503b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Support icon of type URL * Allow sending email with existing attachments * Add paths and model context to action data * Add indentation in CSV export of tree diff --git a/tryton/common/common.py b/tryton/common/common.py index 83a0f99a80..374363b7a2 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -17,7 +17,7 @@ try: from http import HTTPStatus except ImportError: from http import client as HTTPStatus -from functools import wraps +from functools import wraps, lru_cache from tryton.config import CONFIG from tryton.config import TRYTON_ICON, PIXMAPS_DIR import sys @@ -169,6 +169,36 @@ class IconFactory: image.set_from_pixbuf(pixbuf) return image + @classmethod + def _convert_url(cls, value, size=16, size_param=None): + if not value: + return + parts = urllib.parse.urlsplit(value) + parts = list(parts) + if not parts[0]: + parts[0] = 'https' if rpc.CONNECTION.ssl else 'http' + if not parts[1]: + hostname = get_hostname(CONFIG['login.host']) + port = get_port(CONFIG['login.host']) + parts[1] = '%s:%s' % (hostname, port) + if size_param: + query = urllib.parse.parse_qsl(parts[4]) + query.append((size_param, size)) + parts[4] = urllib.parse.urlencode(query) + return urllib.parse.urlunsplit(parts) + + @classmethod + @lru_cache(maxsize=CONFIG['image.cache_size']) + def get_pixbuf_url(cls, url, size=16, size_param=None): + if not url: + return + url = cls._convert_url(url, size, size_param=size_param) + try: + with urllib.request.urlopen(url) as response: + return data2pixbuf(response.read(), size, size) + except urllib.error.URLError: + logger.info("Can not fetch %s", url, exc_info=True) + IconFactory.load_local_icons() diff --git a/tryton/config.py b/tryton/config.py index 2ad91e2491..3fe2febabc 100644 --- a/tryton/config.py +++ b/tryton/config.py @@ -60,6 +60,7 @@ class ConfigManager(object): 'calendar.colors': '#fff,#3465a4', 'graph.color': '#3465a4', 'image.max_size': 10 ** 6, + 'image.cache_size': 1024, 'bug.url': 'https://bugs.tryton.org/', 'download.url': 'https://downloads-cdn.tryton.org/', 'download.frequency': 60 * 60 * 8, diff --git a/tryton/gui/window/view_form/view/form_gtk/state_widget.py b/tryton/gui/window/view_form/view/form_gtk/state_widget.py index fb67b7b2b9..300f7f3d31 100644 --- a/tryton/gui/window/view_form/view/form_gtk/state_widget.py +++ b/tryton/gui/window/view_form/view/form_gtk/state_widget.py @@ -66,8 +66,13 @@ class Image(StateMixin, Gtk.Image): if name in record.group.fields: field = record.group.fields[name] name = field.get(record) - self.set_from_pixbuf(common.IconFactory.get_pixbuf( - name, int(self.attrs.get('size', 48)))) + size = int(self.attrs.get('size', 48)) + if self.attrs.get('type') == 'url': + pixbuf = common.IconFactory.get_pixbuf_url( + name, size=size, size_param=self.attrs.get('url_size')) + else: + pixbuf = common.IconFactory.get_pixbuf(name, size) + self.set_from_pixbuf(pixbuf) class Frame(StateMixin, Gtk.Frame): diff --git a/tryton/gui/window/view_form/view/list_gtk/widget.py b/tryton/gui/window/view_form/view/list_gtk/widget.py index eebaf9b1b0..37e462e71c 100644 --- a/tryton/gui/window/view_form/view/list_gtk/widget.py +++ b/tryton/gui/window/view_form/view/list_gtk/widget.py @@ -185,7 +185,12 @@ class Affix(Cell): value = record[self.icon].get_client(record) or '' else: value = self.icon - pixbuf = common.IconFactory.get_pixbuf(value, Gtk.IconSize.BUTTON) + if self.attrs.get('icon_type') == 'url': + pixbuf = common.IconFactory.get_pixbuf_url( + value, size_param=self.attrs.get('url_size')) + else: + pixbuf = common.IconFactory.get_pixbuf( + value, Gtk.IconSize.BUTTON) cell.set_property('pixbuf', pixbuf) else: text = self.attrs.get('string', '')