diff -Nru tryton-client-2.8.4/CHANGELOG tryton-client-2.8.7/CHANGELOG --- tryton-client-2.8.4/CHANGELOG 2013-11-03 17:50:12.000000000 +0000 +++ tryton-client-2.8.7/CHANGELOG 2014-05-06 16:26:52.000000000 +0000 @@ -1,3 +1,12 @@ +Version 2.8.7 - 2014-05-06 +* Bug fixes (see mercurial logs for details) + +Version 2.8.6 - 2014-04-07 +* Bug fixes (see mercurial logs for details) + +Version 2.8.5 - 2013-12-04 +* Bug fixes (see mercurial logs for details) + Version 2.8.4 - 2013-11-03 * Bug fixes (see mercurial logs for details) * Sanitize report file extension diff -Nru tryton-client-2.8.4/COPYRIGHT tryton-client-2.8.7/COPYRIGHT --- tryton-client-2.8.4/COPYRIGHT 2013-11-03 17:50:10.000000000 +0000 +++ tryton-client-2.8.7/COPYRIGHT 2014-05-06 16:26:51.000000000 +0000 @@ -1,7 +1,7 @@ -Copyright (C) 2010-2013 Nicolas Évrard. -Copyright (C) 2007-2013 Cédric Krier. +Copyright (C) 2010-2014 Nicolas Évrard. +Copyright (C) 2007-2014 Cédric Krier. Copyright (C) 2007-2013 Bertrand Chenal. -Copyright (C) 2008-2013 B2CK SPRL. +Copyright (C) 2008-2014 B2CK SPRL. Copyright (C) 2008-2011 Udo Spallek. Copyright (C) 2008-2011 virtual things - Preisler & Spallek GbR. Copyright (C) 2011-2012 Rodrigo Hübner. diff -Nru tryton-client-2.8.4/debian/changelog tryton-client-2.8.7/debian/changelog --- tryton-client-2.8.4/debian/changelog 2013-11-21 16:10:38.000000000 +0000 +++ tryton-client-2.8.7/debian/changelog 2014-06-26 15:48:54.000000000 +0000 @@ -1,8 +1,29 @@ -tryton-client (2.8.4-1ubuntu0~ppa1~saucy) saucy; urgency=low +tryton-client (2.8.7-1ubuntu0~ppa2~saucy) saucy; urgency=low * Ubuntu build - -- Ilya Melnikov Thu, 21 Nov 2013 21:28:33 +0600 + -- Ilya Melnikov Thu, 26 Jun 2014 21:22:28 +0600 + +tryton-client (2.8.7-1) unstable; urgency=medium + + * Merging upstream version 2.8.7. + + -- Mathias Behrle Mon, 12 May 2014 16:39:06 +0200 + +tryton-client (2.8.6-1) unstable; urgency=medium + + * Merging upstream version 2.8.6. + * Updating copyright. + + -- Mathias Behrle Thu, 17 Apr 2014 13:46:24 +0200 + +tryton-client (2.8.5-1) unstable; urgency=low + + * Adding doc packages to Suggests. + * Fixing the branch version in the watch file. + * Merging upstream version 2.8.5. + + -- Mathias Behrle Wed, 11 Dec 2013 18:40:46 +0100 tryton-client (2.8.4-1) unstable; urgency=high diff -Nru tryton-client-2.8.4/debian/control tryton-client-2.8.7/debian/control --- tryton-client-2.8.4/debian/control 2013-11-21 15:27:43.000000000 +0000 +++ tryton-client-2.8.7/debian/control 2014-06-26 14:44:27.000000000 +0000 @@ -1,8 +1,7 @@ Source: tryton-client Section: python Priority: optional -Maintainer: Ilya Melnikov -XSBC-Original-Maintainer: Debian Tryton Maintainers +Maintainer: Debian Tryton Maintainers Uploaders: Mathias Behrle Build-Depends: debhelper (>= 9), python (>= 2.6.6-3~), python-setuptools, diff -Nru tryton-client-2.8.4/debian/copyright tryton-client-2.8.7/debian/copyright --- tryton-client-2.8.4/debian/copyright 2013-11-21 02:42:34.000000000 +0000 +++ tryton-client-2.8.7/debian/copyright 2014-06-26 14:44:27.000000000 +0000 @@ -1,10 +1,10 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: * -Copyright: 2010-2013 Nicolas Évrard - 2007-2013 Cédric Krier +Copyright: 2010-2014 Nicolas Évrard + 2007-2014 Cédric Krier 2007-2013 Bertrand Chenal - 2008-2013 B2CK SPRL + 2008-2014 B2CK SPRL 2008-2011 Udo Spallek 2008-2011 virtual things - Preisler & Spallek GbR 2011-2012 Rodrigo Hübner diff -Nru tryton-client-2.8.4/debian/watch tryton-client-2.8.7/debian/watch --- tryton-client-2.8.4/debian/watch 2013-04-24 05:18:48.000000000 +0000 +++ tryton-client-2.8.7/debian/watch 2014-06-26 14:44:27.000000000 +0000 @@ -1,2 +1,2 @@ version=3 -http://downloads.tryton.org/current/ .*tryton-(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz)) +http://downloads.tryton.org/2.8/ .*tryton-(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz)) diff -Nru tryton-client-2.8.4/PKG-INFO tryton-client-2.8.7/PKG-INFO --- tryton-client-2.8.4/PKG-INFO 2013-11-03 17:50:17.000000000 +0000 +++ tryton-client-2.8.7/PKG-INFO 2014-05-06 16:26:58.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: tryton -Version: 2.8.4 +Version: 2.8.7 Summary: Tryton client Home-page: http://www.tryton.org/ Author: Tryton diff -Nru tryton-client-2.8.4/tryton/common/button.py tryton-client-2.8.7/tryton/common/button.py --- tryton-client-2.8.4/tryton/common/button.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/common/button.py 2014-03-04 23:10:35.000000000 +0000 @@ -17,6 +17,11 @@ self._set_icon(attrs.get('icon')) def _set_icon(self, stock): + image = self.get_image() + if not image and not stock: + return + elif image and image.get_stock()[0] == stock: + return if not stock: self.set_image(gtk.Image()) return diff -Nru tryton-client-2.8.4/tryton/common/common.py tryton-client-2.8.7/tryton/common/common.py --- tryton-client-2.8.4/tryton/common/common.py 2013-08-09 21:16:34.000000000 +0000 +++ tryton-client-2.8.7/tryton/common/common.py 2014-03-04 23:10:35.000000000 +0000 @@ -10,6 +10,7 @@ import subprocess import re import logging +from functools import partial from tryton.config import CONFIG from tryton.config import TRYTON_ICON, PIXMAPS_DIR import time @@ -971,9 +972,10 @@ protocol = 'http' if ssl or hasattr(socket, 'ssl'): protocol = 'https' + quote = partial(urllib.quote, safe="!$&'()*+,;=:") server = xmlrpclib.Server( ('%s://%s:%s@' + CONFIG['roundup.xmlrpc']) - % (protocol, user, password), allow_none=True) + % (protocol, quote(user), quote(password)), allow_none=True) if hashlib: msg_md5 = hashlib.md5(msg + '\n' + title).hexdigest() else: diff -Nru tryton-client-2.8.4/tryton/common/domain_inversion.py tryton-client-2.8.7/tryton/common/domain_inversion.py --- tryton-client-2.8.4/tryton/common/domain_inversion.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/common/domain_inversion.py 2014-05-06 16:26:39.000000000 +0000 @@ -20,7 +20,7 @@ '>=': operator.ge, '!=': operator.ne, 'in': in_, - 'not in': lambda a, b: not in_(b, a), + 'not in': lambda a, b: not in_(a, b), # Those operators are not supported (yet ?) 'like': lambda a, b: True, 'ilike': lambda a, b: True, @@ -462,6 +462,13 @@ assert eval_domain(domain, {'x': [3, 4]}) assert not eval_domain(domain, {'x': [1, 2]}) + domain = [['x', 'not in', [3, 5]]] + assert not eval_domain(domain, {'x': 3}) + assert eval_domain(domain, {'x': 4}) + assert not eval_domain(domain, {'x': [3]}) + assert not eval_domain(domain, {'x': [3, 4]}) + assert eval_domain(domain, {'x': [1, 2]}) + domain = ['OR', ['x', '>', 10], ['x', '<', 0]] assert eval_domain(domain, {'x': 11}) assert eval_domain(domain, {'x': -4}) diff -Nru tryton-client-2.8.4/tryton/common/domain_parser.py tryton-client-2.8.7/tryton/common/domain_parser.py --- tryton-client-2.8.4/tryton/common/domain_parser.py 2013-09-10 19:21:08.000000000 +0000 +++ tryton-client-2.8.7/tryton/common/domain_parser.py 2014-03-04 23:10:35.000000000 +0000 @@ -184,7 +184,7 @@ def convert_boolean(): if isinstance(value, basestring): - return any(test.lower().startswith(value.lower()) + return any(test.decode('utf-8').lower().startswith(value.lower()) for test in (_('y'), _('yes'), _('true'), _('t'), '1')) else: return bool(value) diff -Nru tryton-client-2.8.4/tryton/common/selection.py tryton-client-2.8.7/tryton/common/selection.py --- tryton-client-2.8.4/tryton/common/selection.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/common/selection.py 2014-04-07 17:37:30.000000000 +0000 @@ -22,7 +22,7 @@ if (not isinstance(selection, (list, tuple)) and key not in self._values2selection): try: - if key: + if self.attrs.get('selection_change_with'): selection = RPCExecute('model', self.model_name, selection, dict(key)) else: diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/model/field.py tryton-client-2.8.7/tryton/gui/window/view_form/model/field.py --- tryton-client-2.8.4/tryton/gui/window/view_form/model/field.py 2013-10-11 20:24:43.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/model/field.py 2014-05-06 16:26:39.000000000 +0000 @@ -48,7 +48,7 @@ screen_domain = domain_inversion(record.group.domain4inversion, self.name, EvalEnvironment(record)) if isinstance(screen_domain, bool) and not screen_domain: - screen_domain = [('id', '=', False)] + screen_domain = [('id', '=', None)] elif isinstance(screen_domain, bool) and screen_domain: screen_domain = [] attr_domain = record.expr_eval(self.attrs.get('domain', [])) @@ -76,7 +76,7 @@ def check_required(self, record): state_attrs = self.get_state_attrs(record) if bool(int(state_attrs.get('required') or 0)): - if (not self.get(record) + if (not self.get_eval(record) and not bool(int(state_attrs.get('readonly') or 0))): return False return True @@ -196,13 +196,14 @@ _default = None def set_client(self, record, value, force_change=False): - if not isinstance(value, datetime.datetime): + if not isinstance(value, datetime.datetime) and value is not None: try: value = datetime.datetime(*time.strptime(value, date_format() + ' ' + self.time_format(record))[:6]) - value = common.untimezoned_date(value) except ValueError: value = self._default + if value: + value = common.untimezoned_date(value) super(DateTimeField, self).set_client(record, value, force_change=force_change) @@ -223,12 +224,15 @@ _default = None def set_client(self, record, value, force_change=False): - if not isinstance(value, datetime.date): + if not isinstance(value, datetime.date) and value is not None: try: value = datetime.date(*time.strptime(value, date_format())[:3]) except ValueError: value = self._default + elif isinstance(value, datetime.datetime): + assert(value.time() == datetime.time()) + value = value.date() super(DateField, self).set_client(record, value, force_change=force_change) @@ -244,12 +248,14 @@ _default = None def set_client(self, record, value, force_change=False): - if not isinstance(value, datetime.time): + if not isinstance(value, datetime.time) and value is not None: try: value = datetime.time(*time.strptime(value, self.time_format(record))[3:6]) except ValueError: value = None + elif isinstance(value, datetime.datetime): + value = value.time() super(TimeField, self).set_client(record, value, force_change=force_change) @@ -486,25 +492,29 @@ return record.parent.signal('record-modified') - def _set_default_value(self, record): + def _set_default_value(self, record, fields=None): if record.value.get(self.name) is not None: return from group import Group parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], {}, + fields = fields or {} + group = Group(self.attrs['relation'], fields, parent=record, parent_name=parent_name, child_name=self.name, context=self.context, parent_datetime_field=self.attrs.get('datetime_field')) - if record.model_name == self.attrs['relation']: + if not fields and record.model_name == self.attrs['relation']: group.fields = record.group.fields + record.value[self.name] = group + self._connect_value(group) + + def _connect_value(self, group): 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) group.signal_connect(group, 'record-modified', self._record_modified) - record.value[self.name] = group def get_client(self, record): self._set_default_value(record) @@ -570,44 +580,29 @@ return result def _set_value(self, record, value, default=False): - from group import Group - + self._set_default_value(record) + group = record.value[self.name] if not value or (len(value) and isinstance(value[0], (int, long))): mode = 'list ids' else: mode = 'list values' - group = record.value.get(self.name) - fields = {} - if group is not None: - fields = group.fields.copy() - # Unconnect to prevent infinite loop - group.signal_unconnect(group) - group.destroy() - elif record.model_name == self.attrs['relation']: - fields = record.group.fields - if fields: - fields = dict((fname, field.attrs) - for fname, field in fields.iteritems()) if mode == 'list values' and len(value): context = self.context_get(record) - field_names = set(f for v in value for f in v if f not in fields) + field_names = set(f for v in value for f in v + if f not in group.fields) if field_names: try: - fields.update(RPCExecute('model', self.attrs['relation'], - 'fields_get', list(field_names), - main_iteration=False, context=context)) + fields = RPCExecute('model', self.attrs['relation'], + 'fields_get', list(field_names), + main_iteration=False, context=context) except RPCException: return + group.load_fields(fields) - parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], fields, - parent=record, parent_name=parent_name, - child_name=self.name, - context=self.context, - parent_datetime_field=self.attrs.get('datetime_field')) - record.value[self.name] = group if mode == 'list ids': + for old_record in group: + group.remove(old_record, remove=True, signal=False) group.load(value) else: for vals in value: @@ -619,30 +614,37 @@ new_record.id *= -1 # Don't consider record as unsaved new_record.set(vals) group.append(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) - group.signal_connect(group, 'record-modified', self._record_modified) - return group - def set(self, record, value): - self._set_value(record, value, default=False) + def set(self, record, value, _default=False): + group = record.value.get(self.name) + fields = {} + if group is not None: + fields = group.fields.copy() + # Unconnect to prevent infinite loop + group.signal_unconnect(group) + group.destroy() + elif record.model_name == self.attrs['relation']: + fields = record.group.fields + if fields: + fields = dict((fname, field.attrs) + for fname, field in fields.iteritems()) + + record.value[self.name] = None + self._set_default_value(record, fields=fields) + group = record.value[self.name] + + group.signal_unconnect(group) + self._set_value(record, value, default=_default) + self._connect_value(group) def set_client(self, record, value, force_change=False): pass def set_default(self, record, value): - previous_group = record.value.get(self.name) - group = self._set_value(record, value, default=True) - if previous_group: - group.record_deleted.extend(x for x in previous_group if x.id >= 0) - group.record_deleted.extend(previous_group.record_deleted) - group.record_removed.extend(previous_group.record_removed) + self.set(record, value, _default=True) record.modified_fields.setdefault(self.name) def set_on_change(self, record, value): - self._set_default_value(record) if isinstance(value, (list, tuple)): self._set_value(record, value) record.modified_fields.setdefault(self.name) @@ -730,36 +732,6 @@ class M2MField(O2MField): - def set(self, record, value): - from group import Group - group = record.value.get(self.name) - fields = {} - if group is not None: - fields = group.fields.copy() - # Unconnect to prevent infinite loop - group.signal_unconnect(group) - group.destroy() - elif record.model_name == self.attrs['relation']: - fields = record.group.fields - parent_name = self.attrs.get('relation_field', '') - group = Group(self.attrs['relation'], {}, - parent=record, parent_name=parent_name, - child_name=self.name, - context=self.context, - parent_datetime_field=self.attrs.get('datetime_field')) - if record.value.get(self.name): - group.record_removed.extend(record.value[self.name]) - 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 - group.load(value) - 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) - group.signal_connect(group, 'record-modified', self._record_modified) - def get_on_change_value(self, record): return self.get_eval(record) @@ -777,6 +749,12 @@ return None def get(self, record): + if record.parent_name == self.name: + if record.parent: + return '%s,%s' % (record.group.parent.model_name, + record.parent.id) + else: + return None if (record.value.get(self.name) and record.value[self.name][0] and record.value[self.name][1] >= -1): diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/model/group.py tryton-client-2.8.7/tryton/gui/window/view_form/model/group.py --- tryton-client-2.8.4/tryton/gui/window/view_form/model/group.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/model/group.py 2014-03-04 23:10:36.000000000 +0000 @@ -398,9 +398,6 @@ to_add.keys(), main_iteration=False, context=self.context) except RPCException: return False - for name in to_add: - if name not in values: - values[name] = False for record in new: record.set_default(values, signal=signal) diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/model/record.py tryton-client-2.8.7/tryton/gui/window/view_form/model/record.py --- tryton-client-2.8.4/tryton/gui/window/view_form/model/record.py 2013-10-01 11:51:01.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/model/record.py 2014-03-04 23:10:36.000000000 +0000 @@ -496,7 +496,7 @@ scope = values for i in arg.split('.'): if i not in scope: - scope = False + scope = None break scope = scope[i] res[arg] = scope diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/form_gtk/calendar.py tryton-client-2.8.7/tryton/gui/window/view_form/view/form_gtk/calendar.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/form_gtk/calendar.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/form_gtk/calendar.py 2014-05-06 16:26:39.000000000 +0000 @@ -48,8 +48,7 @@ return self.entry.grab_focus() def set_value(self, record, field): - field.set_client(record, self.entry.get_text()) - return True + field.set_client(record, self.get_value()) def get_value(self): return self.entry.date_get(set_text=False) diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/form_gtk/char.py tryton-client-2.8.7/tryton/gui/window/view_form/view/form_gtk/char.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/form_gtk/char.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/form_gtk/char.py 2014-03-04 23:10:36.000000000 +0000 @@ -49,8 +49,10 @@ def translate_widget(self): entry = gtk.Entry() entry.set_property('activates_default', True) - entry.set_width_chars(int(self.attrs.get('size', -1))) - entry.set_max_length(int(self.attrs.get('size', 0))) + if self.record: + field_size = self.record.expr_eval(self.attrs.get('size')) + entry.set_width_chars(field_size or -1) + entry.set_max_length(field_size or 0) return entry @staticmethod diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/bar.py tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/bar.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/bar.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/bar.py 2014-04-07 17:37:30.000000000 +0000 @@ -65,6 +65,9 @@ def motion(self, widget, event): super(Bar, self).motion(widget, event) + if not getattr(self, 'area', None): + return + def intersect(bar, event): x = self.area.w * bar.x + self.area.x y = self.area.h * bar.y + self.area.y diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/line.py tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/line.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/line.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/line.py 2014-04-07 17:37:30.000000000 +0000 @@ -154,6 +154,9 @@ cr.restore() def motion(self, widget, event): + if not getattr(self, 'area', None): + return + nearest = None for point in self.points: x = point.x * self.area.w + self.area.x diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/pie.py tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/pie.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/graph_gtk/pie.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/graph_gtk/pie.py 2014-04-07 17:37:30.000000000 +0000 @@ -108,6 +108,9 @@ def motion(self, widget, event): super(Pie, self).motion(widget, event) + if not getattr(self, 'area', None): + return + d = (event.x - self.centerx) ** 2 + (event.y - self.centery) ** 2 if d > self.radius ** 2: self.popup.hide() diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/list_gtk/editabletree.py tryton-client-2.8.7/tryton/gui/window/view_form/view/list_gtk/editabletree.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/list_gtk/editabletree.py 2013-06-26 21:30:13.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/list_gtk/editabletree.py 2014-03-04 23:10:36.000000000 +0000 @@ -21,7 +21,7 @@ def next_column(self, path, column=None, _sign=1): columns = self.get_columns() if column is None: - column = columns[-1 * _sign] + column = columns[-1 if _sign > 0 else 0] model = self.get_model() record = model.get_value(model.get_iter(path), 0) if _sign < 0: diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/list_gtk/parser.py tryton-client-2.8.7/tryton/gui/window/view_form/view/list_gtk/parser.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/list_gtk/parser.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/list_gtk/parser.py 2014-05-06 16:26:39.000000000 +0000 @@ -68,7 +68,7 @@ store = treeview.get_model() unsaved_records = [x for x in store.group if x.id < 0] search_string = screen.screen_container.get_text() or None - if screen.search_count == len(store) or unsaved_records: + if screen.search_count == len(store) or unsaved_records or screen.parent: ids = screen.search_filter(search_string=search_string, only_ids=True) store.sort(ids) else: diff -Nru tryton-client-2.8.4/tryton/gui/window/view_form/view/list.py tryton-client-2.8.7/tryton/gui/window/view_form/view/list.py --- tryton-client-2.8.4/tryton/gui/window/view_form/view/list.py 2013-10-11 20:25:48.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/view_form/view/list.py 2014-04-07 17:37:30.000000000 +0000 @@ -587,16 +587,19 @@ def __button_press(self, treeview, event): if event.button == 3: - path = treeview.get_path_at_pos(int(event.x), int(event.y)) + try: + path, col, x, y = treeview.get_path_at_pos( + int(event.x), int(event.y)) + except TypeError: + # Outside row + return False selection = treeview.get_selection() if selection.get_mode() == gtk.SELECTION_SINGLE: model = selection.get_selected()[0] elif selection.get_mode() == gtk.SELECTION_MULTIPLE: model = selection.get_selected_rows()[0] - if (not path) or not path[0]: - return False - group = model.group - record = group[path[0][0]] + record = model.get_value(model.get_iter(path), 0) + group = record.group menu = gtk.Menu() menu.popup(None, None, None, event.button, event.time) diff -Nru tryton-client-2.8.4/tryton/gui/window/win_search.py tryton-client-2.8.7/tryton/gui/window/win_search.py --- tryton-client-2.8.4/tryton/gui/window/win_search.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/win_search.py 2014-03-04 23:10:36.000000000 +0000 @@ -107,10 +107,8 @@ if response_id == gtk.RESPONSE_OK: res = self.screen.sel_ids_get() elif response_id == gtk.RESPONSE_APPLY: - if not self.screen.search_filter(): - res = self.screen.sel_ids_get() - else: - return + self.screen.search_filter(self.screen.screen_container.get_text()) + return elif response_id == gtk.RESPONSE_ACCEPT: screen = Screen(self.model_name, domain=self.domain, context=self.context, mode=['form']) diff -Nru tryton-client-2.8.4/tryton/gui/window/wizard.py tryton-client-2.8.7/tryton/gui/window/wizard.py --- tryton-client-2.8.4/tryton/gui/window/wizard.py 2013-04-22 09:59:56.000000000 +0000 +++ tryton-client-2.8.7/tryton/gui/window/wizard.py 2014-03-04 23:10:36.000000000 +0000 @@ -350,9 +350,13 @@ dialog = self.page if (hasattr(dialog, 'screen') and dialog.screen.current_record - and self.sensible_widget != main.window - and self.ids): - dialog.screen.reload(self.ids, written=True) + and self.sensible_widget != main.window): + if dialog.screen.model_name == self.model: + ids = self.ids + else: + # Wizard run from a children record so reload parent record + ids = [dialog.screen.current_record.id] + dialog.screen.reload(ids, written=True) def end(self): super(WizardDialog, self).end() diff -Nru tryton-client-2.8.4/tryton/version.py tryton-client-2.8.7/tryton/version.py --- tryton-client-2.8.4/tryton/version.py 2013-10-10 21:21:42.000000000 +0000 +++ tryton-client-2.8.7/tryton/version.py 2014-04-07 17:38:07.000000000 +0000 @@ -1,6 +1,6 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. PACKAGE = "tryton" -VERSION = "2.8.4" +VERSION = "2.8.7" LICENSE = "GPL-3" WEBSITE = "http://www.tryton.org/" diff -Nru tryton-client-2.8.4/tryton.egg-info/PKG-INFO tryton-client-2.8.7/tryton.egg-info/PKG-INFO --- tryton-client-2.8.4/tryton.egg-info/PKG-INFO 2013-11-03 17:50:15.000000000 +0000 +++ tryton-client-2.8.7/tryton.egg-info/PKG-INFO 2014-05-06 16:26:57.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: tryton -Version: 2.8.4 +Version: 2.8.7 Summary: Tryton client Home-page: http://www.tryton.org/ Author: Tryton