[tryton-debian-vcs] tryton-client branch upstream-2.2 created. 735ca6b3aa8a510dcfad732d1e0defe535c6dd6d
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Wed Nov 27 16:51:06 UTC 2013
The following commit has been merged in the upstream-2.2 branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-client.git;a=commitdiff;h=735ca6b3aa8a510dcfad732d1e0defe535c6dd6d
commit 735ca6b3aa8a510dcfad732d1e0defe535c6dd6d
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Mon Nov 4 14:16:41 2013 +0100
Adding upstream version 2.2.11.
diff --git a/CHANGELOG b/CHANGELOG
index 91c3772..f13ed51 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+Version 2.2.11 - 2013-11-03
+* Bug fixes (see mercurial logs for details)
+* Sanitize report file extension
+
Version 2.2.10 - 2013-10-10
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 15fa977..ce9cbba 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.10
+Version: 2.2.11
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 15fa977..ce9cbba 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.10
+Version: 2.2.11
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/action/main.py b/tryton/action/main.py
index 3c81170..d5df3e8 100644
--- a/tryton/action/main.py
+++ b/tryton/action/main.py
@@ -59,7 +59,8 @@ class Action(object):
dtemp = tempfile.mkdtemp(prefix='tryton_')
fp_name = os.path.join(dtemp,
name.replace(os.sep, '_').replace(os.altsep or os.sep, '_') \
- + os.extsep + type)
+ + os.extsep
+ + type.replace(os.sep, '_').replace(os.altsep or os.sep, '_'))
with open(fp_name, 'wb') as file_d:
file_d.write(data)
if email_print:
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 21ae30c..99eeebc 100644
--- a/tryton/gui/window/view_form/view/form_gtk/one2many.py
+++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py
@@ -297,9 +297,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:
diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py
index 1efca22..7c26376 100644
--- a/tryton/gui/window/view_form/view/list.py
+++ b/tryton/gui/window/view_form/view/list.py
@@ -129,7 +129,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)
diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py
index 43f2c96..107956e 100644
--- a/tryton/gui/window/win_export.py
+++ b/tryton/gui/window/win_export.py
@@ -370,7 +370,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)
diff --git a/tryton/version.py b/tryton/version.py
index fdefcfd..ae1e1c5 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.2.10"
+VERSION = "2.2.11"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 80f7acb500987894809ed10c6582a66f0ef248e1
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Thu Oct 17 12:37:24 2013 +0200
Adding upstream version 2.2.10.
diff --git a/CHANGELOG b/CHANGELOG
index 7068b22..91c3772 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.10 - 2013-10-10
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.9 - 2013-07-22
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 3b6ecf9..15fa977 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.9
+Version: 2.2.10
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 3b6ecf9..15fa977 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.9
+Version: 2.2.10
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py
index 7b6ba2d..598b108 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -55,13 +55,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
@@ -394,7 +394,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)
@@ -685,7 +686,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):
diff --git a/tryton/version.py b/tryton/version.py
index 6b2b241..fdefcfd 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.2.9"
+VERSION = "2.2.10"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 4d3a03d3725807c6e998167b691bebcdc2c3f971
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Wed Aug 7 17:11:57 2013 +0200
Adding upstream version 2.2.9.
diff --git a/CHANGELOG b/CHANGELOG
index 22700eb..7068b22 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.9 - 2013-07-22
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.8 - 2013-06-09
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 0ed926e..3b6ecf9 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.8
+Version: 2.2.9
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 0ed926e..3b6ecf9 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.8
+Version: 2.2.9
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
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 3c79a7b..701898f 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, callback=None):
field = current_record[fieldname]
- if hasattr(field, 'editabletree_entry'):
- del field.editabletree_entry
cell = self.cells[fieldname]
# The value has not changed and is valid ... do nothing.
@@ -234,6 +232,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
diff --git a/tryton/version.py b/tryton/version.py
index 6435eba..6b2b241 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.2.8"
+VERSION = "2.2.9"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 805ed7ff8b00af63bfac07d5bb662c42d8c2d0ab
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Tue Jun 11 13:53:09 2013 +0200
Adding upstream version 2.2.8.
diff --git a/CHANGELOG b/CHANGELOG
index 3933461..22700eb 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.8 - 2013-06-09
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.7 - 2013-05-02
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index d7b3feb..0ed926e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.7
+Version: 2.2.8
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index d7b3feb..0ed926e 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.7
+Version: 2.2.8
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/gui/main.py b/tryton/gui/main.py
index 9d5b687..02611bf 100644
--- a/tryton/gui/main.py
+++ b/tryton/gui/main.py
@@ -18,6 +18,7 @@ import tryton.rpc as rpc
from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, DATA_DIR, \
get_config_dir
import tryton.common as common
+from tryton.jsonrpc import object_hook
from tryton.action import Action
from tryton.exceptions import TrytonServerError, TrytonError
from tryton.gui.window import Window
@@ -1445,9 +1446,12 @@ class Main(object):
limit = json.loads(params.get('limit', 'null'))
auto_refresh = json.loads(params.get('auto_refresh', 'false'))
name = json.loads(params.get('window_name', 'false'))
- search_value = json.loads(params.get('search_value', '{}'))
- domain = json.loads(params.get('domain', '[]'))
- context = json.loads(params.get('context', '{}'))
+ search_value = json.loads(params.get('search_value', '{}'),
+ object_hook=object_hook)
+ domain = json.loads(params.get('domain', '[]'),
+ object_hook=object_hook)
+ context = json.loads(params.get('context', '{}'),
+ object_hook=object_hook)
except ValueError:
return
if path:
@@ -1468,13 +1472,15 @@ class Main(object):
if not wizard:
return
try:
- data = json.loads(params.get('data', '{}'))
+ data = json.loads(params.get('data', '{}'),
+ object_hook=object_hook)
direct_print = json.loads(params.get('direct_print', 'false'))
email_print = json.loads(params.get('email_print', 'false'))
email = json.loads(params.get('email', 'null'))
name = json.loads(params.get('name', 'false'))
window = json.loads(params.get('window', 'false'))
- context = json.loads(params.get('context', '{}'))
+ context = json.loads(params.get('context', '{}'),
+ object_hook=object_hook)
except ValueError:
return
try:
@@ -1489,12 +1495,13 @@ class Main(object):
if not report:
return
try:
- data = json.loads(params.get('data'))
+ data = json.loads(params.get('data'), object_hook=object_hook)
direct_print = json.loads(params.get('direct_print', 'false'))
email_print = json.loads(params.get('email_print', 'false'))
email = json.loads(params.get('email', 'null'))
name = json.loads(params.get('name', 'false'))
- context = json.loads(params.get('context', '{}'))
+ context = json.loads(params.get('context', '{}'),
+ object_hook=object_hook)
except ValueError:
return
try:
diff --git a/tryton/version.py b/tryton/version.py
index 7a5d714..6435eba 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.2.7"
+VERSION = "2.2.8"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 7326b7761d81e41f89eefb6b1dce15cb855a82cd
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Sat May 4 16:48:34 2013 +0200
Adding upstream version 2.2.7.
diff --git a/CHANGELOG b/CHANGELOG
index 69a750a..3933461 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.7 - 2013-05-02
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.6 - 2013-02-12
* Bug fixes (see mercurial logs for details)
diff --git a/COPYRIGHT b/COPYRIGHT
index 49c6ef7..d30cab4 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright (C) 2010-2012 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.
diff --git a/PKG-INFO b/PKG-INFO
index f031600..d7b3feb 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.6
+Version: 2.2.7
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index f031600..d7b3feb 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.6
+Version: 2.2.7
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/gui/main.py b/tryton/gui/main.py
index 6b41eab..9d5b687 100644
--- a/tryton/gui/main.py
+++ b/tryton/gui/main.py
@@ -5,7 +5,7 @@ import os
import sys
import socket
import gettext
-from urlparse import urlparse
+from urlparse import urlparse, parse_qsl
import urllib
import gobject
import gtk
@@ -1412,14 +1412,14 @@ class Main(object):
Main.get_main().refresh_ssl()
def _open_url(self, url):
- url = urllib.unquote(url)
urlp = urlparse(url)
if not urlp.scheme == 'tryton':
return
urlp = urlparse('http' + url[6:])
- hostname, port = (urlp.netloc.split(':', 1)
- + [CONFIG.defaults['login.port']])[:2]
- database, path = (urlp.path[1:].split('/', 1) + [None])[:2]
+ hostname, port = map(urllib.unquote,
+ (urlp.netloc.split(':', 1) + [CONFIG.defaults['login.port']])[:2])
+ database, path = map(urllib.unquote,
+ (urlp.path[1:].split('/', 1) + [None])[:2])
if (not path or
hostname != rpc._HOST or
int(port) != rpc._PORT or
@@ -1429,8 +1429,8 @@ class Main(object):
params = {}
if urlp.params:
try:
- params = dict(param.split('=', 1)
- for param in urlp.params.split('&'))
+ params.update(dict(parse_qsl(urlp.params,
+ strict_parsing=True)))
except ValueError:
return
diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py
index 1ebde12..7b6ba2d 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -629,7 +629,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)
diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py
index c64ea84..2b6bb18 100644
--- a/tryton/gui/window/view_form/model/record.py
+++ b/tryton/gui/window/view_form/model/record.py
@@ -46,6 +46,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':
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 73b248a..26f5431 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):
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 080ba54..b77abb5 100644
--- a/tryton/gui/window/view_form/view/list_gtk/parser.py
+++ b/tryton/gui/window/view_form/view/list_gtk/parser.py
@@ -518,8 +518,8 @@ class M2O(Char):
def value_from_text(self, record, text, callback=None):
field = record.group.fields[self.field_name]
- if not text and not field.get_state_attrs(
- record)['required']:
+ if not text:
+ field.set_client(record, (False, ''))
if callback:
callback()
return False
@@ -527,11 +527,7 @@ class M2O(Char):
relation = record[self.field_name].attrs['relation']
domain = record[self.field_name].domain_get(record)
context = record[self.field_name].context_get(record)
- if text:
- dom = [('rec_name', 'ilike', '%' + text + '%'),
- domain]
- else:
- dom = domain
+ dom = [('rec_name', 'ilike', '%' + text + '%'), domain]
args = ('model', relation, 'search', dom, 0, None, None,
context)
try:
@@ -539,7 +535,7 @@ class M2O(Char):
except TrytonServerError, exception:
ids = common.process_exception(exception, *args)
if not ids:
- field.set_client(record, '???')
+ field.set_client(record, (False, ''))
if callback:
callback()
return
diff --git a/tryton/version.py b/tryton/version.py
index 8c0fe7e..7a5d714 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.2.6"
+VERSION = "2.2.7"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 5e522c04291d1bed7beaacfa08069dde6f23a998
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Sun Feb 24 21:45:46 2013 +0100
Adding upstream version 2.2.6.
diff --git a/CHANGELOG b/CHANGELOG
index 6373ef7..69a750a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.6 - 2013-02-12
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.5 - 2012-12-23
* Bug fixes (see mercurial logs for details)
diff --git a/COPYRIGHT b/COPYRIGHT
index 5db8542..49c6ef7 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,7 +1,7 @@
Copyright (C) 2010-2012 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.
diff --git a/PKG-INFO b/PKG-INFO
index fd6dd20..f031600 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.5
+Version: 2.2.6
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index fd6dd20..f031600 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.5
+Version: 2.2.6
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py
index d63d7e1..1ebde12 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -660,9 +660,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:
diff --git a/tryton/version.py b/tryton/version.py
index fa988ef..8c0fe7e 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.2.5"
+VERSION = "2.2.6"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 1b80b4e294ef3e23fd30c7fc3072b776767674ca
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Sun Feb 24 21:43:51 2013 +0100
Adding upstream version 2.2.5.
diff --git a/CHANGELOG b/CHANGELOG
index 9ce8cd0..6373ef7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.5 - 2012-12-23
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.4 - 2012-11-05
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 1a46c5d..fd6dd20 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.4
+Version: 2.2.5
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/setup.py b/setup.py
index 817acea..833e105 100644
--- a/setup.py
+++ b/setup.py
@@ -233,6 +233,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'))
@@ -331,6 +336,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(
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 1a46c5d..fd6dd20 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.4
+Version: 2.2.5
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py
index 335eee8..15c3b58 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/field.py b/tryton/gui/window/view_form/model/field.py
index 6aa6530..d63d7e1 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -631,7 +631,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,
diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py
index 926540a..c64ea84 100644
--- a/tryton/gui/window/view_form/model/record.py
+++ b/tryton/gui/window/view_form/model/record.py
@@ -224,6 +224,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
@@ -442,7 +444,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):
diff --git a/tryton/version.py b/tryton/version.py
index 9690753..fa988ef 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.2.4"
+VERSION = "2.2.5"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 388329b55432f4cdb5d75acc9232252711f4eb7a
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Sun Feb 24 19:50:19 2013 +0100
Adding upstream version 2.2.4.
diff --git a/CHANGELOG b/CHANGELOG
index f97db53..9ce8cd0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.4 - 2012-11-05
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.3 - 2012-09-01
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 94147e1..1a46c5d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: tryton
-Version: 2.2.3
+Version: 2.2.4
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 94147e1..1a46c5d 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: tryton
-Version: 2.2.3
+Version: 2.2.4
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/common/common.py b/tryton/common/common.py
index 6bffd9f..00ad4bd 100644
--- a/tryton/common/common.py
+++ b/tryton/common/common.py
@@ -244,7 +244,7 @@ def request_server(server_widget):
def get_toplevel_window():
windows = [x for x in gtk.window_list_toplevels()
if x.window and x.props.visible
- and x.get_window_type() == gtk.WINDOW_TOPLEVEL]
+ and x.props.type == gtk.WINDOW_TOPLEVEL]
trans2windows = dict((x.get_transient_for(), x) for x in windows)
for window in set(windows) - set(trans2windows.iterkeys()):
return window
diff --git a/tryton/gui/main.py b/tryton/gui/main.py
index 17a6ad5..6b41eab 100644
--- a/tryton/gui/main.py
+++ b/tryton/gui/main.py
@@ -1201,6 +1201,8 @@ class Main(object):
def _sig_remove_book(self, widget, page_widget):
for page in self.pages:
if page.widget == page_widget:
+ if not page.widget.props.sensitive:
+ return
page_num = self.notebook.page_num(page.widget)
self.notebook.set_current_page(page_num)
res = page.sig_close()
@@ -1318,7 +1320,7 @@ class Main(object):
self.refresh_ssl()
common.message(_("Database dropped successfully!"))
- 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...'),
@@ -1360,7 +1362,7 @@ class Main(object):
else:
common.message(_('Database restore failed!'))
- def sig_db_dump(self, widget):
+ def sig_db_dump(self, widget=None):
if not self.sig_logout(widget):
return False
dialog = DBBackupDrop(function='backup')
diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py
index b459869..926540a 100644
--- a/tryton/gui/window/view_form/model/record.py
+++ b/tryton/gui/window/view_form/model/record.py
@@ -115,6 +115,15 @@ class Record(SignalEvent):
def parent_name(self):
return self.group.parent_name
+ @property
+ def depth(self):
+ parent = self.parent
+ i = 0
+ while parent:
+ i += 1
+ parent = parent.parent
+ return i
+
def set_modified(self, value):
if value:
self.signal('record-modified')
diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py
index 3ff1368..4c5d40e 100644
--- a/tryton/gui/window/view_form/screen/screen.py
+++ b/tryton/gui/window/view_form/screen/screen.py
@@ -548,6 +548,8 @@ class Screen(SignalEvent):
if not records:
return
if delete:
+ # Must delete children records before parent
+ records.sort(key=lambda r: r.depth, reverse=True)
if not self.group.delete(records):
return False
@@ -679,7 +681,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:
@@ -706,7 +710,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()
@@ -721,7 +725,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
@@ -738,7 +744,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()
diff --git a/tryton/gui/window/view_form/view/list.py b/tryton/gui/window/view_form/view/list.py
index 69d93e7..1efca22 100644
--- a/tryton/gui/window/view_form/view/list.py
+++ b/tryton/gui/window/view_form/view/list.py
@@ -126,6 +126,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)
diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py
index da34c31..76d7690 100644
--- a/tryton/gui/window/win_form.py
+++ b/tryton/gui/window/win_form.py
@@ -75,9 +75,8 @@ class WinForm(NoModal):
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('<b>' + self.screen.current_view.title + '</b>')
+ 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"))
diff --git a/tryton/version.py b/tryton/version.py
index b409f6a..9690753 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.2.3"
+VERSION = "2.2.4"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit 506a2c81e5e6c453043d271acf3dec75c7c51a52
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Tue Sep 11 19:36:27 2012 +0200
Adding upstream version 2.2.3.
diff --git a/CHANGELOG b/CHANGELOG
index a67af88..f97db53 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.3 - 2012-09-01
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.2 - 2012-05-07
* Bug fixes (see mercurial logs for details)
diff --git a/PKG-INFO b/PKG-INFO
index 4d4255a..94147e1 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.0
Name: tryton
-Version: 2.2.2
+Version: 2.2.3
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 4d4255a..94147e1 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.0
Name: tryton
-Version: 2.2.2
+Version: 2.2.3
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/common/common.py b/tryton/common/common.py
index 83cb472..6bffd9f 100644
--- a/tryton/common/common.py
+++ b/tryton/common/common.py
@@ -243,7 +243,8 @@ def request_server(server_widget):
def get_toplevel_window():
windows = [x for x in gtk.window_list_toplevels()
- if x.window and x.props.visible]
+ if x.window and x.props.visible
+ and x.get_window_type() == gtk.WINDOW_TOPLEVEL]
trans2windows = dict((x.get_transient_for(), x) for x in windows)
for window in set(windows) - set(trans2windows.iterkeys()):
return window
diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py
index 8da0a6a..335eee8 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})
diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py
index 7e46d07..2f351c9 100644
--- a/tryton/gui/window/form.py
+++ b/tryton/gui/window/form.py
@@ -406,19 +406,24 @@ class Form(SignalEvent, TabContent):
return True
def sig_action(self, widget):
- self.buttons['action'].props.active = True
+ if self.buttons['action'].props.sensitive:
+ self.buttons['action'].props.active = True
def sig_print(self, widget):
- self.buttons['print'].props.active = True
+ if self.buttons['print'].props.sensitive:
+ self.buttons['print'].props.active = True
def sig_print_open(self, widget):
- self.buttons['open'].props.active = True
+ if self.buttons['open'].props.sensitive:
+ self.buttons['open'].props.active = True
def sig_print_email(self, widget):
- self.buttons['email'].props.active = True
+ if self.buttons['email'].props.sensitive:
+ self.buttons['email'].props.active = True
def sig_relate(self, widget):
- self.buttons['relate'].props.active = True
+ if self.buttons['relate'].props.sensitive:
+ self.buttons['relate'].props.active = True
def action_popup(self, widget):
button, = widget.get_children()
diff --git a/tryton/gui/window/view_form/view/form.py b/tryton/gui/window/view_form/view/form.py
index 6e05a63..d25e566 100644
--- a/tryton/gui/window/view_form/view/form.py
+++ b/tryton/gui/window/view_form/view/form.py
@@ -106,7 +106,7 @@ class ViewForm(ParserView):
# Get first the lazy one to reduce number of requests
fields = [(name, field.attrs.get('loading', 'eager'))
for name, field in record.group.fields.iteritems()]
- fields.sort(key=operator.itemgetter(1))
+ fields.sort(key=operator.itemgetter(1), reverse=True)
for field, _ in fields:
record[field].get(record, check_load=False)
for name, widgets in self.widgets.iteritems():
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 81d8bf5..85d5b87 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
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 854c100..695bcec 100644
--- a/tryton/gui/window/view_form/view/graph_gtk/graph.py
+++ b/tryton/gui/window/view_form/view/graph_gtk/graph.py
@@ -276,7 +276,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
diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py
index 79dae47..43f2c96 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)
diff --git a/tryton/jsonrpc.py b/tryton/jsonrpc.py
index a4c1c17..cda04d6 100644
--- a/tryton/jsonrpc.py
+++ b/tryton/jsonrpc.py
@@ -32,6 +32,11 @@ class Fault(xmlrpclib.Fault):
super(Fault, self).__init__(faultCode, faultString, **extra)
self.args = faultString
+ def __repr__(self):
+ return (
+ "<Fault %s: %s>" %
+ (repr(self.faultCode), repr(self.faultString))
+ )
class ProtocolError(xmlrpclib.ProtocolError):
pass
diff --git a/tryton/version.py b/tryton/version.py
index 3b71650..b409f6a 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.2.2"
+VERSION = "2.2.3"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
commit e8d1701d46f5cedf426cfbe7177359f120000ea5
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Wed May 9 11:47:25 2012 +0200
Adding upstream version 2.2.2.
diff --git a/CHANGELOG b/CHANGELOG
index 5d86a51..a67af88 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+Version 2.2.2 - 2012-05-07
+* Bug fixes (see mercurial logs for details)
+
Version 2.2.1 - 2011-12-26
* Bug fixes (see mercurial logs for details)
diff --git a/COPYRIGHT b/COPYRIGHT
index 9636f7a..5db8542 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,7 +1,7 @@
-Copyright (C) 2010-2011 Nicolas Évrard.
-Copyright (C) 2007-2011 Cédric Krier.
+Copyright (C) 2010-2012 Nicolas Évrard.
+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.
diff --git a/PKG-INFO b/PKG-INFO
index 59e16ad..4d4255a 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.1
+Version: 2.2.2
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton.egg-info/PKG-INFO b/tryton.egg-info/PKG-INFO
index 59e16ad..4d4255a 100644
--- a/tryton.egg-info/PKG-INFO
+++ b/tryton.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: tryton
-Version: 2.2.1
+Version: 2.2.2
Summary: Tryton client
Home-page: http://www.tryton.org/
Author: B2CK
diff --git a/tryton/common/common.py b/tryton/common/common.py
index a68a88d..83cb472 100644
--- a/tryton/common/common.py
+++ b/tryton/common/common.py
@@ -954,7 +954,7 @@ def send_bugtracker(msg):
and 'roundup.cgi.exceptions.Unauthorised' in
exception.faultString):
message(_('Connection error!\nBad username or password!'))
- return send_bugtracker(msg, parent)
+ return send_bugtracker(msg)
tb_s = reduce(lambda x, y: x + y,
traceback.format_exception(sys.exc_type,
sys.exc_value, sys.exc_traceback))
@@ -1461,11 +1461,17 @@ def safe_eval(source, data=None):
'dict': dict,
}}, data)
-def timezoned_date(date):
- if pytz and rpc.CONTEXT.get('timezone'):
+def timezoned_date(date, reverse=False):
+ if pytz and rpc.CONTEXT.get('timezone') and rpc.TIMEZONE:
lzone = pytz.timezone(rpc.CONTEXT['timezone'])
szone = pytz.timezone(rpc.TIMEZONE)
+ if reverse:
+ lzone, szone = szone, lzone
sdt = szone.localize(date, is_dst=True)
ldt = sdt.astimezone(lzone)
date = ldt
return date
+
+
+def untimezoned_date(date):
+ return timezoned_date(date, reverse=True).replace(tzinfo=None)
diff --git a/tryton/gui/window/dblogin.py b/tryton/gui/window/dblogin.py
index 4e28d7c..e113121 100644
--- a/tryton/gui/window/dblogin.py
+++ b/tryton/gui/window/dblogin.py
@@ -26,6 +26,7 @@ class DBListEditor(object):
self.profiles = profiles
self.current_database = None
self.old_profile, self.current_profile = None, None
+ self.db_cache = None
self.updating_db = False
# GTK Stuffs
@@ -41,9 +42,7 @@ 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.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'),
@@ -174,10 +173,12 @@ class DBListEditor(object):
def clear_entries(self):
for entryname in ('host', 'port', 'database', 'username'):
entry = getattr(self, '%s_entry' % entryname)
+ entry.handler_block_by_func(self.update_profiles)
if entryname == 'port':
entry.set_text('8000')
else:
entry.set_text('')
+ entry.handler_unblock_by_func(self.update_profiles)
self.current_database = None
self.database_combo.set_active(-1)
self.database_combo.get_model().clear()
@@ -231,22 +232,13 @@ 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
-
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 == '':
@@ -290,6 +282,8 @@ class DBListEditor(object):
port = self.port_entry.get_text()
if not (host and port):
return
+ if (host, port, self.current_profile['name']) == self.db_cache:
+ return
if self.updating_db:
return
if dbname is None:
@@ -307,6 +301,7 @@ class DBListEditor(object):
def callback(dbs, createdb):
self.updating_db = False
+ self.db_cache = (host, port, self.current_profile['name'])
if dbs is None and createdb is None:
pass
@@ -343,6 +338,7 @@ class DBListEditor(object):
port = int(self.port_entry.get_text())
dia = DBCreate(host, port)
dbname = dia.run()
+ self.db_cache = None
self.username_entry.set_text('admin')
self.display_dbwidget(None, None, dbname)
diff --git a/tryton/gui/window/form.py b/tryton/gui/window/form.py
index 7c9e27d..7e46d07 100644
--- a/tryton/gui/window/form.py
+++ b/tryton/gui/window/form.py
@@ -476,6 +476,7 @@ class Form(SignalEvent, TabContent):
self.activate_save()
def modified_save(self, reload=True):
+ self.screen.current_view.set_value()
if self.screen.modified():
value = sur_3b(
_('This record has been modified\n' \
diff --git a/tryton/gui/window/nomodal.py b/tryton/gui/window/nomodal.py
index c100e2b..95e5206 100644
--- a/tryton/gui/window/nomodal.py
+++ b/tryton/gui/window/nomodal.py
@@ -1,5 +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 gtk
+
from tryton.gui.main import Main
import tryton.common as common
@@ -22,6 +24,9 @@ class NoModal(object):
def destroy(self):
self.page.dialogs.remove(self)
+ # Test if the parent is not already destroyed
+ if self.parent not in gtk.window_list_toplevels():
+ return
self.parent.present()
self.sensible_widget.props.sensitive = True
if self.parent_focus:
diff --git a/tryton/gui/window/preference.py b/tryton/gui/window/preference.py
index 3f03596..c86088b 100644
--- a/tryton/gui/window/preference.py
+++ b/tryton/gui/window/preference.py
@@ -96,8 +96,7 @@ class Preference(object):
try:
rpc.execute(*args)
except TrytonServerError, exception:
- if not common.process_exception(exception, self.win,
- *args):
+ if not common.process_exception(exception, *args):
continue
res = True
break
diff --git a/tryton/gui/window/view_board/parser.py b/tryton/gui/window/view_board/parser.py
index 7aa0abe..e22021c 100644
--- a/tryton/gui/window/view_board/parser.py
+++ b/tryton/gui/window/view_board/parser.py
@@ -2,10 +2,13 @@
#this repository contains the full copyright notices and license terms.
'Parser'
import gtk
-from tryton.gui.window.view_form.view.form_gtk.parser import _container
+import gettext
+from tryton.gui.window.view_form.view.form_gtk.parser import _container, VBox
import tryton.common as common
from action import Action
-from tryton.config import CONFIG, TRYTON_ICON
+from tryton.config import CONFIG
+
+_ = gettext.gettext
class ParserBoard(object):
@@ -47,13 +50,6 @@ class ParserBoard(object):
xexpand=xexpand, xfill=xfill)
elif node.localName == 'separator':
text = attrs.get('string', '')
- if 'string' in attrs or 'name' in attrs:
- if not text:
- if 'name' in attrs and attrs['name'] in fields:
- if 'states' in fields[attrs['name']]:
- attrs['states'] = \
- fields[attrs['name']]['states']
- text = fields[attrs['name']]['string']
vbox = VBox(attrs=attrs)
if text:
label = gtk.Label(text)
@@ -69,22 +65,6 @@ class ParserBoard(object):
elif node.localName == 'label':
text = attrs.get('string', '')
if not text:
- if 'name' in attrs and attrs['name'] in fields:
- if 'states' in fields[attrs['name']]:
- attrs['states'] = fields[attrs['name']]['states']
- if gtk.widget_get_default_direction() == gtk.TEXT_DIR_RTL:
- text = _(':') + fields[attrs['name']]['string']
- else:
- text = fields[attrs['name']]['string'] + _(':')
- if 'align' not in attrs:
- attrs['align'] = 1.0
- else:
- for node in node.childNodes:
- if node.nodeType == node.TEXT_NODE:
- text += node.data
- else:
- text += node.toxml()
- if not text:
container.empty_add(int(attrs.get('colspan', 1)))
continue
label = gtk.Label(text)
@@ -115,7 +95,8 @@ class ParserBoard(object):
container.wid_add(notebook,
colspan=int(attrs.get('colspan', 4)),
yexpand=True, yfill=True)
- widget, new_widgets = self.parse(node, notebook, tooltips=tooltips)
+ widget, new_widgets = self.parse(node, notebook,
+ tooltips=tooltips)
widgets += new_widgets
elif node.localName == 'page':
if CONFIG['client.form_tab'] == 'left':
@@ -124,9 +105,10 @@ class ParserBoard(object):
angle = -90
else:
angle = 0
- label = gtk.Label(attrs.get('string','No String Attr.'))
+ label = gtk.Label(attrs.get('string', _('No String Attr.')))
label.set_angle(angle)
- widget, new_widgets = self.parse(node, notebook, tooltips=tooltips)
+ widget, new_widgets = self.parse(node, notebook,
+ tooltips=tooltips)
widgets += new_widgets
notebook.append_page(widget, label)
elif node.localName == 'group':
@@ -145,7 +127,8 @@ class ParserBoard(object):
hpaned = gtk.HPaned()
container.wid_add(hpaned, colspan=int(attrs.get('colspan', 4)),
yexpand=True, yfill=True)
- widget, new_widgets = self.parse(node, paned=hpaned, tooltips=tooltips)
+ widget, new_widgets = self.parse(node, paned=hpaned,
+ tooltips=tooltips)
widgets += new_widgets
if 'position' in attrs:
hpaned.set_position(int(attrs['position']))
@@ -153,19 +136,20 @@ class ParserBoard(object):
vpaned = gtk.VPaned()
container.wid_add(vpaned, colspan=int(attrs.get('colspan', 4)),
yexpand=True, yfill=True)
- widget, new_widgets = self.parse(node, paned=vpaned, tooltips=tooltips)
+ widget, new_widgets = self.parse(node, paned=vpaned,
+ tooltips=tooltips)
widgets += new_widgets
if 'position' in attrs:
vpaned.set_position(int(attrs['position']))
elif node.localName == 'child':
- widget, new_widgets = self.parse(node, paned=paned, tooltips=tooltips)
+ widget, new_widgets = self.parse(node, paned=paned,
+ tooltips=tooltips)
widgets += new_widgets
if not paned.get_child1():
paned.pack1(widget, resize=True, shrink=True)
elif not paned.get_child2():
paned.pack2(widget, resize=True, shrink=True)
elif node.localName == 'action':
- name = str(attrs['name'])
widget_act = Action(attrs, self.context)
widgets.append(widget_act)
yexpand = bool(attrs.get('yexpand', 1))
diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py
index d0f469e..6aa6530 100644
--- a/tryton/gui/window/view_form/model/field.py
+++ b/tryton/gui/window/view_form/model/field.py
@@ -483,6 +483,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:
diff --git a/tryton/gui/window/view_form/model/group.py b/tryton/gui/window/view_form/model/group.py
index 338cf67..7e88343 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):
@@ -201,15 +202,15 @@ class Group(SignalEvent, list):
new_records = []
for id in ids:
- if self.get(id):
- continue
- new_record = Record(self.model_name, id, group=self)
- self.append(new_record)
+ new_record = self.get(id)
+ if not new_record:
+ new_record = Record(self.model_name, id, 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[:]:
diff --git a/tryton/gui/window/view_form/model/record.py b/tryton/gui/window/view_form/model/record.py
index 128f3a4..b459869 100644
--- a/tryton/gui/window/view_form/model/record.py
+++ b/tryton/gui/window/view_form/model/record.py
@@ -277,9 +277,9 @@ class Record(SignalEvent):
if not records:
return
record = records[0]
- group = record.group
+ root_group = record.group.root_group
assert all(r.model_name == record.model_name for r in records)
- assert all(r.group == group for r in records)
+ assert all(r.group.root_group == root_group for r in records)
records = [r for r in records if r.id >= 0]
ctx = {}
ctx.update(rpc.CONTEXT)
@@ -288,7 +288,7 @@ class Record(SignalEvent):
for rec in records:
ctx['_timestamp'].update(rec.get_timestamp())
record_ids = set(r.id for r in records)
- reload_ids = set(group.on_write_ids(list(record_ids)))
+ reload_ids = set(root_group.on_write_ids(list(record_ids)))
reload_ids -= record_ids
reload_ids = list(reload_ids)
args = ('model', record.model_name, 'delete', list(record_ids), ctx)
@@ -298,7 +298,7 @@ class Record(SignalEvent):
if not common.process_exception(exception, *args):
return False
if reload_ids:
- group.root_group.reload(reload_ids)
+ root_group.reload(reload_ids)
return True
def default_get(self, domain=None, context=None):
@@ -584,5 +584,8 @@ class Record(SignalEvent):
def destroy(self):
super(Record, self).destroy()
self.group = None
+ for v in self.value.itervalues():
+ if hasattr(v, 'destroy'):
+ v.destroy()
self.value = None
self.next = None
diff --git a/tryton/gui/window/view_form/screen/screen.py b/tryton/gui/window/view_form/screen/screen.py
index 3853549..3ff1368 100644
--- a/tryton/gui/window/view_form/screen/screen.py
+++ b/tryton/gui/window/view_form/screen/screen.py
@@ -368,6 +368,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:
@@ -375,6 +377,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')
@@ -540,6 +545,8 @@ class Screen(SignalEvent):
records = [self.current_record]
elif self.current_view.view_type == 'tree':
records = self.current_view.selected_records()
+ if not records:
+ return
if delete:
if not self.group.delete(records):
return False
@@ -747,8 +754,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)
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 0966ee1..e6e28ae 100644
--- a/tryton/gui/window/view_form/view/form_gtk/calendar.py
+++ b/tryton/gui/window/view_form/view/form_gtk/calendar.py
@@ -8,7 +8,7 @@ import locale
from interface import WidgetInterface
import tryton.rpc as rpc
from tryton.common import DT_FORMAT, DHM_FORMAT, HM_FORMAT, message, \
- TRYTON_ICON, timezoned_date
+ TRYTON_ICON, timezoned_date, untimezoned_date
from tryton.common import date_widget, Tooltips, datetime_strftime, \
get_toplevel_window
from tryton.translate import date_format
@@ -192,7 +192,8 @@ class DateTime(WidgetInterface):
date = datetime.datetime(*time.strptime(value, self.format)[:6])
except ValueError:
return False
- date = timezoned_date(date)
+ if timezone:
+ date = untimezoned_date(date)
return datetime_strftime(date, DHM_FORMAT)
def set_value(self, record, field):
@@ -210,7 +211,8 @@ class DateTime(WidgetInterface):
self.entry.clear()
else:
date = datetime.datetime(*time.strptime(dt_val, DHM_FORMAT)[:6])
- date = timezoned_date(date)
+ if timezone:
+ date = timezoned_date(date)
value = datetime_strftime(date, self.format)
if len(value) > self.entry.get_width_chars():
self.entry.set_width_chars(len(value))
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 1644bab..86c2d49 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
@@ -35,8 +35,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/form_gtk/image.py b/tryton/gui/window/view_form/view/form_gtk/image.py
index 3422406..efc9ac5 100644
--- a/tryton/gui/window/view_form/view/form_gtk/image.py
+++ b/tryton/gui/window/view_form/view/form_gtk/image.py
@@ -207,8 +207,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 glib.GError:
continue
if pixbuf:
@@ -216,8 +216,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:
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 fc5915f..c429d46 100644
--- a/tryton/gui/window/view_form/view/form_gtk/many2many.py
+++ b/tryton/gui/window/view_form/view/form_gtk/many2many.py
@@ -37,6 +37,7 @@ class Many2Many(WidgetInterface):
self.wid_text.set_property('width_chars', 13)
self.wid_text.connect('activate', self._sig_activate)
self.wid_text.connect('focus-out-event', self._focus_out)
+ self.focus_out = True
hbox.pack_start(self.wid_text, expand=True, fill=True)
self.but_add = gtk.Button()
@@ -120,10 +121,13 @@ class Many2Many(WidgetInterface):
self._sig_add()
def _sig_add(self, *args):
+ if not self.focus_out:
+ return
domain = self.field.domain_get(self.record)
context = self.field.context_get(self.record)
value = self.wid_text.get_text()
+ self.focus_out = False
try:
if value:
dom = [('rec_name', 'ilike', '%' + value + '%'), domain]
@@ -133,12 +137,14 @@ class Many2Many(WidgetInterface):
dom , 0, CONFIG['client.limit'], None, context)
except TrytonServerError, exception:
common.process_exception(exception)
+ self.focus_out = True
return False
def callback(ids):
res_id = None
if ids:
res_id = ids[0]
+ self.focus_out = True
self.screen.load(ids, modified=True)
self.screen.display(res_id=res_id)
if self.screen.current_view:
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 11863cd..21ae30c 100644
--- a/tryton/gui/window/view_form/view/form_gtk/one2many.py
+++ b/tryton/gui/window/view_form/view/form_gtk/one2many.py
@@ -230,7 +230,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
diff --git a/tryton/gui/window/view_form/view/form_gtk/parser.py b/tryton/gui/window/view_form/view/form_gtk/parser.py
index 19bef62..36fa795 100644
--- a/tryton/gui/window/view_form/view/form_gtk/parser.py
+++ b/tryton/gui/window/view_form/view/form_gtk/parser.py
@@ -732,7 +732,7 @@ class ParserForm(ParserInterface):
scrolledwindow.set_size_request(-1, 80)
scrolledwindow.add(textview)
textview.set_accepts_tab(False)
- return scrolledwindow, gtk.FILL | gtk.EXPAND
+ return textview, gtk.FILL | gtk.EXPAND
else:
return None, False
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 adb7d11..b84f82c 100644
--- a/tryton/gui/window/view_form/view/form_gtk/reference.py
+++ b/tryton/gui/window/view_form/view/form_gtk/reference.py
@@ -212,7 +212,8 @@ class Reference(WidgetInterface):
WinSearch(model, callback, sel_multi=False, ids=ids,
context=context, domain=domain)
return
- self.field.set_client(self.record, ('', (name, name)))
+ else:
+ self.field.set_client(self.record, ('', (name, name)))
self.focus_out = True
self.changed = True
self.display(self.record, self.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 ac66ca0..080ba54 100644
--- a/tryton/gui/window/view_form/view/list_gtk/parser.py
+++ b/tryton/gui/window/view_form/view/list_gtk/parser.py
@@ -90,6 +90,7 @@ class ParserTree(ParserInterface):
treeview.sequence = attrs.get('sequence', False)
treeview.colors = attrs.get('colors', '"black"')
treeview.keyword_open = attrs.get('keyword_open', False)
+ treeview.connect('focus', self.set_selection)
self.treeview = treeview
treeview.set_property('rules-hint', True)
if not self.title:
@@ -258,6 +259,12 @@ class ParserTree(ParserInterface):
treeview.set_fixed_height_mode(True)
return treeview, dict_widget, button_list, on_write, [], None
+ def set_selection(self, treeview, direction):
+ selection = treeview.get_selection()
+ if len(treeview.get_model()):
+ selection.select_path(0)
+ return False
+
class Char(object):
@@ -446,7 +453,7 @@ class Datetime(Date):
try:
date = datetime.datetime(*time.strptime(text,
self.display_format)[:6])
- date = common.timezoned_date(date)
+ date = common.untimezoned_date(date)
date = common.datetime_strftime(date, self.server_format)
except ValueError:
date = False
@@ -501,7 +508,9 @@ class FloatTime(Char):
def value_from_text(self, record, text, callback=None):
field = record[self.field_name]
- field.set_client(record, common.text_to_float_time(text, self.conv))
+ digits = record.expr_eval(field.attrs.get('digits', (16, 2)))
+ field.set_client(record,
+ round(common.text_to_float_time(text, self.conv), digits[1]))
if callback:
callback()
diff --git a/tryton/gui/window/win_export.py b/tryton/gui/window/win_export.py
index 94499aa..79dae47 100644
--- a/tryton/gui/window/win_export.py
+++ b/tryton/gui/window/win_export.py
@@ -327,7 +327,7 @@ class WinExport(object):
try:
new_id = rpc.execute(*args)
except TrytonServerError, exception:
- new_ids = common.process_exception(exception, self.dialog, *args)
+ new_id = common.process_exception(exception, *args)
if not new_id:
return
self.predef_model.append((
@@ -348,7 +348,7 @@ class WinExport(object):
try:
rpc.execute(*args)
except TrytonServerError, exception:
- if not common.process_exception(exception, self.dialog, *args):
+ if not common.process_exception(exception, *args):
return
for i in range(len(self.predef_model)):
if self.predef_model[i][0] == export_id:
@@ -368,9 +368,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))
@@ -444,6 +447,6 @@ class WinExport(object):
datas = rpc.execute('model', model,
'export_data', ids, fields, ctx)
except TrytonServerError, exception:
- common.process_exception(exception, self.dialog)
+ common.process_exception(exception)
return []
return datas
diff --git a/tryton/gui/window/win_form.py b/tryton/gui/window/win_form.py
index c81cf0c..da34c31 100644
--- a/tryton/gui/window/win_form.py
+++ b/tryton/gui/window/win_form.py
@@ -1,6 +1,6 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
-from tryton.common import TRYTON_ICON
+from tryton.common import TRYTON_ICON, COLOR_SCHEMES
import tryton.common as common
from tryton.config import CONFIG
import gtk
@@ -8,6 +8,7 @@ import pango
import gettext
from tryton.exceptions import TrytonServerError
from tryton.gui.window.nomodal import NoModal
+import tryton.rpc as rpc
_ = gettext.gettext
@@ -56,7 +57,7 @@ class WinForm(NoModal):
if new and many:
self.but_ok.add_accelerator('clicked',
self.accel_group, gtk.keysyms.Return,
- gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK,
+ gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK,
gtk.ACCEL_VISIBLE)
self.but_new = self.win.add_button(gtk.STOCK_NEW,
@@ -130,7 +131,8 @@ class WinForm(NoModal):
tooltips.set_tip(self.but_del, _('Delete selected record'))
self.but_del.connect('clicked', self._sig_remove)
img_del = gtk.Image()
- img_del.set_from_stock('tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_del.set_from_stock('tryton-delete',
+ gtk.ICON_SIZE_SMALL_TOOLBAR)
img_del.set_alignment(0.5, 0.5)
self.but_del.add(img_del)
self.but_del.set_relief(gtk.RELIEF_NONE)
@@ -142,7 +144,8 @@ class WinForm(NoModal):
tooltips.set_tip(but_pre, _('Previous'))
but_pre.connect('clicked', self._sig_previous)
img_pre = gtk.Image()
- img_pre.set_from_stock('tryton-go-previous', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_pre.set_from_stock('tryton-go-previous',
+ gtk.ICON_SIZE_SMALL_TOOLBAR)
img_pre.set_alignment(0.5, 0.5)
but_pre.add(img_pre)
but_pre.set_relief(gtk.RELIEF_NONE)
@@ -155,7 +158,8 @@ class WinForm(NoModal):
tooltips.set_tip(but_next, _('Next'))
but_next.connect('clicked', self._sig_next)
img_next = gtk.Image()
- img_next.set_from_stock('tryton-go-next', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_next.set_from_stock('tryton-go-next',
+ gtk.ICON_SIZE_SMALL_TOOLBAR)
img_next.set_alignment(0.5, 0.5)
but_next.add(img_next)
but_next.set_relief(gtk.RELIEF_NONE)
@@ -167,7 +171,8 @@ class WinForm(NoModal):
tooltips.set_tip(but_switch, _('Switch'))
but_switch.connect('clicked', self.switch_view)
img_switch = gtk.Image()
- img_switch.set_from_stock('tryton-fullscreen', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ img_switch.set_from_stock('tryton-fullscreen',
+ gtk.ICON_SIZE_SMALL_TOOLBAR)
img_switch.set_alignment(0.5, 0.5)
but_switch.add(img_switch)
but_switch.set_relief(gtk.RELIEF_NONE)
@@ -251,6 +256,7 @@ class WinForm(NoModal):
from tryton.gui.window.win_search import WinSearch
domain = []
context = rpc.CONTEXT.copy()
+ model_name = self.screen.model_name
try:
if self.wid_text.get_text():
@@ -258,7 +264,7 @@ class WinForm(NoModal):
'%' + self.wid_text.get_text() + '%'), domain]
else:
dom = domain
- ids = rpc.execute('model', self.attrs['relation'], 'search', dom,
+ ids = rpc.execute('model', model_name, 'search', dom,
0, CONFIG['client.limit'], None, context)
except TrytonServerError, exception:
common.process_exception(exception)
@@ -275,9 +281,8 @@ class WinForm(NoModal):
self.wid_text.set_text('')
if len(ids) != 1:
- WinSearch(self.attrs['relation'], callback, sel_multi=True,
- ids=ids, context=context, domain=domain,
- views_preload=self.attrs.get('views', {}))
+ WinSearch(model_name, callback, sel_multi=True,
+ ids=ids, context=context, domain=domain)
else:
callback(ids)
diff --git a/tryton/gui/window/win_import.py b/tryton/gui/window/win_import.py
index 06f6b44..b9d0f7c 100644
--- a/tryton/gui/window/win_import.py
+++ b/tryton/gui/window/win_import.py
@@ -145,9 +145,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:"))
@@ -231,7 +228,7 @@ class WinImport(object):
try:
return rpc.execute(*args)
except TrytonServerError, exception:
- return common.process_exception(exception, self.dialog, *args)
+ return common.process_exception(exception, *args)
def on_row_expanded(self, treeview, iter, path):
child = self.model1.iter_children(iter)
@@ -245,8 +242,7 @@ class WinImport(object):
def sig_autodetect(self, widget=None):
fname = self.import_csv_file.get_filename()
if not fname:
- common.message(_('You must select an import file first!'),
- self.dialog)
+ common.message(_('You must select an import file first!'))
return True
csvsep = self.import_csv_sep.get_text()
csvdel = self.import_csv_del.get_text()
@@ -258,8 +254,7 @@ class WinImport(object):
data = csv.reader(open(fname, 'rb'), quotechar=csvdel,
delimiter=csvsep)
except IOError:
- common.warning(_('Error opening CSV file'), self.dialog,
- _('Error'))
+ common.warning(_('Error opening CSV file'), _('Error'))
return True
self.sig_unsel_all()
word = ''
@@ -287,9 +282,8 @@ class WinImport(object):
name = self.fields[word][0]
field = word
else:
- common.warning(
- _('Error processing the file at field %s.') %
- word, self.dialog, _('Error'))
+ common.warning(_('Error processing the file at field %s.')
+ % word, _('Error'))
return True
num = self.model2.append()
self.model2.set(num, 0, name, 1, field)
@@ -356,7 +350,7 @@ class WinImport(object):
res = rpc.execute('model', model, 'import_data', fields, datas,
rpc.CONTEXT)
except TrytonServerError, exception:
- common.process_exception(exception, self.dialog)
+ common.process_exception(exception)
return False
if res[0] >= 0:
if res[0] == 1:
diff --git a/tryton/gui/window/win_search.py b/tryton/gui/window/win_search.py
index 4712a6c..8495aa7 100644
--- a/tryton/gui/window/win_search.py
+++ b/tryton/gui/window/win_search.py
@@ -85,10 +85,8 @@ class WinSearch(NoModal):
def sig_activate(self, *args):
self.view.widget_tree.emit_stop_by_name('row_activated')
- if not self.sel_multi:
- self.win.response(gtk.RESPONSE_OK)
- return True
- return False
+ self.win.response(gtk.RESPONSE_OK)
+ return True
def sig_button(self, view, event):
if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
diff --git a/tryton/gui/window/wizard.py b/tryton/gui/window/wizard.py
index a15d7b2..863787b 100644
--- a/tryton/gui/window/wizard.py
+++ b/tryton/gui/window/wizard.py
@@ -135,8 +135,8 @@ class Wizard(object):
try:
rpc.execute('wizard', self.action, 'delete', self.wiz_id,
rpc.CONTEXT)
- #XXX to remove when company displayed in status bar
- rpc.context_reload()
+ if self.action == 'ir.module.module.config_wizard':
+ rpc.context_reload()
except TrytonServerError:
pass
@@ -355,9 +355,13 @@ class WizardDialog(Wizard, NoModal):
if current_form:
for dialog in current_form.dialogs:
dialog.show()
- if hasattr(self.page, 'screen'):
- self.page.screen.reload(written=True)
super(WizardDialog, self).destroy()
+ if self.page.dialogs:
+ dialog = self.page.dialogs[-1]
+ else:
+ dialog = self.page
+ if hasattr(dialog, 'screen'):
+ dialog.screen.reload(written=True)
def end(self):
super(WizardDialog, self).end()
diff --git a/tryton/jsonrpc.py b/tryton/jsonrpc.py
index a38f4a9..a4c1c17 100644
--- a/tryton/jsonrpc.py
+++ b/tryton/jsonrpc.py
@@ -29,7 +29,7 @@ class ResponseError(xmlrpclib.ResponseError):
class Fault(xmlrpclib.Fault):
def __init__(self, faultCode, faultString='', **extra):
- super(Fault, self).__init__(faultCode, str(faultString), **extra)
+ super(Fault, self).__init__(faultCode, faultString, **extra)
self.args = faultString
diff --git a/tryton/pyson.py b/tryton/pyson.py
index 9c7dde7..1656eaf 100644
--- a/tryton/pyson.py
+++ b/tryton/pyson.py
@@ -6,6 +6,7 @@ try:
except ImportError:
import json
import datetime
+from dateutil.relativedelta import relativedelta
from functools import reduce
@@ -453,23 +454,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):
@@ -517,22 +509,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,
diff --git a/tryton/version.py b/tryton/version.py
index 77eeb38..3b71650 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.2.1"
+VERSION = "2.2.2"
LICENSE = "GPL-3"
WEBSITE = "http://www.tryton.org/"
--
tryton-client
More information about the tryton-debian-vcs
mailing list