From 7d4a991104a00c754a83ec2f7363ad1c8ac78a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Sun, 29 Jan 2023 00:56:28 +0100 Subject: [PATCH] Do record (pre)validation and saving on selection change for list-form views Closes #12025 --- sao/CHANGELOG | 1 + sao/src/view/list_form.js | 54 ++++++++++++------- tryton/CHANGELOG | 1 + .../gui/window/view_form/view/list_form.py | 45 ++++++++++++++-- 4 files changed, 78 insertions(+), 23 deletions(-) diff --git a/sao/CHANGELOG b/sao/CHANGELOG index c8487c996a..e0074e42cf 100644 --- a/sao/CHANGELOG +++ b/sao/CHANGELOG @@ -1,3 +1,4 @@ +* Do record (pre)validation and saving on selection change for list-form views * Eagerly read string value of selection fields * Do not select first record by default * Use ``&`` and ``|`` as boolean operator in search widget diff --git a/sao/src/view/list_form.js b/sao/src/view/list_form.js index 2529ef4465..6ebafd6e0e 100644 --- a/sao/src/view/list_form.js +++ b/sao/src/view/list_form.js @@ -119,28 +119,46 @@ } }, _select_row: function(event_) { - var current_view_form; - var view_form_idx = event_.data; - var view_form = this._view_forms[view_form_idx]; + var next_form_idx = event_.data; + var next_view_form = this._view_forms[next_form_idx]; - if (event_.shiftKey) { - for (const other_view_form of this._view_forms) { - if (other_view_forms.record === this.record) { - current_view_form = other_view_form; - break; + var prm = jQuery.when(); + if (this.record && (next_view_form.record != this.record)) { + if (!this.screen.group.parent) { + if (!this.record.validate( + this.get_fields(), false, false, false)) { + prm = jQuery.Deferred().reject(); + } else { + prm = this.record.save(); } + } else if (this.screen.attributes.pre_validate) { + prm = this.record.pre_validate(); } - this.select_records(i, view_form_idx); - } else { - if (!(event_.ctrlKey || event_.metaKey)) { - this.select_records(null, null); + } + + prm.done(() => { + var current_view_form; + + if (event_.shiftKey) { + for (const other_view_form of this._view_forms) { + if (other_view_forms.record === this.record) { + current_view_form = other_view_form; + break; + } + } + this.select_records(i, next_form_idx); + } else { + if (!(event_.ctrlKey || event_.metaKey)) { + this.select_records(null, null); + } + this.record = next_view_form.record; + next_view_form.el.parent() + .toggleClass('list-group-item-selected'); } - this.record = view_form.record; - view_form.el.parent().toggleClass('list-group-item-selected'); - } - if (current_view_form) { - this.record = current_view_form.record; - } + if (current_view_form) { + this.record = current_view_form.record; + } + }); } }); diff --git a/tryton/CHANGELOG b/tryton/CHANGELOG index bb64077982..4a0bdc7e72 100644 --- a/tryton/CHANGELOG +++ b/tryton/CHANGELOG @@ -1,3 +1,4 @@ +* Do record (pre)validation and saving on selection change for list-form views * Eagerly read string value of selection fields * Do not select first record by default * Use ``&`` and ``|`` as boolean operator in search widget diff --git a/tryton/tryton/gui/window/view_form/view/list_form.py b/tryton/tryton/gui/window/view_form/view/list_form.py index 9a7673fddc..8ae05651c8 100644 --- a/tryton/tryton/gui/window/view_form/view/list_form.py +++ b/tryton/tryton/gui/window/view_form/view/list_form.py @@ -1,6 +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 gi.repository import Gio, GObject, Gtk +from gi.repository import Gio, GLib, GObject, Gtk from tryton.common import common @@ -132,16 +132,51 @@ class ViewListForm(View): break def _row_selected(self, listbox, row): - if not row: - return - self.record = self._model.get_item(row.get_index()).record + previous_record = self.record + if (previous_record + and previous_record not in previous_record.group): + previous_record = None + + if row: + self.record = self._model.get_item(row.get_index()).record + else: + self.record = None + + def go_previous(): + self.record = previous_record + self.set_cursor() + + def save(): + if not previous_record.destroyed: + if not previous_record.save(): + go_previous() + + def pre_validate(): + if not previous_record.destroyed: + if not previous_record.pre_validate(): + go_previous() + + if previous_record and previous_record != self.record: + if not self.screen.parent: + if not previous_record.validate(self.get_fields()): + go_previous() + return True + GLib.idle_add(save) + elif self.screen.pre_validate: + GLib.idle_add(pre_validate) @common.idle_add def _select_show_row(self, index): # translate_coordinates requires that both widgets are realized if not self.listbox.get_realized(): return - self.listbox.unselect_all() + # unselect_all triggers a loop in _row_selected if the record is not + # valid + self.listbox.handler_block_by_func(self._select_show_row) + try: + self.listbox.unselect_all() + finally: + self.listbox.handler_unblock_by_func(self._select_show_row) row = self.listbox.get_row_at_index(index) if not row or not row.get_realized(): return