details:   https://code.tryton.org/tryton/commit/027042dcaa8d
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu Aug 06 14:53:51 2026 +0200
description:
        Edit selected One2Many rows at once

        Closes #14997
diffstat:

 sao/CHANGELOG                                                |   1 +
 sao/src/view/form.js                                         |  27 ++++++++---
 sao/src/window.js                                            |   4 +
 tryton/CHANGELOG                                             |   1 +
 tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py |  22 +++++++--
 tryton/tryton/gui/window/win_form.py                         |   6 ++-
 6 files changed, 48 insertions(+), 13 deletions(-)

diffs (144 lines):

diff -r 42067e83b4f7 -r 027042dcaa8d sao/CHANGELOG
--- a/sao/CHANGELOG     Thu Aug 06 09:46:51 2026 +0200
+++ b/sao/CHANGELOG     Thu Aug 06 14:53:51 2026 +0200
@@ -1,3 +1,4 @@
+* Edit the selected One2Many rows sequentially
 * Support filename extension for Binary field
 * Use record name as fallback for filename of Binary field
 * Support filters attribute for binary and image widgets
diff -r 42067e83b4f7 -r 027042dcaa8d sao/src/view/form.js
--- a/sao/src/view/form.js      Thu Aug 06 09:46:51 2026 +0200
+++ b/sao/src/view/form.js      Thu Aug 06 14:53:51 2026 +0200
@@ -4010,16 +4010,29 @@
                 return;
             }
             return this.validate().then(() => {
-                var record = this.screen.current_record;
-                if (record) {
+                let records = Array.from(this.screen.selected_records);
+                let size = records.length;
+                if (size) {
                     if (this._popup) {
                         return;
-                    } else {
-                        this._popup = true;
                     }
-                    new Sao.Window.Form(this.screen, () => {
-                        this._popup = false;
-                    });
+                    let edit_next_record = () => {
+                        if (records.length) {
+                            this.screen.current_record = records.shift();
+                            this._popup = true;
+                            new Sao.Window.Form(this.screen, (result) => {
+                                this._popup = false;
+                                if (!result) {
+                                    records.length = 0;
+                                }
+                            }, {
+                                title: (size > 1 ?
+                                    `(${size - records.length}/${size})` : ''),
+                                on_destroy: edit_next_record,
+                            });
+                        }
+                    };
+                    edit_next_record();
                 }
             });
         },
diff -r 42067e83b4f7 -r 027042dcaa8d sao/src/window.js
--- a/sao/src/window.js Thu Aug 06 09:46:51 2026 +0200
+++ b/sao/src/window.js Thu Aug 06 14:53:51 2026 +0200
@@ -124,6 +124,7 @@
             this.domain = kwargs.domain || null;
             this.context = kwargs.context || null;
             this.save_current = kwargs.save_current;
+            this.on_destroy = kwargs.on_destroy;
             var title_prm = jQuery.when(kwargs.title || '').then(
                 title => {
                     if (screen.breadcrumb.length) {
@@ -683,6 +684,9 @@
                 this.screen.switch_view(this.prev_view.view_type);
             }
             this.el.modal('hide');
+            if (this.on_destroy) {
+                this.el.on('hidden.bs.modal', () => this.on_destroy());
+            }
         }
     });
 
diff -r 42067e83b4f7 -r 027042dcaa8d tryton/CHANGELOG
--- a/tryton/CHANGELOG  Thu Aug 06 09:46:51 2026 +0200
+++ b/tryton/CHANGELOG  Thu Aug 06 14:53:51 2026 +0200
@@ -1,3 +1,4 @@
+* Edit the selected One2Many rows sequentially
 * Support filename extension for Binary field
 * Use record name as fallback for filename of Binary field
 * Support filters attribute for binary and image widgets
diff -r 42067e83b4f7 -r 027042dcaa8d 
tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py      Thu Aug 
06 09:46:51 2026 +0200
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/one2many.py      Thu Aug 
06 14:53:51 2026 +0200
@@ -464,16 +464,28 @@
             return
         if not self._validate():
             return
-        record = self.screen.current_record
-        if record:
+        records = list(self.screen.selected_records)
+        size = len(records)
+        if records:
             if self._popup:
                 return
-            else:
-                self._popup = True
 
             def callback(result):
                 self._popup = False
-            WinForm(self.screen, callback, prev_view=self.screen.current_view)
+                if not result:
+                    records.clear()
+
+            def edit_next_record():
+                if records:
+                    self.screen.current_record = records.pop(0)
+                    self._popup = True
+                    WinForm(
+                        self.screen, callback,
+                        title=('(%s/%s)' % (size - len(records), size)
+                            if size > 1 else ''),
+                        prev_view=self.screen.current_view,
+                        on_destroy=edit_next_record)
+            edit_next_record()
 
     def _sig_next(self, widget):
         if not self._validate():
diff -r 42067e83b4f7 -r 027042dcaa8d tryton/tryton/gui/window/win_form.py
--- a/tryton/tryton/gui/window/win_form.py      Thu Aug 06 09:46:51 2026 +0200
+++ b/tryton/tryton/gui/window/win_form.py      Thu Aug 06 14:53:51 2026 +0200
@@ -24,7 +24,8 @@
 
     def __init__(self, screen, callback=None, view_type='form',
             new=False, many=0, domain=None, context=None,
-            save_current=False, title='', defaults=None, prev_view=SENTINEL):
+            save_current=False, title='', defaults=None, prev_view=SENTINEL,
+            on_destroy=None):
         tooltips = common.Tooltips()
         NoModal.__init__(self)
 
@@ -37,6 +38,7 @@
         self.domain = domain
         self.context = context
         self.save_current = save_current
+        self.on_destroy = on_destroy
         if screen.breadcrumb:
             breadcrumb = list(screen.breadcrumb)
             if title:
@@ -528,6 +530,8 @@
         if getattr(self, 'win', None):
             self.win.destroy()
         NoModal.destroy(self)
+        if self.on_destroy:
+            self.on_destroy()
 
     def show(self):
         self.win.show()

Reply via email to