1 # -*- encoding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ##############################################################################
23 # Copyright (C) 2005, Fabien Pinckaers, UCL, FSA
25 # This library is free software; you can redistribute it and/or
26 # modify it under the terms of the GNU Lesser General Public
27 # License as published by the Free Software Foundation; either
28 # version 2.1 of the License, or (at your option) any later version.
30 # This library is distributed in the hope that it will be useful,
31 # but WITHOUT ANY WARRANTY; without even the implied warranty of
32 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 # Lesser General Public License for more details.
35 # You should have received a copy of the GNU Lesser General Public
36 # License along with this library; if not, write to the Free Software
37 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 from lxml import etree
44 from report.render.rml2pdf import utils
46 class _flowable(object):
47 def __init__(self, template, doc, localcontext = None):
49 'title': self._tag_title,
50 'spacer': self._tag_spacer,
51 'para': self._tag_para,
52 'section':self._section,
53 'nextFrame': self._tag_next_frame,
54 'blockTable': self._tag_table,
55 'pageBreak': self._tag_page_break,
56 'setNextTemplate': self._tag_next_template,
58 self.template = template
60 self.localcontext = localcontext
63 def _tag_page_break(self, node):
66 def _tag_next_template(self, node):
69 def _tag_next_frame(self, node):
70 result=self.template.frame_stop()
72 result+=self.template.frame_start()
75 def _tag_title(self, node):
77 return etree.tostring(node)
79 def _tag_spacer(self, node):
80 length = 1+int(utils.unit_get(node.get('length')))/35
83 def _tag_table(self, node):
84 new_node = copy.deepcopy(node)
85 for child in new_node:
86 new_node.remove(child)
87 new_node.tag = 'table'
88 def process(node,new_node):
89 for child in utils._child_get(node,self):
90 new_child = copy.deepcopy(child)
91 new_node.append(new_child)
95 process(child, new_child)
97 new_child.text = utils._process_text(self, child.text)
100 if new_child.get('style').find('terp_tblheader')!= -1:
104 process(node,new_node)
105 if new_node.get('colWidths',False):
106 sizes = map(lambda x: utils.unit_get(x), new_node.get('colWidths').split(','))
107 tr = etree.Element('tr')
109 td = etree.Element('td')
110 td.set("width", str(s))
113 return etree.tostring(new_node)
115 def _tag_para(self, node):
116 new_node = copy.deepcopy(node)
118 if new_node.attrib.get('style',False):
119 new_node.set('class', new_node.get('style'))
120 new_node.text = utils._process_text(self, node.text)
121 return etree.tostring(new_node)
123 def _section(self, node):
125 for child in utils._child_get(node, self):
126 if child.tag in self._tags:
127 result += self._tags[child.tag](child)
130 def render(self, node):
131 result = self.template.start()
132 result += self.template.frame_start()
133 for n in utils._child_get(node, self):
134 if n.tag in self._tags:
135 result += self._tags[n.tag](n)
138 result += self.template.frame_stop()
139 result += self.template.end()
140 return result.encode('utf-8').replace('"',"\'").replace('°','°')
142 class _rml_tmpl_tag(object):
143 def __init__(self, *args):
151 def tag_mergeable(self):
154 class _rml_tmpl_frame(_rml_tmpl_tag):
155 def __init__(self, posx, width):
159 return "<table border=\'0\' width=\'%d\'><tr><td width=\'%d\'> </td><td>" % (self.width+self.posx,self.posx)
163 return '</td></tr></table><br/>'
164 def tag_mergeable(self):
167 def merge(self, frame):
170 class _rml_tmpl_draw_string(_rml_tmpl_tag):
171 def __init__(self, node, style,localcontext = {}):
172 self.localcontext = localcontext
173 self.posx = utils.unit_get(node.get('x'))
174 self.posy = utils.unit_get(node.get('y'))
177 'drawString': 'left',
178 'drawRightString': 'right',
179 'drawCentredString': 'center'
181 align = aligns[node.tag]
182 self.pos = [(self.posx, self.posy, align, utils._process_text(self, node.text), style.get('td'), style.font_size_get('td'))]
186 res = "<table border='0' cellpadding='0' cellspacing='0'><tr>"
189 for (x,y,align,txt, style, fs) in self.pos:
192 res+="<td width=\'%d\'></td><td style=\'%s\' width=\'%d\'>%s</td>" % (x - posx, style, pos2, txt)
195 res+="<td width=\'%d\' align=\'right\' style=\'%s\'>%s</td>" % (x - posx, style, txt)
198 res+="<td width=\'%d\' align=\'center\' style=\'%s\'>%s</td>" % ((x - posx)*2, style, txt)
206 class _rml_tmpl_draw_lines(_rml_tmpl_tag):
207 def __init__(self, node, style, localcontext = {}):
208 self.localcontext = localcontext
209 coord = [utils.unit_get(x) for x in utils._process_text(self, node.text).split(' ')]
213 self.width = coord[2]-coord[0]
214 self.ok = coord[1]==coord[3]
216 self.style = style.get('hr')
220 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)
224 class _rml_stylesheet(object):
225 def __init__(self, localcontext, stylesheet, doc):
227 self.localcontext = localcontext
230 'fontSize': lambda x: ('font-size',str(utils.unit_get(x)+5.0)+'px'),
231 'alignment': lambda x: ('text-align',str(x))
234 for ps in stylesheet.findall('paraStyle'):
237 for key, val in attrs.items():
242 attrs.append('%s:%s' % self._tags[a](attr[a]))
244 result += 'p.'+attr['name']+' {'+'; '.join(attrs)+'}\n'
250 class _rml_draw_style(object):
254 'fill': lambda x: {'td': {'color':x.get('color')}},
255 'setFont': lambda x: {'td': {'font-size':x.get('size')+'px'}},
256 'stroke': lambda x: {'hr': {'color':x.get('color')}},
258 def update(self, node):
259 if node.tag in self._styles:
260 result = self._styles[node.tag](node)
262 if key in self.style:
263 self.style[key].update(result[key])
265 self.style[key] = result[key]
266 def font_size_get(self,tag):
267 size = utils.unit_get(self.style.get('td', {}).get('font-size','16'))
271 if not tag in self.style:
273 return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()])
275 class _rml_template(object):
276 def __init__(self, template, localcontext=None):
278 self.localcontext = localcontext
280 self.template_order = []
281 self.page_template = {}
284 'drawString': _rml_tmpl_draw_string,
285 'drawRightString': _rml_tmpl_draw_string,
286 'drawCentredString': _rml_tmpl_draw_string,
287 'lines': _rml_tmpl_draw_lines
289 self.style = _rml_draw_style()
290 rc = 'data:image/png;base64,'
292 for pt in template.findall('pageTemplate'):
295 self.template_order.append(id)
296 for tmpl in pt.findall('frame'):
297 posy = int(utils.unit_get(tmpl.get('y1')))
298 posx = int(utils.unit_get(tmpl.get('x1')))
299 frames[(posy,posx,tmpl.get('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.get('width')))
300 for tmpl in pt.findall('pageGraphics'):
301 for n in tmpl.getchildren():
303 self.data = rc + utils._process_text(self, n.text)
304 if n.tag in self._tags:
305 t = self._tags[n.tag](n, self.style,self.localcontext)
306 frames[(t.posy,t.posx,n.tag)] = t
312 self.page_template[id] = []
313 for key in range(len(keys)):
314 if key>0 and keys[key-1][0] == keys[key][0]:
315 if type(self.page_template[id][-1]) == type(frames[keys[key]]):
316 if self.page_template[id][-1].tag_mergeable():
317 self.page_template[id][-1].merge(frames[keys[key]])
319 self.page_template[id].append(frames[keys[key]])
320 self.template = self.template_order[0]
322 def _get_style(self):
325 def set_next_template(self):
326 self.template = self.template_order[(self.template_order.index(name)+1) % self.template_order]
329 def set_template(self, name):
333 def frame_start(self):
335 frames = self.page_template[self.template]
339 if self.frame_pos>=len(frames):
344 f = frames[self.frame_pos]
345 result+=f.tag_start()
351 def frame_stop(self):
352 frames = self.page_template[self.template]
353 f = frames[self.frame_pos]
363 result += self.frame_start()
364 result += self.frame_stop()
367 class _rml_doc(object):
368 def __init__(self, data, localcontext):
369 self.dom = etree.XML(data)
370 self.localcontext = localcontext
371 self.filename = self.dom.get('filename')
374 def render(self, out):
375 self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
378 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
379 <style type="text/css">
380 p {margin:0px; font-size:12px;}
383 style = self.dom.findall('stylesheet')[0]
384 s = _rml_stylesheet(self.localcontext, style, self.dom)
385 self.result += s.render()
390 for story in utils._child_get(self.dom, self, 'story'):
391 template = _rml_template(self.dom.findall('template')[0], self.localcontext)
392 f = _flowable(template, self.dom, localcontext = self.localcontext)
393 story_text = f.render(story)
394 list_story.append(story_text)
397 tag = '''<img src = '%s' width=80 height=72/>'''%(template.data)
401 <script type="text/javascript">
407 if(indexer < aryTest.length -1)
410 document.getElementById("tiny_data").innerHTML=aryTest[indexer];
418 document.getElementById("tiny_data").innerHTML=aryTest[indexer];
429 <input type="button" value="next" onclick="nextData();">
430 <input type="button" value="prev" onclick="prevData();">
432 </body></html>'''%(list_story,tag,list_story[0])
433 out.write( self.result)
435 def parseString(data,localcontext = {}, fout=None):
436 r = _rml_doc(data, localcontext)
443 fp = cStringIO.StringIO()
448 print 'Usage: rml2html input.rml >output.html'
449 print 'Render the standard input (RML) and output an HTML file'
452 if __name__=="__main__":
454 if sys.argv[1]=='--help':
456 print parseString(file(sys.argv[1], 'r').read()),
458 print 'Usage: trml2pdf input.rml >output.pdf'
459 print 'Try \'trml2pdf --help\' for more information.'
461 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: