~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/report/render/rml2html/rml2html.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- coding: utf-8 -*-
 
3
 
 
4
# Copyright (C) 2005, Fabien Pinckaers, UCL, FSA
 
5
#
 
6
# This library is free software; you can redistribute it and/or
 
7
# modify it under the terms of the GNU Lesser General Public
 
8
# License as published by the Free Software Foundation; either
 
9
# version 2.1 of the License, or (at your option) any later version.
 
10
#
 
11
# This library is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
# Lesser General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU Lesser General Public
 
17
# License along with this library; if not, write to the Free Software
 
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 
 
20
import sys
 
21
import StringIO
 
22
import xml.dom.minidom
 
23
import copy
 
24
 
 
25
import utils
 
26
 
 
27
class _flowable(object):
 
28
        def __init__(self, template, doc):
 
29
                self._tags = {
 
30
                        'title': self._tag_title,
 
31
                        'spacer': self._tag_spacer,
 
32
                        'para': self._tag_para,
 
33
                        'nextFrame': self._tag_next_frame,
 
34
                        'blockTable': self._tag_table,
 
35
                        'pageBreak': self._tag_page_break,
 
36
                        'setNextTemplate': self._tag_next_template,
 
37
                }
 
38
                self.template = template
 
39
                self.doc = doc
 
40
 
 
41
        def _tag_page_break(self, node):
 
42
                return '<br/>'*3
 
43
 
 
44
        def _tag_next_template(self, node):
 
45
                return ''
 
46
 
 
47
        def _tag_next_frame(self, node):
 
48
                result=self.template.frame_stop()
 
49
                result+='<br/>'
 
50
                result+=self.template.frame_start()
 
51
                return result
 
52
 
 
53
        def _tag_title(self, node):
 
54
                node.tagName='h1'
 
55
                return node.toxml()
 
56
 
 
57
        def _tag_spacer(self, node):
 
58
                length = 1+int(utils.unit_get(node.getAttribute('length')))/35
 
59
                return "<br/>"*length
 
60
 
 
61
        def _tag_table(self, node):
 
62
                node.tagName='table'
 
63
                if node.hasAttribute('colWidths'):
 
64
                        sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(','))
 
65
                        tr = self.doc.createElement('tr')
 
66
                        for s in sizes:
 
67
                                td = self.doc.createElement('td')
 
68
                                td.setAttribute("width", str(s))
 
69
                                tr.appendChild(td)
 
70
                        node.appendChild(tr)
 
71
                return node.toxml()
 
72
 
 
73
        def _tag_para(self, node):
 
74
                node.tagName='p'
 
75
                if node.hasAttribute('style'):
 
76
                        node.setAttribute('class', node.getAttribute('style'))
 
77
                return node.toxml()
 
78
 
 
79
        def render(self, node):
 
80
                result = self.template.start()
 
81
                result += self.template.frame_start()
 
82
                for n in node.childNodes:
 
83
                        if n.nodeType==node.ELEMENT_NODE:
 
84
                                if n.localName in self._tags:
 
85
                                        result += self._tags[n.localName](n)
 
86
                                else:
 
87
                                        pass
 
88
                                        #print 'tag', n.localName, 'not yet implemented!'
 
89
                result += self.template.frame_stop()
 
90
                result += self.template.end()
 
91
                return result
 
92
 
 
93
class _rml_tmpl_tag(object):
 
94
        def __init__(self, *args):
 
95
                pass
 
96
        def tag_start(self):
 
97
                return ''
 
98
        def tag_end(self):
 
99
                return False
 
100
        def tag_stop(self):
 
101
                return ''
 
102
        def tag_mergeable(self):
 
103
                return True
 
104
 
 
105
class _rml_tmpl_frame(_rml_tmpl_tag):
 
106
        def __init__(self, posx, width):
 
107
                self.width = width
 
108
                self.posx = posx
 
109
        def tag_start(self):
 
110
                return '<table border="0" width="%d"><tr><td width="%d">&nbsp;</td><td>' % (self.width+self.posx,self.posx)
 
111
        def tag_end(self):
 
112
                return True
 
113
        def tag_stop(self):
 
114
                return '</td></tr></table><br/>'
 
115
        def tag_mergeable(self):
 
116
                return False
 
117
 
 
118
        # An awfull workaround since I don't really understand the semantic behind merge.
 
119
        def merge(self, frame):
 
120
                pass
 
121
 
 
122
class _rml_tmpl_draw_string(_rml_tmpl_tag):
 
123
        def __init__(self, node, style):
 
124
                self.posx = utils.unit_get(node.getAttribute('x'))
 
125
                self.posy =  utils.unit_get(node.getAttribute('y'))
 
126
                aligns = {
 
127
                        'drawString': 'left',
 
128
                        'drawRightString': 'right',
 
129
                        'drawCentredString': 'center'
 
130
                }
 
131
                align = aligns[node.localName]
 
132
                self.pos = [(self.posx, self.posy, align, utils.text_get(node), style.get('td'), style.font_size_get('td'))]
 
133
 
 
134
        def tag_start(self):
 
135
                self.pos.sort()
 
136
                res = '<table border="0" cellpadding="0" cellspacing="0"><tr>'
 
137
                posx = 0
 
138
                i = 0
 
139
                for (x,y,align,txt, style, fs) in self.pos:
 
140
                        if align=="left":
 
141
                                pos2 = len(txt)*fs
 
142
                                res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
 
143
                                posx = x+pos2
 
144
                        if align=="right":
 
145
                                res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
 
146
                                posx = x
 
147
                        if align=="center":
 
148
                                res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
 
149
                                posx = 2*x-posx
 
150
                        i+=1
 
151
                res+='</tr></table>'
 
152
                return res
 
153
        def merge(self, ds):
 
154
                self.pos+=ds.pos
 
155
 
 
156
class _rml_tmpl_draw_lines(_rml_tmpl_tag):
 
157
        def __init__(self, node, style):
 
158
                coord = [utils.unit_get(x) for x in utils.text_get(node).split(' ')]
 
159
                self.ok = False
 
160
                self.posx = coord[0]
 
161
                self.posy = coord[1]
 
162
                self.width = coord[2]-coord[0]
 
163
                self.ok = coord[1]==coord[3]
 
164
                self.style = style
 
165
                self.style = style.get('hr')
 
166
 
 
167
        def tag_start(self):
 
168
                if self.ok:
 
169
                        return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
 
170
                else:
 
171
                        return ''
 
172
 
 
173
class _rml_stylesheet(object):
 
174
        def __init__(self, stylesheet, doc):
 
175
                self.doc = doc
 
176
                self.attrs = {}
 
177
                self._tags = {
 
178
                        'fontSize': lambda x: ('font-size',str(utils.unit_get(x))+'px'),
 
179
                        'alignment': lambda x: ('text-align',str(x))
 
180
                }
 
181
                result = ''
 
182
                for ps in stylesheet.getElementsByTagName('paraStyle'):
 
183
                        attr = {}
 
184
                        attrs = ps.attributes
 
185
                        for i in range(attrs.length):
 
186
                                 name = attrs.item(i).localName
 
187
                                 attr[name] = ps.getAttribute(name)
 
188
                        attrs = []
 
189
                        for a in attr:
 
190
                                if a in self._tags:
 
191
                                        attrs.append("%s:%s" % self._tags[a](attr[a]))
 
192
                        if len(attrs):
 
193
                                result += "p."+attr['name']+" {"+'; '.join(attrs)+"}\n"
 
194
                self.result = result
 
195
 
 
196
        def render(self):
 
197
                return self.result
 
198
 
 
199
class _rml_draw_style(object):
 
200
        def __init__(self):
 
201
                self.style = {}
 
202
                self._styles = {
 
203
                        'fill': lambda x: {'td': {'color':x.getAttribute('color')}},
 
204
                        'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}},
 
205
                        'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}},
 
206
                }
 
207
        def update(self, node):
 
208
                if node.localName in self._styles:
 
209
                        result = self._styles[node.localName](node)
 
210
                        for key in result:
 
211
                                if key in self.style:
 
212
                                        self.style[key].update(result[key])
 
213
                                else:
 
214
                                        self.style[key] = result[key]
 
215
        def font_size_get(self,tag):
 
216
                size  = utils.unit_get(self.style.get('td', {}).get('font-size','16'))
 
217
                return size
 
218
 
 
219
        def get(self,tag):
 
220
                if not tag in self.style:
 
221
                        return ""
 
222
                return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
 
223
 
 
224
class _rml_template(object):
 
225
        def __init__(self, template):
 
226
                self.frame_pos = -1
 
227
                self.frames = []
 
228
                self.template_order = []
 
229
                self.page_template = {}
 
230
                self.loop = 0
 
231
                self._tags = {
 
232
                        'drawString': _rml_tmpl_draw_string,
 
233
                        'drawRightString': _rml_tmpl_draw_string,
 
234
                        'drawCentredString': _rml_tmpl_draw_string,
 
235
                        'lines': _rml_tmpl_draw_lines
 
236
                }
 
237
                self.style = _rml_draw_style()
 
238
                for pt in template.getElementsByTagName('pageTemplate'):
 
239
                        frames = {}
 
240
                        id = pt.getAttribute('id')
 
241
                        self.template_order.append(id)
 
242
                        for tmpl in pt.getElementsByTagName('frame'):
 
243
                                posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height')))
 
244
                                posx = int(utils.unit_get(tmpl.getAttribute('x1')))
 
245
                                frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width')))
 
246
                        for tmpl in template.getElementsByTagName('pageGraphics'):
 
247
                                for n in tmpl.childNodes:
 
248
                                        if n.nodeType==n.ELEMENT_NODE:
 
249
                                                if n.localName in self._tags:
 
250
                                                        t = self._tags[n.localName](n, self.style)
 
251
                                                        frames[(t.posy,t.posx,n.localName)] = t
 
252
                                                else:
 
253
                                                        self.style.update(n)
 
254
                        keys = frames.keys()
 
255
                        keys.sort()
 
256
                        keys.reverse()
 
257
                        self.page_template[id] = []
 
258
                        for key in range(len(keys)):
 
259
                                if key>0 and keys[key-1][0] == keys[key][0]:
 
260
                                        if type(self.page_template[id][-1]) == type(frames[keys[key]]):
 
261
                                                if self.page_template[id][-1].tag_mergeable():
 
262
                                                        self.page_template[id][-1].merge(frames[keys[key]])
 
263
                                                continue
 
264
                                self.page_template[id].append(frames[keys[key]])
 
265
                self.template = self.template_order[0]
 
266
 
 
267
        def _get_style(self):
 
268
                return self.style
 
269
 
 
270
        def set_next_template(self):
 
271
                self.template = self.template_order[(self.template_order.index(name)+1) % self.template_order]
 
272
                self.frame_pos = -1
 
273
 
 
274
        def set_template(self, name):
 
275
                self.template = name
 
276
                self.frame_pos = -1
 
277
 
 
278
        def frame_start(self):
 
279
                result = ''
 
280
                frames = self.page_template[self.template]
 
281
                ok = True
 
282
                while ok:
 
283
                        self.frame_pos += 1
 
284
                        if self.frame_pos>=len(frames):
 
285
                                self.frame_pos=0
 
286
                                self.loop=1
 
287
                                ok = False
 
288
                                continue
 
289
                        f = frames[self.frame_pos]
 
290
                        result+=f.tag_start()
 
291
                        ok = not f.tag_end()
 
292
                        if ok:
 
293
                                result+=f.tag_stop()
 
294
                return result
 
295
 
 
296
        def frame_stop(self):
 
297
                frames = self.page_template[self.template]
 
298
                f = frames[self.frame_pos]
 
299
                result=f.tag_stop()
 
300
                return result
 
301
 
 
302
        def start(self):
 
303
                return ''
 
304
        
 
305
        def end(self):
 
306
                result = ''
 
307
                while not self.loop:
 
308
                        result += self.frame_start()
 
309
                        result += self.frame_stop()
 
310
                return result
 
311
 
 
312
class _rml_doc(object):
 
313
        def __init__(self, data):
 
314
                self.dom = xml.dom.minidom.parseString(data)
 
315
                self.filename = self.dom.documentElement.getAttribute('filename')
 
316
                self.result = ''
 
317
 
 
318
        def render(self, out):
 
319
                self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
 
320
<html>
 
321
<head>
 
322
        <style type="text/css">
 
323
                p {margin:0px; font-size:12px;}
 
324
                td {font-size:14px;}
 
325
'''
 
326
                style = self.dom.documentElement.getElementsByTagName('stylesheet')[0]
 
327
                s = _rml_stylesheet(style, self.dom)
 
328
                self.result += s.render()
 
329
                self.result+='''
 
330
        </style>
 
331
</head>
 
332
<body>'''
 
333
 
 
334
                template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
 
335
                f = _flowable(template, self.dom)
 
336
                self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
 
337
                del f
 
338
                self.result += '</body></html>'
 
339
                out.write( self.result)
 
340
 
 
341
def parseString(data, fout=None):
 
342
        r = _rml_doc(data)
 
343
        if fout:
 
344
                fp = file(fout,'wb')
 
345
                r.render(fp)
 
346
                fp.close()
 
347
                return fout
 
348
        else:
 
349
                fp = StringIO.StringIO()
 
350
                r.render(fp)
 
351
                return fp.getvalue()
 
352
 
 
353
def trml2pdf_help():
 
354
        print 'Usage: rml2html input.rml >output.html'
 
355
        print 'Render the standard input (RML) and output an HTML file'
 
356
        sys.exit(0)
 
357
 
 
358
if __name__=="__main__":
 
359
        if len(sys.argv)>1:
 
360
                if sys.argv[1]=='--help':
 
361
                        trml2pdf_help()
 
362
                print parseString(file(sys.argv[1], 'r').read()),
 
363
        else:
 
364
                print 'Usage: trml2pdf input.rml >output.pdf'
 
365
                print 'Try \'trml2pdf --help\' for more information.'