[IMP] use new fsf address
[odoo/odoo.git] / openerp / report / render / rml2pdf / utils.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 # Copyright (C) 2003, Fabien Pinckaers, UCL, FSA
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-13017  USA
20 #
21 ##############################################################################
22
23 import copy
24 import locale
25
26 import logging
27 import re
28 import reportlab
29
30 import openerp.tools as tools
31 from openerp.tools.safe_eval import safe_eval as eval
32 from openerp.tools.misc import ustr
33
34 _logger = logging.getLogger(__name__)
35
36 _regex = re.compile('\[\[(.+?)\]\]')
37
38 def str2xml(s):
39     return (s or '').replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
40
41 def xml2str(s):
42     return (s or '').replace('&amp;','&').replace('&lt;','<').replace('&gt;','>')
43
44 def _child_get(node, self=None, tagname=None):
45     for n in node:
46         if self and self.localcontext and n.get('rml_loop'):
47
48             for ctx in eval(n.get('rml_loop'),{}, self.localcontext):
49                 self.localcontext.update(ctx)
50                 if (tagname is None) or (n.tag==tagname):
51                     if n.get('rml_except', False):
52                         try:
53                             eval(n.get('rml_except'), {}, self.localcontext)
54                         except GeneratorExit:
55                             continue
56                         except Exception, e:
57                             _logger.warning('rml_except: "%s"', n.get('rml_except',''), exc_info=True)
58                             continue
59                     if n.get('rml_tag'):
60                         try:
61                             (tag,attr) = eval(n.get('rml_tag'),{}, self.localcontext)
62                             n2 = copy.deepcopy(n)
63                             n2.tag = tag
64                             n2.attrib.update(attr)
65                             yield n2
66                         except GeneratorExit:
67                             yield n
68                         except Exception, e:
69                             _logger.warning('rml_tag: "%s"', n.get('rml_tag',''), exc_info=True)
70                             yield n
71                     else:
72                         yield n
73             continue
74         if self and self.localcontext and n.get('rml_except'):
75             try:
76                 eval(n.get('rml_except'), {}, self.localcontext)
77             except GeneratorExit:
78                 continue
79             except Exception, e:
80                 _logger.warning('rml_except: "%s"', n.get('rml_except',''), exc_info=True)
81                 continue
82         if self and self.localcontext and n.get('rml_tag'):
83             try:
84                 (tag,attr) = eval(n.get('rml_tag'),{}, self.localcontext)
85                 n2 = copy.deepcopy(n)
86                 n2.tag = tag
87                 n2.attrib.update(attr or {})
88                 yield n2
89                 tagname = ''
90             except GeneratorExit:
91                 pass
92             except Exception, e:
93                 _logger.warning('rml_tag: "%s"', n.get('rml_tag',''), exc_info=True)
94                 pass
95         if (tagname is None) or (n.tag==tagname):
96             yield n
97
98 def _process_text(self, txt):
99         """Translate ``txt`` according to the language in the local context,
100            replace dynamic ``[[expr]]`` with their real value, then escape
101            the result for XML.
102
103            :param str txt: original text to translate (must NOT be XML-escaped)
104            :return: translated text, with dynamic expressions evaluated and
105                     with special XML characters escaped (``&,<,>``).
106         """
107         if not self.localcontext:
108             return str2xml(txt)
109         if not txt:
110             return ''
111         result = ''
112         sps = _regex.split(txt)
113         while sps:
114             # This is a simple text to translate
115             to_translate = tools.ustr(sps.pop(0))
116             result += tools.ustr(self.localcontext.get('translate', lambda x:x)(to_translate))
117             if sps:
118                 try:
119                     txt = None
120                     expr = sps.pop(0)
121                     txt = eval(expr, self.localcontext)
122                     if txt and isinstance(txt, basestring):
123                         txt = tools.ustr(txt)
124                 except Exception:
125                     pass
126                 if isinstance(txt, basestring):
127                     result += txt
128                 elif txt and (txt is not None) and (txt is not False):
129                     result += ustr(txt)
130         return str2xml(result)
131
132 def text_get(node):
133     return ''.join([ustr(n.text) for n in node])
134
135 units = [
136     (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch),
137     (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm),
138     (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm),
139     (re.compile('^(-?[0-9\.]+)\s*$'), 1)
140 ]
141
142 def unit_get(size):
143     global units
144     if size:
145         if size.find('.') == -1:
146             decimal_point = '.'
147             try:
148                 decimal_point = locale.nl_langinfo(locale.RADIXCHAR)
149             except Exception:
150                 decimal_point = locale.localeconv()['decimal_point']
151
152             size = size.replace(decimal_point, '.')
153
154         for unit in units:
155             res = unit[0].search(size, 0)
156             if res:
157                 return unit[1]*float(res.group(1))
158     return False
159
160 def tuple_int_get(node, attr_name, default=None):
161     if not node.get(attr_name):
162         return default
163     return map(int, node.get(attr_name).split(','))
164
165 def bool_get(value):
166     return (str(value)=="1") or (value.lower()=='yes')
167
168 def attr_get(node, attrs, dict=None):
169     if dict is None:
170         dict = {}
171     res = {}
172     for name in attrs:
173         if node.get(name):
174             res[name] = unit_get(node.get(name))
175     for key in dict:
176         if node.get(key):
177             if dict[key]=='str':
178                 res[key] = tools.ustr(node.get(key))
179             elif dict[key]=='bool':
180                 res[key] = bool_get(node.get(key))
181             elif dict[key]=='int':
182                 res[key] = int(node.get(key))
183             elif dict[key]=='unit':
184                 res[key] = unit_get(node.get(key))
185             elif dict[key] == 'float' :
186                 res[key] = float(node.get(key))
187     return res
188
189 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: