From be1fcd09dca80d62089cbc1523d73bbf9dadc777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 27 Apr 2011 23:50:50 +0200 Subject: [PATCH 001/147] 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 e944275335..d11e6d8d31 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.0" +VERSION = "2.0.1" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 2d3166e1d27679ef8a83ce07d827b642638e74bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 6 May 2011 16:00:30 +0200 Subject: [PATCH 002/147] Fix typo in Changelog (transplanted from aea5cf417b447ce5a06874b57bed2bddd706ed60) --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 9504c7d1fd..61fe653da3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -Version 2.0.0 - 2010-04-26 +Version 2.0.0 - 2011-04-26 * Bug fixes (see mercurial logs for details) * Popup form dialog has 3 buttons (close, ok, new) * New UI layout From a381ae4c5ec3412a6e861b8a1cc0742a4ec4d16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Tue, 3 May 2011 11:11:11 +0200 Subject: [PATCH 003/147] Fix missing attribute in UserWarningDialog for issue1997 (transplanted from 30060d3b4665f7ffb97fc8ca299dd65a9284c0fb) --- tryton/common/common.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index a8474f8bb9..53734bc5d9 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -535,10 +535,18 @@ warning = WarningDialog() class UserWarningDialog(WarningDialog): + def __init__(self): + super(UserWarningDialog, self).__init__() + self.always = False + + def _set_always(self, toggle): + self.always = toggle.get_active() + def build_dialog(self, message, parent, title): dialog = super(UserWarningDialog, self).build_dialog(message, parent, title) check = gtk.CheckButton(_('Always ignore this warning.')) + check.connect_after('toggled', self._set_always) alignment = gtk.Alignment(1, 0.5) alignment.add(check) dialog.vbox.pack_end(alignment, True, False) @@ -548,7 +556,7 @@ class UserWarningDialog(WarningDialog): response = super(UserWarningDialog, self).__call__(message, parent, title) if response == gtk.RESPONSE_OK: - if always: + if self.always: return 'always' return 'ok' return 'cancel' From acbdd23f58db0e8e357d7c7669e6a0e5df9da6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 May 2011 15:13:49 +0200 Subject: [PATCH 004/147] Fix concurrency conflict on DND for issue1991 (transplanted from 64c742f26ec23cf054e09d95da373298eb4b6c4b) --- tryton/gui/window/view_form/model/group.py | 6 ++++++ tryton/gui/window/view_form/view/list.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index e2b706be55..efe1f478c0 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -228,6 +228,12 @@ class Group(SignalEvent, list): self.append(record) else: self.insert(position, record) + for record_rm in self.record_removed: + if record_rm.id == record.id: + self.record_removed.remove(record) + for record_del in self.record_deleted: + if record_del.id == record.id: + self.record_deleted.remove(record) self.current_idx = position if modified: record.modified_fields.setdefault('id') diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 3b70c3c502..b2b3a3738a 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -84,9 +84,18 @@ class AdaptModelGroup(gtk.GenericTreeModel): group = record_pos.group pos = group.index(record_pos) + offset if group is not record.group: + prev_group = record.group record.group.remove(record, remove=True, force_remove=True) + # 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) group.add(record) - record.modified_fields.setdefault(record.parent_name or 'id') + if not record.parent_name: + record.modified_fields.setdefault(prev_group.parent_name) + record.value[prev_group.parent_name] = False + else: + record.modified_fields.setdefault(record.parent_name) group.move(record, pos) def move_before(self, record, path): From 7f8e273df31edf6fb3277b34b70454e3e7701e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 10 May 2011 15:23:36 +0200 Subject: [PATCH 005/147] Limit the size of form inside dialog according to the parent/transiant window (transplanted from b8860bd91cca75f5790a13a912fee718d0a36a0a) --- tryton/gui/window/view_form/view/form.py | 6 ++++++ tryton/wizard/main.py | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py index f41a4c02a9..12bc70aa88 100644 --- a/tryton/gui/window/view_form/view/form.py +++ b/tryton/gui/window/view_form/view/form.py @@ -43,6 +43,12 @@ class ViewForm(ParserView): viewport.add(scroll) if isinstance(self.screen.window, gtk.Dialog): width, height = self.widget.size_request() + if self.screen.window: + parent = self.screen.window.get_transient_for() + if parent: + parent_width, parent_height = parent.get_size() + width = min(parent_width - 40, width) + height = min(parent_height - 80, height) vbox.set_size_request(width or -1, height or -1) vbox.pack_start(viewport, expand=True, fill=True) diff --git a/tryton/wizard/main.py b/tryton/wizard/main.py index ec9479235b..6cb22a3aec 100644 --- a/tryton/wizard/main.py +++ b/tryton/wizard/main.py @@ -103,10 +103,10 @@ class Dialog(object): width, height = self.screen.screen_container.size_get() parent_width, parent_height = parent.get_size() dia_width, dia_height = self.dia.get_size() - self.widget_width = max(min(parent_width - 20, - max(dia_width, width + 20)), size[0]) - self.widget_height = max(min(parent_height - 60, - height + dia_height + 20), size[1]) + self.widget_width = min(parent_width - 20, + max(dia_width, width + 20, size[0])) + self.widget_height = min(parent_height - 60, + max(height + dia_height + 20, size[1])) self.dia.set_default_size(self.widget_width, self.widget_height) self.screen.widget.show() From 3d47601b55ee5d9a6204afbdb0f2877f87452c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 16 May 2011 12:24:55 +0200 Subject: [PATCH 006/147] get_fields in graph view should return empty list (transplanted from 856e42b7ed8c395cc98dcb668cbbe4d12ddbeff6) --- tryton/gui/window/view_form/view/graph.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tryton/gui/window/view_form/view/graph.py b/tryton/gui/window/view_form/view/graph.py index 6d4d6a16ef..75c43fc037 100644 --- a/tryton/gui/window/view_form/view/graph.py +++ b/tryton/gui/window/view_form/view/graph.py @@ -44,3 +44,6 @@ class ViewGraph(ParserView): def set_cursor(self, new=False, reset_view=True): pass + + def get_fields(self): + return [] From 65f898f1d5d048b5215273b0acfafcb4710b873d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 16 May 2011 12:26:19 +0200 Subject: [PATCH 007/147] Manage selection changed for empty selection (transplanted from fa7a8406dcfc0cc2d212c335665540e9f890528f) --- tryton/gui/window/view_form/view/list.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index b2b3a3738a..4494e7d0e4 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -749,6 +749,8 @@ class ViewList(ParserView): if model and iter_: record = model.get_value(iter_, 0) self.screen.current_record = record + else: + self.screen.current_record = None elif tree_sel.get_mode() == gtk.SELECTION_MULTIPLE: model, paths = tree_sel.get_selected_rows() @@ -756,6 +758,8 @@ class ViewList(ParserView): iter_ = model.get_iter(paths[0]) record = model.get_value(iter_, 0) self.screen.current_record = record + else: + self.screen.current_record = None if hasattr(self.widget_tree, 'editable') \ and self.widget_tree.editable \ From 3073e802420e8faeb63fba65b614a497debf4250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 16 May 2011 12:58:06 +0200 Subject: [PATCH 008/147] Fix activate event of many2one when search is required for issue1993 (transplanted from cc6afc5c180f04f7ccceaafde3f43c59700a794d) --- tryton/gui/window/view_form/view/form_gtk/many2one.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index 309c1b2791..4f9f967307 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -36,7 +36,7 @@ class Many2One(WidgetInterface): self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out()) self.wid_text.connect_after('changed', self.sig_changed) self.changed = True - self.wid_text.connect_after('activate', self.sig_activate) + self.wid_text.connect('activate', self.sig_activate) self.wid_text.connect_after('focus-out-event', self.sig_activate) self.focus_out = True self.widget.pack_start(self.wid_text, expand=True, fill=True) @@ -93,6 +93,8 @@ class Many2One(WidgetInterface): self.focus_out = False if not value: + if not key_press and not event: + widget.emit_stop_by_name('activate') if not self._readonly and (self.wid_text.get_text() or \ (self.field.get_state_attrs( self.record)['required']) and key_press): From a51df9c572247e8c184ff60422fb61ced43f48e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Tue, 17 May 2011 15:21:04 +0200 Subject: [PATCH 009/147] Use different environment's evaluation according to context of evaluation (transplanted from f0fc9ea42a6156f49d9fdabd8c9e2c438b2d9412) --- tryton/common/environment.py | 9 +++++++-- tryton/gui/window/view_form/model/record.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tryton/common/environment.py b/tryton/common/environment.py index 296cf9eee6..f644537bfc 100644 --- a/tryton/common/environment.py +++ b/tryton/common/environment.py @@ -4,15 +4,20 @@ class EvalEnvironment(dict): - def __init__(self, parent, check_load): + def __init__(self, parent, check_load, eval_type='eval'): super(EvalEnvironment, self).__init__() self.parent = parent self.check_load = check_load + assert eval_type in ('eval', 'on_change') + self.eval_type = eval_type def __getitem__(self, item): if item == '_parent_' + self.parent.parent_name and self.parent.parent: return EvalEnvironment(self.parent.parent, self.check_load) - return self.parent.get_eval(check_load=self.check_load)[item] + if self.eval_type == 'eval': + return self.parent.get_eval(check_load=self.check_load)[item] + else: + return self.parent._get_on_change_args([item])[item] def __getattr__(self, item): return self.__getitem__(item) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index 46a9c7b07c..40917df90a 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -434,7 +434,7 @@ class Record(SignalEvent): values[name] = field.get_on_change_value(self, check_load=False) if self.parent and self.parent_name: values['_parent_' + self.parent_name] = \ - common.EvalEnvironment(self.parent, False) + common.EvalEnvironment(self.parent, False, 'on_change') for arg in args: scope = values for i in arg.split('.'): From 8a9cee3cd81e3ac32b3eff059a7d90f77011ae34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Fri, 20 May 2011 18:32:25 +0200 Subject: [PATCH 010/147] Do clear_entries before show_all for issue2019 This will prevent a concurrency issue on windows (transplanted from f9333a459303d46203a074d08352d00531f7838b) --- tryton/gui/window/dblogin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index da061d3186..348cc96904 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -142,8 +142,8 @@ class DBListEditor(object): self.dialog.set_default_response(gtk.RESPONSE_ACCEPT) def run(self, profile_name): + self.clear_entries() # must be done before show_all for windows self.dialog.show_all() - self.clear_entries() model = self.profile_tree.get_model() if model: for i, row in enumerate(model): From 833e00b6435d5674564fae765046ef6b11ad9037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 23 May 2011 15:18:40 +0200 Subject: [PATCH 011/147] Fix wizard in window and missing icon Wizard in window must manage the new toolbar Every windows must have an icon attribute (transplanted from d46e7b14fed6d868b1899986844491570cbcd462) --- tryton/action/main.py | 2 +- tryton/gui/window/window.py | 4 +++- tryton/gui/window/wizard.py | 10 +++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tryton/action/main.py b/tryton/action/main.py index 84b9262cfc..0ca095c67e 100644 --- a/tryton/action/main.py +++ b/tryton/action/main.py @@ -154,7 +154,7 @@ class Action(object): direct_print=action.get('direct_print', False), email_print=action.get('email_print', False), email=action.get('email'), name=action.get('name', False), - context=context) + context=context, icon=(action.get('icon.rec_name') or '')) else: Wizard.execute(action['wiz_name'], data, window, direct_print=action.get('direct_print', False), diff --git a/tryton/gui/window/window.py b/tryton/gui/window/window.py index f6a24abf2c..f95863b576 100644 --- a/tryton/gui/window/window.py +++ b/tryton/gui/window/window.py @@ -29,10 +29,12 @@ class Window(object): @staticmethod def create_wizard(action, datas, parent, state='init', direct_print=False, - email_print=False, email=None, name=False, context=None): + email_print=False, email=None, name=False, context=None, + icon=None): from tryton.gui import Main from wizard import Wizard win = Wizard(parent, name=name) + win.icon = icon Main.get_main().win_add(win) win.run(action, datas, state=state, direct_print=direct_print, email_print=email_print, email=email, context=context) diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py index 84e0f8d274..f65949fec6 100644 --- a/tryton/gui/window/wizard.py +++ b/tryton/gui/window/wizard.py @@ -16,6 +16,8 @@ class Wizard(SignalEvent): super(Wizard, self).__init__() self.window = window self.widget = gtk.VBox(spacing=3) + self.toolbar_box = gtk.HBox() + self.widget.pack_start(self.toolbar_box, False, True) self.widget.show() self.name = name or '' self.model = '' @@ -117,6 +119,9 @@ class Wizard(SignalEvent): self.end() def destroy(self): + if self.toolbar_box.get_children(): + toolbar = self.toolbar_box.get_children()[0] + self.toolbar_box.remove(toolbar) if hasattr(self, 'screen'): self.screen.signal_unconnect(self) self.screen.destroy() @@ -125,7 +130,8 @@ class Wizard(SignalEvent): def end(self): try: - rpc.execute('wizard', self.action, 'delete', self.wiz_id) + rpc.execute('wizard', self.action, 'delete', self.wiz_id, + rpc.CONTEXT) #XXX to remove when company displayed in status bar rpc.context_reload() except Exception: @@ -217,6 +223,8 @@ class Wizard(SignalEvent): self.widget.pack_start(eb, expand=False, fill=True, padding=3) + self.widget.pack_start(self.toolbar_box, False, True) + viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) viewport.add(self.screen.widget) From 01cd76cd78235ef9caf09bc63b493f5753a622d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 25 May 2011 11:33:37 +0200 Subject: [PATCH 012/147] Fix concurrency window creation (transplanted from ba29430a1d7bba86dc44785138ff7441a8c83888) --- tryton/common/common.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index 53734bc5d9..d4bdd5a0e9 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -718,8 +718,9 @@ class ConcurrencyDialog(UniqueDialog): return True if res == gtk.RESPONSE_APPLY: from tryton.gui.window import Window - Window.create(False, resource, obj_id, [('id', '=', obj_id)], - 'form', parent, context, ['form', 'tree']) + Window.create(False, resource, res_id=obj_id, + domain=[('id', '=', obj_id)], window=parent, + context=context, mode=['form', 'tree']) return False concurrency = ConcurrencyDialog() From ac42b801e41e1b9151384a4098200406f72e6503 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sun, 29 May 2011 14:20:13 +0200 Subject: [PATCH 013/147] Prepare release 2.0.1 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 61fe653da3..98630b0fea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.1 - 2011-05-29 +* Bug fixes (see mercurial logs for details) + Version 2.0.0 - 2011-04-26 * Bug fixes (see mercurial logs for details) * Popup form dialog has 3 buttons (close, ok, new) From 062385b9ce2493390c0944e278b016463864d274 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sun, 29 May 2011 14:20:13 +0200 Subject: [PATCH 014/147] Added tag 2.0.1 for changeset b9cc8cd7419d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index ccce20955a..d62e268bde 100644 --- a/.hgtags +++ b/.hgtags @@ -4,3 +4,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 3976912b23dfc5db2525d4c2e55d17f099d9492d 1.6.0 8aa050da53cbdfabe1353a37da91c011b7fff549 1.8.0 1876747b3f963ba6011b4bcf6968e681624c6e24 2.0.0 +b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 From f22c174f2591764357248f88f851cd1878e5bdbf Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sun, 29 May 2011 14:20:44 +0200 Subject: [PATCH 015/147] 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 d11e6d8d31..b1bf33f366 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.1" +VERSION = "2.0.2" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From c9e44c690c0cde2ebd3e55b8582f2babe56975bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 26 May 2011 15:08:27 +0200 Subject: [PATCH 016/147] Enforce the value of port to be an integer for issue2012 (transplanted from 30e829aed9a2713d92143cf0b6815432b6886444) --- tryton/gui/window/dblogin.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 348cc96904..ede836a068 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -85,6 +85,7 @@ class DBListEditor(object): self.port_entry = gtk.Entry() self.port_entry.connect('focus-out-event', self.display_dbwidget) self.port_entry.connect('changed', self.update_profiles, 'port') + self.port_entry.connect('insert_text', self.insert_text_port) self.port_entry.set_activates_default(True) table.attach(port, 0, 1, 2, 3, yoptions=False, xoptions=gtk.FILL) table.attach(self.port_entry, 1, 2, 2, 3, yoptions=False) @@ -344,6 +345,15 @@ class DBListEditor(object): self.profiles.set(self.current_profile['name'], 'database', dbname) self.validate_profile(self.current_profile['name']) + def insert_text_port(self, entry, new_text, new_text_length, position): + value = entry.get_text() + position = entry.get_position() + new_value = value[:position] + new_text + value[position:] + try: + int(new_value) + except ValueError: + entry.stop_emission('insert-text') + class DBLogin(object): def __init__(self, parent): @@ -576,6 +586,10 @@ class DBLogin(object): CONFIG['login.profile'] = profile host, port = (self.entry_host.get_text().split(':', 1) + ['8070'])[:2] + try: + port = int(port) + except ValueError: + continue database = self.entry_database.get_text() login = self.entry_login.get_text() CONFIG['login.server'] = host @@ -584,7 +598,7 @@ class DBLogin(object): CONFIG['login.expanded'] = self.expander.props.expanded CONFIG['login.login'] = login result = (self.entry_login.get_text(), - self.entry_password.get_text(), host, int(port), database) + self.entry_password.get_text(), host, port, database) if res != gtk.RESPONSE_OK: parent.present() From 070e9dbfdc0f58f92f9b025be7f42b45bd0eb5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 26 May 2011 15:10:32 +0200 Subject: [PATCH 017/147] Don't validate readonly field for issue2014 (transplanted from f9f818400a0be81a6117be264f7b8e5471aca045) --- 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 40917df90a..db0c9ab61b 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -321,6 +321,8 @@ class Record(SignalEvent): for field_name, field in self.group.fields.iteritems(): if fields and field_name not in fields: continue + if field.get_state_attrs(self).get('readonly', False): + continue if not field.validate(self, softvalidation): res = False return res From 7f2152ac5484c9d9a2d635172061728dc957e8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 30 May 2011 17:33:23 +0200 Subject: [PATCH 018/147] Fix float_time_to_text with Python 2.7 for issue2032 (transplanted from ee26ae500b83f2001371d0e05b83f1049c09ed5d) --- tryton/common/common.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index d4bdd5a0e9..71d4acc27a 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -1333,17 +1333,13 @@ def float_time_to_text(val, conv=None): val = val - hours mins = int((val% 1 + 0.01) / conv['m']) if years: - value += ' ' + locale.format('%d' + FLOAT_TIME_SEPS['Y'], - years, True) + value += ' ' + locale.format('%d', years, True) + FLOAT_TIME_SEPS['Y'] if months: - value += ' ' + locale.format('%d' + FLOAT_TIME_SEPS['M'], - months, True) + value += ' ' + locale.format('%d', months, True) + FLOAT_TIME_SEPS['M'] if weeks: - value += ' ' + locale.format('%d' + FLOAT_TIME_SEPS['w'], - weeks, True) + value += ' ' + locale.format('%d', weeks, True) + FLOAT_TIME_SEPS['w'] if days: - value += ' ' + locale.format('%d' + FLOAT_TIME_SEPS['d'], - days, True) + value += ' ' + locale.format('%d', days, True) + FLOAT_TIME_SEPS['d'] if hours or mins: value += ' %02d:%02d' % (hours, mins) value = value.strip() From 4340ba4a14515cbeb116d68f32644f2281b43338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 1 Jun 2011 18:10:16 +0200 Subject: [PATCH 019/147] Only switch to validated profile in the login window for issue2009 (transplanted from 0285941783ea21d5d24a1bac47b82568f90bac3e) --- tryton/gui/window/dblogin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index ede836a068..18447d0170 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -488,7 +488,7 @@ class DBLogin(object): self.profiles.write(configfile) for idx, row in enumerate(self.profile_store): - if row[0] == profile_name: + if row[0] == profile_name and row[1]: self.combo_profile.set_active(idx) self.profile_changed(self.combo_profile) break From 945a5a65b1e8115bd21ca44bb74516fed1e4776e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 1 Jun 2011 18:48:08 +0200 Subject: [PATCH 020/147] Do not compare with invalid profile (transplanted from 54e396234d13473eedd277ccba4ccc82a5d002e4) --- tryton/gui/window/dblogin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 18447d0170..337c79814f 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -524,6 +524,8 @@ class DBLogin(object): host, port = host_entry.split(':', 1) if ':' in host_entry else ('', '') database = self.entry_database.get_text().strip() for idx, profile_info in enumerate(self.profile_store): + if not profile_info[1]: + continue profile = profile_info[0] if (host == self.profiles.get(profile, 'host') and port == self.profiles.get(profile, 'port') From 6c4dcc2803efc9e3de6a157b5207daba9ae91d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jun 2011 17:28:16 +0200 Subject: [PATCH 021/147] Disable MOD1 shortcut on mac issue2011 review40002 (transplanted from 687b010615089e0051b9acd4f88fb877cdfede24) --- tryton/gui/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 107648b82d..134079728b 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -87,8 +87,9 @@ class Main(object): gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/File/Quit', gtk.keysyms.Q, gtk.gdk.CONTROL_MASK) - gtk.accel_map_add_entry('/User/Menu Reload', gtk.keysyms.T, - gtk.gdk.MOD1_MASK) + if os.name != 'mac': + gtk.accel_map_add_entry('/User/Menu Reload', gtk.keysyms.T, + gtk.gdk.MOD1_MASK) gtk.accel_map_add_entry('/User/Menu Toggle', gtk.keysyms.T, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/User/Home', gtk.keysyms.H, From 8e119a87fd0a0e878555f486d906e72141ece5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jun 2011 17:56:26 +0200 Subject: [PATCH 022/147] Fix selection widget in list view for dynamic Many2One review35013 (transplanted from cb571409086f481a7992bbd8986d8b91a55dc57c) --- .../window/view_form/view/list_gtk/parser.py | 119 ++++++++++-------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index 332b494856..f2b4c3babf 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -1,6 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. +import gobject from editabletree import EditableTreeView from tryton.gui.window.view_form.view.interface import ParserInterface from tryton.gui.window.win_search import WinSearch @@ -703,68 +704,88 @@ class Selection(Char): def __init__(self, *args): super(Selection, self).__init__(*args) self.renderer = CellRendererCombo() - selection_data = gtk.ListStore(str, str) + self.renderer.connect('editing-started', self.editing_started) + self._last_domain = None + self._domain_cache = {} selection = self.attrs.get('selection', [])[:] - self.selection = selection[:] - if not self.attrs.get('domain'): - domain = [] - else: - domain = PYSONDecoder(rpc.CONTEXT).decode(self.attrs['domain']) - if 'relation' in self.attrs: - args = ('model', self.attrs['relation'], 'search_read', - domain, 0, None, None, ['rec_name'], rpc.CONTEXT) + if not isinstance(selection, (list, tuple)): try: - result = rpc.execute(*args) + selection = rpc.execute('model', + self.model_name, selection, rpc.CONTEXT) except Exception, exception: - result = common.process_exception(exception, self.window, *args) - if not result: - result = [] - selection = [(x['id'], x['rec_name']) for x in result] - self.selection = selection[:] - else: - if not isinstance(selection, (list, tuple)): - try: - selection = rpc.execute('model', - self.model_name, selection, rpc.CONTEXT) - except Exception, exception: - common.process_exception(exception, self.window) - selection = [] - self.selection = selection[:] - - for dom in common.filter_domain(domain): - if dom[1] in ('=', '!='): - todel = [] - for i in xrange(len(selection)): - if (dom[1] == '=' \ - and selection[i][0] != dom[2]) \ - or (dom[1] == '!=' \ - and selection[i][0] == dom[2]): - todel.append(i) - for i in todel[::-1]: - del selection[i] - + common.process_exception(exception, self.window) + selection = [] + self.selection = selection[:] if self.attrs.get('sort', True): selection.sort(lambda x, y: cmp(x[1], y[1])) - self._selection = selection - for i in selection: - selection_data.append(i) - self.renderer.set_property('model', selection_data) - self.renderer.set_property('text-column', 1) + self.renderer.set_property('model', self.get_model(selection)) + self.renderer.set_property('text-column', 0) + + def get_model(self, selection): + model = gtk.ListStore(gobject.TYPE_STRING) + self._selection = {} + lst = [] + for (value, name) in selection: + name = str(name) + lst.append(name) + self._selection[name] = value + i = model.append() + model.set(i, 0, name) + return model def get_textual_value(self, record): + self.update_selection(record) value = record[self.field_name].get(record) if isinstance(value, (list, tuple)): value = value[0] return dict(self.selection).get(value, '') def value_from_text(self, record, text): - res = False - for val, txt in self._selection: - if txt[:len(text)].lower() == text.lower(): - if len(txt) == len(text): - return val - res = val - return res + return self._selection.get(text, False), text + + def editing_started(self, cell, editable, path): + store = self.treeview.get_model() + record = store.get_value(store.get_iter(path), 0) + self.update_selection(record) + model = self.get_model(self.selection) + editable.set_model(model) + editable.set_text_column(0) + completion = gtk.EntryCompletion() + #Only available in PyGTK 2.6 and above. + if hasattr(completion, 'set_inline_selection'): + completion.set_inline_selection(True) + completion.set_model(model) + editable.get_child().set_completion(completion) + completion.set_text_column(0) + return False + + def update_selection(self, record): + if 'relation' not in self.attrs: + return + field = record[self.field_name] + domain = field.domain_get(record) + if str(domain) in self._domain_cache: + self.selection = self._domain_cache[str(domain)] + self._last_domain = domain + if domain != self._last_domain: + args = ('model', self.attrs['relation'], 'search_read', domain, + 0, None, None, ['rec_name'], rpc.CONTEXT) + try: + result = rpc.execute(*args) + except Exception, exception: + result = common.process_exception(exception, self.window, *args) + + if isinstance(result, list): + selection = [(x['id'], x['rec_name']) for x in result] + selection.append((False, '')) + self._last_domain = domain + self._domain_cache[str(domain)] = selection + else: + selection = [] + self._last_domain = None + else: + selection = self.selection + self.selection = selection[:] class Reference(Char): From 251fecbd20444071b1685aa11559dd3a882f0547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 6 Jun 2011 17:59:04 +0200 Subject: [PATCH 023/147] Add missing check of version compatibility client/server at login issue2006 review38011 (transplanted from 63c0fc0f83f435f288a97a0d30b6815877336bdd) --- tryton/common/common.py | 10 ++++++---- tryton/gui/window/dblogin.py | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index 71d4acc27a..c48a6a2e55 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -128,6 +128,10 @@ def find_in_path(name): return val return name +def test_server_version(host, port): + version = rpc.server_version(host, port) + return version.split('.')[:2] == VERSION.split('.')[:2] + def refresh_dblist(host, port): ''' Return the number of database available @@ -135,10 +139,8 @@ def refresh_dblist(host, port): or -1 if the server version doesn't match the client version ''' rpc.logout() - version = rpc.server_version(host, port) - if hasattr(version, 'split'): - if version.split('.')[:2] != VERSION.split('.')[:2]: - return -1 + if not test_server_version(host, port): + return -1 return rpc.db_list(host, port) def refresh_langlist(lang_widget, host, port): diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 337c79814f..315ec017d9 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -592,6 +592,8 @@ class DBLogin(object): port = int(port) except ValueError: continue + if not common.test_server_version(host, port): + continue database = self.entry_database.get_text() login = self.entry_login.get_text() CONFIG['login.server'] = host From fc047b7a3d209f5e8392ed9954fdf80f84bda93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 14 Jun 2011 11:20:21 +0200 Subject: [PATCH 024/147] Allow to enter IPv6 address as hostname in DBLogin review39004 (transplanted from 1affb763757a165743ea8fee41b5788d0fe2353d) --- tryton/gui/window/dblogin.py | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 315ec017d9..f74ce9ebde 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -503,6 +503,8 @@ class DBLogin(object): except ConfigParser.NoOptionError: username = '' host = self.profiles.get(profile, 'host') + if ':' in host: + host = '[%s]' % host port = self.profiles.get(profile, 'port') self.entry_host.set_text('%s:%s' % (host, port)) self.entry_database.set_text(self.profiles.get(profile, 'database')) @@ -520,8 +522,13 @@ class DBLogin(object): self.move_active = True def clear_profile_combo(self, entry, event): - host_entry = self.entry_host.get_text() - host, port = host_entry.split(':', 1) if ':' in host_entry else ('', '') + netloc = self.entry_host.get_text() + host = self.get_hostname(netloc) + try: + port = str(self.get_port(netloc)) + except ValueError: + host = '' + port = '' database = self.entry_database.get_text().strip() for idx, profile_info in enumerate(self.profile_store): if not profile_info[1]: @@ -542,6 +549,21 @@ class DBLogin(object): self.entry_database.props.visible = visibility self.label_database.props.visible = visibility + def get_hostname(self, netloc): + if '[' in netloc and ']' in netloc: + return netloc.split(']')[0][1:] + elif ':' in netloc: + return netloc.split(':')[0] + else: + return netloc + + def get_port(self, netloc): + netloc = netloc.split(']')[-1] + if ':' in netloc: + return int(netloc.split(':')[1]) + else: + return 8070 + def run(self, parent): profile_name = CONFIG['login.profile'] can_use_profile = self.profiles.has_section(profile_name) @@ -560,7 +582,11 @@ class DBLogin(object): break else: self.combo_profile.set_active(-1) - self.entry_host.set_text('%s:%s' % (CONFIG['login.server'], + if ':' in CONFIG['login.server']: + host = '[%s]' % CONFIG['login.server'] + else: + host = CONFIG['login.server'] + self.entry_host.set_text('%s:%s' % (host, CONFIG['login.port'])) db = CONFIG['login.db'] if CONFIG['login.db'] else '' self.entry_database.set_text(db) @@ -586,12 +612,16 @@ class DBLogin(object): if active_profile != -1: profile = self.profile_store[active_profile][0] CONFIG['login.profile'] = profile - host, port = (self.entry_host.get_text().split(':', 1) - + ['8070'])[:2] + netloc = self.entry_host.get_text() + host = self.get_hostname(netloc) try: - port = int(port) + port = self.get_port(netloc) except ValueError: continue + if ':' in host: + hostname = '[%s]' % host + else: + hostname = host if not common.test_server_version(host, port): continue database = self.entry_database.get_text() From b92ae2bb17ed5e39b49cd4d7a20c18663c5d6832 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 11 Jun 2011 20:46:32 +0200 Subject: [PATCH 025/147] Add missing share/locale/ja_JP/LC_MESSAGES/tryton.mo. issue2051 review45001 (transplanted from 0185e6929906c7040658bb6c8ee7791b721d5df6) --- share/locale/ja_JP/LC_MESSAGES/tryton.mo | Bin 0 -> 31597 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 share/locale/ja_JP/LC_MESSAGES/tryton.mo diff --git a/share/locale/ja_JP/LC_MESSAGES/tryton.mo b/share/locale/ja_JP/LC_MESSAGES/tryton.mo new file mode 100644 index 0000000000000000000000000000000000000000..342a2943f2de83e2484b9994e2d4c65fd8d4f1a6 GIT binary patch literal 31597 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 G5d0r5{#V-o literal 0 HcmV?d00001 From 31f5092e0a96b5a6d1d64e9b23970dd809a6ab0a Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 11 Jun 2011 20:50:28 +0200 Subject: [PATCH 026/147] Refactor and update translated languages to point to a variable. issue2051 review45001 (transplanted from 79c06808cad4d664379f4880244a90e80a9fa2ff) --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index f01c3ae3b8..adbadc355e 100644 --- a/setup.py +++ b/setup.py @@ -52,6 +52,8 @@ data_files=[ glob.glob('share/locale/ja_JP/LC_MESSAGES/*.mo')), ] +trans_lang = ('bg', 'cs', 'de', 'es', 'fr', 'ru', 'sl', 'ja') + if os.name == 'nt': import py2exe @@ -225,7 +227,7 @@ if os.name == 'nt': if os.path.isfile(file): shutil.copy(file, dist_dir) - for lang in ('de', 'es', 'fr', 'ru'): + for lang in trans_lang: if os.path.isdir(os.path.join(dist_dir, 'share', 'locale', lang)): shutil.rmtree(os.path.join(dist_dir, 'share', 'locale', lang)) shutil.copytree(os.path.join(gtk_dir, 'share', 'locale', lang), @@ -318,7 +320,7 @@ elif os.name == 'mac' \ shutil.copy(os.path.join(gtk_dir, 'share', 'themes', 'Clearlooks', 'gtk-2.0', 'gtkrc'), os.path.join(resources_dir, 'gtkrc')) - for lang in ('de', 'es', 'fr', 'ru'): + for lang in trans_lang: if os.path.isdir(os.path.join(resources_dir, 'share', 'locale', lang)): shutil.rmtree(os.path.join(resources_dir, 'share', 'locale', lang)) shutil.copytree(os.path.join(gtk_dir, 'share', 'locale', lang), From 8fd656619c003ddd8186a8f70b35ea867c2f56b6 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 11 Jun 2011 20:51:36 +0200 Subject: [PATCH 027/147] Update trove classifiers to current available languages. issue2051 review45001 (transplanted from b28cec3a943924f6a01f29439df6b9d092f1db5d) --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index adbadc355e..0d176fa292 100644 --- a/setup.py +++ b/setup.py @@ -142,6 +142,9 @@ dist = setup(name=PACKAGE, 'Natural Language :: German', 'Natural Language :: Russian', 'Natural Language :: Spanish', + 'Natural Language :: Slovak', + 'Natural Language :: Slovenian', + 'Natural Language :: Japanese', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', From 8f3957a24ecc5c6a0471e9cddd8930c7b82a866f Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 11 Jun 2011 20:52:59 +0200 Subject: [PATCH 028/147] Add Slovenian to data_files. issue2051 review45001 (transplanted from 9ae5e5efd5e7504f0fac5c75300a55ff7021df6a) --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 0d176fa292..351cb37e8e 100644 --- a/setup.py +++ b/setup.py @@ -48,6 +48,8 @@ data_files=[ glob.glob('share/locale/fr_FR/LC_MESSAGES/*.mo')), ('share/locale/ru_RU/LC_MESSAGES', glob.glob('share/locale/ru_RU/LC_MESSAGES/*.mo')), + ('share/locale/sl_SI/LC_MESSAGES', + glob.glob('share/locale/sl_SI/LC_MESSAGES/*.mo')), ('share/locale/ja_JP/LC_MESSAGES', glob.glob('share/locale/ja_JP/LC_MESSAGES/*.mo')), ] From d2d603e3316ee69379d1cd6e9da7bb81788c23ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 15 Jun 2011 13:19:15 +0200 Subject: [PATCH 029/147] Action active status is only valid when there is a current_record (transplanted from 9f957c8d0f12c84340dc936e3a15019ac187f1a4) --- tryton/gui/window/view_board/action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py index 65c16b3993..4d7864029a 100644 --- a/tryton/gui/window/view_board/action.py +++ b/tryton/gui/window/view_board/action.py @@ -238,7 +238,7 @@ class Action(SignalEvent): self.signal('active-changed') def _get_active(self): - if self.screen: + if self.screen and self.screen.current_record: return common.EvalEnvironment(self.screen.current_record, False) elif self.tree: return {'id': self.tree.sel_id_get()} From 362c23ef128f675feb8c1040f695d0a216b1d3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 14 Jun 2011 12:31:09 +0200 Subject: [PATCH 030/147] Enforce test_server_version if not version is returned (transplanted from d96a3d6cbab61dd8da60222570503a786f4c2572) --- tryton/common/common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/common/common.py b/tryton/common/common.py index c48a6a2e55..aad7cca3a7 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -130,6 +130,8 @@ def find_in_path(name): def test_server_version(host, port): version = rpc.server_version(host, port) + if not version: + return False return version.split('.')[:2] == VERSION.split('.')[:2] def refresh_dblist(host, port): From 4afa650e12ccd8b1de3fe85202e1d639856b74a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 23 Jun 2011 16:55:44 +0200 Subject: [PATCH 031/147] Fix parent window of Dialogs opened from field The window attribute is not always the right parent window when the form is in a Dialog. issue2064 review49001 (transplanted from 5bc59d75f8cca0764756a14bba0922d6aced20c0) --- tryton/gui/window/view_form/view/form_gtk/binary.py | 5 +++-- tryton/gui/window/view_form/view/form_gtk/many2many.py | 7 ++++--- tryton/gui/window/view_form/view/form_gtk/many2one.py | 8 ++++---- tryton/gui/window/view_form/view/form_gtk/one2many.py | 4 ++-- tryton/gui/window/view_form/view/form_gtk/reference.py | 6 +++--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/binary.py b/tryton/gui/window/view_form/view/form_gtk/binary.py index d9d4c19a78..d22e8325f6 100644 --- a/tryton/gui/window/view_form/view/form_gtk/binary.py +++ b/tryton/gui/window/view_form/view/form_gtk/binary.py @@ -116,7 +116,7 @@ class Binary(WidgetInterface): def sig_new(self, widget=None): filename = file_selection(_('Open...'), - parent=self.window) + parent=self.widget.get_toplevel()) if filename and self.field: self.field.set_client(self.record, base64.encodestring(open(filename, 'rb').read())) @@ -144,7 +144,8 @@ class Binary(WidgetInterface): if self.filename_field: filename = self.filename_field.get(self.record) filename = file_selection(_('Save As...'), filename=filename, - parent=self.window, action=gtk.FILE_CHOOSER_ACTION_SAVE) + parent=self.widget.get_toplevel(), + action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: with open(filename,'wb') as fp: fp.write(base64.decodestring(self.field.get(self.record))) diff --git a/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/gui/window/view_form/view/form_gtk/many2many.py index bbee21c720..87d177c21a 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py @@ -121,8 +121,9 @@ class Many2Many(WidgetInterface): return False if len(ids) != 1 or not value: win = WinSearch(self.attrs['relation'], sel_multi=True, ids=ids, - context=context, domain=domain, parent=self.window, - views_preload=self.attrs.get('views', {})) + context=context, domain=domain, + parent=self.widget.get_toplevel(), + views_preload=self.attrs.get('views', {})) ids = win.run() res_id = None @@ -146,7 +147,7 @@ class Many2Many(WidgetInterface): def _sig_edit(self): if self.screen.current_record: - win = WinForm(self.screen, self.window) + win = WinForm(self.screen, self.widget.get_toplevel()) if win.run(): self.screen.current_record.save() else: diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index 4f9f967307..3436187e32 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -127,7 +127,7 @@ class Many2One(WidgetInterface): win = WinSearch(self.attrs['relation'], sel_multi=False, ids=ids, context=context, domain=domain, - parent=self.window, + parent=self.widget.get_toplevel(), views_preload=self.attrs.get('views', {})) ids = win.run() if ids: @@ -155,7 +155,7 @@ class Many2One(WidgetInterface): def sig_new(self, *args): self.focus_out = False screen = self.get_screen() - win = WinForm(screen, self.window, new=True) + win = WinForm(screen, self.widget.get_toplevel(), new=True) if win.run(): if screen.save_current(): value = (screen.current_record.id, @@ -171,7 +171,7 @@ class Many2One(WidgetInterface): if value: screen = self.get_screen() screen.load([self.field.get(self.record)]) - win = WinForm(screen, self.window) + win = WinForm(screen, self.widget.get_toplevel()) while win.run(): if screen.save_current(): value = (screen.current_record.id, @@ -212,7 +212,7 @@ class Many2One(WidgetInterface): win = WinSearch(self.attrs['relation'], sel_multi=False, ids=ids, context=context, - domain=domain, parent=self.window, + domain=domain, parent=self.widget.get_toplevel(), views_preload=self.attrs.get('views', {})) ids = win.run() if ids: 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 a42b3e917f..f8c78b7253 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -240,7 +240,7 @@ class One2Many(WidgetInterface): self.screen.new(context=ctx) self.screen.current_view.widget.set_sensitive(True) else: - win = WinForm(self.screen, self.window, new=True, + win = WinForm(self.screen, self.widget.get_toplevel(), new=True, many=True, context=ctx) win.run() win.destroy() @@ -255,7 +255,7 @@ class One2Many(WidgetInterface): if not record.validate(fields): self.screen.display() return - win = WinForm(self.screen, self.window) + win = WinForm(self.screen, self.widget.get_toplevel()) win.run() win.destroy() 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 0397ae38d4..b15282de4a 100644 --- a/tryton/gui/window/view_form/view/form_gtk/reference.py +++ b/tryton/gui/window/view_form/view/form_gtk/reference.py @@ -155,7 +155,7 @@ class Reference(WidgetInterface): if not leave: screen = Screen(model, self.window, mode=['form']) screen.load([obj_id]) - win = WinForm(screen, self.window) + win = WinForm(screen, self.widget.get_toplevel()) if win.run(): if screen.save_current(): value = (screen.current_record.id, @@ -190,7 +190,7 @@ class Reference(WidgetInterface): return True win = WinSearch(model, sel_multi=False, ids=ids, context=context, - domain=domain, parent=self.window) + domain=domain, parent=self.widget.get_toplevel()) ids = win.run() if ids: self.field.set_client(self.record, (model, (ids[0], ''))) @@ -205,7 +205,7 @@ class Reference(WidgetInterface): if not model: return screen = Screen(model, self.window, mode=['form']) - win = WinForm(screen, self.window, new=True) + win = WinForm(screen, self.widget.get_toplevel(), new=True) if win.run(): if screen.save_current(): value = (screen.current_record.id, From 9d4da038653d19fd0a3e35aadfbd9d98a9641680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 24 Jun 2011 16:07:08 +0200 Subject: [PATCH 032/147] Add missing import of WinSearch in WinForm (transplanted from 4cbbde98a309d4ad31acb77b007254565b6adc07) --- tryton/gui/window/win_form.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index 2675430d71..65b9211aad 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -251,6 +251,7 @@ class WinForm(object): self.wid_text.grab_focus() def _sig_add(self, *args): + from tryton.gui.window.win_search import WinSearch domain = [] context = rpc.CONTEXT.copy() From 159da13d02909a0c9fe09370f4c3b2e0ec3bbab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 28 Jun 2011 23:34:32 +0200 Subject: [PATCH 033/147] Ensure that parent_name is always a string (transplanted from f399f9288753fc0916ecb4f85d41d6a3b01ba422) --- tryton/gui/window/view_form/model/group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index efe1f478c0..2b0aef64fe 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -20,7 +20,7 @@ class Group(SignalEvent, list): self.lock_signal = False self.__window = window self.parent = parent - self.parent_name = parent_name + self.parent_name = parent_name or '' self.child_name = child_name self.parent_datetime_field = parent_datetime_field self._context = context or {} From d9dbf9531af19ca0e12771153939b2c6d75b392d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 29 Jun 2011 20:15:42 +0200 Subject: [PATCH 034/147] Ensure that thread of DBProgress will stop review50001 (transplanted from 384694905d4efdd4f768642a23a1021c79d659d3) --- tryton/common/common.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index aad7cca3a7..a352a5a08f 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -1084,16 +1084,13 @@ class DBProgress(object): def start(self): key = (self.host, self.port) + dbs, createdb = [], False try: dbs = refresh_dblist(self.host, self.port) createdb = True - except Exception, exception: - if exception[0] == 'AccessDenied': - dbs, createdb = [], False - else: - raise - self.db_info = (dbs, createdb) - self.updated.set() + finally: + self.db_info = (dbs, createdb) + self.updated.set() def update(self, combo, progressbar, dbname=''): key = (self.host, self.port) From b8c04523e2dd34ccde8ed3ef27e60f0f288016e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 29 Jun 2011 20:19:03 +0200 Subject: [PATCH 035/147] Don't process CANCEL or DELETE_EVENT response issue2076 review47002 (transplanted from 869d996c3efafdf89fcd4d9ecaac609d1828629b) --- tryton/gui/window/dblogin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index f74ce9ebde..6201642b28 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -605,9 +605,10 @@ class DBLogin(object): self.expand_hostspec(self.expander) res, result = None, ('', '', '', '', '') - while not (res in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT) - or (res == gtk.RESPONSE_OK and all(result))): + while not all(result): res = self.dialog.run() + if res != gtk.RESPONSE_OK: + break active_profile = self.combo_profile.get_active() if active_profile != -1: profile = self.profile_store[active_profile][0] From 68ae9bcbf32f05d11be31dbaa98fad97dfb116ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 29 Jun 2011 20:21:25 +0200 Subject: [PATCH 036/147] Fix double row_deleted event review47005 (transplanted from fa0c2535200666f39f2bc6f30c0435973c975837) --- tryton/gui/window/view_form/view/list_gtk/editabletree.py | 1 - 1 file changed, 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 9a3b1ca983..1d5223505d 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -213,7 +213,6 @@ class EditableTreeView(gtk.TreeView): elif event.keyval == gtk.keysyms.Escape: if record.id < 0: model.remove(model.get_iter(path)) - model.row_deleted(path) self.screen.current_record = False if not path[0]: self.screen.current_record = False From 532dd0e8da437809054b397d9f4eb75b7d107602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 29 Jun 2011 20:22:42 +0200 Subject: [PATCH 037/147] Fix next/previous with empty group issue2058 review50002 (transplanted from df7a2be9ee1155c604788638d4cef8c507d49d9c) --- tryton/gui/window/view_form/screen/screen.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 29fd753e65..d2e9b59d98 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -661,14 +661,14 @@ class Screen(SignalEvent): view = self.current_view view.set_value() view.set_cursor(reset_view=False) - if view.view_type == 'tree': + if view.view_type == 'tree' and len(self.group): start, end = view.widget_tree.get_visible_range() vadjustment = view.widget_tree.get_vadjustment() vadjustment.value = vadjustment.value + vadjustment.page_increment store = view.store iter_ = store.get_iter(end) self.current_record = store.get_value(iter_, 0) - elif self.current_record.group: + elif view.view_type == 'form' and self.current_record.group: group = self.current_record.group record = self.current_record while group: @@ -703,14 +703,14 @@ class Screen(SignalEvent): view = self.current_view view.set_value() view.set_cursor(reset_view=False) - if view.view_type == 'tree': + if view.view_type == 'tree' and len(self.group): start, end = view.widget_tree.get_visible_range() vadjustment = view.widget_tree.get_vadjustment() vadjustment.value = vadjustment.value - vadjustment.page_increment store = view.store iter_ = store.get_iter(start) self.current_record = store.get_value(iter_, 0) - elif self.current_record.group: + elif view.view_type == 'form' and self.current_record.group: group = self.current_record.group record = self.current_record idx = group.index(record) - 1 From bc623a4e71a4abf4229725c38b8bd15bffedd5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 29 Jun 2011 20:24:29 +0200 Subject: [PATCH 038/147] Fix select_changed of list if previous_record is no more in the group issue2059 review49004 (transplanted from 99baef36dc094122745bdcb335797821c7c2606d) --- tryton/gui/window/view_form/view/list.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 4494e7d0e4..899b445e34 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -743,6 +743,8 @@ class ViewList(ParserView): def __select_changed(self, tree_sel): previous_record = self.screen.current_record + if previous_record and previous_record not in previous_record.group: + previous_record = None if tree_sel.get_mode() == gtk.SELECTION_SINGLE: model, iter_ = tree_sel.get_selected() From d46f5acedca76c7a02a4878398e876457f1ca70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 30 Jun 2011 13:17:29 +0200 Subject: [PATCH 039/147] Remove old parent parameter in progressbar (transplanted from 206f28cc49a147db59a32e91e338e44f82906ad4) --- tryton/gui/window/view_form/view/form_gtk/progressbar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/progressbar.py b/tryton/gui/window/view_form/view/form_gtk/progressbar.py index 1734f5f659..79e2b00f03 100644 --- a/tryton/gui/window/view_form/view/form_gtk/progressbar.py +++ b/tryton/gui/window/view_form/view/form_gtk/progressbar.py @@ -16,7 +16,7 @@ class ProgressBar(WidgetInterface): def __init__(self, field_name, model_name, window, attrs=None): super(ProgressBar, self).__init__(field_name, model_name, window, - parent, attrs=attrs) + attrs=attrs) self.widget = gtk.ProgressBar() orientation = self.orientations.get(attrs.get('orientation', 'left_to_right'), gtk.PROGRESS_LEFT_TO_RIGHT) From 90c61e596cd7472279e0a9b8c5e00dac778b1c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Jul 2011 13:28:52 +0200 Subject: [PATCH 040/147] Fix wrong parent value due to naming collision Use the parent id only when it is a real tree (same Model) Manage exclude field in validation review40006 (transplanted from d5df30b6407293d8e071ca86203f346bd211ab7b) --- tryton/gui/window/view_form/model/field.py | 19 ++++++++++++------- tryton/gui/window/view_form/model/group.py | 1 + tryton/gui/window/view_form/model/record.py | 7 ++++++- tryton/gui/window/view_form/screen/screen.py | 3 ++- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 381374ad53..2acc030f26 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -316,12 +316,13 @@ class M2OField(CharField): def get(self, record, check_load=True, readonly=True, modified=False): value = record.value.get(self.name) - if record.parent_name == self.name: + if (record.parent_name == self.name + and self.attrs['relation'] == record.group.parent.model_name): value = record.parent.id if record.parent else False if value: if isinstance(value, (int, basestring, long)): self.set(record, value) - value = record.value.get(self.name) + value = record.value.get(self.name, value) if isinstance(value, (int, basestring, long)): return value return value[0] or False @@ -329,19 +330,21 @@ class M2OField(CharField): def get_client(self, record): value = record.value.get(self.name) - if record.parent_name == self.name: + if (record.parent_name == self.name + and self.attrs['relation'] == record.group.parent.model_name): value = record.parent.id if record.parent else False if value: if isinstance(value, (int, basestring, long)): self.set(record, value) - value = record.value.get(self.name) + value = record.value.get(self.name, value) if isinstance(value, (int, basestring, long)): return value return value[1] return False def set(self, record, value, modified=False): - if record.parent_name == self.name: + if (record.parent_name == self.name + and self.attrs['relation'] == record.group.parent.model_name): if record.parent: if 'rec_name' in record.parent.value: value = (record.parent.id, record.parent.value['rec_name']) @@ -370,7 +373,8 @@ class M2OField(CharField): else: record.value[self.name + '.rec_name'] = '' record.value[self.name] = value or (False, '') - if record.parent_name == self.name: + if (record.parent_name == self.name + and self.attrs['relation'] == record.group.parent.model_name): if record.parent: if 'rec_name' not in record.parent.value: record.parent.value['rec_name'] = \ @@ -422,7 +426,8 @@ class M2OField(CharField): def get_state_attrs(self, record): result = super(M2OField, self).get_state_attrs(record) - if record.parent_name == self.name: + if (record.parent_name == self.name + and self.attrs['relation'] == record.group.parent.model_name): result = result.copy() result['readonly'] = True return result diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 2b0aef64fe..d4ea6b8629 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -36,6 +36,7 @@ class Group(SignalEvent, list): self.readonly = True self.__id2record = {} self.__field_childs = None + self.exclude_field = None def __get_window(self): return self.__window diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index db0c9ab61b..a712d85d65 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -292,7 +292,10 @@ class Record(SignalEvent): vals = common.process_exception(exception, self.window, *args) if not vals: return - if self.parent_name in self.group.fields and self.parent: + if (self.parent + and self.parent_name in self.group.fields + and (self.group.fields[self.parent_name].attrs['relation'] + == self.group.parent.model_name)): vals[self.parent_name] = self.parent.id self.set_default(vals) for fieldname, fieldinfo in self.group.fields.iteritems(): @@ -323,6 +326,8 @@ class Record(SignalEvent): continue if field.get_state_attrs(self).get('readonly', False): continue + if field_name == self.group.exclude_field: + continue if not field.validate(self, softvalidation): res = False return res diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index d2e9b59d98..73125316b0 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -48,6 +48,7 @@ class Screen(SignalEvent): self.view_ids = view_ids self.parent = None self.parent_name = None + self.exclude_field = exclude_field self.__window = window self.__group = None self.new_group() @@ -61,7 +62,6 @@ class Screen(SignalEvent): self.limit = limit self.search_value = search_value self.fields_view_tree = None - self.exclude_field = exclude_field self.sort = sort self.view_to_load = [] @@ -190,6 +190,7 @@ class Screen(SignalEvent): self._record_modified) self.__group.signal_connect(self, 'group-changed', self._group_changed) self.__group.add_fields(fields) + self.__group.exclude_field = self.exclude_field group = property(__get_group, __set_group) From 1f5e0dc0f3dd065b07697f6bbde0d5867517ce59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Jul 2011 13:29:52 +0200 Subject: [PATCH 041/147] Domain can have length > 3 for child_of review51002 (transplanted from 2b3d7fe7f3cf006e9690ae4dc3e428e0838aab24) --- tryton/common/domain_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index a4a83758da..69266da96f 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -180,7 +180,7 @@ class And(object): elif is_leaf(part) and self.base(part[0]) == symbol: result.append(part) else: - field, _, _ = part + field = part[0] if (field not in context or field in context and eval_leaf(part, context, operator.and_)): From 45506e3e8cc8522fb4a9ede8d20fa6042082bdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 11 Jul 2011 20:54:13 +0200 Subject: [PATCH 042/147] Fix fields loading when setting default value of One2Many (transplanted from ce7f9b8ae8ab06d7fa3ecd7b16ecc007d6c81013) --- tryton/gui/window/view_form/model/field.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 2acc030f26..65f9f5123d 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -589,7 +589,7 @@ class O2MField(CharField): args = ('model', self.attrs['relation'], 'fields_get', field_names, context) try: - fields_to_load = rpc.execute(*args) + fields_dict = rpc.execute(*args) except Exception, exception: fields_dict = common.process_exception(exception, record.window, *args) @@ -597,17 +597,17 @@ class O2MField(CharField): return False parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], fields_dict, record.window, + group = Group(self.attrs['relation'], fields, record.window, parent=record, parent_name=parent_name, child_name=self.name, context=self.context, parent_datetime_field=self.attrs.get('datetime_field')) + group.load_fields(fields_dict) if record.value.get(self.name): group.record_deleted.extend(x for x in record.value[self.name] if x.id > 0) group.record_deleted.extend(record.value[self.name].record_deleted) group.record_removed.extend(record.value[self.name].record_removed) record.value[self.name] = group - group.fields = fields for vals in (value or []): new_record = record.value[self.name].new(default=False) new_record.set_default(vals, modified=modified) From b4543c0ad341831f52913ec8c06ee6f09e6d87ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Jul 2011 16:59:51 +0200 Subject: [PATCH 043/147] Fix wrong fields passed to Group introduced by ce7f9b8ae8ab review70001 (transplanted from 7284c3c6b4f30f9f08a2e673ab107e535c3a9328) --- tryton/gui/window/view_form/model/field.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 65f9f5123d..fe61735ed6 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -574,6 +574,9 @@ class O2MField(CharField): fields = group.fields elif record.model_name == self.attrs['relation']: fields = record.group.fields + if fields: + fields = dict((fname, field.attrs) + for fname, field in fields.iteritems()) # value is a list of dict fields_dict = {} From ea21275e4cfe4732b441c63aa5a134773aee44fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 15 Jul 2011 18:15:12 +0200 Subject: [PATCH 044/147] Close every PixbufLoader (transplanted from 23939a938789dcc9914e898298647bae0531bb2a) --- tryton/gui/window/view_form/view/form_gtk/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py index 124149bf99..539d02f72d 100644 --- a/tryton/gui/window/view_form/view/form_gtk/image.py +++ b/tryton/gui/window/view_form/view/form_gtk/image.py @@ -211,14 +211,14 @@ class Image(WidgetInterface): except Exception: continue pixbuf = loader.get_pixbuf() + loader.close() if pixbuf: break if not pixbuf: loader = gtk.gdk.PixbufLoader('png') loader.write(NOIMAGE, len(NOIMAGE)) pixbuf = loader.get_pixbuf() - - loader.close() + loader.close() img_height = pixbuf.get_height() if img_height > self.height: From a23431863f82d1a46db1757d0883c212cfd8dd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 15 Jul 2011 18:16:55 +0200 Subject: [PATCH 045/147] Remove spreading active_id(s) in board action review49009 (transplanted from ca470354201defe937abd164b5fc962a29371301) --- tryton/gui/window/view_board/action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py index 4d7864029a..9e105d838b 100644 --- a/tryton/gui/window/view_board/action.py +++ b/tryton/gui/window/view_board/action.py @@ -44,7 +44,7 @@ class Action(SignalEvent): self.action['view_mode'] = attrs['view_mode'] self.action.setdefault('pyson_domain', '[]') - self.context = {'active_id': False, 'active_ids': []} + self.context = {} self.context.update(rpc.CONTEXT) self.context.update(PYSONDecoder(self.context).decode( self.action.get('pyson_context', '{}'))) From 761f1717d4a80ae9f8a46116e52f58b0990c0e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Jul 2011 18:56:33 +0200 Subject: [PATCH 046/147] Remove wrong parent propagation of signal from O2M issue2081 review63001 (transplanted from f6365561cf3537d2c0651a5610acf19fc2e726cc) --- tryton/gui/window/view_form/model/field.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index fe61735ed6..42b8871926 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -459,12 +459,6 @@ class O2MField(CharField): record.parent.validate(softvalidation=True) record.parent.signal('record-changed') - def _group_list_changed(self, group, signal): - group.parent.group.signal('group-list-changed', signal) - - def _group_cleared(self, group, signal): - group.parent.signal('group-cleared') - def _set_default_value(self, record): if record.value.get(self.name) is not None: return @@ -479,8 +473,6 @@ class O2MField(CharField): if record.model_name == self.attrs['relation']: group.fields = record.group.fields group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) - group.signal_connect(group, 'group-cleared', self._group_cleared) record.value[self.name] = group def get_client(self, record): @@ -550,8 +542,6 @@ class O2MField(CharField): record.value[self.name] = group group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) - group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) record.signal('record-modified') @@ -616,8 +606,6 @@ class O2MField(CharField): new_record.set_default(vals, modified=modified) group.add(new_record) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) - group.signal_connect(group, 'group-cleared', self._group_cleared) return True def set_on_change(self, record, value): @@ -743,8 +731,6 @@ class M2MField(O2MField): group.fields = fields group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) - group.signal_connect(group, 'group-list-changed', self._group_list_changed) - group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) record.signal('record-modified') From 5af9ed9d48d6944947db900436a6718feb06ccd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Jul 2011 18:59:08 +0200 Subject: [PATCH 047/147] Fix value of O2M to not add/write for deleted/removed record issue2085 review64001 (transplanted from 792588d4a43de83ba56d3dbb1da1531a11858526) --- tryton/gui/window/view_form/model/field.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 42b8871926..158eae1c0d 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -482,8 +482,12 @@ class O2MField(CharField): def get(self, record, check_load=True, readonly=True, modified=False): if record.value.get(self.name) is None: return [] + record_removed = record.value[self.name].record_removed + record_deleted = record.value[self.name].record_deleted result = [('add', [])] for record2 in record.value[self.name]: + if record2 in record_removed or record2 in record_deleted: + continue if record2.id > 0: values = record2.get(check_load=check_load, get_readonly=readonly, get_modifiedonly=modified) @@ -493,12 +497,10 @@ class O2MField(CharField): else: result.append(('create', record2.get(check_load=check_load, get_readonly=readonly))) - if record.value[self.name].record_removed: - result.append(('unlink', [x.id for x in \ - record.value[self.name].record_removed])) - if record.value[self.name].record_deleted: - result.append(('delete', [x.id for x in \ - record.value[self.name].record_deleted])) + if record_removed: + result.append(('unlink', [x.id for x in record_removed])) + if record_deleted: + result.append(('delete', [x.id for x in record_deleted])) return result def get_timestamp(self, record): From 2dee50d8ce46215306700ac34e5f21d52db0cb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 20 Jul 2011 19:12:09 +0200 Subject: [PATCH 048/147] Filter readonly fields of the domain for inversion issue56001 (transplanted from f04101cff8d2dc62e354cf8a70fd7e82285f3348) --- tryton/gui/window/view_form/model/field.py | 2 +- tryton/gui/window/view_form/model/group.py | 25 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 158eae1c0d..8769246078 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -42,7 +42,7 @@ class CharField(object): record.autocomplete_with(self.name) def domains_get(self, record): - screen_domain = domain_inversion(record.group.domain, + screen_domain = domain_inversion(record.group.domain4inversion, self.name, EvalEnvironment(record, False)) if isinstance(screen_domain, bool) and not screen_domain: screen_domain = [('id', '=', False)] diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index d4ea6b8629..27ff8d4b13 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -6,6 +6,7 @@ from record import Record from field import Field, O2MField from tryton.signal_event import SignalEvent import tryton.common as common +from tryton.common.domain_inversion import is_leaf class Group(SignalEvent, list): @@ -17,6 +18,7 @@ class Group(SignalEvent, list): if domain is None: domain = [] self.domain = domain + self.__domain4inversion = None self.lock_signal = False self.__window = window self.parent = parent @@ -48,6 +50,29 @@ class Group(SignalEvent, list): window = property(__get_window, __set_window) + def clean4inversion(self, domain): + "This method will replace non relevant fields for domain inversion" + if domain in ([], ()): + return [] + head, tail = domain[0], domain[1:] + if head in ('AND', 'OR'): + pass + elif is_leaf(head): + field = head[0] + if (field in self.fields + and self.fields[field].attrs.get('readonly')): + head = [] + else: + head = self.clean4inversion(head) + return [head] + self.clean4inversion(tail) + + def __get_domain4inversion(self): + if self.__domain4inversion is None: + self.__domain4inversion = self.clean4inversion(self.domain) + return self.__domain4inversion + + domain4inversion = property(__get_domain4inversion) + def insert(self, pos, record): assert record.group is self if pos >= 1: From 82ec15825e55f5f804bb811827187799fc02ff6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Jul 2011 21:54:36 +0200 Subject: [PATCH 049/147] Test if any column has width before saving it otherwise list is hidden and there is no width review48004 (transplanted from 223e96d3b08f76519fe935089d346242e9e9e522) --- tryton/gui/window/view_form/view/list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 899b445e34..7017517070 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -721,7 +721,7 @@ class ViewList(ParserView): if last_col and last_col.name in fields: del fields[last_col.name] - if fields: + if fields and any(fields.itervalues()): try: rpc.execute('model', 'ir.ui.view_tree_width', 'set_width', self.screen.model_name, fields, rpc.CONTEXT) From b5d081621aae1749419dcc4f44ce520df5716220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 22 Jul 2011 15:42:56 +0200 Subject: [PATCH 050/147] Fix typo filepath -> filename when saving graph (transplanted from 3fd018519880c72ecbab5747587c11939adfbca6) --- tryton/gui/window/view_form/view/graph_gtk/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/graph_gtk/parser.py b/tryton/gui/window/view_form/view/graph_gtk/parser.py index 27a5950ab7..03efdcc3f7 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/parser.py +++ b/tryton/gui/window/view_form/view/graph_gtk/parser.py @@ -77,7 +77,7 @@ def save(widget, graph, window): filename = filename.decode('utf-8') try: CONFIG['client.default_path'] = \ - os.path.dirname(filepath) + os.path.dirname(filename) CONFIG.save() except Exception: pass From c10b6f4db1cac770b7f5d59fad5846eec953acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 22 Jul 2011 15:54:49 +0200 Subject: [PATCH 051/147] Use str for cairo.Surface.write_to_png Old version doesn't support unicode (transplanted from 45368348fad448334fe324e5fb0ec729c63d0ebe) --- tryton/gui/window/view_form/view/graph_gtk/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/graph_gtk/graph.py b/tryton/gui/window/view_form/view/graph_gtk/graph.py index ec1fbb4d60..0dcd6cf155 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/graph.py +++ b/tryton/gui/window/view_form/view/graph_gtk/graph.py @@ -122,7 +122,7 @@ class Graph(gtk.DrawingArea): self.drawGraph(cx, width, height) self.drawAxis(cx, width, height) self.drawLegend(cx, width, height) - surface.write_to_png(filename) + surface.write_to_png(filename.encode('utf-8')) self.queue_draw() From d8cc29c2be1dec4110d4ab1f575dde75d53745bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 31 Jul 2011 17:27:58 +0200 Subject: [PATCH 052/147] Add missing Cancel button to UserWarningDialog Bug was introduced in changeset b61f48ca78b5 review77003 (transplanted from e9137ce78233cd7f245bcb64125214a4d2036d9d) --- tryton/common/common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tryton/common/common.py b/tryton/common/common.py index a352a5a08f..70db2859e2 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -524,9 +524,9 @@ message = MessageDialog() class WarningDialog(UniqueDialog): - def build_dialog(self, message, parent, title): + def build_dialog(self, message, parent, title, buttons=gtk.BUTTONS_OK): dialog = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_WARNING, gtk.BUTTONS_OK) + gtk.MESSAGE_WARNING, buttons) if hasattr(dialog, 'format_secondary_markup'): dialog.set_markup('%s' % (to_xml(title))) dialog.format_secondary_markup(to_xml(message)) @@ -548,7 +548,7 @@ class UserWarningDialog(WarningDialog): def build_dialog(self, message, parent, title): dialog = super(UserWarningDialog, self).build_dialog(message, parent, - title) + title, gtk.BUTTONS_OK_CANCEL) check = gtk.CheckButton(_('Always ignore this warning.')) check.connect_after('toggled', self._set_always) alignment = gtk.Alignment(1, 0.5) From 47ffbc8f2b40fd6c1c9ae0341e9713cb493230e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 4 Aug 2011 11:33:37 +0200 Subject: [PATCH 053/147] Fix load of predefined export without lines issue2124 (transplanted from 4b3a3808b0d11ad2de119bdefaec9e34e93bc2a8) --- 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 fee597f4e3..4d1afe18a8 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -304,7 +304,7 @@ class WinExport(object): for export in exports: self.predef_model.append(( export['id'], - [x['name'] for x in id2lines[export['id']]], + [x['name'] for x in id2lines.get(export['id'], [])], export['name'])) self.pref_export.set_model(self.predef_model) From 1e96fb6eb91d863855fa7b6e29e3013d9b4938f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 5 Aug 2011 12:54:50 +0200 Subject: [PATCH 054/147] Backed out changeset f6365561cf35 (transplanted from 7211707b5cfe5dccef71bdf292ae8d8614562dee) --- tryton/gui/window/view_form/model/field.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 8769246078..018036a9eb 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -459,6 +459,12 @@ class O2MField(CharField): record.parent.validate(softvalidation=True) record.parent.signal('record-changed') + def _group_list_changed(self, group, signal): + group.parent.group.signal('group-list-changed', signal) + + def _group_cleared(self, group, signal): + group.parent.signal('group-cleared') + def _set_default_value(self, record): if record.value.get(self.name) is not None: return @@ -473,6 +479,8 @@ class O2MField(CharField): if record.model_name == self.attrs['relation']: group.fields = record.group.fields group.signal_connect(group, 'group-changed', self._group_changed) + group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-cleared', self._group_cleared) record.value[self.name] = group def get_client(self, record): @@ -544,6 +552,8 @@ class O2MField(CharField): record.value[self.name] = group group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) + group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) record.signal('record-modified') @@ -608,6 +618,8 @@ class O2MField(CharField): new_record.set_default(vals, modified=modified) group.add(new_record) group.signal_connect(group, 'group-changed', self._group_changed) + group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-cleared', self._group_cleared) return True def set_on_change(self, record, value): @@ -733,6 +745,8 @@ class M2MField(O2MField): group.fields = fields group.load(value, display=False) group.signal_connect(group, 'group-changed', self._group_changed) + group.signal_connect(group, 'group-list-changed', self._group_list_changed) + group.signal_connect(group, 'group-cleared', self._group_cleared) if modified: record.modified_fields.setdefault(self.name) record.signal('record-modified') From 6ead51173ad334336c20f51d207f492abc17b276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 5 Aug 2011 12:57:34 +0200 Subject: [PATCH 055/147] Propagate "group-" signal only if parent is the same model issue2081 (transplanted from 09df638676352c99e90c6ed428564fc58e7eba8b) --- tryton/gui/window/view_form/model/field.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 018036a9eb..9652e70f9e 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -460,10 +460,12 @@ class O2MField(CharField): record.parent.signal('record-changed') def _group_list_changed(self, group, signal): - group.parent.group.signal('group-list-changed', signal) + if group.model_name == group.parent.model_name: + group.parent.group.signal('group-list-changed', signal) def _group_cleared(self, group, signal): - group.parent.signal('group-cleared') + if group.model_name == group.parent.model_name: + group.parent.signal('group-cleared') def _set_default_value(self, record): if record.value.get(self.name) is not None: From 2138df39afa9b19c1a9bb718f9910ed4da028975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 5 Aug 2011 17:52:55 +0200 Subject: [PATCH 056/147] Fix crash with Esc on editable list issue2123 (transplanted from 0d133797a7965e622409fade88c72ef7d9e943a9) --- tryton/gui/window/view_form/screen/screen.py | 11 ++++++----- .../window/view_form/view/list_gtk/editabletree.py | 14 ++++---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 73125316b0..6bdbed7f5f 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -571,20 +571,21 @@ class Screen(SignalEvent): res = True if self.current_view.view_type == 'tree': records = self.current_view.selected_records() - if delete and records: + saved_records = [r for r in records if r.id >= 0] + if delete and saved_records: context = {} context.update(rpc.CONTEXT) context.update(self.context) context['_timestamp'] = {} - for record in records: + for record in saved_records: context['_timestamp'].update(record.get_timestamp()) - reload_ids = self.group.on_write_ids([x.id for x in records]) + reload_ids = self.group.on_write_ids([x.id for x in saved_records]) if reload_ids: - for record in records: + for record in saved_records: if record.id in reload_ids: reload_ids.remove(record.id) args = ('model', self.model_name, 'delete', - [x.id for x in records], context) + [x.id for x in saved_records], context) try: res = rpc.execute(*args) except Exception, exception: 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 1d5223505d..54df75f86e 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -212,16 +212,10 @@ class EditableTreeView(gtk.TreeView): self.on_editing_done) elif event.keyval == gtk.keysyms.Escape: if record.id < 0: - model.remove(model.get_iter(path)) - self.screen.current_record = False - if not path[0]: - self.screen.current_record = False - if path[0] == len(self.screen.group) \ - and path[0]: - path = (path[0] - 1,) - self.screen.display() - if len(self.screen.group): - self.set_cursor(path, column, False) + self.screen.remove(delete=False, remove=True, + force_remove=True) + else: + return False elif event.keyval in (gtk.keysyms.F3, gtk.keysyms.F2): if isinstance(entry, gtk.Entry): value = entry.get_text() From baf1c5a3945f26c2e904f30e72507c14a5648a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Mon, 22 Aug 2011 19:21:55 +0200 Subject: [PATCH 057/147] Ensure environment variable are str issue87001 (transplanted from 75fb228ad8ad7cd412d27af5ae511dae2b9b9518) --- tryton/translate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/translate.py b/tryton/translate.py index 82726553db..b5a0ad94a5 100644 --- a/tryton/translate.py +++ b/tryton/translate.py @@ -172,11 +172,13 @@ def setlang(lang=None, locale_dict=None): elif os.name == 'mac' or \ (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): encoding = 'UTF-8' + # ensure environment variable are str + lang, lang2, encoding = str(lang), str(lang2), str(encoding) os.environ['LANGUAGE'] = lang os.environ['LC_ALL'] = lang2 + '.' + encoding os.environ['LC_MESSAGES'] = lang2 + '.' + encoding os.environ['LANG'] = lang + '.' + encoding - locale.setlocale(locale.LC_ALL, str(lang2 + '.' + encoding)) + locale.setlocale(locale.LC_ALL, lang2 + '.' + encoding) except Exception: logging.getLogger('translate').info( _('Unable to set locale %s') % lang2 + '.' + encoding) From 8890118b3e0ecb21ce152fbdb42455862c127fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Thu, 1 Sep 2011 17:06:19 +0200 Subject: [PATCH 058/147] Fix typo preventing save of records in tree view when no record is selected (transplanted from efc1641589eab8c9a874c90dc73f4c2850b06ea9) --- tryton/gui/window/view_form/screen/screen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 6bdbed7f5f..5232b4888e 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -458,7 +458,7 @@ class Screen(SignalEvent): def save_current(self): if not self.current_record: - if self.current_view == 'tree' and len(self.group): + if self.current_view.view_type == 'tree' and len(self.group): self.current_record = self.group[0] else: return True From cfcd707641ce640480a4f5cf0d70220c91681cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Fri, 2 Sep 2011 16:53:37 +0200 Subject: [PATCH 059/147] Fix drag'n'drop in tree when dropping way down the last item review100002 (transplanted from a3b9823685c534c52ec15dcee4343cb98fb10f94) --- tryton/gui/window/view_form/view/list.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 7017517070..65ad9fa26b 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -114,14 +114,6 @@ class AdaptModelGroup(gtk.GenericTreeModel): record.modified_fields.setdefault(record.parent_name or 'id') group.move(record, 0) - def move_end(self, record): - group = self.group - if group != record.group: - record.group.remove(record, remove=True) - group.add(record) - record.modified_fields.setdefault(record.parent_name or 'id') - group.move(record, -1) - def sort(self, ids): ids2pos = {} pos = 0 @@ -593,7 +585,7 @@ class ViewList(ParserView): elif self.children_field: store.move_into(record, path) else: - store.move_end(record) + store.move_after(record, (len(store) - 1,)) context.drop_finish(False, etime) if treeview.sequence: record.group.set_sequence(field=treeview.sequence) From 62a23ce81c766daf87a69227f2d67c181571e480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 12 Sep 2011 12:39:52 +0200 Subject: [PATCH 060/147] Catch all GError exception when using PixbufLoader issue2144 (transplanted from 216ea2f5406ab8fc60d596c7fddfd7db90ad0964) --- tryton/gui/window/view_form/view/form_gtk/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py index 539d02f72d..cf244c28c4 100644 --- a/tryton/gui/window/view_form/view/form_gtk/image.py +++ b/tryton/gui/window/view_form/view/form_gtk/image.py @@ -208,10 +208,10 @@ class Image(WidgetInterface): try: loader = gtk.gdk.PixbufLoader(ftype) loader.write(data, len(data)) + pixbuf = loader.get_pixbuf() + loader.close() except Exception: continue - pixbuf = loader.get_pixbuf() - loader.close() if pixbuf: break if not pixbuf: From 04c75576e8e09ec51334f48bee8c8e658d976b91 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 1 Oct 2011 14:18:18 +0200 Subject: [PATCH 061/147] Prepare release 2.0.2 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 98630b0fea..9170a0aa56 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.2 - 2011-10-01 +* Bug fixes (see mercurial logs for details) + Version 2.0.1 - 2011-05-29 * Bug fixes (see mercurial logs for details) From 3b7df9a8857141c56e087d662ff93a121fe18e9a Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 1 Oct 2011 14:18:18 +0200 Subject: [PATCH 062/147] Added tag 2.0.2 for changeset 46c952b8bb0b --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d62e268bde..daf4fddc60 100644 --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 8aa050da53cbdfabe1353a37da91c011b7fff549 1.8.0 1876747b3f963ba6011b4bcf6968e681624c6e24 2.0.0 b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 +46c952b8bb0b11b1516196b32e5e006759320a57 2.0.2 From 6d49f3e39a16d3b06c6a14019112e3a8597bc106 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Sat, 1 Oct 2011 14:18:53 +0200 Subject: [PATCH 063/147] 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 b1bf33f366..b5e7b062d3 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.2" +VERSION = "2.0.3" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 144bad6bcf1cfaeb51f4dd3f8de3d231bad658cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 30 Sep 2011 17:01:39 +0200 Subject: [PATCH 064/147] Ensure to concatenate always list in domain_inversion issue2160 review128001 (transplanted from da765f3f3d6e99da69503408b6f06158c496f964) --- tryton/common/domain_inversion.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 69266da96f..fbca01c6ec 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -56,7 +56,7 @@ def inverse_leaf(domain): if len(domain) == 3: return domain else: - return [domain[3]] + domain[1:] + return [domain[3]] + list(domain[1:]) return domain else: return map(inverse_leaf, domain) @@ -86,8 +86,8 @@ def localize_domain(domain, field_name=None): if len(domain) == 3: return domain else: - return [domain[3]] + domain[1:-1] - return [locale_part(domain[0], field_name)] + domain[1:] + return [domain[3]] + list(domain[1:-1]) + return [locale_part(domain[0], field_name)] + list(domain[1:]) else: return [localize_domain(part, field_name) for part in domain] @@ -95,7 +95,7 @@ def unlocalize_domain(domain, fieldname): if domain in ('AND', 'OR', True, False): return domain elif is_leaf(domain): - return ['%s.%s' % (fieldname, domain[0])] + domain[1:] + return ['%s.%s' % (fieldname, domain[0])] + list(domain[1:]) else: return [unlocalize_domain(part, fieldname) for part in domain] From 341967d8a1558e216c4c1ac6976c9d46efbd7a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 10 Oct 2011 18:39:35 +0200 Subject: [PATCH 065/147] Don't set parent_name in One2Many values issue2163 review143001 (transplanted from 0f8d7d3b990086a3eafc7cb8150033bbd770a430) --- tryton/gui/window/view_form/model/field.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 9652e70f9e..6d9f625581 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -495,18 +495,22 @@ class O2MField(CharField): record_removed = record.value[self.name].record_removed record_deleted = record.value[self.name].record_deleted result = [('add', [])] + parent_name = self.attrs.get('relation_field', '') for record2 in record.value[self.name]: if record2 in record_removed or record2 in record_deleted: continue if record2.id > 0: values = record2.get(check_load=check_load, get_readonly=readonly, get_modifiedonly=modified) + values.pop(parent_name, None) if record2.modified and values: result.append(('write', record2.id, values)) result[0][1].append(record2.id) else: - result.append(('create', - record2.get(check_load=check_load, get_readonly=readonly))) + values = record2.get(check_load=check_load, + get_readonly=readonly) + values.pop(parent_name, None) + result.append(('create', values)) if record_removed: result.append(('unlink', [x.id for x in record_removed])) if record_deleted: From b44e88b1c57bc0069138aa782f8544aafee29c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 10 Oct 2011 18:40:29 +0200 Subject: [PATCH 066/147] Always load fields to generate on_change arguments issue2163 review142001 (transplanted from cdb6ef371fa77415e37de21d5239af078a35135d) --- tryton/common/environment.py | 3 ++- tryton/gui/window/view_form/model/record.py | 7 +------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tryton/common/environment.py b/tryton/common/environment.py index f644537bfc..e4f31692b9 100644 --- a/tryton/common/environment.py +++ b/tryton/common/environment.py @@ -17,7 +17,8 @@ class EvalEnvironment(dict): if self.eval_type == 'eval': return self.parent.get_eval(check_load=self.check_load)[item] else: - return self.parent._get_on_change_args([item])[item] + return self.parent.group.fields[item].get_on_change_value(self.parent, + check_load=self.check_load) def __getattr__(self, item): return self.__getitem__(item) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index a712d85d65..a653a707da 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -436,12 +436,7 @@ class Record(SignalEvent): def _get_on_change_args(self, args): res = {} - values = {} - for name, field in self.group.fields.iteritems(): - values[name] = field.get_on_change_value(self, check_load=False) - if self.parent and self.parent_name: - values['_parent_' + self.parent_name] = \ - common.EvalEnvironment(self.parent, False, 'on_change') + values = common.EvalEnvironment(self, True, 'on_change') for arg in args: scope = values for i in arg.split('.'): From ed34f370a895e25f8651765a605904ca8f41f5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 11 Oct 2011 11:43:22 +0200 Subject: [PATCH 067/147] Always test record in AdaptModelGroup issue2162 review148001 (transplanted from d093e7b7ed387cd9257c4f8c806a0335ee12e8f8) --- tryton/gui/window/view_form/view/list.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 65ad9fa26b..36e047ff68 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -191,12 +191,12 @@ class AdaptModelGroup(gtk.GenericTreeModel): return record def on_iter_next(self, record): - if not record: + if record is None: return None return record.next.get(id(record.group)) def on_iter_has_child(self, record): - if not self.children_field: + if record is None or not self.children_field: return False children = record.children_group(self.children_field) length = len(children) @@ -205,8 +205,12 @@ class AdaptModelGroup(gtk.GenericTreeModel): return bool(length) def on_iter_children(self, record): - if self.children_field and record.children_group(self.children_field): - return record.children_group(self.children_field)[0] + if record is None: + return None + if self.children_field: + children = record.children_group(self.children_field) + if children: + return children[0] return None def on_iter_n_children(self, record): From d87f427a98fe19e55f724776b16c3fa716f5768e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 19 Oct 2011 13:14:06 +0200 Subject: [PATCH 068/147] Set default view_ids to None instead of False issue2213 review158002 (transplanted from c5efff6a74778ebe78169375c7eec290c844404e) --- tryton/gui/window/view_board/action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_board/action.py b/tryton/gui/window/view_board/action.py index 9e105d838b..c5c2023191 100644 --- a/tryton/gui/window/view_board/action.py +++ b/tryton/gui/window/view_board/action.py @@ -32,7 +32,7 @@ class Action(SignalEvent): common.process_exception(exception, self._window) raise - view_ids = False + view_ids = None self.action['view_mode'] = None if self.action.get('views', []): view_ids = [x[0] for x in self.action['views']] From 47a518675cceba169f9d49c16e37c200b239c31b Mon Sep 17 00:00:00 2001 From: Max Holtzberg Date: Wed, 19 Oct 2011 13:06:49 +0200 Subject: [PATCH 069/147] Fix handling of dates < 1900 issue2040 review113002 (transplanted from 38a62d96a6ef13b53e285db64c2ff0fcad198a10) --- tryton/common/date_widget.py | 9 +------ tryton/common/datetime_strftime.py | 2 +- .../view_form/view/form_gtk/calendar.py | 27 +++---------------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/tryton/common/date_widget.py b/tryton/common/date_widget.py index 1d44a1c3a1..6fcd847de8 100644 --- a/tryton/common/date_widget.py +++ b/tryton/common/date_widget.py @@ -141,14 +141,7 @@ class DateEntry(gtk.Entry): def date_set(self, dt): if dt: - format = self.format - if dt.year < 10: - format = format.replace('%Y', '000%Y') - elif dt.year < 100: - format = format.replace('%Y', '00%Y') - elif dt.year < 1000: - format = format.replace('%Y', '0%Y') - self.set_text(datetime_strftime(dt, format)) + self.set_text(datetime_strftime(dt, self.format)) else: if self.is_focus(): self.set_text(self.initial_value) diff --git a/tryton/common/datetime_strftime.py b/tryton/common/datetime_strftime.py index 65f6fa50f4..d125d8d204 100644 --- a/tryton/common/datetime_strftime.py +++ b/tryton/common/datetime_strftime.py @@ -44,7 +44,7 @@ def datetime_strftime(dt, fmt): sites.append(site) s = s1 - syear = "%4d" % (dt.year,) + syear = "%04d" % (dt.year,) for site in sites: s = s[:site] + syear + s[site+4:] return s diff --git a/tryton/gui/window/view_form/view/form_gtk/calendar.py b/tryton/gui/window/view_form/view/form_gtk/calendar.py index d8afdf414c..a935ee3386 100644 --- a/tryton/gui/window/view_form/view/form_gtk/calendar.py +++ b/tryton/gui/window/view_form/view/form_gtk/calendar.py @@ -92,14 +92,7 @@ class Calendar(WidgetInterface): if len(value)>10: value = value[:10] date = datetime.date(*time.strptime(value, DT_FORMAT)[:3]) - format = self.format - if date.year < 10: - format = format.replace('%Y', '000%Y') - elif date.year < 100: - format = format.replace('%Y', '00%Y') - elif date.year < 1000: - format = format.replace('%Y', '0%Y') - value = datetime_strftime(date, format) + value = datetime_strftime(date, self.format) if len(value) > self.entry.get_width_chars(): self.entry.set_width_chars(len(value)) self.entry.set_text(value) @@ -138,14 +131,7 @@ class Calendar(WidgetInterface): if response == gtk.RESPONSE_OK: year, month, day = cal.get_date() date = datetime.date(year, month + 1, day) - format = self.format - if date.year < 10: - format = format.replace('%Y', '000%Y') - elif date.year < 100: - format = format.replace('%Y', '00%Y') - elif date.year < 1000: - format = format.replace('%Y', '0%Y') - self.entry.set_text(datetime_strftime(date, format)) + self.entry.set_text(datetime_strftime(date, self.format)) self._focus_out() self.window.present() win.destroy() @@ -246,14 +232,7 @@ class DateTime(WidgetInterface): date = ldt except Exception: pass - format = self.format - if date.year < 10: - format = format.replace('%Y', '000%Y') - elif date.year < 100: - format = format.replace('%Y', '00%Y') - elif date.year < 1000: - format = format.replace('%Y', '0%Y') - value = datetime_strftime(date, format) + value = datetime_strftime(date, self.format) if len(value) > self.entry.get_width_chars(): self.entry.set_width_chars(len(value)) self.entry.set_text(value) From 9ad09148d55b53c426e4a7d90b89ca9ee8d51637 Mon Sep 17 00:00:00 2001 From: Udo Spallek Date: Wed, 2 Nov 2011 11:12:56 +0100 Subject: [PATCH 070/147] Do not use PYSONDecoder() to eval states of button in list view issue2244 (transplanted from a5609b61695b8a7bdb6f7b21a96054b04a5d047a) --- tryton/gui/window/view_form/view/list_gtk/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index f2b4c3babf..a5df7e52b6 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -892,8 +892,8 @@ class Button(object): store = self.treeview.get_model() record = store.get_value(store.get_iter(path), 0) - state_changes = PYSONDecoder().decode(record.expr_eval( - self.attrs.get('states', {}), check_load=False)) + state_changes = record.expr_eval( + self.attrs.get('states', {}), check_load=False) if state_changes.get('invisible') \ or state_changes.get('readonly'): return True From a35ca71cd80a292fc7c82181ad1747adcef5d26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 2 Nov 2011 21:16:42 +0100 Subject: [PATCH 071/147] Test if editable has set_text_column GTK 2.24 and above use a ComboBox instead of a ComboBoxEntry issue2211 (transplanted from 44a56ceafb3436ed61985af1fe5c44c0fc425d7c) --- tryton/gui/window/view_form/view/list_gtk/parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index a5df7e52b6..fef24a1d96 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -749,7 +749,9 @@ class Selection(Char): self.update_selection(record) model = self.get_model(self.selection) editable.set_model(model) - editable.set_text_column(0) + # GTK 2.24 and above use a ComboBox instead of a ComboBoxEntry + if hasattr(editable, 'set_text_column'): + editable.set_text_column(0) completion = gtk.EntryCompletion() #Only available in PyGTK 2.6 and above. if hasattr(completion, 'set_inline_selection'): From 905e3cc32aa2090226b13225f8eb1894e303829e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 4 Nov 2011 17:26:45 +0100 Subject: [PATCH 072/147] Fix EvalEnvironment - works also on id - use the same eval_type for parent - fix __contains__ with parent - use eval_type in __contains__ review169002 (transplanted from 86f1e613dabb911d526ccc89037cb348b202d5dd) --- tryton/common/environment.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tryton/common/environment.py b/tryton/common/environment.py index e4f31692b9..40057ccd0e 100644 --- a/tryton/common/environment.py +++ b/tryton/common/environment.py @@ -12,8 +12,11 @@ class EvalEnvironment(dict): self.eval_type = eval_type def __getitem__(self, item): + if item == 'id': + return self.parent.id if item == '_parent_' + self.parent.parent_name and self.parent.parent: - return EvalEnvironment(self.parent.parent, self.check_load) + return EvalEnvironment(self.parent.parent, self.check_load, + eval_type=self.eval_type) if self.eval_type == 'eval': return self.parent.get_eval(check_load=self.check_load)[item] else: @@ -39,6 +42,11 @@ class EvalEnvironment(dict): __repr__ = __str__ def __contains__(self, item): + if item == 'id': + return True if item == '_parent_' + self.parent.parent_name and self.parent.parent: - return item in EvalEnvironment(self.parent.parent, self.check_load) - return item in self.parent.get_eval(check_load=self.check_load) + return True + if self.eval_type == 'eval': + return item in self.parent.get_eval(check_load=self.check_load) + else: + return item in self.parent.group.fields From e080b32e8024aae5b265d3d0159830853b73c91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 14 Nov 2011 18:01:15 +0100 Subject: [PATCH 073/147] Add allowed ops in safe_eval for Python 2.7 (transplanted from 886cd06d78838bfca94095d8d6fc3e5809dd2f1f) --- tryton/common/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/common/common.py b/tryton/common/common.py index 70db2859e2..ab0e4df1bb 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -1375,6 +1375,7 @@ _ALLOWED_CODES = set(dis.opmap[x] for x in [ 'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR', 'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE', 'DELETE_NAME', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_IF_FALSE_OR_POP', + 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', 'BINARY_SUBSCR', ] if x in dis.opmap) From 1ec484dbe63225c8f30b363d260616395f135f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 19 Nov 2011 19:42:09 +0100 Subject: [PATCH 074/147] domain part can have more than 3 elements issue2285 review178003 (transplanted from 5bd25b87a9d05725a344741e228ca8cd08e0f04a) --- tryton/common/domain_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index fbca01c6ec..62b262fb63 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -223,7 +223,7 @@ class Or(And): elif is_leaf(part) and self.base(part[0]) == symbol: result.append(part) else: - field, _, _ = part + field = part[0] field = self.base(field) if (field in context and eval_leaf(part, context, operator.or_)): From dd08d6d9b6858090ea826ba3b4812f0f6c70e806 Mon Sep 17 00:00:00 2001 From: Phillip Heller Date: Tue, 22 Nov 2011 13:15:45 -0500 Subject: [PATCH 075/147] Fix discovery of gdk-pixbuf-loaders gdk-pixbuf-loaders location has changed with recent builds of gtk, which breaks the build of binary client distributions. This changeset discovers their proper location by parsing output of gdk-pixbuf-query-loaders. issue1976 review176001 (transplanted from 01783c935c47d0d718f1b33e8706f05541ab4fa5) --- setup.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 351cb37e8e..af297feeb0 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ from setuptools import setup, find_packages import os import glob import sys +import re def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() @@ -273,7 +274,7 @@ elif os.name == 'mac' \ 'gtk+-2.0'], stdout=PIPE).stdout.read().strip() dist_dir = dist.command_obj['py2app'].dist_dir - resources_dir = os.path.join(dist_dir, 'tryton.app', 'Contents', 'Resources') + resources_dir = os.path.join(dist_dir, 'Tryton.app', 'Contents', 'Resources') gtk_2_dist_dir = os.path.join(resources_dir, 'lib', 'gtk-2.0') pango_dist_dir = os.path.join(resources_dir, 'lib', 'pango') @@ -293,10 +294,6 @@ elif os.name == 'mac' \ pangorc.write('ModuleFiles=./pango.modules\n') pangorc.close() - if os.path.isdir(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'loaders')): - shutil.rmtree(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'loaders')) - shutil.copytree(os.path.join(gtk_dir, 'lib', 'gtk-2.0', gtk_binary_version, - 'loaders'), os.path.join(gtk_2_dist_dir, gtk_binary_version, 'loaders')) if not os.path.isdir(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'engines')): os.makedirs(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'engines')) shutil.copyfile(os.path.join(gtk_dir, 'lib', 'gtk-2.0', gtk_binary_version, @@ -305,6 +302,15 @@ elif os.name == 'mac' \ query_loaders = Popen(os.path.join(gtk_dir,'bin','gdk-pixbuf-query-loaders'), stdout=PIPE).stdout.read() + loader_dir, = re.findall('# LoaderDir = (.*)', query_loaders) + loader_pkg = (loader_dir.replace(os.path.join(gtk_dir,'lib'), ''). + split(os.path.sep)[-3]) + loader_dist_dir = os.path.join(resources_dir, 'lib', loader_pkg, + gtk_binary_version, 'loaders') + if os.path.isdir(loader_dist_dir): + shutil.rmtree(loader_dist_dir) + if os.path.isdir(loader_dir): + shutil.copytree(loader_dir, loader_dist_dir) query_loaders = query_loaders.replace(gtk_dir, '@executable_path/../Resources') loaders = open(os.path.join(resources_dir, 'gdk-pixbuf.loaders'), 'w') loaders.write(query_loaders) @@ -333,7 +339,7 @@ elif os.name == 'mac' \ # fix pathes within shared libraries for library in chain( - iglob(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'loaders', '*.so')), + iglob(os.path.join(loader_dist_dir, '*.so')), iglob(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'engines', '*.so')), iglob(os.path.join(gtk_2_dist_dir, gtk_binary_version, 'immodules', '*.so')), iglob(os.path.join(pango_dist_dir,'*','modules','*.so'))): From 68258ec233909c9f64b8fea84d2e1ecd2bfe989e Mon Sep 17 00:00:00 2001 From: Phillip Heller Date: Wed, 23 Nov 2011 20:42:04 -0500 Subject: [PATCH 076/147] Fix recognition of Mac OS X based systems Previously, Mac OS X was recognized during py2app invocation, as well as runtime by comparison of os.name with 'macos'. The value of os.name reports as 'posix' under more recent version of Python built on Mac OS X. Now, the recognition is instead done by comparing sys.platform with 'darwin'. issue2258 review171004 (transplanted from d2d9d6ec6da433a5d7df4b07e089f21536b9e4fb) --- setup.py | 6 ++---- tryton/common/common.py | 3 +-- tryton/config.py | 3 +-- tryton/gui/main.py | 5 ++--- tryton/gui/window/view_form/view/list.py | 7 ++----- tryton/translate.py | 4 ++-- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index af297feeb0..34fdc3833b 100644 --- a/setup.py +++ b/setup.py @@ -89,8 +89,7 @@ if os.name == 'nt': args['windows'][0]['other_resources'] = [(24, 1, manifest)] -elif os.name == 'mac' \ - or (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): +elif sys.platform == 'darwin': import py2app from modulegraph.find_modules import PY_SUFFIXES PY_SUFFIXES.append('') @@ -253,8 +252,7 @@ if os.name == 'nt': Popen([makensis, "/DVERSION=" + VERSION, str(os.path.join(os.path.dirname(__file__), 'setup-single.nsi'))]).wait() -elif os.name == 'mac' \ - or (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): +elif sys.platform == 'darwin': def find_gtk_dir(): for directory in os.environ['PATH'].split(':'): if not os.path.isdir(directory): diff --git a/tryton/common/common.py b/tryton/common/common.py index ab0e4df1bb..4b09ed71e6 100644 --- a/tryton/common/common.py +++ b/tryton/common/common.py @@ -376,8 +376,7 @@ def file_open(filename, type, parent, print_p=False): save_p.close() file_p.close() return - elif os.name == 'mac' or \ - (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): + elif sys.platform == 'darwin': pid = os.fork() if not pid: pid = os.fork() diff --git a/tryton/config.py b/tryton/config.py index 32098f7765..2c3f532aed 100644 --- a/tryton/config.py +++ b/tryton/config.py @@ -30,8 +30,7 @@ if not os.path.isdir(get_config_dir()): def find_path(progs, args): if os.name == 'nt': return '' - if os.name == 'mac' or \ - (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): + if sys.platform == 'darwin': return '' paths = [x for x in os.environ['PATH'].split(':') if os.path.isdir(x)] diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 134079728b..3098966d21 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -87,7 +87,7 @@ class Main(object): gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/File/Quit', gtk.keysyms.Q, gtk.gdk.CONTROL_MASK) - if os.name != 'mac': + if sys.platform != 'darwin': gtk.accel_map_add_entry('/User/Menu Reload', gtk.keysyms.T, gtk.gdk.MOD1_MASK) gtk.accel_map_add_entry('/User/Menu Toggle', gtk.keysyms.T, @@ -191,8 +191,7 @@ class Main(object): self.sig_toolbar_show() self.sig_statusbar_show() - if os.name in ('nt', 'mac') or \ - (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): + if os.name == 'nt' or sys.platform == 'darwin': # Disable actions, on win32 we use os.startfile # and on mac we use /usr/bin/open self.menuitem_actions.set_sensitive(False) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index 36e047ff68..ff459af822 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -351,9 +351,7 @@ class ViewList(ParserView): elif self.widget_tree.sequence: dnd = True # Disable DnD on mac until it is fully supported - if os.name == 'mac': - dnd = False - elif hasattr(os, 'uname') and os.uname()[0] == 'Darwin': + if sys.platform == 'darwin': dnd = False if screen.readonly: dnd = False @@ -480,8 +478,7 @@ class ViewList(ParserView): # Don't use set_with_data on mac see: # http://bugzilla.gnome.org/show_bug.cgi?id=508601 if selection.count_selected_rows() < 100 \ - or os.name == 'mac' \ - or (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): + or sys.platform == 'darwin': data = [] selection.selected_foreach(self.copy_foreach, data) clipboard.set_text('\n'.join(data)) diff --git a/tryton/translate.py b/tryton/translate.py index b5a0ad94a5..54654d09c6 100644 --- a/tryton/translate.py +++ b/tryton/translate.py @@ -8,6 +8,7 @@ from version import PACKAGE from tryton.client import CURRENT_DIR, PREFIX import logging import gtk +import sys _ = gettext.gettext @@ -169,8 +170,7 @@ def setlang(lang=None, locale_dict=None): lang2 = lang if os.name == 'nt': lang2 = _LOCALE2WIN32.get(lang, lang) - elif os.name == 'mac' or \ - (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'): + elif sys.platform == 'darwin': encoding = 'UTF-8' # ensure environment variable are str lang, lang2, encoding = str(lang), str(lang2), str(encoding) From 86b16dde1696a1b2053518b50a39d24c82f5132b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 6 Dec 2011 11:26:05 +0100 Subject: [PATCH 077/147] Fix "undefined name 'datas'" in wizard --- tryton/gui/window/wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py index f65949fec6..1c5d213e7e 100644 --- a/tryton/gui/window/wizard.py +++ b/tryton/gui/window/wizard.py @@ -99,7 +99,7 @@ class Wizard(SignalEvent): elif res['type'] == 'print': self.datas['report_id'] = res.get('report_id', False) if res.get('get_id_from_action', False): - backup_ids = datas['ids'] + backup_ids = self.datas['ids'] self.datas['ids'] = self.datas['form']['ids'] Action.exec_report(res['report'], self.datas, self.window, direct_print=self.direct_print, From 6fbdc706a507a1c2d2581cf5dd8772211e4bcafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 1 Dec 2011 15:28:38 +0100 Subject: [PATCH 078/147] Fix in operator to work with xxx2many review186004 (transplanted from 9b406777703293f8c3f4cab683e69d913a80cf6b) --- tryton/common/domain_inversion.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 62b262fb63..8da0a6aa2a 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -4,6 +4,12 @@ import operator import types +def in_(a, b): + if isinstance(a, (list, tuple)): + return any(operator.contains(b, x) for x in a) + else: + return operator.contains(b, a) + OPERATORS = { '=': operator.eq, '>': operator.gt, @@ -11,8 +17,8 @@ OPERATORS = { '<=': operator.le, '>=': operator.ge, '!=': operator.ne, - 'in': lambda a, b: operator.contains(b, a), - 'not in': lambda a, b: not operator.contains(b, a), + 'in': in_, + 'not in': lambda a, b: not in_(b, a), # Those operators are not supported (yet ?) 'like': lambda a, b: True, 'ilike': lambda a, b: True, @@ -390,6 +396,13 @@ def test_evaldomain(): assert eval_domain(domain, {'x': 6}) assert not eval_domain(domain, {'x': 4}) + domain = [['x', 'in', [3, 5]]] + assert eval_domain(domain, {'x': 3}) + assert not eval_domain(domain, {'x': 4}) + assert eval_domain(domain, {'x': [3]}) + assert eval_domain(domain, {'x': [3, 4]}) + assert not eval_domain(domain, {'x': [1, 2]}) + domain = ['OR', ['x', '>', 10], ['x', '<', 0]] assert eval_domain(domain, {'x': 11}) assert eval_domain(domain, {'x': -4}) From 0b542f68e761d3e053bf37f2796d94dd28acde8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 17 Dec 2011 21:13:22 +0100 Subject: [PATCH 079/147] Test instance also for ComboBox GTK 2.24 and above use a ComboBox instead of a ComboBoxEntry issue2288 review207001 (transplanted from acdc4008c2fbaaf3e4d0c6079ea871c0544aee77) --- tryton/gui/window/view_form/view/list_gtk/editabletree.py | 2 +- tryton/gui/window/view_form/view/list_gtk/parser.py | 2 +- 2 files changed, 2 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 54df75f86e..069f861adc 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -268,5 +268,5 @@ class EditableTreeView(gtk.TreeView): record = model.get_value(model.get_iter(path), 0) if isinstance(entry, gtk.Entry): self.on_quit_cell(record, column.name, entry.get_text()) - elif isinstance(entry, gtk.ComboBoxEntry): + elif isinstance(entry, (gtk.ComboBoxEntry, gtk.ComboBox)): self.on_quit_cell(record, column.name, entry.get_active_text()) diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index fef24a1d96..ca0a5956c7 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -34,7 +34,7 @@ def send_keys(renderer, editable, position, treeview): editable.connect('key_press_event', treeview.on_keypressed) editable.editing_done_id = editable.connect('editing_done', treeview.on_editing_done) - if isinstance(editable, gtk.ComboBoxEntry): + if isinstance(editable, (gtk.ComboBoxEntry, gtk.ComboBox)): editable.connect('changed', treeview.on_editing_done) def sort_model(column, treeview, screen): From a7872d31915798e3d9b2a739b4191dc196c632c8 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 26 Dec 2011 10:38:56 +0100 Subject: [PATCH 080/147] Prepare release 2.0.3 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 9170a0aa56..16e5c138d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.3 - 2011-12-26 +* Bug fixes (see mercurial logs for details) + Version 2.0.2 - 2011-10-01 * Bug fixes (see mercurial logs for details) From af6d1629161d917293e68e945f6faf4532a893c7 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 26 Dec 2011 10:38:56 +0100 Subject: [PATCH 081/147] Added tag 2.0.3 for changeset cd972be66532 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index daf4fddc60..6310904dc5 100644 --- a/.hgtags +++ b/.hgtags @@ -6,3 +6,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 1876747b3f963ba6011b4bcf6968e681624c6e24 2.0.0 b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 46c952b8bb0b11b1516196b32e5e006759320a57 2.0.2 +cd972be665323ca5fedfc7d08d259b54d96d4f9c 2.0.3 From 41216d54a8ebdec8b4a9cba4cf116e29c99e1405 Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 26 Dec 2011 10:39:27 +0100 Subject: [PATCH 082/147] 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 b5e7b062d3..ba7aece1cf 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.3" +VERSION = "2.0.4" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 007e82ea901d4f8b3feaabfbc7a51d6a0b2d5aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 2 Jan 2012 18:50:01 +0100 Subject: [PATCH 083/147] Remove entry added to combobox in win_import review210009 (transplanted from 40d5157e9d58f50a00464d280de36a4a0af4a876) --- tryton/gui/window/win_import.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tryton/gui/window/win_import.py b/tryton/gui/window/win_import.py index e159f46dea..50ba60c377 100644 --- a/tryton/gui/window/win_import.py +++ b/tryton/gui/window/win_import.py @@ -143,9 +143,6 @@ class WinImport(object): self.import_csv_enc = gtk.combo_box_new_text() self.import_csv_enc.append_text("UTF-8") self.import_csv_enc.append_text("Latin1") - cboxent_import_csv_enc = gtk.Entry() - cboxent_import_csv_enc.unset_flags(gtk.CAN_FOCUS) - self.import_csv_enc.add(cboxent_import_csv_enc) table.attach(self.import_csv_enc, 1, 2, 1, 2) label_import_csv_skip = gtk.Label(_("Lines to Skip:")) From e13402b1948036f2c21ddaeb1a8a383d188ff6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 11 Jan 2012 10:44:26 +0100 Subject: [PATCH 084/147] Ensure that loading is always eager for fields on tree view issue2378 review220001 (transplanted from 65513b69d0913f4443eb53ebe1a4e449ae1570b9) --- tryton/gui/window/view_form/screen/screen.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 5232b4888e..c67379cc19 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -359,6 +359,8 @@ class Screen(SignalEvent): self.fields_view_tree = view break + # Ensure that loading is always eager for fields on tree view + # and always lazy for fields only on form view if node.localName == 'tree': loading = 'eager' else: @@ -366,6 +368,9 @@ class Screen(SignalEvent): for field in fields: if field not in self.group.fields: fields[field]['loading'] = loading + else: + fields[field]['loading'] = \ + self.group.fields[field].attrs['loading'] children_field = view.get('field_childs') From 58ce8bd9b8d417be2de4af2ca6f218250a94cb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 17 Jan 2012 13:56:50 +0100 Subject: [PATCH 085/147] Fix float_time widget to round value according to digits review222007 (transplanted from 2aa50bbdde4d89b314fd85b24ec4dcf7f4f0a56d) --- tryton/gui/window/view_form/view/form_gtk/float_time.py | 3 ++- tryton/gui/window/view_form/view/list_gtk/parser.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/float_time.py b/tryton/gui/window/view_form/view/form_gtk/float_time.py index 3fa5c60b25..063321ba97 100644 --- a/tryton/gui/window/view_form/view/form_gtk/float_time.py +++ b/tryton/gui/window/view_form/view/form_gtk/float_time.py @@ -36,8 +36,9 @@ class FloatTime(WidgetInterface): value = self.entry.get_text() if not value: return field.set_client(record, 0.0) + digits = record.expr_eval(field.attrs.get('digits', (16, 2))) return field.set_client(record, - common.text_to_float_time(value, self.conv)) + round(common.text_to_float_time(value, self.conv), digits[1])) def display(self, record, field): super(FloatTime, self).display(record, field) diff --git a/tryton/gui/window/view_form/view/list_gtk/parser.py b/tryton/gui/window/view_form/view/list_gtk/parser.py index ca0a5956c7..61bea38e7f 100644 --- a/tryton/gui/window/view_form/view/list_gtk/parser.py +++ b/tryton/gui/window/view_form/view/list_gtk/parser.py @@ -503,7 +503,9 @@ class FloatTime(Char): return common.float_time_to_text(val, self.conv) def value_from_text(self, record, text): - return common.text_to_float_time(text, self.conv) + field = record[self.field_name] + digits = record.expr_eval(field.attrs.get('digits', (16, 2))) + return round(common.text_to_float_time(text, self.conv), digits[1]) class M2O(Char): From 7dc7333d6c1015dbe4b50204f285aaad1e4a770b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 17 Jan 2012 15:38:02 +0100 Subject: [PATCH 086/147] Destroy also values of record Otherwise the groups of xxx2many records stay in the memory due to reference cycle between Group and Record. review222006 (transplanted from 34842c74fbc585bd9b8e9a3be64fa2640967ece7) --- tryton/gui/window/view_form/model/record.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py index a653a707da..5468943b85 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -566,5 +566,8 @@ class Record(SignalEvent): super(Record, self).destroy() self.window = None self.group = None + for v in self.value.itervalues(): + if hasattr(v, 'destroy'): + v.destroy() self.value = None self.next = None From 7f6b855d4d3a5b9884d93d514840649e7075b2f2 Mon Sep 17 00:00:00 2001 From: Oscar Alvarez Date: Mon, 30 Jan 2012 22:06:29 -0500 Subject: [PATCH 087/147] Fix the export wizard for load all predef fields saved It modified using method iter_children issue2383 review219002 (transplanted from 232508536908ca64d4f8380896e884d6d1093acf) --- tryton/gui/window/win_export.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index 4d1afe18a8..271d1d6dc3 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -369,9 +369,12 @@ class WinExport(object): (prefix + parent): self.on_row_expanded(self.view1, iter, self.model1.get_path(iter)) + iter = self.model1.iter_children(iter) + prefix = parent + '/' break - iter = self.model1.iter_next(iter) - prefix = parent + '/' + else: + iter = self.model1.iter_next(iter) + if field not in self.fields_data: continue self.model2.append((self.fields_data[field]['string'], field)) From ff579161f57dc79f27863fe2340993d7f923d27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 1 Feb 2012 17:11:41 +0100 Subject: [PATCH 088/147] Remove edit_canceled as empty profile is managed by edit_profilename issue2292 review237001 (transplanted from 9a4dc93abe96d51322877c973768ee31fa09ec8f) --- tryton/gui/window/dblogin.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 6201642b28..7cebb75ea0 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -43,7 +43,6 @@ class DBListEditor(object): self.cell.set_property('editable', True) self.cell.connect('edited', self.edit_profilename) self.cell.connect('editing-started', self.edit_started) - self.cell.connect('editing-canceled', self.edit_canceled) self.profile_tree = gtk.TreeView() self.profile_tree.set_model(profile_store) self.profile_tree.insert_column_with_attributes(-1, _(u'Profile'), @@ -225,12 +224,6 @@ class DBListEditor(object): self.display_dbwidget(None, None, self.current_database) - def edit_canceled(self, renderer): - model = self.profile_tree.get_model() - for i, row in enumerate(list(model)): - if not row[0]: - del model[i] - def check_edit_cancel(self, editable, event, renderer, path): renderer.emit('edited', path, editable.get_text()) return False From d1195a125c2df9d931b93cc101eb5869c15c69bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 21 Feb 2012 16:19:03 +0100 Subject: [PATCH 089/147] Remove trailing space (transplanted from af3e207f00156b9388eb124ce13cb3380e81b670) --- 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 271d1d6dc3..e1ea9aa4ef 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -374,7 +374,7 @@ class WinExport(object): break else: iter = self.model1.iter_next(iter) - + if field not in self.fields_data: continue self.model2.append((self.fields_data[field]['string'], field)) From 3edab86a02c214d1b133053e824ac63009ddab1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 22 Feb 2012 17:20:50 +0100 Subject: [PATCH 090/147] Prevent double sent of edited event Rely only on the focus-out-event of the editable otherwise the edited event can be sent twice and if the selected profile was removed it generates a IndexError. (transplanted from 14d5bec084d1cf4550faa04bbd850b4004e8246d) --- tryton/gui/window/dblogin.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py index 7cebb75ea0..98962504d1 100644 --- a/tryton/gui/window/dblogin.py +++ b/tryton/gui/window/dblogin.py @@ -41,7 +41,6 @@ class DBListEditor(object): vbox_profiles = gtk.VBox(homogeneous=False, spacing=6) self.cell = gtk.CellRendererText() self.cell.set_property('editable', True) - self.cell.connect('edited', self.edit_profilename) self.cell.connect('editing-started', self.edit_started) self.profile_tree = gtk.TreeView() self.profile_tree.set_model(profile_store) @@ -224,16 +223,13 @@ class DBListEditor(object): self.display_dbwidget(None, None, self.current_database) - def check_edit_cancel(self, editable, event, renderer, path): - renderer.emit('edited', path, editable.get_text()) - return False - def edit_started(self, renderer, editable, path): if isinstance(editable, gtk.Entry): - editable.connect('focus-out-event', self.check_edit_cancel, + editable.connect('focus-out-event', self.edit_profilename, renderer, path) - def edit_profilename(self, renderer, path, newtext): + def edit_profilename(self, editable, event, renderer, path): + newtext = editable.get_text() model = self.profile_tree.get_model() oldname = model[path][0] if oldname == newtext == '': From 3030f23fd7d43480d2c687d25b2d84d66e4f7848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 1 Mar 2012 10:18:31 +0100 Subject: [PATCH 091/147] Return empty list when calling O2M.get if empty Test on required state except to have a value evaluated to False in case of empty O2M. issue2382 review258002 (transplanted from 9364d03b9467364498b3f0e97b0fd2e0e85dfa10) --- 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 6d9f625581..e16dc76af6 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -511,6 +511,8 @@ class O2MField(CharField): get_readonly=readonly) values.pop(parent_name, None) result.append(('create', values)) + if not result[0][1]: + del result[0] if record_removed: result.append(('unlink', [x.id for x in record_removed])) if record_deleted: From e952c552ee788e583ce8410dd88f167e1ce89c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 5 Mar 2012 10:15:53 +0100 Subject: [PATCH 092/147] Use relativedelta to make all the datetime computation issue2469 (transplanted from 9516267d90bd89a0c49c225d639380cbc991e928) --- tryton/pyson.py | 59 ++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/tryton/pyson.py b/tryton/pyson.py index b3d375bb30..eaead71f2c 100644 --- a/tryton/pyson.py +++ b/tryton/pyson.py @@ -6,6 +6,7 @@ if sys.version_info < (2, 6): else: import json import datetime +from dateutil.relativedelta import relativedelta class PYSON(object): @@ -394,23 +395,14 @@ class Date(PYSON): @staticmethod def eval(dct, context): - date = datetime.date.today() - replace = {} - for i, j in (('y', 'year'), ('M', 'month'), ('d', 'day')): - if dct[i] is not None: - replace[j] = dct[i] - date = date.replace(**replace) - if dct['dy']: - year = date.year + dct['dy'] - date = date.replace(year=year) - if dct['dM']: - month = date.month + dct['dM'] - year = date.year + month / 12 - month = month % 12 - date = date.replace(year=year, month=month) - if dct['dd']: - date += datetime.timedelta(days=dct['dd']) - return date + return datetime.date.today() + relativedelta( + year=dct['y'], + month=dct['M'], + day=dct['d'], + years=dct['dy'], + months=dct['dM'], + days=dct['dd'], + ) class DateTime(Date): @@ -458,22 +450,23 @@ class DateTime(Date): @staticmethod def eval(dct, context): - date = Date.eval(dct, context) - datetime_ = datetime.datetime.combine(date, - datetime.datetime.now().time()) - replace = {} - for i, j in (('h', 'hour'), ('m', 'minute'), ('s', 'second'), - ('ms', 'microsecond')): - if dct[i] is not None: - replace[j] = dct[i] - datetime_ = datetime_.replace(**replace) - delta = {} - for i, j in (('dh', 'hours'), ('dm', 'minutes'), ('ds', 'seconds'), - ('dms', 'microseconds')): - if dct[i]: - delta[j] = dct[i] - datetime_ += datetime.timedelta(**delta) - return datetime_ + return datetime.datetime.now() + relativedelta( + year=dct['y'], + month=dct['M'], + day=dct['d'], + hour=dct['h'], + minute=dct['m'], + second=dct['s'], + microsecond=dct['ms'], + years=dct['dy'], + months=dct['dM'], + days=dct['dd'], + hours=dct['dh'], + minutes=dct['dm'], + seconds=dct['ds'], + microseconds=dct['dms'], + ) + CONTEXT = { 'Eval': Eval, From 0d1731d5b88a83837a0e4e010239535f027797b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 7 Mar 2012 16:17:19 +0100 Subject: [PATCH 093/147] Use field.context_get instead of evaluating the context attribute (transplanted from 676c65f18b1142f3d97df308a0b1253a44775973) --- tryton/gui/window/view_form/view/form_gtk/one2many.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f8c78b7253..7f7a68571d 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -231,7 +231,7 @@ class One2Many(WidgetInterface): self.screen.display() return ctx = {} - ctx.update(self.record.expr_eval(self.attrs.get('context', {}))) + ctx.update(self.field.context_get(self.record)) sequence = None if self.screen.current_view.view_type == 'tree': sequence = self.screen.current_view.widget_tree.sequence From 6330121bcd4e9bf4e330ea7ddba8a57442d028a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 13 Apr 2012 11:42:14 +0200 Subject: [PATCH 094/147] Loading a record, already there, must trigger signals review322003 (transplanted from 731b2c915a0869532e27d8ad2421301e2b2a758d) --- tryton/gui/window/view_form/model/group.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index 27ff8d4b13..ac5fa25791 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -201,16 +201,16 @@ class Group(SignalEvent, list): new_records = [] for id in ids: - if self.get(id): - continue - new_record = Record(self.model_name, id, self.window, - group=self) - self.append(new_record) + new_record = self.get(id) + if not new_record: + new_record = Record(self.model_name, id, self.window, + group=self) + self.append(new_record) + new_record.signal_connect(self, 'record-changed', + self._record_changed) + new_record.signal_connect(self, 'record-modified', + self._record_modified) new_records.append(new_record) - new_record.signal_connect(self, 'record-changed', - self._record_changed) - new_record.signal_connect(self, 'record-modified', - self._record_modified) # Remove previously removed or deleted records for record in self.record_removed[:]: From c2fc098b63dbe3977de71eb4ed1a06fd934c11c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 13 Apr 2012 14:24:08 +0200 Subject: [PATCH 095/147] PixbufLoader must be closed before getting pixbuf On windows, jpeg loader needs to be closed to return correct pixbuf. issue2482 (transplanted from 726bb7cfc5e424cdc919ce9cdc37b4fa5f553cf0) --- tryton/gui/window/view_form/view/form_gtk/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py index cf244c28c4..b020277279 100644 --- a/tryton/gui/window/view_form/view/form_gtk/image.py +++ b/tryton/gui/window/view_form/view/form_gtk/image.py @@ -208,8 +208,8 @@ class Image(WidgetInterface): try: loader = gtk.gdk.PixbufLoader(ftype) loader.write(data, len(data)) - pixbuf = loader.get_pixbuf() loader.close() + pixbuf = loader.get_pixbuf() except Exception: continue if pixbuf: @@ -217,8 +217,8 @@ class Image(WidgetInterface): if not pixbuf: loader = gtk.gdk.PixbufLoader('png') loader.write(NOIMAGE, len(NOIMAGE)) - pixbuf = loader.get_pixbuf() loader.close() + pixbuf = loader.get_pixbuf() img_height = pixbuf.get_height() if img_height > self.height: From 4fb67d39f1fa94fe0e3cb50ba85f6c004572b756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 18 Apr 2012 20:00:06 +0200 Subject: [PATCH 096/147] Reset current_record before clearing group (transplanted from 6c8591e020f818a25b62925a3e4eccd4e49a057f) --- tryton/gui/window/view_form/screen/screen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index c67379cc19..a767235d0c 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -750,8 +750,8 @@ class Screen(SignalEvent): return [x.id for x in self.group if x.id] def clear(self): - self.group.clear() self.current_record = None + self.group.clear() def on_change(self, fieldname, attr): self.current_record.on_change(fieldname, attr) From d40189b408ed532b7751c6fef2108835231aca86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 19 Apr 2012 23:34:49 +0200 Subject: [PATCH 097/147] Fix infinit loop when computing root_group (transplanted from bdea2cca8183d2e59e2e02b8c80419b7d5172ba9) --- tryton/gui/window/view_form/model/group.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py index ac5fa25791..11bc1f2e72 100644 --- a/tryton/gui/window/view_form/model/group.py +++ b/tryton/gui/window/view_form/model/group.py @@ -161,6 +161,7 @@ class Group(SignalEvent, list): parent = self.parent while parent: root = parent.group + parent = parent.parent return root def written(self, ids): From 7d7c19037cf8b9b6de68697e870cab2075d2e66e Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 7 May 2012 11:08:21 +0200 Subject: [PATCH 098/147] Prepare release 2.0.4 --- CHANGELOG | 3 +++ COPYRIGHT | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 16e5c138d8..00ce8f4a01 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.4 - 2012-05-07 +* Bug fixes (see mercurial logs for details) + Version 2.0.3 - 2011-12-26 * Bug fixes (see mercurial logs for details) diff --git a/COPYRIGHT b/COPYRIGHT index 9636f7aac5..a3c3253906 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ Copyright (C) 2010-2011 Nicolas Évrard. -Copyright (C) 2007-2011 Cédric Krier. +Copyright (C) 2007-2012 Cédric Krier. Copyright (C) 2007-2011 Bertrand Chenal. -Copyright (C) 2008-2011 B2CK SPRL. +Copyright (C) 2008-2012 B2CK SPRL. Copyright (C) 2008-2011 Udo Spallek. Copyright (C) 2008-2011 virtual things - Preisler & Spallek GbR. Copyright (C) 2007-2009 Lorenzo Gil Sanchez. From 3abe99c1a2b327f71462ac7d7ee9511eb4b1521d Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 7 May 2012 11:08:21 +0200 Subject: [PATCH 099/147] Added tag 2.0.4 for changeset e81fe66bc048 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 6310904dc5..84327d2b9a 100644 --- a/.hgtags +++ b/.hgtags @@ -7,3 +7,4 @@ de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 46c952b8bb0b11b1516196b32e5e006759320a57 2.0.2 cd972be665323ca5fedfc7d08d259b54d96d4f9c 2.0.3 +e81fe66bc0487db26a59df8a8ac93c61a8eae176 2.0.4 From 34a0e37b18cb56128f97da2c255e57aa554e9a5c Mon Sep 17 00:00:00 2001 From: Mathias Behrle Date: Mon, 7 May 2012 11:08:52 +0200 Subject: [PATCH 100/147] 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 ba7aece1cf..bddd242b1d 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.4" +VERSION = "2.0.5" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From b2347197ec1b254c3af130d067721a4daa3de18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 12 May 2012 16:48:17 +0200 Subject: [PATCH 101/147] Fix domain_inversion for comparison of datetime with None review359002 (transplanted from 49609073c798e7b019a5d2dc28dcebb627ad10dd) --- tryton/common/domain_inversion.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 8da0a6aa2a..335eee831a 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -3,6 +3,7 @@ import operator import types +import datetime def in_(a, b): if isinstance(a, (list, tuple)): @@ -52,7 +53,18 @@ def eval_leaf(part, context, boolop=operator.and_): # We should consider that other domain inversion will set a correct # value to this field return True - return OPERATORS[operand](context[field], value) + context_field = context[field] + if isinstance(context_field, datetime.date) and not value: + if isinstance(context_field, datetime.datetime): + value = datetime.datetime.min + else: + value = datetime.date.min + if isinstance(value, datetime.date) and not context_field: + if isinstance(value, datetime.datetime): + context_field = datetime.datetime.min + else: + context_field = datetime.date.min + return OPERATORS[operand](context_field, value) def inverse_leaf(domain): if domain in ('AND', 'OR'): @@ -396,6 +408,15 @@ def test_evaldomain(): assert eval_domain(domain, {'x': 6}) assert not eval_domain(domain, {'x': 4}) + domain = [['x', '>', None]] + assert eval_domain(domain, {'x': datetime.date.today()}) + assert eval_domain(domain, {'x': datetime.datetime.now()}) + + domain = [['x', '<', datetime.date.today()]] + assert eval_domain(domain, {'x': None}) + domain = [['x', '<', datetime.datetime.now()]] + assert eval_domain(domain, {'x': None}) + domain = [['x', 'in', [3, 5]]] assert eval_domain(domain, {'x': 3}) assert not eval_domain(domain, {'x': 4}) From 0fa97a7c6c0dbde12536678409d333442c83fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 22 Jun 2012 17:53:35 +0200 Subject: [PATCH 102/147] Fix name of fields loaded from predefined export issue2648 review404001 (transplanted from 481bf839727a0a1afff30fb963e46afa368b4306) --- tryton/gui/window/win_export.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py index e1ea9aa4ef..142ca62e56 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -246,7 +246,8 @@ class WinExport(object): child = self.model1.iter_children(iter) if self.model1.get_value(child, 0) is None: prefix_field = self.model1.get_value(iter, 1) - name, model = self.fields[prefix_field] + _, model = self.fields[prefix_field] + name = self.fields_data[prefix_field]['string'] self.model_populate(self._get_fields(model), iter, prefix_field + '/', name + '/') self.model1.remove(child) From 2d11b3886b98939f3f8666aa8fba2bbeffebbe68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 28 Jun 2012 15:11:17 +0200 Subject: [PATCH 103/147] set_value of M2O must simulate a focus-out in case it did not yet occur issue2624 review408001 (transplanted from a07d90df4d9e6b98778260ec684b6f1317a4cb8b) --- tryton/gui/window/view_form/view/form_gtk/many2one.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tryton/gui/window/view_form/view/form_gtk/many2one.py b/tryton/gui/window/view_form/view/form_gtk/many2one.py index 3436187e32..9ed58b35e7 100644 --- a/tryton/gui/window/view_form/view/form_gtk/many2one.py +++ b/tryton/gui/window/view_form/view/form_gtk/many2one.py @@ -83,7 +83,7 @@ class Many2One(WidgetInterface): def _color_widget(self): return self.wid_text - def sig_activate(self, widget, event=None, key_press=False): + def sig_activate(self, widget=None, event=None, key_press=False): if not self.focus_out: return if not self.field: @@ -93,7 +93,7 @@ class Many2One(WidgetInterface): self.focus_out = False if not value: - if not key_press and not event: + if not key_press and not event and widget: widget.emit_stop_by_name('activate') if not self._readonly and (self.wid_text.get_text() or \ (self.field.get_state_attrs( @@ -243,7 +243,8 @@ class Many2One(WidgetInterface): return False def set_value(self, record, field): - pass # No update of the model, the model is updated in real time ! + # Simulate a focus-out + self.sig_activate() def display(self, record, field): self.changed = False From a8140485820e70ca91fd682351317bb5f64d34f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 25 Jul 2012 20:31:56 +0200 Subject: [PATCH 104/147] Fix test on legend graph attribute review421001 (transplanted from 883480d210a7b3361afc69df26e766c62a4e76dc) --- tryton/gui/window/view_form/view/graph_gtk/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tryton/gui/window/view_form/view/graph_gtk/graph.py b/tryton/gui/window/view_form/view/graph_gtk/graph.py index 0dcd6cf155..ae02977611 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/graph.py +++ b/tryton/gui/window/view_form/view/graph_gtk/graph.py @@ -268,7 +268,7 @@ class Graph(gtk.DrawingArea): cr.restore() def drawLegend(self, cr, width, height): - if not self.attrs.get('legend', True): + if not int(self.attrs.get('legend', 1)): return padding = 4 From 7309a0cfd21eaec7edc4178f17174ca587ef9305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 1 Sep 2012 18:59:36 +0200 Subject: [PATCH 105/147] Prepare release 2.0.5 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 00ce8f4a01..ec719cf32f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.5 - 2012-09-01 +* Bug fixes (see mercurial logs for details) + Version 2.0.4 - 2012-05-07 * Bug fixes (see mercurial logs for details) From e46ef4b3efffdddea4058adf9a610eab3a93ba7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 1 Sep 2012 18:59:37 +0200 Subject: [PATCH 106/147] Added tag 2.0.5 for changeset b0e372e50183 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 84327d2b9a..42cc467be6 100644 --- a/.hgtags +++ b/.hgtags @@ -8,3 +8,4 @@ b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 46c952b8bb0b11b1516196b32e5e006759320a57 2.0.2 cd972be665323ca5fedfc7d08d259b54d96d4f9c 2.0.3 e81fe66bc0487db26a59df8a8ac93c61a8eae176 2.0.4 +b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 From 686692f5ee03749698ab6dc467e69c7aca5bd362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 1 Sep 2012 19:00:20 +0200 Subject: [PATCH 107/147] 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 bddd242b1d..659a2e71e4 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.5" +VERSION = "2.0.6" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 8628e3a55330cd3124ced6a2cb54f09362792a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 1 Oct 2012 16:07:19 +0200 Subject: [PATCH 108/147] Don't store interger as current record Use inline if/else instead of and issue2701 (transplanted from 33f9f70a701fb253463297e173345e8d08cc58f3) --- tryton/gui/window/view_form/screen/screen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index a767235d0c..832f1a190f 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -702,7 +702,7 @@ class Screen(SignalEvent): break self.current_record = record else: - self.current_record = len(self.group) and self.group[0] + self.current_record = self.group[0] if len(self.group) else None view.set_cursor(reset_view=False) view.display() @@ -734,7 +734,7 @@ class Screen(SignalEvent): record = parent self.current_record = record else: - self.current_record = len(self.group) and self.group[-1] + self.current_record = self.group[-1] if len(self.group) else None view.set_cursor(reset_view=False) view.display() From 176a4c951d4fda15eb06fc5254e740dc529d6177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 6 Oct 2012 17:11:18 +0200 Subject: [PATCH 109/147] Use the same pattern for move_into than _move to prevent concurrency (transplanted from f57702fc015c87566146ee11623d8481ff2388c8) --- tryton/gui/window/view_form/view/list.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py index ff459af822..f6def95cfa 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -110,6 +110,10 @@ class AdaptModelGroup(gtk.GenericTreeModel): group = parent.children_group(self.children_field, check_load=True) if group is not record.group: record.group.remove(record, remove=True, force_remove=True) + # 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) group.add(record) record.modified_fields.setdefault(record.parent_name or 'id') group.move(record, 0) From c01feb47fcd68818a853228e2fc3be8db91f3b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 9 Oct 2012 17:18:35 +0200 Subject: [PATCH 110/147] Fix next/previous in form view when there is no current record issue2788 review548003 (transplanted from bd5d0d004c19cd4fe33f3263b065d3fdba630130) --- tryton/gui/window/view_form/screen/screen.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py index 832f1a190f..1c51863985 100644 --- a/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/gui/window/view_form/screen/screen.py @@ -675,7 +675,9 @@ class Screen(SignalEvent): store = view.store iter_ = store.get_iter(end) self.current_record = store.get_value(iter_, 0) - elif view.view_type == 'form' and self.current_record.group: + elif (view.view_type == 'form' + and self.current_record + and self.current_record.group): group = self.current_record.group record = self.current_record while group: @@ -717,7 +719,9 @@ class Screen(SignalEvent): store = view.store iter_ = store.get_iter(start) self.current_record = store.get_value(iter_, 0) - elif view.view_type == 'form' and self.current_record.group: + elif (view.view_type == 'form' + and self.current_record + and self.current_record.group): group = self.current_record.group record = self.current_record idx = group.index(record) - 1 From 2ea0f605fbd044f2ba127d74e8b1e555ad6f95f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 17 Oct 2012 21:19:22 +0200 Subject: [PATCH 111/147] Fix calls to sig_db_dump/restore issue2814 (transplanted from 2105a3798a43a68f2813a0258597c20d653c87a0) --- tryton/gui/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tryton/gui/main.py b/tryton/gui/main.py index 3098966d21..0050a82968 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -1611,7 +1611,7 @@ class Main(object): common.message(_("Database dropped successfully!"), \ parent=self.window) - def sig_db_restore(self, widget): + def sig_db_restore(self, widget=None): if not self.sig_logout(widget): return False filename = common.file_selection(_('Open Backup File to Restore...'), \ @@ -1656,7 +1656,7 @@ class Main(object): common.message(_('Database restore failed!'), \ parent=self.window) - def sig_db_dump(self, widget): + def sig_db_dump(self, widget=None): if not self.sig_logout(widget): return False dialog = DBBackupDrop(self.window, function='backup') From 6cd534e7c5424a1c06c084ed341444aa3e0801fe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bonicoli Date: Sat, 20 Oct 2012 13:46:07 +0200 Subject: [PATCH 112/147] avoid markup on unknown strings issue2843 review576002 (transplanted from ee1eeb93e98c8a82678b6cf37fa44fbc1b41fd55) --- tryton/gui/window/win_form.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py index 65b9211aad..2af528340b 100644 --- a/tryton/gui/window/win_form.py +++ b/tryton/gui/window/win_form.py @@ -73,9 +73,8 @@ class WinForm(object): self.win.set_title(self.screen.current_view.title) title = gtk.Label() - title.set_use_markup(True) - title.modify_font(pango.FontDescription("12")) - title.set_label('' + self.screen.current_view.title + '') + title.modify_font(pango.FontDescription("bold 12")) + title.set_label(self.screen.current_view.title) title.set_padding(20, 3) title.set_alignment(0.0, 0.5) title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) From 56d1f262c33cb361c63347c3ff8dd108f5d78462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 5 Nov 2012 17:33:32 +0100 Subject: [PATCH 113/147] Prepare release 2.0.6 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index ec719cf32f..28f1f63b67 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.6 - 2012-11-05 +* Bug fixes (see mercurial logs for details) + Version 2.0.5 - 2012-09-01 * Bug fixes (see mercurial logs for details) From 40139d5342a7b1306bca484baab0fd4c4fb2cc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 5 Nov 2012 17:33:33 +0100 Subject: [PATCH 114/147] Added tag 2.0.6 for changeset 41a147a9ba5c --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 42cc467be6..266f0b00db 100644 --- a/.hgtags +++ b/.hgtags @@ -9,3 +9,4 @@ b9cc8cd7419df6846efdb367a1e1b7d536e81fe0 2.0.1 cd972be665323ca5fedfc7d08d259b54d96d4f9c 2.0.3 e81fe66bc0487db26a59df8a8ac93c61a8eae176 2.0.4 b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 +41a147a9ba5cb6bae96373d55a6efea72f26b6eb 2.0.6 From 5b6fd09b504062eb9cc7cc21c46cf9b8f12cdaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 5 Nov 2012 17:34:17 +0100 Subject: [PATCH 115/147] 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 659a2e71e4..0f3a065100 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.6" +VERSION = "2.0.7" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From a13585edbe86b65c1d53543d574944d3fbba677d 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 116/147] 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 335eee831a..15c3b58183 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -49,11 +49,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 5468943b85..62b3d7f76d 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -223,6 +223,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 @@ -414,7 +416,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 ce82c867b895491894acdfc9422b75351dc60501 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 117/147] 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 e16dc76af6..4c73254724 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -665,7 +665,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 b2fde9d4d36be31d1bbda00e8e4892a25f0f0ad5 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 118/147] 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 34fdc3833b..0002988897 100644 --- a/setup.py +++ b/setup.py @@ -237,6 +237,11 @@ if os.name == 'nt': shutil.rmtree(os.path.join(dist_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')): shutil.rmtree(os.path.join(dist_dir, 'share', 'themes', 'MS-Windows')) @@ -334,6 +339,11 @@ elif sys.platform == 'darwin': shutil.rmtree(os.path.join(resources_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 1680d38478be90dd8b7da438dcc4a50c6e17f17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 16:59:31 +0100 Subject: [PATCH 119/147] Prepare release 2.0.7 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 28f1f63b67..a865f98dcd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.7 - 2012-12-23 +* Bug fixes (see mercurial logs for details) + Version 2.0.6 - 2012-11-05 * Bug fixes (see mercurial logs for details) From 229ebca503472237f7170ca1918783d61e2e75db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 16:59:33 +0100 Subject: [PATCH 120/147] Added tag 2.0.7 for changeset 831d73a123b6 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 266f0b00db..f66c5c1f32 100644 --- a/.hgtags +++ b/.hgtags @@ -10,3 +10,4 @@ cd972be665323ca5fedfc7d08d259b54d96d4f9c 2.0.3 e81fe66bc0487db26a59df8a8ac93c61a8eae176 2.0.4 b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 41a147a9ba5cb6bae96373d55a6efea72f26b6eb 2.0.6 +831d73a123b62f037f7fa7eadf173a7d0683dede 2.0.7 From 24ab95c582917c55ad458e348ec10b7d852dcac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 23 Dec 2012 17:00:05 +0100 Subject: [PATCH 121/147] 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 0f3a065100..b04afcdf86 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.7" +VERSION = "2.0.8" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From e3b2de03ec9891915b92f63a8734fcd593f30fa2 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 122/147] 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 4c73254724..60d8e2f9aa 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -694,9 +694,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 cc1e32bd61038dab000bc3616a94ebf4ae550885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 18:03:30 +0100 Subject: [PATCH 123/147] Prepare release 2.0.8 --- CHANGELOG | 3 +++ COPYRIGHT | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a865f98dcd..040e4a60db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.8 - 2013-02-12 +* Bug fixes (see mercurial logs for details) + Version 2.0.7 - 2012-12-23 * Bug fixes (see mercurial logs for details) diff --git a/COPYRIGHT b/COPYRIGHT index a3c3253906..3e10027acc 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,7 +1,7 @@ Copyright (C) 2010-2011 Nicolas Évrard. -Copyright (C) 2007-2012 Cédric Krier. +Copyright (C) 2007-2013 Cédric Krier. Copyright (C) 2007-2011 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) 2007-2009 Lorenzo Gil Sanchez. From 1e0573da38c257f95bccbcc4df056ce6f4ae87dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 18:03:31 +0100 Subject: [PATCH 124/147] Added tag 2.0.8 for changeset 7672fdcaf290 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index f66c5c1f32..790876ff95 100644 --- a/.hgtags +++ b/.hgtags @@ -11,3 +11,4 @@ e81fe66bc0487db26a59df8a8ac93c61a8eae176 2.0.4 b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 41a147a9ba5cb6bae96373d55a6efea72f26b6eb 2.0.6 831d73a123b62f037f7fa7eadf173a7d0683dede 2.0.7 +7672fdcaf2900751b78a57fe5f3cc8b2b73ba9f9 2.0.8 From 82b6b53b65c873a164f6046e47d51d23511580b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 12 Feb 2013 18:04:13 +0100 Subject: [PATCH 125/147] 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 b04afcdf86..1f9914bce2 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.8" +VERSION = "2.0.9" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 93c1646d257a5e21c1ec8a45d790847847188281 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 126/147] 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 0050a82968..7ec90e75c1 100644 --- a/tryton/gui/main.py +++ b/tryton/gui/main.py @@ -5,7 +5,7 @@ from __future__ import with_statement import os import sys import gettext -from urlparse import urlparse +from urlparse import urlparse, parse_qsl import urllib import gobject import gtk @@ -1710,14 +1710,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._SOCK.hostname or int(port) != rpc._SOCK.port or @@ -1727,8 +1727,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 Exception: return From 985c32e965ba74e67a1e909a57d8ee2192678132 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 127/147] 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 62b3d7f76d..6bee705fdd 100644 --- a/tryton/gui/window/view_form/model/record.py +++ b/tryton/gui/window/view_form/model/record.py @@ -42,6 +42,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 7a711dfa5a892dbcc03d3e801f35413817a0c702 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 128/147] 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 a189ef0b23..807f32b11c 100644 --- a/tryton/gui/window/view_form/view/graph_gtk/bar.py +++ b/tryton/gui/window/view_form/view/graph_gtk/bar.py @@ -11,6 +11,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 2d919d1677ce6c7f885df50191e31115a0b0f924 Mon Sep 17 00:00:00 2001 From: Ralf Peschke Date: Fri, 29 Mar 2013 08:28:27 +0100 Subject: [PATCH 129/147] 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 60d8e2f9aa..de14ee8855 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -663,7 +663,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 4ed33d89f5c7eea9a384cea57321213b951cf365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:31:57 +0200 Subject: [PATCH 130/147] Prepare release 2.0.9 --- CHANGELOG | 3 +++ COPYRIGHT | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 040e4a60db..d18f1f4df2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.9 - 2013-05-02 +* Bug fixes (see mercurial logs for details) + Version 2.0.8 - 2013-02-12 * Bug fixes (see mercurial logs for details) diff --git a/COPYRIGHT b/COPYRIGHT index 3e10027acc..d30cab46fa 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright (C) 2010-2011 Nicolas Évrard. +Copyright (C) 2010-2013 Nicolas Évrard. Copyright (C) 2007-2013 Cédric Krier. Copyright (C) 2007-2011 Bertrand Chenal. Copyright (C) 2008-2013 B2CK SPRL. From 3c1b120a6146cb6dd603870e0c99597a4df1dc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:31:58 +0200 Subject: [PATCH 131/147] Added tag 2.0.9 for changeset 9a321439a4b6 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 790876ff95..c36282219e 100644 --- a/.hgtags +++ b/.hgtags @@ -12,3 +12,4 @@ b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 41a147a9ba5cb6bae96373d55a6efea72f26b6eb 2.0.6 831d73a123b62f037f7fa7eadf173a7d0683dede 2.0.7 7672fdcaf2900751b78a57fe5f3cc8b2b73ba9f9 2.0.8 +9a321439a4b62b8ace6af586b61c9d7b63427515 2.0.9 From b9d9770c99c8bb6e468f801b1583ab778a3dbcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 2 May 2013 09:32:18 +0200 Subject: [PATCH 132/147] 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 1f9914bce2..aad4b104d2 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.9" +VERSION = "2.0.10" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 6aa21418b463b9dde30600412637a69ae9fea63d 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 133/147] 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 069f861adc..cfbc2a59bc 100644 --- a/tryton/gui/window/view_form/view/list_gtk/editabletree.py +++ b/tryton/gui/window/view_form/view/list_gtk/editabletree.py @@ -22,8 +22,6 @@ class EditableTreeView(gtk.TreeView): def on_quit_cell(self, current_record, fieldname, value): 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. @@ -237,6 +235,11 @@ class EditableTreeView(gtk.TreeView): entry.set_max_length(int(field.attrs.get('size', 0))) # 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 b8d69e1d0d29cbae6c29eccfae9ca331b6fb22bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:35:17 +0200 Subject: [PATCH 134/147] Prepare release 2.0.10 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d18f1f4df2..904dac2b91 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.10 - 2013-07-22 +* Bug fixes (see mercurial logs for details) + Version 2.0.9 - 2013-05-02 * Bug fixes (see mercurial logs for details) From 627ab9e6e95d1d201678ee1d5d56d2d8e2c1a3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:35:18 +0200 Subject: [PATCH 135/147] Added tag 2.0.10 for changeset d76ecce9889c --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index c36282219e..2c2b909717 100644 --- a/.hgtags +++ b/.hgtags @@ -13,3 +13,4 @@ b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 831d73a123b62f037f7fa7eadf173a7d0683dede 2.0.7 7672fdcaf2900751b78a57fe5f3cc8b2b73ba9f9 2.0.8 9a321439a4b62b8ace6af586b61c9d7b63427515 2.0.9 +d76ecce9889c354e4f58e7c4ab938f12108e824d 2.0.10 From 6c53e5687a63e1b4b9b31f3ecca8e27b199843ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 22 Jul 2013 11:35:43 +0200 Subject: [PATCH 136/147] 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 aad4b104d2..c3bf65c08e 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.10" +VERSION = "2.0.11" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 812b45d95617f813d4d17dcdb7d85d4bfe9e3bca 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 137/147] 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 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index de14ee8855..a45ce4c5cb 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -53,13 +53,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 @@ -422,7 +422,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) @@ -719,7 +720,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 0ffd080f765eb23b84c8fb6a80971163a77cd3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:25:06 +0200 Subject: [PATCH 138/147] Prepare release 2.0.11 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 904dac2b91..28cb2f175b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2.0.11 - 2013-10-10 +* Bug fixes (see mercurial logs for details) + Version 2.0.10 - 2013-07-22 * Bug fixes (see mercurial logs for details) From 151eb955e37c5a9c993e3ed108b502291e2135fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:25:07 +0200 Subject: [PATCH 139/147] Added tag 2.0.11 for changeset a8471db2392c --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 2c2b909717..8b8fc72c18 100644 --- a/.hgtags +++ b/.hgtags @@ -14,3 +14,4 @@ b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 7672fdcaf2900751b78a57fe5f3cc8b2b73ba9f9 2.0.8 9a321439a4b62b8ace6af586b61c9d7b63427515 2.0.9 d76ecce9889c354e4f58e7c4ab938f12108e824d 2.0.10 +a8471db2392cd73cfc27c2ece190116da68e974b 2.0.11 From 4bae074e11c825eb639b625a69f2c29047a61e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 10 Oct 2013 23:26:11 +0200 Subject: [PATCH 140/147] 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 c3bf65c08e..889b0f9fee 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.11" +VERSION = "2.0.12" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" From 441b4cacaf97437505d6f021689f54d09c854f66 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 141/147] Don't extend domain but wrap into a new list review1106002 (transplanted from e4a2d43ad02e5c5d3ddd4c22a3c2a0890afff0aa) --- tryton/gui/window/view_form/view/form_gtk/one2many.py | 5 ++--- 1 file changed, 2 insertions(+), 3 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 7f7a68571d..aec26d6220 100644 --- a/tryton/gui/window/view_form/view/form_gtk/one2many.py +++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py @@ -294,9 +294,8 @@ class One2Many(WidgetInterface): domain = self.field.domain_get(self.record) context = rpc.CONTEXT.copy() context.update(self.field.context_get(self.record)) - domain = domain[:] - domain.extend(self.record.expr_eval(self.attrs.get('add_remove'), - context)) + domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'), + context)] removed_ids = self.field.get_removed_ids(self.record) try: From 3a53646e182f41a5408e350bf739a5304dcb41dc 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 142/147] 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 f6def95cfa..b3e7697616 100644 --- a/tryton/gui/window/view_form/view/list.py +++ b/tryton/gui/window/view_form/view/list.py @@ -113,7 +113,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 1f858b56c3afac288b13f53bf6d20f12d1df69e6 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 143/147] 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 142ca62e56..75fc3d34d0 100644 --- a/tryton/gui/window/win_export.py +++ b/tryton/gui/window/win_export.py @@ -371,7 +371,7 @@ class WinExport(object): 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 530c93f894ee5c42d29a7c967f2b9c1b1497f6b2 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 144/147] 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 28cb2f175b..452dba8bd5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Sanitize report file extension + Version 2.0.11 - 2013-10-10 * Bug fixes (see mercurial logs for details) diff --git a/tryton/action/main.py b/tryton/action/main.py index 0ca095c67e..7bcd14efce 100644 --- a/tryton/action/main.py +++ b/tryton/action/main.py @@ -57,7 +57,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, '_')) file_d = open(fp_name, 'wb') file_d.write(base64.decodestring(data)) file_d.close() From cca28e67a25bcad56bfabd44f4ef24e3ad3ee053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:53:26 +0100 Subject: [PATCH 145/147] Prepare release 2.0.12 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 452dba8bd5..957079fcd1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +Version 2.0.12 - 2013-11-03 +* Bug fixes (see mercurial logs for details) * Sanitize report file extension Version 2.0.11 - 2013-10-10 From 1db0ac90c25ab2b4a84b53338566669ac25a3294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:53:27 +0100 Subject: [PATCH 146/147] Added tag 2.0.12 for changeset 1a8cf8f58392 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8b8fc72c18..62594204cc 100644 --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ b0e372e501835b813fb478c57160fb639a5613c6 2.0.5 9a321439a4b62b8ace6af586b61c9d7b63427515 2.0.9 d76ecce9889c354e4f58e7c4ab938f12108e824d 2.0.10 a8471db2392cd73cfc27c2ece190116da68e974b 2.0.11 +1a8cf8f583922e655a1a9f34174b055a61f47a31 2.0.12 From 042f1487be4656c6ec7febaf583eb3f4a97baaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sun, 3 Nov 2013 18:53:50 +0100 Subject: [PATCH 147/147] 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 889b0f9fee..e5bafe831e 100644 --- a/tryton/version.py +++ b/tryton/version.py @@ -1,7 +1,7 @@ #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.0.12" +VERSION = "2.0.13" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/"