From 09854b887b9e7d69f844f0c4b8da5dbf65556c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Oct 2012 22:56:50 +0200 Subject: [PATCH 01/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 40db171ffc..420e049fc2 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.0" +VERSION = "2.6.1" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From f65821b2496de1e5f7a90d8bfaa65f0c7ddf98a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 30 Oct 2012 13:04:27 +0100 Subject: [PATCH 02/78] Fix domain parser to not always strip default operator review585002 (transplanted from 548cb6aeab1f9cb6aa456a7221e79c53de6f6cbe) --- tryton/common/domain_parser.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index 08ec81efb1..9f625fc3c8 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -747,7 +747,9 @@ class DomainParser(object): operator = '!' value = value.replace('%%', '%') def_operator = default_operator(field) - if def_operator in operator: + if (def_operator == operator.strip() + or (def_operator in operator + and 'not' in operator)): operator = operator.rstrip(def_operator ).replace('not', '!').strip() if operator.endswith('in'): @@ -956,6 +958,10 @@ def test_string(): 'string': '(Sur)Name', 'type': 'char', }, + 'date': { + 'string': 'Date', + 'type': 'date', + }, }) assert dom.string([('name', '=', 'Doe')]) == 'Name: =Doe' assert dom.string([('name', 'ilike', '%Doe%')]) == 'Name: Doe' @@ -983,6 +989,8 @@ def test_string(): 'Name: Doe (Name: John or Name: Jane)' assert dom.string([]) == '' assert dom.string([('surname', 'ilike', '%Doe%')]) == '"(Sur)Name": Doe' + assert dom.string([('date', '>=', datetime.date(2012, 10, 24))]) == \ + 'Date: >=10/24/2012' def test_group(): From d16dfcc110acfee1d3604a79e3b9c869e6330c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 2 Nov 2012 16:19:00 +0100 Subject: [PATCH 03/78] Fix domain parser when value is a list review591002 (transplanted from 61d834ed6a8c49c89c29b85b3134ae28112cb9ee) --- tryton/common/domain_parser.py | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index 9f625fc3c8..74970766b2 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -569,9 +569,15 @@ def complete_value(field, value): yield True def complete_selection(): + test_value = value + if isinstance(value, list): + test_value = value[-1] for svalue, test in field['selection']: - if test.lower().startswith(value.lower()): - yield svalue + if test.lower().startswith(test_value.lower()): + if test_value == value: + yield svalue + else: + yield value[:-1] + [svalue] def complete_datetime(): yield datetime.date.today() @@ -594,6 +600,23 @@ def complete_value(field, value): return completes.get(field['type'], lambda: [])() +def test_complete_selection(): + field = { + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + } + for value, result in ( + ('m', ['male']), + ('test', []), + ('', ['male', 'female']), + (['male', 'f'], [['male', 'female']]), + ): + assert list(complete_value(field, value)) == result + + def parenthesize(tokens): "Nest tokens according to parenthesis" for token in tokens: @@ -944,7 +967,10 @@ class DomainParser(object): (field['name'], '<', rvalue), ]) continue - value = convert_value(field, value) + if isinstance(value, list): + value = [convert_value(field, v) for v in value] + else: + value = convert_value(field, value) yield field['name'], operator, value @@ -1077,6 +1103,15 @@ def test_parse_clause(): 'name': 'integer', 'type': 'integer', }, + 'selection': { + 'string': 'Selection', + 'name': 'selection', + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + }, }) assert rlist(dom.parse_clause([('John',)])) == [ ('rec_name', 'ilike', '%John%')] @@ -1090,6 +1125,10 @@ def test_parse_clause(): assert rlist(dom.parse_clause([('Name', '!', ['John', 'Jane'])])) == [ ('name', 'not in', ['John', 'Jane']), ] + assert rlist(dom.parse_clause([('Selection', None, ['Male', 'Female'])])) \ + == [ + ('selection', 'in', ['male', 'female']) + ] assert rlist(dom.parse_clause([('Integer', None, '3..5')])) == [[ ('integer', '>=', 3), ('integer', '<', 5), From db0708a4718ba82001c274313968a89d651179d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 2 Nov 2012 16:20:04 +0100 Subject: [PATCH 04/78] Fix Char.translate_widget_set when value is None review587004 (transplanted from 4b45f57716e5a9576db6c02bc16a51e77daf6aef) --- tryton/gui/window/view_form/view/form_gtk/char.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/char.py b/tryton/gui/window/view_form/view/form_gtk/char.py index d29df108db..c29062316e 100644 --- a/tryton/gui/window/view_form/view/form_gtk/char.py +++ b/tryton/gui/window/view_form/view/form_gtk/char.py @@ -57,7 +57,7 @@ class Char(WidgetInterface, TranslateMixin): @staticmethod def translate_widget_set(widget, value): - widget.set_text(value) + widget.set_text(value or '') @staticmethod def translate_widget_get(widget): From ec084de93d35327ae881f473a3864bce92538785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 6 Nov 2012 17:43:42 +0100 Subject: [PATCH 05/78] Set the date before calling get_text DateEntry doesn't manage some leaving key press event like Return, Tab etc. since changeset b2cc6f966070 EditableTreeView must set the date on the DateEntry before using get_text. issue2872 review591005 (transplanted from d02d38096828571fd917a16d15d3fe580cce6179) --- tryton/gui/window/view_form/view/list_gtk/editabletree.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index e65547f6a2..a38b8542f2 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -7,6 +7,7 @@ import gobject from itertools import islice, cycle from tryton.common import MODELACCESS +from tryton.common.date_widget import DateEntry _ = gettext.gettext @@ -145,6 +146,8 @@ class EditableTreeView(TreeView): if event.keyval in self.leaving_events or leaving: if isinstance(entry, gtk.Entry): + if isinstance(entry, DateEntry): + entry.date_get() txt = entry.get_text() else: txt = entry.get_active_text() @@ -257,6 +260,8 @@ class EditableTreeView(TreeView): model = self.get_model() record = model.get_value(model.get_iter(path), 0) if isinstance(entry, gtk.Entry): + if isinstance(entry, DateEntry): + entry.date_get() self.on_quit_cell(record, column.name, entry.get_text()) elif isinstance(entry, (gtk.ComboBoxEntry, gtk.ComboBox)): self.on_quit_cell(record, column.name, entry.get_active_text()) From 722bfab6576ae34144fd1109d5430cfb650a6fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 7 Nov 2012 12:42:05 +0100 Subject: [PATCH 06/78] Add missing call to super in Reference._set_button_sensitive (transplanted from ec0e7ce137ffbd5af9f1a2b2a80eae88c60bbe49) --- tryton/gui/window/view_form/view/form_gtk/reference.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/gui/window/view_form/view/form_gtk/reference.py b/tryton/gui/window/view_form/view/form_gtk/reference.py index 1323718747..b546c750ac 100644 --- a/tryton/gui/window/view_form/view/form_gtk/reference.py +++ b/tryton/gui/window/view_form/view/form_gtk/reference.py @@ -71,6 +71,7 @@ class Reference(Many2One): self.widget.set_focus_chain([self.widget_combo, self.wid_text]) def _set_button_sensitive(self): + super(Reference, self)._set_button_sensitive() self.widget_combo.set_sensitive(not self._readonly) @property From f79bd986bf0ac385a7d22eba0ef46e73d942017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 7 Nov 2012 12:42:49 +0100 Subject: [PATCH 07/78] Don't open calendar if DateEntry is not editable (transplanted from ad9c8341d2eef843a1f5046f23967e05e7f65d44) --- tryton/common/date_widget.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/common/date_widget.py b/tryton/common/date_widget.py index 7a26a9d0e7..54d8ea97de 100644 --- a/tryton/common/date_widget.py +++ b/tryton/common/date_widget.py @@ -266,6 +266,8 @@ class DateEntry(gtk.Entry): return False def cal_open(self, *args): + if not self.get_editable(): + return False parent = self.get_toplevel() dialog = gtk.Dialog(_('Date Selection'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, From 31f15548d2791da5e92d145458b31d078177279d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Nov 2012 10:34:41 +0100 Subject: [PATCH 08/78] Improve test on focused widget issue2856 review585005 (transplanted from f5ada17e858e1d14ffdc5b80e46cafaa2151eef4) --- tryton/gui/window/view_form/view/form.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index df653171dd..c6653491ec 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -82,7 +82,9 @@ class ViewForm(ParserView): field = record.group.fields[name] for widget in widgets: if (not focused_widget - or widget.widget.get_focus_child()): + or widget.widget.is_focus() + or (isinstance(widget.widget, gtk.Container) + and widget.widget.get_focus_child())): widget.set_value(record, field) def sel_ids_get(self): From 33d18e73eef72ec3765aba129969a98733b8ed88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Nov 2012 18:50:16 +0100 Subject: [PATCH 09/78] Record.get_eval must return only loaded values and validate only fields Domain inversion should not have fields that are not loaded otherwise the inversion could be wrong. issue2865 review583003 (transplanted from 4d2bd7127a51862ab1293e8cdc4cf9f8bf217945) --- tryton/common/domain_inversion.py | 4 ++-- tryton/gui/window/view_form/model/record.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 27743297b8..1b72db6907 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -53,11 +53,11 @@ def eval_leaf(part, context, boolop=operator.and_): # In the case where the leaf concerns a m2o then having a value in the # evaluation context is deemed suffisant return bool(context.get(field.split('.')[0])) - if operand == '=' and not context[field] and boolop == operator.and_: + if operand == '=' and not context.get(field) and boolop == operator.and_: # We should consider that other domain inversion will set a correct # value to this field return True - context_field = context[field] + context_field = context.get(field) if isinstance(context_field, datetime.date) and not value: if isinstance(context_field, datetime.datetime): value = datetime.datetime.min diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index adb455b58d..da0ed7874a 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -249,6 +249,8 @@ class Record(SignalEvent): self._check_load() value = {} for name, field in self.group.fields.iteritems(): + if name not in self._loaded and self.id >= 0: + continue value[name] = field.get_eval(self, check_load=check_load) value['id'] = self.id return value @@ -460,7 +462,7 @@ class Record(SignalEvent): else: for field in fields: self[field] - self.validate([]) + self.validate(fields or []) def expr_eval(self, expr, check_load=False): if not isinstance(expr, basestring): From 4babc7b5cc5623218e077a7e1255722e3a82268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Nov 2012 19:49:00 +0100 Subject: [PATCH 10/78] Don't untimezone fallback date for converting datetime (transplanted from aa2764ccc856dd2c589caf1f02e957c32211c79a) --- tryton/common/domain_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index 74970766b2..b2952d80e1 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -220,8 +220,8 @@ def convert_value(field, value): date_format() + ' ' + time_format(field))[:6])) except ValueError: try: - return untimezoned_date(datetime.datetime(*time.strptime(value, - date_format())[:6])) + return datetime.datetime(*time.strptime(value, + date_format())[:6]) except ValueError: return except TypeError: From 609945f019a79e0f7173c65fabe42faf4fde843c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 16 Nov 2012 11:03:43 +0100 Subject: [PATCH 11/78] Reset rec_name for on_change_with calls issue2888 review594006 (transplanted from ea3353be76ad7370364874c1d08c767b15b49e8e) --- tryton/gui/window/view_form/model/record.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index da0ed7874a..fccfb1cebc 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -549,6 +549,11 @@ class Record(SignalEvent): continue fieldnames.add(fieldname) values.update(self._get_on_change_args(on_change_with)) + if isinstance(self.group.fields[fieldname], (fields.M2OField, + fields.ReferenceField)): + field_rec_name = fieldname + '.rec_name' + if field_rec_name in self.value: + del self.value[field_rec_name] if fieldnames: try: result = RPCExecute('model', self.model_name, 'on_change_with', From eaf55bc8d026994b0dbbea61f1e078b3b5e679a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 5 Dec 2012 13:31:10 +0100 Subject: [PATCH 12/78] Manage enter on Button as a leave issue2879 review597004 --- tryton/gui/window/view_form/view/form.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index c6653491ec..653751c96e 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -22,6 +22,7 @@ class ViewForm(ParserView): if isinstance(widget, gtk.Button): widget.connect('clicked', self.button_clicked) widget.set_focus_on_click(False) + widget.connect('enter-notify-event', self.leave) # Force to display the first time it switches on a page # This avoids glitch in position of widgets From 43151c303b564f88c8597a02c0b7a40af9cfaaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 22 Nov 2012 23:14:28 +0100 Subject: [PATCH 13/78] Process close of WinForm as cancel if button exists review597002 (transplanted from 86b2d51967d81d1f1995af668b7383725f2f08c2) --- tryton/gui/window/win_form.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index 5d5f4ff0a7..6f1ebab6fd 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -392,6 +392,8 @@ class WinForm(NoModal): def close(self, widget): widget.emit_stop_by_name('close') + if self.but_cancel: + self.response(self.win, gtk.RESPONSE_CANCEL) return True def response(self, win, response_id): From ffd638f6ac4609543dc866ca67b4274363bc3a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Sun, 25 Nov 2012 18:43:40 +0100 Subject: [PATCH 14/78] Do not execute button action if the record can not be saved review593002 (transplanted from 348cf7a661a46cf7e86d0155e84da6c4278cda0b) --- tryton/gui/window/view_form/screen/screen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 27d2f2afc1..734672859c 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -809,7 +809,8 @@ class Screen(SignalEvent): if button.get('confirm', False) and not sur(button['confirm']): return record = self.current_record - record.save(force_reload=False) + if not record.save(force_reload=False): + return context = record.context_get() try: action_id = RPCExecute('model', self.model_name, button['name'], From 837c47d376a80e9758e3bcb6bc31268e70326303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Dec 2012 00:11:55 +0100 Subject: [PATCH 15/78] Add missing parenthesis on test in O2M.set_on_change issue2917 (transplanted from b76788d09e04a0a80f5fccb26d5a505bdeb35c7d) --- tryton/gui/window/view_form/model/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index bc615150e6..3acd334ae1 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -709,7 +709,7 @@ class O2MField(CharField): record.value[self.name].remove(record2, signal=False, force_remove=True) - if value and value.get('add') or value.get('update', []): + if value and (value.get('add') or value.get('update', [])): record.value[self.name].add_fields(fields, signal=False) for vals in value.get('add', []): new_record = record.value[self.name].new(default=False) From c6a4f4f39550492892bd90d529514df3dda26c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 13 Dec 2012 19:06:01 +0100 Subject: [PATCH 16/78] Copy also tryton locale on win32 as directory is clean before issue2921 review597006 (transplanted from e5cdaf0a7ba1fd96593138d905bebe50de6c5663) --- setup.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/setup.py b/setup.py index d2c9e6f133..d63124590c 100644 --- a/setup.py +++ b/setup.py @@ -251,6 +251,11 @@ if os.name == 'nt': if os.path.isdir(os.path.join(gtk_dir, 'share', 'locale', lang)): shutil.copytree(os.path.join(gtk_dir, 'share', 'locale', lang), os.path.join(dist_dir, 'share', 'locale', lang)) + if os.path.isdir(os.path.join(os.path.dirname(__file__), + 'share', 'locale', lang)): + shutil.copytree(os.path.join(os.path.dirname(__file__), + 'share', 'locale', lang), + os.path.join(dist_dir, 'share', 'locale', lang)) if os.path.isdir(os.path.join(dist_dir, 'share', 'themes', 'MS-Windows')): @@ -369,6 +374,11 @@ elif sys.platform == 'darwin': if os.path.isdir(os.path.join(gtk_dir, 'share', 'locale', lang)): shutil.copytree(os.path.join(gtk_dir, 'share', 'locale', lang), os.path.join(resources_dir, 'share', 'locale', lang)) + if os.path.isdir(os.path.join(os.path.dirname(__file__), + 'share', 'locale', lang)): + shutil.copytree(os.path.join(os.path.dirname(__file__), + 'share', 'locale', lang), + os.path.join(resources_dir, 'share', 'locale', lang)) # fix pathes within shared libraries for library in chain( From 8cc892a79617a4c297b408ec1c97ca2f0fa9d0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 16:29:45 +0100 Subject: [PATCH 17/78] Prepare release 2.6.1 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 73d4beaa52..726c8686e4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.1 - 2012-12-23 +* Bug fixes (see mercurial logs for details) + Version 2.6.0 - 2012-10-22 * Bug fixes (see mercurial logs for details) * Allow to paste in editable list view From 4d2a72daaf0b7efc963c684539ba98e7eef6f840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 16:29:46 +0100 Subject: [PATCH 18/78] Added tag 2.6.1 for changeset 89062be47c1b --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index c1cb65ce05..11d725bd3a 100644 --- a/.hgtags +++ b/.hgtags @@ -7,3 +7,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 5364f8ca6cd2cccfb5f7f39c69bb20bae2b5f495 2.2.0 fe15da23f7333e0e90d2693aadddf6bed53ed602 2.4.0 d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 +89062be47c1b38757e60cf549c3dbcaae1089385 2.6.1 From 4500b75f4d4b9279a6b2bfe5b32b195f5ca7befe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 16:30:18 +0100 Subject: [PATCH 19/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 420e049fc2..72d0205bbb 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.1" +VERSION = "2.6.2" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From f20070b3843f4ccbac11025de8861c7fe2e194ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 22:57:12 +0100 Subject: [PATCH 20/78] Disable main_iteration on RPC query from field RPC query from field could happen during a GTK event. review619002 (transplanted from db149f280d6053d50dd7dd230ce744d9ae397acd) --- tryton/gui/window/view_form/model/field.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 3acd334ae1..158981bd0f 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -421,7 +421,7 @@ class M2OField(CharField): if not rec_name and value >= 0: try: result, = RPCExecute('model', self.attrs['relation'], 'read', - [value], ['rec_name']) + [value], ['rec_name'], main_iteration=False) except RPCException: return False rec_name = result['rec_name'] or '' @@ -649,7 +649,8 @@ class O2MField(CharField): if field_names: try: fields.update(RPCExecute('model', self.attrs['relation'], - 'fields_get', field_names, context=context)) + 'fields_get', field_names, + main_iteration=False, context=context)) except RPCException: return False @@ -692,7 +693,8 @@ class O2MField(CharField): field_names.append(fieldname) try: fields = RPCExecute('model', self.attrs['relation'], - 'fields_get', field_names, context=context) + 'fields_get', field_names, + main_iteration=False, context=context) except RPCException: return False @@ -855,7 +857,7 @@ class ReferenceField(CharField): if not rec_name and ref_id >= 0: try: result, = RPCExecute('model', ref_model, 'read', [ref_id], - ['rec_name']) + ['rec_name'], main_iteration=False) except RPCException: return rec_name = result['rec_name'] @@ -913,7 +915,8 @@ class BinaryField(CharField): context = record.context_get() try: values, = RPCExecute('model', record.model_name, 'read', - [record.id], [self.name], context=context) + [record.id], [self.name], main_iteration=False, + context=context) except RPCException: return '' _, filename = tempfile.mkstemp(prefix='tryton_') From ea9735e54f93a9de21ceb5af5a567c82a9d24c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 3 Jan 2013 16:29:35 +0100 Subject: [PATCH 21/78] Delete takes now a list of ids (transplanted from efe9c59c325b57386fdd3afdfa5cb4444e0cb0d4) --- tryton/gui/window/win_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index 79dfce9395..1fc34e16c2 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -337,7 +337,7 @@ class WinExport(NoModal): return None export_id = model.get_value(i, 0) try: - RPCExecute('model', 'ir.export', 'delete', export_id) + RPCExecute('model', 'ir.export', 'delete', [export_id]) except RPCException: return for i in range(len(self.predef_model)): From b3ee5705b756ed120986eded5ca7bac98e07e019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 10 Jan 2013 11:37:17 +0100 Subject: [PATCH 22/78] Add missing _default for TimeField issue2940 review631003 (transplanted from 034e965007685e470598698fec3a235d2df3bcb3) --- tryton/gui/window/view_form/model/field.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 158981bd0f..8938df102b 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -256,6 +256,8 @@ class DateField(CharField): class TimeField(CharField): + _default = None + def set_client(self, record, value, force_change=False): if not isinstance(value, datetime.time): try: From 3fc4ebbcc98b012a664f7ea5776d2b7237d18837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 19 Jan 2013 17:13:44 +0100 Subject: [PATCH 23/78] Fix list popup when parent modified issue2949 review635004 (transplanted from 97de060117ce1f39dfedb41efc02ef496d7e1979) --- tryton/gui/window/view_form/view/list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 1660d5c189..9a738b7764 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -609,10 +609,10 @@ class ViewList(ParserView): parent = record.parent if record else None while parent: if parent.modified: - record = None break parent = parent.parent - populate(menu, group.model_name, record) + else: + populate(menu, group.model_name, record) for col in self.widget_tree.get_columns(): if not col.get_visible() or not col.name: continue From 206bf83c3a3b785e8d263d2b42be95d156b210cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 26 Jan 2013 15:07:23 +0100 Subject: [PATCH 24/78] Validate non-loaded O2M record when new and pass missing softvalidation issue2968 review637003 (transplanted from f753403e8ebc0455c691361f2c5e9a36be771006) --- tryton/gui/window/view_form/model/field.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 8938df102b..afcfc39e00 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -737,9 +737,9 @@ class O2MField(CharField): return True res = True for record2 in record.value.get(self.name, []): - if not record2.loaded: + if not record2.loaded and record2.id >= 0: continue - if not record2.validate(): + if not record2.validate(softvalidation=softvalidation): if not record2.modified: record.value[self.name].remove(record2) else: From 522969ef7a9071303fb0e19a6ca49f6bee7fb59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 17:57:06 +0100 Subject: [PATCH 25/78] Prepare release 2.6.2 --- CHANGELOG | 3 +++ COPYRIGHT | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 726c8686e4..2d4ee4714a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.2 - 2013-02-12 +* Bug fixes (see mercurial logs for details) + Version 2.6.1 - 2012-12-23 * Bug fixes (see mercurial logs for details) diff --git a/COPYRIGHT b/COPYRIGHT index 55b3570380..3f60d5d9be 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ -Copyright (C) 2010-2012 Nicolas Évrard. -Copyright (C) 2007-2012 Cédric Krier. +Copyright (C) 2010-2013 Nicolas Évrard. +Copyright (C) 2007-2013 Cédric Krier. Copyright (C) 2007-2012 Bertrand Chenal. -Copyright (C) 2008-2012 B2CK SPRL. +Copyright (C) 2008-2013 B2CK SPRL. Copyright (C) 2008-2011 Udo Spallek. Copyright (C) 2008-2011 virtual things - Preisler & Spallek GbR. Copyright (C) 2011-2012 Rodrigo Hübner. From 954913166072fa8f6a0e3500d9f64c6c45f71a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 17:57:07 +0100 Subject: [PATCH 26/78] Added tag 2.6.2 for changeset 01b9c2f204fa --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 11d725bd3a..d7590046ee 100644 --- a/.hgtags +++ b/.hgtags @@ -8,3 +8,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 fe15da23f7333e0e90d2693aadddf6bed53ed602 2.4.0 d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 89062be47c1b38757e60cf549c3dbcaae1089385 2.6.1 +01b9c2f204fa037e9e900640b7be126fa5270357 2.6.2 From 6edbf44c467d454fc949879109134b9c418a768d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 17:57:44 +0100 Subject: [PATCH 27/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 72d0205bbb..6a4f89588f 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.2" +VERSION = "2.6.3" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From d55d01e7a3f918a008c9d6de89e8a0e657d5a19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Mon, 11 Feb 2013 09:38:40 +0100 Subject: [PATCH 28/78] Correctly parse the URL review621003 (transplanted from f690b98c1a382fd36a43ba90c0272adaf6cba370) --- tryton/gui/main.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 4f5b688a45..3bb49edd57 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -5,7 +5,7 @@ import os import sys import socket import gettext -from urlparse import urlparse +from urlparse import urlparse, parse_qsl import urllib import gobject import gtk @@ -1404,14 +1404,14 @@ class Main(object): Main.get_main().refresh_ssl() def _open_url(self, url): - url = urllib.unquote(url) urlp = urlparse(url) if not urlp.scheme == 'tryton': return urlp = urlparse('http' + url[6:]) - hostname, port = (urlp.netloc.split(':', 1) - + [CONFIG.defaults['login.port']])[:2] - database, path = (urlp.path[1:].split('/', 1) + [None])[:2] + hostname, port = map(urllib.unquote, + (urlp.netloc.split(':', 1) + [CONFIG.defaults['login.port']])[:2]) + database, path = map(urllib.unquote, + (urlp.path[1:].split('/', 1) + [None])[:2]) if (not path or hostname != rpc._HOST or int(port) != rpc._PORT or @@ -1421,8 +1421,8 @@ class Main(object): params = {} if urlp.params: try: - params = dict(param.split('=', 1) - for param in urlp.params.split('&')) + params.update(dict(parse_qsl(urlp.params, + strict_parsing=True))) except ValueError: return From fc5be0024e37b3a315618594132b98d590402c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 4 Mar 2013 22:21:52 +0100 Subject: [PATCH 29/78] Disable main iteration for all RPC request from model/ We can not know if the request is fired during the process of a GTK event. review686002 (transplanted from db672c4e45901a05ce23a669648daa25794c3e9b) --- tryton/gui/window/view_form/model/group.py | 4 +-- tryton/gui/window/view_form/model/record.py | 29 +++++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 30bfc7559f..8b6565fa85 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -199,7 +199,7 @@ class Group(SignalEvent, list): for fnct in self.on_write: try: res += RPCExecute('model', self.model_name, fnct, ids, - context=self.context) + main_iteration=False, context=self.context) except RPCException: return [] return list({}.fromkeys(res)) @@ -391,7 +391,7 @@ class Group(SignalEvent, list): ctx.update(self.context) try: values = RPCExecute('model', self.model_name, 'default_get', - to_add.keys(), context=ctx) + to_add.keys(), main_iteration=False, context=ctx) except RPCException: return False for name in to_add: diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index fccfb1cebc..cb5cd6482f 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -279,7 +279,7 @@ class Record(SignalEvent): values = self.get() try: RPCExecute('model', self.model_name, 'pre_validate', values, - context=self.context_get()) + main_iteration=False, context=self.context_get()) except RPCException: return False return True @@ -290,6 +290,7 @@ class Record(SignalEvent): value = self.get(get_readonly=True) try: res = RPCExecute('model', self.model_name, 'create', value, + main_iteration=False, context=self.context_get()) except RPCException: return False @@ -306,7 +307,8 @@ class Record(SignalEvent): context['_timestamp'] = self.get_timestamp() try: RPCExecute('model', self.model_name, 'write', - [self.id], value, context=context) + [self.id], value, main_iteration=False, + context=context) except RPCException: return False self._loaded.clear() @@ -340,7 +342,7 @@ class Record(SignalEvent): reload_ids = list(reload_ids) try: RPCExecute('model', record.model_name, 'delete', list(record_ids), - context=ctx) + main_iteration=False, context=ctx) except RPCException: return False if reload_ids: @@ -351,7 +353,8 @@ class Record(SignalEvent): if len(self.group.fields): try: vals = RPCExecute('model', self.model_name, 'default_get', - self.group.fields.keys(), context=context) + self.group.fields.keys(), main_iteration=False, + context=context) except RPCException: return if (self.parent @@ -372,7 +375,8 @@ class Record(SignalEvent): def rec_name(self): try: return RPCExecute('model', self.model_name, 'read', [self.id], - ['rec_name'], context=self.context_get())[0]['rec_name'] + ['rec_name'], main_iteration=False, + context=self.context_get())[0]['rec_name'] except RPCException: return '' @@ -503,8 +507,9 @@ class Record(SignalEvent): attr = PYSONDecoder().decode(attr) args = self._get_on_change_args(attr) try: - res = RPCExecute('model', self.model_name, - 'on_change_' + fieldname, args, context=self.context_get()) + res = RPCExecute('model', self.model_name, 'on_change_' + + fieldname, args, main_iteration=False, + context=self.context_get()) except RPCException: return later = {} @@ -557,7 +562,8 @@ class Record(SignalEvent): if fieldnames: try: result = RPCExecute('model', self.model_name, 'on_change_with', - values, list(fieldnames), context=self.context_get()) + values, list(fieldnames), main_iteration=False, + context=self.context_get()) except RPCException: return for fieldname, value in result.items(): @@ -569,7 +575,7 @@ class Record(SignalEvent): try: result = RPCExecute('model', self.model_name, 'on_change_with_' + fieldname, values, - context=self.context_get()) + main_iteration=False, context=self.context_get()) except RPCException: return self.group.fields[fieldname].set_on_change(self, result) @@ -587,7 +593,8 @@ class Record(SignalEvent): args = self._get_on_change_args(autocomplete) try: res = RPCExecute('model', self.model_name, 'autocomplete_' + - fieldname, args, context=self.context_get()) + fieldname, args, main_iteration=False, + context=self.context_get()) except RPCException: # ensure res is a list res = [] @@ -602,7 +609,7 @@ class Record(SignalEvent): 'search_count', [ ('resource', '=', '%s,%s' % (self.model_name, self.id)), - ]) + ], main_iteration=False) except RPCException: return 0 return self.attachment_count From 8482d8e40144572900820b696c1f4c5b1f0985e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Mon, 18 Mar 2013 08:01:34 +0100 Subject: [PATCH 30/78] Set sequence when adding existing record in O2M review626002 (transplanted from e330806c145f1f5fd8da721b8502f962f83a3dc4) --- tryton/gui/window/view_form/view/form_gtk/one2many.py | 7 +++++++ 1 file changed, 7 insertions(+) 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 afd845ec28..38426394b7 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -388,14 +388,21 @@ class One2Many(WidgetInterface): self.focus_out = True return False + sequence = None + if self.screen.current_view.view_type == 'tree': + sequence = self.screen.current_view.widget_tree.sequence + def callback(result): self.focus_out = True if result: ids = [x[0] for x in result] self.screen.load(ids, modified=True) self.screen.display(res_id=ids[0]) + if sequence: + self.screen.group.set_sequence(field=sequence) self.screen.set_cursor() self.wid_text.set_text('') + if len(ids) != 1: WinSearch(self.attrs['relation'], callback, sel_multi=True, ids=ids, context=context, domain=domain, From bda8964c428d6ade54515091b1ab53c503c93057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 27 Mar 2013 22:50:08 +0100 Subject: [PATCH 31/78] Fix group loading when using '*' Prevent to load unnecessary records due to wrong loaded matching. issue3069 review744003 (transplanted from 0371410177db3ab0a3721486c1f83444ba549fa8) --- tryton/gui/window/view_form/model/record.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index cb5cd6482f..da8335f81c 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -48,6 +48,11 @@ class Record(SignalEvent): (field.attrs.get('loading', 'eager') for field in self.group.fields.itervalues()), 'eager') + # Set a valid name for next loaded check + for fname, field in self.group.fields.iteritems(): + if field.attrs.get('loading', 'eager') == loading: + name = fname + break else: loading = self.group.fields[name].attrs.get('loading', 'eager') if self in self.group and loading == 'eager': From 51fc9963338a9070584528414be9b5c8b4e3e984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 27 Mar 2013 22:52:48 +0100 Subject: [PATCH 32/78] Add missing initialization of bars in Bar issue3073 review730002 (transplanted from 4ce2f0028aa8ac17114588eacf668de236f9d25a) --- tryton/gui/window/view_form/view/graph_gtk/bar.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tryton/gui/window/view_form/view/graph_gtk/bar.py b/tryton/gui/window/view_form/view/graph_gtk/bar.py index 493b65c594..6833a21cde 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/bar.py +++ b/tryton/gui/window/view_form/view/graph_gtk/bar.py @@ -12,6 +12,10 @@ import tryton.rpc as rpc class Bar(Graph): + def __init__(self, *args, **kwargs): + super(Bar, self).__init__(*args, **kwargs) + self.bars = [] + def drawGraph(self, cr, width, height): def drawBar(bar): From c72a4ffdcb3b627d5cd21c2e8f5f644616ab06d7 Mon Sep 17 00:00:00 2001 From: Ralf Peschke Date: Fri, 29 Mar 2013 08:28:27 +0100 Subject: [PATCH 33/78] Prevent o2m-records to be deleted on client-side When I delete some records of an one2many-field in an on-change-Event, the deleted records are sent to the client and the client hides them in the list. Pressing the save button the record loads again including the deleted o2m-records. The reason is the force_remove-flag. This will delete the record on the client-side and therefore this change will not be reflected on the server side. issue3091 review744002 (transplanted from e40190b28b312f3dd63bceb167698a885826ea0e) --- tryton/gui/window/view_form/model/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index afcfc39e00..cc4b2cc4bb 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -711,7 +711,7 @@ class O2MField(CharField): to_remove.append(record2) for record2 in to_remove: record.value[self.name].remove(record2, signal=False, - force_remove=True) + force_remove=False) if value and (value.get('add') or value.get('update', [])): record.value[self.name].add_fields(fields, signal=False) From f05afb25d2d37575a0218f534a8756f3ddbb2325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:29:36 +0200 Subject: [PATCH 34/78] Prepare release 2.6.3 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2d4ee4714a..be6ecd4bf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.3 - 2013-05-02 +* Bug fixes (see mercurial logs for details) + Version 2.6.2 - 2013-02-12 * Bug fixes (see mercurial logs for details) From 30011d1caa6c6b62955286379ca619ac9c6b4713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:29:37 +0200 Subject: [PATCH 35/78] Added tag 2.6.3 for changeset 946e01f49345 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d7590046ee..24924d1a33 100644 --- a/.hgtags +++ b/.hgtags @@ -9,3 +9,4 @@ fe15da23f7333e0e90d2693aadddf6bed53ed602 2.4.0 d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 89062be47c1b38757e60cf549c3dbcaae1089385 2.6.1 01b9c2f204fa037e9e900640b7be126fa5270357 2.6.2 +946e01f49345e08a4f6c2a334cc597105f1ca277 2.6.3 From 43e680bda2fe6187b0545e4a3addd4eb3e144abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:29:57 +0200 Subject: [PATCH 36/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 6a4f89588f..e1f76e1aff 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.3" +VERSION = "2.6.4" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From b0c0814e74f807d1a7dc5136c71ddbbb34eb8708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 24 May 2013 12:40:34 +0200 Subject: [PATCH 37/78] Use jsonrpc object_hook to load json from URL (transplanted from ead6182dfa926891e9a429363c23466de561b5f0) --- tryton/gui/main.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 3bb49edd57..1613e0f238 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -19,6 +19,7 @@ from tryton.common import RPCExecute, RPCException from tryton.config import CONFIG, TRYTON_ICON, get_config_dir import tryton.common as common from tryton.pyson import PYSONDecoder +from tryton.jsonrpc import object_hook from tryton.action import Action from tryton.exceptions import TrytonServerError, TrytonError, \ TrytonServerUnavailable @@ -1437,9 +1438,12 @@ class Main(object): limit = json.loads(params.get('limit', 'null')) auto_refresh = json.loads(params.get('auto_refresh', 'false')) name = json.loads(params.get('window_name', 'false')) - search_value = json.loads(params.get('search_value', '{}')) - domain = json.loads(params.get('domain', '[]')) - context = json.loads(params.get('context', '{}')) + search_value = json.loads(params.get('search_value', '{}'), + object_hook=object_hook) + domain = json.loads(params.get('domain', '[]'), + object_hook=object_hook) + context = json.loads(params.get('context', '{}'), + object_hook=object_hook) except ValueError: return if path: @@ -1460,13 +1464,15 @@ class Main(object): if not wizard: return try: - data = json.loads(params.get('data', '{}')) + data = json.loads(params.get('data', '{}'), + object_hook=object_hook) direct_print = json.loads(params.get('direct_print', 'false')) email_print = json.loads(params.get('email_print', 'false')) email = json.loads(params.get('email', 'null')) name = json.loads(params.get('name', 'false')) window = json.loads(params.get('window', 'false')) - context = json.loads(params.get('context', '{}')) + context = json.loads(params.get('context', '{}'), + object_hook=object_hook) except ValueError: return try: @@ -1481,11 +1487,12 @@ class Main(object): if not report: return try: - data = json.loads(params.get('data')) + data = json.loads(params.get('data'), object_hook=object_hook) direct_print = json.loads(params.get('direct_print', 'false')) email_print = json.loads(params.get('email_print', 'false')) email = json.loads(params.get('email', 'null')) - context = json.loads(params.get('context', '{}')) + context = json.loads(params.get('context', '{}'), + object_hook=object_hook) except ValueError: return try: From 793250e61dc9f512ae28d10523568bc95ba43328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Jun 2013 22:28:21 +0200 Subject: [PATCH 38/78] Prepare release 2.6.4 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index be6ecd4bf7..9ad039a75d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.4 - 2013-06-09 +* Bug fixes (see mercurial logs for details) + Version 2.6.3 - 2013-05-02 * Bug fixes (see mercurial logs for details) From 418738ea86d9d8ec46d231cb85dc2302c4242cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Jun 2013 22:28:21 +0200 Subject: [PATCH 39/78] Added tag 2.6.4 for changeset a19b876ed9c4 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 24924d1a33..6b14f08d2e 100644 --- a/.hgtags +++ b/.hgtags @@ -10,3 +10,4 @@ d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 89062be47c1b38757e60cf549c3dbcaae1089385 2.6.1 01b9c2f204fa037e9e900640b7be126fa5270357 2.6.2 946e01f49345e08a4f6c2a334cc597105f1ca277 2.6.3 +a19b876ed9c4dd7182ca15302e9720abfa988502 2.6.4 From 5f3e34fcd3e2f62fd060c6ae2558bac1771a2a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Jun 2013 22:28:39 +0200 Subject: [PATCH 40/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index e1f76e1aff..e4b5d7a566 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.4" +VERSION = "2.6.5" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From c0b5664357aadff40a03824f3e46e9de4de1a84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 7 Jun 2013 19:28:16 +0200 Subject: [PATCH 41/78] del editabletree_entry on remove-widget instead of quit_cell issue3245 review918002 (transplanted from bc89814018e620da9d507688c1ba7047addcc39b) --- tryton/gui/window/view_form/view/list_gtk/editabletree.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index a38b8542f2..6387636781 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -55,8 +55,6 @@ class EditableTreeView(TreeView): def on_quit_cell(self, current_record, fieldname, value, callback=None): field = current_record[fieldname] - if hasattr(field, 'editabletree_entry'): - del field.editabletree_entry cell = self.cells[fieldname] # The value has not changed and is valid ... do nothing. @@ -226,6 +224,11 @@ class EditableTreeView(TreeView): # store in the record the entry widget to get the value in # set_value field.editabletree_entry = entry + + def remove_widget(cell): + if hasattr(field, 'editabletree_entry'): + del field.editabletree_entry + entry.connect('remove-widget', remove_widget) record.modified_fields.setdefault(column.name) return False From 3c71a2621414890f41b25662de0f20f8e1d9e361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 21 Jun 2013 23:19:57 +0200 Subject: [PATCH 42/78] Don't send not loaded value for on_change review919003 (transplanted from ce9893ef48f9b9dba34c3487ff4fcc8f0deb9d7d) --- tryton/gui/window/view_form/model/record.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index da8335f81c..153218e3a3 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -265,6 +265,8 @@ class Record(SignalEvent): self._check_load() value = {} for name, field in self.group.fields.iteritems(): + if name not in self._loaded and self.id >= 0: + continue value[name] = field.get_on_change_value(self, check_load=check_load) value['id'] = self.id From 242e085cf32b886488468dd690a7384822efebb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 27 Jun 2013 14:44:43 +0200 Subject: [PATCH 43/78] Set button insensitive when calling their callback review900002 (transplanted from d21e4282542a5bf8a4a4beebc673591782befbf8) --- tryton/gui/window/view_form/view/form.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index 653751c96e..af68eee7d2 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -183,4 +183,8 @@ class ViewForm(ParserView): self.screen.display() return else: - self.screen.button(widget.attrs) + widget.set_sensitive(False) + try: + self.screen.button(widget.attrs) + finally: + widget.set_sensitive(True) From b66486793f69b4abf44fb0e062749f47c7d7bc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:50:04 +0200 Subject: [PATCH 44/78] Prepare release 2.6.5 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 9ad039a75d..0d6e699572 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.5 - 2013-07-22 +* Bug fixes (see mercurial logs for details) + Version 2.6.4 - 2013-06-09 * Bug fixes (see mercurial logs for details) From c0dbbead3f36f2173c8f97c396044fd28a88057a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:50:05 +0200 Subject: [PATCH 45/78] Added tag 2.6.5 for changeset 3442069e4636 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6b14f08d2e..6d2c0dbed0 100644 --- a/.hgtags +++ b/.hgtags @@ -11,3 +11,4 @@ d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 01b9c2f204fa037e9e900640b7be126fa5270357 2.6.2 946e01f49345e08a4f6c2a334cc597105f1ca277 2.6.3 a19b876ed9c4dd7182ca15302e9720abfa988502 2.6.4 +3442069e4636cc6b870b3c658cb6bbb561ede050 2.6.5 From c8d024037a0fba4fb108fbf966975d92a2c1f350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:50:36 +0200 Subject: [PATCH 46/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index e4b5d7a566..674220d109 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.5" +VERSION = "2.6.6" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From c19a0fe809b8e41b17ab6ff40182333d10aaa977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 14:43:55 +0200 Subject: [PATCH 47/78] Fix domain composition between screen and attribute domains domains can not be summed because they can be of 'OR' type review985002 (transplanted from ba60f315fc3e9346c438edd10cdcc2470abd1317) --- tryton/gui/window/view_form/model/field.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index cc4b2cc4bb..85af6a708b 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -58,13 +58,13 @@ class CharField(object): def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) - return localize_domain(screen_domain) + attr_domain + return [localize_domain(screen_domain), attr_domain] def validation_domains(self, record): screen_domain, attr_domain = self.domains_get(record) if attr_domain: - return (screen_domain, screen_domain + - unlocalize_domain(attr_domain, self.name)) + return (screen_domain, [screen_domain, + unlocalize_domain(attr_domain, self.name)]) else: return screen_domain, screen_domain @@ -453,8 +453,8 @@ class M2OField(CharField): def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) - return (localize_domain(inverse_leaf(screen_domain), self.name) - + attr_domain) + return [localize_domain(inverse_leaf(screen_domain), self.name), + attr_domain] def get_state_attrs(self, record): result = super(M2OField, self).get_state_attrs(record) @@ -760,7 +760,7 @@ class O2MField(CharField): def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) - return localize_domain(inverse_leaf(screen_domain)) + attr_domain + return [localize_domain(inverse_leaf(screen_domain)), attr_domain] class M2MField(O2MField): From 454192774dc9ecd8d7f920fcce8c8d8090748008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 1 Aug 2013 15:59:57 +0200 Subject: [PATCH 48/78] Fix fallback value of get_preferences (transplanted from b70b126c0b22c7db6ad9aeb30a752b47eaeeeba2) --- tryton/gui/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 1613e0f238..2f2ecf0d63 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -928,7 +928,7 @@ class Main(object): prefs = RPCExecute('model', 'res.user', 'get_preferences', False) except RPCException: - prefs = None + prefs = {} common.ICONFACTORY.load_icons() common.MODELACCESS.load_models() if prefs and 'language_direction' in prefs: From 1b7b4b8cba99df326b248ac8276bed5ae21cd718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 21 Aug 2013 18:31:42 +0200 Subject: [PATCH 49/78] Set value before validate record in button click issue3322 review1022002 (transplanted from 93fe795cf2b97437598e9155a77957c48e0a1ae0) --- tryton/gui/window/view_form/view/form.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index af68eee7d2..7373db20cc 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -178,6 +178,7 @@ class ViewForm(ParserView): def button_clicked(self, widget): record = self.screen.current_record + self.set_value() fields = self.get_fields() if not record.validate(fields): self.screen.display() From 5e82d749d8230f67051d35e5c8d475d29af8659f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Sep 2013 10:41:21 +0200 Subject: [PATCH 50/78] Don't use field digits to format float/Decimal in domain_parser The conversion of a domain into string should keep the same significant digit, which means to not use the field digits definition but significant digit of the value. issue3266 review1041002 (transplanted from add046625334e0237bc6fc9d684427e6de1b1903) --- tryton/common/domain_parser.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index b2952d80e1..bfb325957b 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -393,10 +393,10 @@ def format_value(field, value): and not isinstance(value, (float, Decimal))): return '' try: - digit = int(field.get('digits', (16, 2))[1]) - except ValueError: - digit = 2 - return locale.format('%.' + str(digit) + 'f', value or 0.0, True) + digit = len(str(value).split('.')[1]) + except IndexError: + digit = 0 + return locale.format('%.*f', (digit, value or 0), True) def format_selection(): selections = dict(field['selection']) @@ -473,13 +473,14 @@ def test_format_integer(): def test_format_float(): field = { 'type': 'float', - 'digits': (16, 2), } for value, result in ( - (1, '1.00'), - (1.5, '1.50'), - (0, '0.00'), - (0.0, '0.00'), + (1, '1'), + (1.5, '1.5'), + (1.50, '1.5'), + (150.79, '150.79'), + (0, '0'), + (0.0, '0.0'), (False, ''), (None, ''), ): @@ -489,13 +490,14 @@ def test_format_float(): def test_format_numeric(): field = { 'type': 'numeric', - 'digits': (16, 2), } for value, result in ( - (Decimal(1), '1.00'), - (Decimal('1.5'), '1.50'), - (Decimal(0), '0.00'), - (Decimal('0.0'), '0.00'), + (Decimal(1), '1'), + (Decimal('1.5'), '1.5'), + (Decimal('1.50'), '1.50'), + (Decimal('150.79'), '150.79'), + (Decimal(0), '0'), + (Decimal('0.0'), '0.0'), (False, ''), (None, ''), ): From 7b92fdc0c6fb8577de77c9d2a857a6e87a1d78e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:22:11 +0200 Subject: [PATCH 51/78] Prepare release 2.6.6 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 0d6e699572..3127310773 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.6 - 2013-10-10 +* Bug fixes (see mercurial logs for details) + Version 2.6.5 - 2013-07-22 * Bug fixes (see mercurial logs for details) From b4a4d690f6ddafed0c4d66f2e47c9263f57f8d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:22:12 +0200 Subject: [PATCH 52/78] Added tag 2.6.6 for changeset f902aa2e8f63 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6d2c0dbed0..1e1b72177c 100644 --- a/.hgtags +++ b/.hgtags @@ -12,3 +12,4 @@ d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 946e01f49345e08a4f6c2a334cc597105f1ca277 2.6.3 a19b876ed9c4dd7182ca15302e9720abfa988502 2.6.4 3442069e4636cc6b870b3c658cb6bbb561ede050 2.6.5 +f902aa2e8f63acf514a4a53c6c458127b0975642 2.6.6 From f62ace468a893873a72432db5068ad90711a4daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:22:35 +0200 Subject: [PATCH 53/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 674220d109..4af25951ff 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.6" +VERSION = "2.6.7" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 2a4cdfe43b618bc787e9c64cf1e0f259dbfa30b3 Mon Sep 17 00:00:00 2001 From: Robin Baumgartner Date: Thu, 26 Sep 2013 10:57:57 +0200 Subject: [PATCH 54/78] Fix value of Reference fields when id is -1 issue3375 review1089002 (transplanted from d24d3b856c487b9904fa60923708faa751a0d6ed) --- tryton/gui/window/view_form/model/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 85af6a708b..b8b2a0152c 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -818,7 +818,7 @@ class ReferenceField(CharField): def get(self, record, check_load=True, readonly=True, modified=False): if (record.value.get(self.name) and record.value[self.name][0] - and record.value[self.name][1] >= 0): + and record.value[self.name][1] >= -1): return ','.join(map(str, record.value[self.name])) return None From cd66e14ee3dffc398f09702007cf25b4b267252b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 28 Sep 2013 14:56:27 +0200 Subject: [PATCH 55/78] Fix Reference widget when no model is selected, value is just text issue3352 review1090002 (transplanted from 5b7b2c1ba521565cb9e052c33f980a28589a47de) --- tryton/gui/window/view_form/view/form_gtk/reference.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/reference.py b/tryton/gui/window/view_form/view/form_gtk/reference.py index b546c750ac..3dd57be43d 100644 --- a/tryton/gui/window/view_form/view/form_gtk/reference.py +++ b/tryton/gui/window/view_form/view/form_gtk/reference.py @@ -114,7 +114,12 @@ class Reference(Many2One): return self.wid_text.set_text('') self.wid_text.set_position(0) - self.field.set_client(self.record, (self.get_model(), (-1, ''))) + model = self.get_model() + if model: + value = (model, (-1, '')) + else: + value = ('', '') + self.field.set_client(self.record, value) def set_value(self, record, field): if not self.get_model(): From ec03f4f9da503cac25d4950fb7bc2ff224903c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 28 Sep 2013 14:57:53 +0200 Subject: [PATCH 56/78] Block button handler instead of deactivate button By deactivating the button, the button lost the focus which makes NoModal selects the wrong sensitive widget and thus the wizard behaves like if it was launched from the menu instead of from a tab. issue3353 review1083003 (transplanted from 0d135623d016ce2d8185fcb5790eb22d9d8de254) --- tryton/gui/window/view_form/view/form.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index 7373db20cc..a4b50243ad 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -184,8 +184,8 @@ class ViewForm(ParserView): self.screen.display() return else: - widget.set_sensitive(False) + widget.handler_block_by_func(self.button_clicked) try: self.screen.button(widget.attrs) finally: - widget.set_sensitive(True) + widget.handler_unblock_by_func(self.button_clicked) From 2ef82a5f522bbbb94ecad4f686925b043a754fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Oct 2013 21:16:47 +0200 Subject: [PATCH 57/78] Don't extend domain but wrap into a new list review1106002 (transplanted from e4a2d43ad02e5c5d3ddd4c22a3c2a0890afff0aa) --- tryton/gui/window/view_form/view/form_gtk/one2many.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 38426394b7..85dcf654e8 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -370,8 +370,7 @@ class One2Many(WidgetInterface): self.view.set_value() domain = self.field.domain_get(self.record) context = self.field.context_get(self.record) - domain = domain[:] - domain.extend(self.record.expr_eval(self.attrs.get('add_remove'))) + domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))] removed_ids = self.field.get_removed_ids(self.record) self.focus_out = False From 383fb98a7bb8f81052eda165895d682c785fe0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Oct 2013 21:15:02 +0200 Subject: [PATCH 58/78] Reference id should be stored as int review1105002 (transplanted from 751e9cde7f7d2069dc902d5a5a90d37590f27b58) --- tryton/gui/window/view_form/model/field.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index b8b2a0152c..ad2d77ec0f 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -830,6 +830,11 @@ class ReferenceField(CharField): if isinstance(ref_id, (tuple, list)): ref_id, rec_name = ref_id else: + if ref_id: + try: + ref_id = int(ref_id) + except ValueError: + pass if '%s,%s' % (ref_model, ref_id) == self.get(record): rec_name = record.value.get(self.name + '.rec_name', '') else: From 3f170a09590fe08c6b085589d6be019b1695d138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Oct 2013 21:17:30 +0200 Subject: [PATCH 59/78] Fix move_into when record is not saved review1107002 (transplanted from d4d4ec2782007eab231325592e4885da76ce1381) --- tryton/gui/window/view_form/view/list.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 9a738b7764..70b10d35ae 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -120,7 +120,8 @@ class AdaptModelGroup(gtk.GenericTreeModel): # Don't remove record from previous group # as the new parent will change the parent # This prevents concurrency conflict - record.group.record_removed.remove(record) + if record in record.group.record_removed: + record.group.record_removed.remove(record) group.add(record) record.modified_fields.setdefault(record.parent_name or 'id') group.move(record, 0) From b2c545adffe8081993a7fbb65eb8551bc9cfd9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 9 Oct 2013 18:19:26 +0200 Subject: [PATCH 60/78] Fix restore predefined export with more than 2 levels depth issue3402 review1124003 (transplanted from 30b291e0bf4f17a0219b4572cee67e8fcc07acc7) --- tryton/gui/window/win_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index 1fc34e16c2..d67c155705 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -359,7 +359,7 @@ class WinExport(NoModal): self.on_row_expanded(self.view1, iter, self.model1.get_path(iter)) iter = self.model1.iter_children(iter) - prefix = parent + '/' + prefix += parent + '/' break else: iter = self.model1.iter_next(iter) From 3cb0fa3b0df3ce8d646afbb4e4de27ea982befd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:41:31 +0100 Subject: [PATCH 61/78] Sanitize report file extension issue3446 (transplanted from 357d0a4d9cb8b3f0f4192cb87996a5720bf1cb37) --- CHANGELOG | 2 ++ tryton/action/main.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3127310773..e275c3209a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Sanitize report file extension + Version 2.6.6 - 2013-10-10 * Bug fixes (see mercurial logs for details) diff --git a/tryton/action/main.py b/tryton/action/main.py index ec681af28d..e466458f8e 100644 --- a/tryton/action/main.py +++ b/tryton/action/main.py @@ -42,7 +42,8 @@ class Action(object): dtemp = tempfile.mkdtemp(prefix='tryton_') fp_name = os.path.join(dtemp, name.replace(os.sep, '_').replace(os.altsep or os.sep, '_') \ - + os.extsep + type) + + os.extsep + + type.replace(os.sep, '_').replace(os.altsep or os.sep, '_')) with open(fp_name, 'wb') as file_d: file_d.write(data) if email_print: From 5ae823074d22d7c5d39eb0977189094101eb9a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:51:02 +0100 Subject: [PATCH 62/78] Prepare release 2.6.7 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index e275c3209a..9a540a2acd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +Version 2.6.7 - 2013-11-03 +* Bug fixes (see mercurial logs for details) * Sanitize report file extension Version 2.6.6 - 2013-10-10 From 55a7e380bf556182b01f9c9e2df066234cccb7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:51:03 +0100 Subject: [PATCH 63/78] Added tag 2.6.7 for changeset 7f774ca25e33 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 1e1b72177c..b2b864c7f3 100644 --- a/.hgtags +++ b/.hgtags @@ -13,3 +13,4 @@ d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 a19b876ed9c4dd7182ca15302e9720abfa988502 2.6.4 3442069e4636cc6b870b3c658cb6bbb561ede050 2.6.5 f902aa2e8f63acf514a4a53c6c458127b0975642 2.6.6 +7f774ca25e331926809bd9d2609f9c158ca28729 2.6.7 From ca993ad8b1c47f9b857d6dbd8aa211eaead1c021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:51:27 +0100 Subject: [PATCH 64/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index 4af25951ff..d1f1b23b07 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.7" +VERSION = "2.6.8" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 89c98fd8997726332e14e62ab17e9a2533e781fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 18 Oct 2013 22:25:45 +0200 Subject: [PATCH 65/78] Quote user and password in the roundup XML-RPC URL review1143002 (transplanted from 8d9757fd30187f3bb35287b10020dd04e320f8d6) --- tryton/common/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index 8f2799b1a4..17ca8170fd 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -10,6 +10,7 @@ import os import subprocess import re import logging +from functools import partial from tryton.config import CONFIG from tryton.config import TRYTON_ICON, PIXMAPS_DIR import time @@ -933,9 +934,10 @@ def send_bugtracker(title, msg): protocol = 'http' if ssl or hasattr(socket, 'ssl'): protocol = 'https' + quote = partial(urllib.quote, safe="!$&'()*+,;=:") server = xmlrpclib.Server( ('%s://%s:%s@' + CONFIG['roundup.xmlrpc']) - % (protocol, user, password), allow_none=True) + % (protocol, quote(user), quote(password)), allow_none=True) if hashlib: msg_md5 = hashlib.md5(msg + '\n' + title).hexdigest() else: From 45f4acf858cc269e208ceb371c3dd521bf0492a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 20:42:34 +0100 Subject: [PATCH 66/78] Don't set image on button if it is still the same It fixes also a strange behavior of GTK that doesn't display any images if the icon is changed before it is realized. issue3191 review1451002 (transplanted from 4bc44691dc89dfd7802c9d84bbb466f98038bb75) --- tryton/common/button.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/common/button.py b/tryton/common/button.py index 2adae35ba6..5a695e8cc3 100644 --- a/tryton/common/button.py +++ b/tryton/common/button.py @@ -17,6 +17,11 @@ class Button(gtk.Button): self._set_icon(attrs.get('icon')) def _set_icon(self, stock): + image = self.get_image() + if not image and not stock: + return + elif image and image.get_stock()[0] == stock: + return if not stock: self.set_image(gtk.Image()) return From 2c623c2bfa43337b5744be20a34c6656a848a47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Fri, 15 Nov 2013 15:03:00 +0100 Subject: [PATCH 67/78] Use get_eval for check_required computation issue3473 review1561002 (transplanted from 4786286136344caf3e4bda27c23ac1ab911d9380) --- tryton/gui/window/view_form/model/field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index ad2d77ec0f..fad9d67454 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -80,7 +80,7 @@ class CharField(object): def check_required(self, record): state_attrs = self.get_state_attrs(record) if bool(int(state_attrs.get('required') or 0)): - if (not self.get(record) + if (not self.get_eval(record) and not bool(int(state_attrs.get('readonly') or 0))): return False return True From f19b47c39ddef6297601be8080cd3b62110b66ba Mon Sep 17 00:00:00 2001 From: Robin Baumgartner Date: Wed, 20 Nov 2013 08:33:58 +0100 Subject: [PATCH 68/78] Send None for missing parent records instead of False issue3448 review1761002 (transplanted from 207e9ee40735a5f9a37b796807f5f56189d25dba) --- tryton/gui/window/view_form/model/record.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index 153218e3a3..5b45f8d0dc 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -503,7 +503,7 @@ class Record(SignalEvent): scope = values for i in arg.split('.'): if i not in scope: - scope = False + scope = None break scope = scope[i] res[arg] = scope From f955432ebbe48993b49f16c89314351e4c9b05e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Dec 2013 17:28:04 +0100 Subject: [PATCH 69/78] Prepare release 2.6.8 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 9a540a2acd..cddd56e125 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.6.8 - 2013-12-04 +* Bug fixes (see mercurial logs for details) + Version 2.6.7 - 2013-11-03 * Bug fixes (see mercurial logs for details) * Sanitize report file extension From ee834d72a46dccab5cbe280e18f57ad2338a41f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Dec 2013 17:28:05 +0100 Subject: [PATCH 70/78] Added tag 2.6.8 for changeset 82fd4f2257e7 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index b2b864c7f3..0a76e6c7c3 100644 --- a/.hgtags +++ b/.hgtags @@ -14,3 +14,4 @@ a19b876ed9c4dd7182ca15302e9720abfa988502 2.6.4 3442069e4636cc6b870b3c658cb6bbb561ede050 2.6.5 f902aa2e8f63acf514a4a53c6c458127b0975642 2.6.6 7f774ca25e331926809bd9d2609f9c158ca28729 2.6.7 +82fd4f2257e739ba4ce479e4fd1b3bf3ff6d4807 2.6.8 From 39d430c6020852346488f774c87ec4754539b4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 4 Dec 2013 17:28:34 +0100 Subject: [PATCH 71/78] Increase version number --- tryton/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/version.py b/tryton/version.py index d1f1b23b07..68a2e0911e 100644 --- a/tryton/version.py +++ b/tryton/version.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. PACKAGE = "tryton" -VERSION = "2.6.8" +VERSION = "2.6.9" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From c8112db48b8ff0769ce07346ef804ea1119271f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 9 Jan 2014 18:44:16 +0100 Subject: [PATCH 72/78] Fix reload of screen at the end of wizard A wizard could be launch by a button defined on a children record. In this case, the ids to reload is not the ids from the wizard as they are from the children model but just the current record. issue3519 review2571002 (transplanted from 6f657eeefffcc5a74be70e7cc8868fc7293d3c44) --- tryton/gui/window/wizard.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py index e366e3cd20..19a5f6c55f 100644 --- a/tryton/gui/window/wizard.py +++ b/tryton/gui/window/wizard.py @@ -349,9 +349,13 @@ class WizardDialog(Wizard, NoModal): dialog = self.page if (hasattr(dialog, 'screen') and dialog.screen.current_record - and self.sensible_widget != main.window - and self.ids): - dialog.screen.reload(self.ids, written=True) + and self.sensible_widget != main.window): + if dialog.screen.model_name == self.model: + ids = self.ids + else: + # Wizard run from a children record so reload parent record + ids = [dialog.screen.current_record.id] + dialog.screen.reload(ids, written=True) def end(self): super(WizardDialog, self).end() From 4bacba8f75226c96d0437652f9b35ce2c081dee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 9 Jan 2014 18:45:14 +0100 Subject: [PATCH 73/78] Force value of parent Reference field Since 2.6, reference field can be used in One2Many so in this case the value should be forced like for Many2One. review2581002 (transplanted from 67acb340ba7caf7f6c801e2c7af6884e6603b614) --- tryton/gui/window/view_form/model/field.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index fad9d67454..7b5b764805 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -816,6 +816,12 @@ class ReferenceField(CharField): return None def get(self, record, check_load=True, readonly=True, modified=False): + if record.parent_name == self.name: + if record.parent: + return '%s,%s' % (record.group.parent.model_name, + record.parent.id) + else: + return None if (record.value.get(self.name) and record.value[self.name][0] and record.value[self.name][1] >= -1): From 24894330bfea824907d79fcc1a588f40690ffae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 26 Jan 2014 22:17:03 +0100 Subject: [PATCH 74/78] Encode gettext value to match with string value issue3587 review2991002 (transplanted from 80a479e15e31f5a97eaf26ddbd3f9a89303c595e) --- tryton/common/domain_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index bfb325957b..e374140da7 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -184,7 +184,7 @@ def convert_value(field, value): def convert_boolean(): if isinstance(value, basestring): - return any(test.lower().startswith(value.lower()) + return any(test.decode('utf-8').lower().startswith(value.lower()) for test in (_('y'), _('yes'), _('true'), _('t'), '1')) else: return bool(value) From 5dbb8de300c6496aa32efea542527fd61bf301ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 6 Feb 2014 22:36:44 +0100 Subject: [PATCH 75/78] Fix find button in search window It should use the text filled in the search entry. And it should not close the window if nothing is found. review3101003 (transplanted from 8b22f7366f7caeb7ecbe86c28b8b4f8f3bf32627) --- tryton/gui/window/win_search.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py index 0f901d4cbc..e12865569d 100644 --- a/tryton/gui/window/win_search.py +++ b/tryton/gui/window/win_search.py @@ -107,10 +107,8 @@ class WinSearch(NoModal): if response_id == gtk.RESPONSE_OK: res = self.screen.sel_ids_get() elif response_id == gtk.RESPONSE_APPLY: - if not self.screen.search_filter(): - res = self.screen.sel_ids_get() - else: - return + self.screen.search_filter(self.screen.screen_container.get_text()) + return elif response_id == gtk.RESPONSE_ACCEPT: screen = Screen(self.model_name, domain=self.domain, context=self.context, mode=['form']) From eb70c9fba5dcef8359c2071be4712131b4c04473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Feb 2014 23:54:56 +0100 Subject: [PATCH 76/78] Don't set missing default value to False False is not always a good valid value for the field, so it is better to let the field dealing with default value. issue3643 review3281002 (transplanted from 9a16381241f48ca880e7544edeef54c255c99255) --- tryton/gui/window/view_form/model/group.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 8b6565fa85..da93272335 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -394,9 +394,6 @@ class Group(SignalEvent, list): to_add.keys(), main_iteration=False, context=ctx) except RPCException: return False - for name in to_add: - if name not in values: - values[name] = False for record in new: record.set_default(values, signal=signal) From 034beccaf2a080fefab96df78245353f5ea648cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Feb 2014 23:56:27 +0100 Subject: [PATCH 77/78] Fix selection of column in next/previous When _sign is negative, it doesn't select the first column but the second. So despite of selection the wrong column, it could crash if there is only one column in the view. review3241004 (transplanted from f05cc122d3fd52141386f8097d0fc3989b85abd4) --- tryton/gui/window/view_form/view/list_gtk/editabletree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/list_gtk/editabletree.py b/tryton/gui/window/view_form/view/list_gtk/editabletree.py index 6387636781..602b721300 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -21,7 +21,7 @@ class TreeView(gtk.TreeView): def next_column(self, path, column=None, _sign=1): columns = self.get_columns() if column is None: - column = columns[-1 * _sign] + column = columns[-1 if _sign > 0 else 0] model = self.get_model() record = model.get_value(model.get_iter(path), 0) if _sign < 0: From 3f36df524ebb121548627bde9e0176b41937c20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 9 Feb 2014 23:57:24 +0100 Subject: [PATCH 78/78] Fix dynamic size for translate widget Dynamic size was added in changeset 8ee7e142c8fd but the translate widget was not updated. review3271004 (transplanted from 1a9e84ba4d48a8e2ca2a98680e2bff1c66aa7791) --- tryton/gui/window/view_form/view/form_gtk/char.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/char.py b/tryton/gui/window/view_form/view/form_gtk/char.py index c29062316e..1cfce7efb2 100644 --- a/tryton/gui/window/view_form/view/form_gtk/char.py +++ b/tryton/gui/window/view_form/view/form_gtk/char.py @@ -51,8 +51,10 @@ class Char(WidgetInterface, TranslateMixin): def translate_widget(self): entry = gtk.Entry() entry.set_property('activates_default', True) - entry.set_width_chars(int(self.attrs.get('size', -1))) - entry.set_max_length(int(self.attrs.get('size', 0))) + if self.record: + field_size = self.record.expr_eval(self.attrs.get('size')) + entry.set_width_chars(field_size or -1) + entry.set_max_length(field_size or 0) return entry @staticmethod