diff --git a/CHANGELOG b/CHANGELOG index ebf7b514ed..2c5ee9fef0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add breadcrumb as title of window form * Display revision on dialog * Execute report asynchronously * Add support for Python 3.9 diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py index 0da761c1dd..895a9d787f 100644 --- a/tryton/gui/window/form.py +++ b/tryton/gui/window/form.py @@ -45,13 +45,13 @@ class Form(SignalEvent, TabContent): self.view_ids = attributes.get('view_ids') self.dialogs = [] - self.screen = Screen(self.model, **attributes) - self.screen.widget.show() - if not name: name = common.MODELNAME.get(model) self.name = name + self.screen = Screen(self.model, breadcrumb=[self.name], **attributes) + self.screen.widget.show() + self.create_tabcontent() self.set_buttons_sensitive() diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 8005756684..77774ac7c0 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -76,6 +76,7 @@ class Screen(SignalEvent): self.screen_container.alternate_view = attributes.get( 'alternate_view', False) self.widget = self.screen_container.widget_get() + self.breadcrumb = attributes.get('breadcrumb') or [] self.context_screen = None if attributes.get('context_model'): diff --git a/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/gui/window/view_form/view/form_gtk/many2many.py index 0a38ca6508..da14c99052 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py @@ -182,10 +182,14 @@ class Many2Many(Widget): context = self.field.get_context(self.record) # Remove the first tree view as mode is form only view_ids = self.attrs.get('view_ids', '').split(',')[1:] - return Screen(self.attrs['relation'], domain=domain, + model = self.attrs['relation'] + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + self.attrs.get('string') or common.MODELNAME.get(model)) + return Screen(model, domain=domain, view_ids=view_ids, mode=['form'], views_preload=self.attrs.get('views', {}), - context=context) + context=context, breadcrumb=breadcrumb) def _sig_edit(self): if not self.screen.current_record: @@ -202,7 +206,7 @@ class Many2Many(Widget): self.screen.current_record.cancel() # Force a display to clear the CellCache self.screen.display() - WinForm(screen, callback, title=self.attrs.get('string')) + WinForm(screen, callback) def _sig_new(self): screen = self._get_screen_form() @@ -217,7 +221,7 @@ class Many2Many(Widget): self.focus_out = False WinForm(screen, callback, new=True, save_current=True, - title=self.attrs.get('string'), rec_name=self.wid_text.get_text()) + rec_name=self.wid_text.get_text()) def _readonly_set(self, value): self._readonly = value diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index ee98d28d7f..5bb3ed3c2c 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -152,10 +152,15 @@ class Many2One(Widget): context = self.field.get_context(self.record) # Remove first tree view as mode is form only view_ids = self.attrs.get('view_ids', '').split(',')[1:] - return Screen(self.get_model(), domain=domain, context=context, + model = self.get_model() + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + self.attrs.get('string') or common.MODELNAME.get(model)) + return Screen(model, domain=domain, context=context, mode=['form'], view_ids=view_ids, views_preload=self.attrs.get('views', {}), readonly=self._readonly, - exclude_field=self.attrs.get('relation_field')) + exclude_field=self.attrs.get('relation_field'), + breadcrumb=breadcrumb) def sig_new(self, *args): model = self.get_model() @@ -171,7 +176,7 @@ class Many2One(Widget): screen.current_record.rec_name())) self.focus_out = True WinForm(screen, callback, new=True, save_current=True, - title=self.attrs.get('string'), rec_name=self.wid_text.get_text()) + rec_name=self.wid_text.get_text()) def sig_edit(self, entry=None, icon_pos=None, *args): model = self.get_model() @@ -204,8 +209,7 @@ class Many2One(Widget): force_change=True) self.focus_out = True self.changed = True - WinForm(screen, callback, save_current=True, - title=self.attrs.get('string')) + WinForm(screen, callback, save_current=True) return if not self._readonly: domain = self.field.domain_get(self.record) diff --git a/tryton/gui/window/view_form/view/form_gtk/one2many.py b/tryton/gui/window/view_form/view/form_gtk/one2many.py index 7a7c4368c8..7fe49531ec 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -156,14 +156,19 @@ class One2Many(Widget): frame.set_shadow_type(Gtk.ShadowType.OUT) vbox.pack_start(frame, expand=False, fill=True, padding=0) - self.screen = Screen(attrs['relation'], + model = attrs['relation'] + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + attrs.get('string') or common.MODELNAME.get(model)) + self.screen = Screen(model, mode=attrs.get('mode', 'tree,form').split(','), view_ids=attrs.get('view_ids', '').split(','), views_preload=attrs.get('views', {}), order=attrs.get('order'), row_activate=self._on_activate, exclude_field=attrs.get('relation_field', None), - limit=None) + limit=None, + breadcrumb=breadcrumb) self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0))) self.screen.signal_connect(self, 'record-message', self._sig_label) @@ -353,7 +358,7 @@ class One2Many(Widget): field_size = self.record.expr_eval(self.attrs.get('size')) or -1 field_size -= len(self.field.get_eval(self.record)) + 1 WinForm(self.screen, lambda a: update_sequence(), new=True, - many=field_size, title=self.attrs.get('string')) + many=field_size) def _new_product(self): fields = self.attrs['product'].split(',') @@ -414,8 +419,7 @@ class One2Many(Widget): return record = self.screen.current_record if record: - WinForm(self.screen, lambda a: None, - title=self.attrs.get('string')) + WinForm(self.screen, lambda a: None) def _sig_next(self, widget): if not self._validate(): 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 da8ae941da..e80abe81b8 100644 --- a/tryton/gui/window/view_form/view/list_gtk/widget.py +++ b/tryton/gui/window/view_form/view/list_gtk/widget.py @@ -838,9 +838,13 @@ class M2O(GenericText): return target_id = self.id_from_value(field.get(record)) + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + field.attrs.get('string') or common.MODELNAME.get(model)) screen = Screen(model, domain=domain, context=context, mode=['form'], view_ids=self.attrs.get('view_ids', '').split(','), - exclude_field=field.attrs.get('relation_field')) + exclude_field=field.attrs.get('relation_field'), + breadcrumb=breadcrumb) def open_callback(result): if result: @@ -853,11 +857,10 @@ class M2O(GenericText): callback() if target_id and target_id >= 0: screen.load([target_id]) - WinForm(screen, open_callback, save_current=True, - title=field.attrs.get('string')) + WinForm(screen, open_callback, save_current=True) else: WinForm(screen, open_callback, new=True, save_current=True, - title=field.attrs.get('string'), rec_name=text) + rec_name=text) def search_remote(self, record, field, text, callback=None): model = self.get_model(record, field) @@ -970,17 +973,20 @@ class O2M(GenericText): if not access['read']: return + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + field.attrs.get('string') or common.MODELNAME.get(relation)) screen = Screen(relation, mode=['tree', 'form'], view_ids=self.attrs.get('view_ids', '').split(','), - exclude_field=field.attrs.get('relation_field')) + exclude_field=field.attrs.get('relation_field'), + breadcrumb=breadcrumb) screen.pre_validate = bool(int(self.attrs.get('pre_validate', 0))) screen.group = group def open_callback(result): if callback: callback() - WinForm(screen, open_callback, view_type='tree', context=context, - title=field.attrs.get('string')) + WinForm(screen, open_callback, view_type='tree', context=context) class M2M(O2M): @@ -993,16 +999,20 @@ class M2M(O2M): context = field.get_context(record) domain = field.domain_get(record) + breadcrumb = list(self.view.screen.breadcrumb) + breadcrumb.append( + field.attrs.get('string') or common.MODELNAME.get(relation)) screen = Screen(relation, mode=['tree', 'form'], view_ids=self.attrs.get('view_ids', '').split(','), - exclude_field=field.attrs.get('relation_field')) + exclude_field=field.attrs.get('relation_field'), + breadcrumb=breadcrumb) screen.group = group def open_callback(result): if callback: callback() WinForm(screen, open_callback, view_type='tree', domain=domain, - context=context, title=field.attrs.get('string')) + context=context) class Selection(GenericText, SelectionMixin, PopdownMixin): diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index d784e280ff..26cce02732 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -1,5 +1,6 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +from itertools import chain import gettext from gi.repository import Gdk, Gtk, Pango @@ -30,9 +31,19 @@ class WinForm(NoModal, InfoBar): self.domain = domain self.context = context self.save_current = save_current - if not title: - title = MODELNAME.get(screen.model_name) - self.title = title + if screen.breadcrumb: + breadcrumb = list(screen.breadcrumb) + if title: + breadcrumb.append(title) + self.title = ' › '.join(chain( + (common.ellipsize(x, 30) for x in breadcrumb[-3:-1]), + breadcrumb[-1:])) + if len(breadcrumb) > 3: + self.title = '... › ' + self.title + else: + if not title: + title = MODELNAME.get(screen.model_name) + self.title = title self.prev_view = self.screen.current_view self.screen.screen_container.alternate_view = True self.screen.switch_view(view_type=view_type) diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py index 44ab9ee8cd..2003a49fc7 100644 --- a/tryton/gui/window/win_search.py +++ b/tryton/gui/window/win_search.py @@ -134,7 +134,8 @@ class WinSearch(NoModal): screen = Screen(self.model_name, domain=self.domain, context=self.context, order=self.order, mode=['form'], view_ids=view_ids, views_preload=self.views_preload, - exclude_field=self.exclude_field) + exclude_field=self.exclude_field, + breadcrumb=[self.title]) def callback(result): if result: @@ -144,9 +145,7 @@ class WinSearch(NoModal): else: self.callback(None) self.destroy() - WinForm( - screen, callback, new=True, save_current=True, - title=self.title) + WinForm(screen, callback, new=True, save_current=True) return if res: group = self.screen.group