From: P. Christeas Date: Thu, 7 May 2009 17:17:06 +0000 (+0300) Subject: Port txt report to new report engine. X-Git-Tag: 6.0.0-rc1-addons~2025^2~5^2~8^2~88 X-Git-Url: http://git.inspyration.org/?a=commitdiff_plain;h=eac36b4a19c57a922cf412e9d894c585f68a9360;p=odoo%2Fodoo.git Port txt report to new report engine. bzr revid: p_christ@hol.gr-20090507171706-ozmwxiuwv5jf1q4p --- diff --git a/bin/report/interface.py b/bin/report/interface.py index 486ba5e..bcbcd0f 100644 --- a/bin/report/interface.py +++ b/bin/report/interface.py @@ -205,8 +205,8 @@ class report_rml(report_int): obj.render() return obj.get() - def create_txt(self, xml, logo=None, title=None): - obj = render.rml2txt(xml, self.bin_datas) + def create_txt(self, rml,localcontext, logo=None, title=None): + obj = render.rml2txt(rml, localcontext, self.bin_datas) obj.render() return obj.get().encode('utf-8') diff --git a/bin/report/preprocess.py b/bin/report/preprocess.py index 441df89..dbb6f4c 100644 --- a/bin/report/preprocess.py +++ b/bin/report/preprocess.py @@ -6,7 +6,7 @@ html_parents = ['tr','body','div'] sxw_parents = ['{http://openoffice.org/2000/table}table-row','{http://openoffice.org/2000/office}body','{http://openoffice.org/2000/text}section'] class report(object): - def preprocess_rml(self, root_node,type='pdf'): + def preprocess_rml(self, root_node,ntype='pdf'): _regex1 = re.compile("\[\[(.*?)(repeatIn\(.*?\s*,\s*[\'\"].*?[\'\"]\s*(?:,\s*(.*?)\s*)?\s*\))(.*?)\]\]") _regex11= re.compile("\[\[(.*?)(repeatIn\(.*?\s*\(.*?\s*[\'\"].*?[\'\"]\s*\),[\'\"].*?[\'\"](?:,\s*(.*?)\s*)?\s*\))(.*?)\]\]") _regex2 = re.compile("\[\[(.*?)(removeParentNode\(\s*(?:['\"](.*?)['\"])\s*\))(.*?)\]\]") @@ -35,9 +35,9 @@ class report(object): if len(txt.group(4)) > 1: return " " match = rml_parents - if type in ['odt','sxw']: + if ntype in ['odt','sxw']: match = sxw_parents - if type =='html2html': + if ntype =='html2html': match = html_parents if txt.group(3): match = [txt.group(3)] @@ -51,7 +51,7 @@ class report(object): t = _regex11.sub(_sub1, node.text) t = _regex3.sub(_sub3, t) node.text = _regex2.sub(_sub2, t) - self.preprocess_rml(node,type) + self.preprocess_rml(node,ntype) return root_node if __name__=='__main__': diff --git a/bin/report/render/rml.py b/bin/report/render/rml.py index e695cb3..d0b2d236 100644 --- a/bin/report/render/rml.py +++ b/bin/report/render/rml.py @@ -52,13 +52,14 @@ class rml2html(render.render): return htmlizer.parseString(self.rml,self.localcontext) class rml2txt(render.render): - def __init__(self, xml, datas={}): + def __init__(self, rml, localcontext= None, datas={}): super(rml2txt, self).__init__(datas) - self.xml = xml + self.rml = rml + self.localcontext = localcontext self.output_type = 'txt' def _render(self): - return txtizer.parseString(self.xml) + return txtizer.parseString(self.rml, self.localcontext) class odt2odt(render.render): def __init__(self, rml, localcontext = None, datas = {}): diff --git a/bin/report/render/rml2html/rml2html.py b/bin/report/render/rml2html/rml2html.py index 5e7bb5c..9987caa 100644 --- a/bin/report/render/rml2html/rml2html.py +++ b/bin/report/render/rml2html/rml2html.py @@ -455,7 +455,7 @@ if __name__=="__main__": rml2html_help() print parseString(file(sys.argv[1], 'r').read()), else: - print 'Usage: trml2pdf input.rml >output.pdf' - print 'Try \'trml2pdf --help\' for more information.' + print 'Usage: rml2html input.rml >output.html' + print 'Try \'rml2html --help\' for more information.' # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/bin/report/render/rml2txt/__init__.py b/bin/report/render/rml2txt/__init__.py index b37936a..410b9f5 100644 --- a/bin/report/render/rml2txt/__init__.py +++ b/bin/report/render/rml2txt/__init__.py @@ -20,7 +20,7 @@ # ############################################################################## -from rml2txt import parseString +from rml2txt import parseString, parseNode # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/bin/report/render/rml2txt/rml2txt.py b/bin/report/render/rml2txt/rml2txt.py index ed99a3d..05fc547 100755 --- a/bin/report/render/rml2txt/rml2txt.py +++ b/bin/report/render/rml2txt/rml2txt.py @@ -40,8 +40,9 @@ import sys import StringIO -import xml.dom.minidom import copy +from lxml import etree +import base64 import utils @@ -80,6 +81,8 @@ class textbox(): """Append some text to the current line. Mimic the HTML behaviour, where all whitespace evaluates to a single space """ + if not txt: + return bs = es = False if txt[0].isspace(): bs = True @@ -135,7 +138,7 @@ class textbox(): class _flowable(object): - def __init__(self, template, doc): + def __init__(self, template, doc,localcontext): self._tags = { '1title': self._tag_title, '1spacer': self._tag_spacer, @@ -149,6 +152,7 @@ class _flowable(object): } self.template = template self.doc = doc + self.localcontext = localcontext self.nitags = [] self.tbox = None @@ -174,7 +178,7 @@ class _flowable(object): return node.toxml() def _tag_spacer(self, node): - length = 1+int(utils.unit_get(node.getAttribute('length')))/35 + length = 1+int(utils.unit_get(node.get('length')))/35 return "\n"*length def _tag_table(self, node): @@ -182,14 +186,14 @@ class _flowable(object): saved_tb = self.tb self.tb = None sizes = None - if node.hasAttribute('colWidths'): - sizes = map(lambda x: utils.unit_get(x), node.getAttribute('colWidths').split(',')) + if node.get('colWidths'): + sizes = map(lambda x: utils.unit_get(x), node.get('colWidths').split(',')) trs = [] - for n in node.childNodes: - if n.nodeType == node.ELEMENT_NODE and n.localName == 'tr': + for n in utils._child_get(node,self): + if n.tag == 'tr': tds = [] - for m in n.childNodes: - if m.nodeType == node.ELEMENT_NODE and m.localName == 'td': + for m in utils._child_get(n,self): + if m.tag == 'td': self.tb = textbox() self.rec_render_cnodes(m) tds.append(self.tb) @@ -228,21 +232,19 @@ class _flowable(object): self.rec_render_cnodes(node) def rec_render_cnodes(self,node): - for n in node.childNodes: - self.rec_render(n) + self.tb.appendtxt(utils._process_text(self, node.text or '')) + for n in utils._child_get(node,self): + self.rec_render(n) + self.tb.appendtxt(utils._process_text(self, node.tail or '')) def rec_render(self,node): """ Recursive render: fill outarr with text of current node """ - if node.nodeType == node.TEXT_NODE: - self.tb.appendtxt(node.data) - elif node.nodeType==node.ELEMENT_NODE: - if node.localName in self._tags: - self._tags[node.localName](node) + if node.tag != None: + if node.tag in self._tags: + self._tags[node.tag](node) else: - self.warn_nitag(node.localName) - else: - verbose("Unknown nodeType: %d" % node.nodeType) + self.warn_nitag(node.tag) def render(self, node): self.tb= textbox() @@ -288,8 +290,8 @@ class _rml_tmpl_frame(_rml_tmpl_tag): class _rml_tmpl_draw_string(_rml_tmpl_tag): def __init__(self, node, style): - self.posx = utils.unit_get(node.getAttribute('x')) - self.posy = utils.unit_get(node.getAttribute('y')) + self.posx = utils.unit_get(node.get('x')) + self.posy = utils.unit_get(node.get('y')) aligns = { 'drawString': 'left', 'drawRightString': 'right', @@ -348,12 +350,12 @@ class _rml_stylesheet(object): 'alignment': lambda x: ('text-align',str(x)) } result = '' - for ps in stylesheet.getElementsByTagName('paraStyle'): + for ps in stylesheet.findall('paraStyle'): attr = {} attrs = ps.attributes for i in range(attrs.length): name = attrs.item(i).localName - attr[name] = ps.getAttribute(name) + attr[name] = ps.get(name) attrs = [] for a in attr: if a in self._tags: @@ -369,9 +371,9 @@ class _rml_draw_style(object): def __init__(self): self.style = {} self._styles = { - 'fill': lambda x: {'td': {'color':x.getAttribute('color')}}, - 'setFont': lambda x: {'td': {'font-size':x.getAttribute('size')+'px'}}, - 'stroke': lambda x: {'hr': {'color':x.getAttribute('color')}}, + 'fill': lambda x: {'td': {'color':x.get('color')}}, + 'setFont': lambda x: {'td': {'font-size':x.get('size')+'px'}}, + 'stroke': lambda x: {'hr': {'color':x.get('color')}}, } def update(self, node): if node.localName in self._styles: @@ -391,7 +393,8 @@ class _rml_draw_style(object): return ';'.join(['%s:%s' % (x[0],x[1]) for x in self.style[tag].items()]) class _rml_template(object): - def __init__(self, template): + def __init__(self, localcontext, out, node, doc, images={}, path='.', title=None): + self.localcontext = localcontext self.frame_pos = -1 self.frames = [] self.template_order = [] @@ -404,16 +407,16 @@ class _rml_template(object): 'lines': _rml_tmpl_draw_lines } self.style = _rml_draw_style() - for pt in template.getElementsByTagName('pageTemplate'): + for pt in node.findall('pageTemplate'): frames = {} - id = pt.getAttribute('id') + id = pt.get('id') self.template_order.append(id) - for tmpl in pt.getElementsByTagName('frame'): - posy = int(utils.unit_get(tmpl.getAttribute('y1'))) #+utils.unit_get(tmpl.getAttribute('height'))) - posx = int(utils.unit_get(tmpl.getAttribute('x1'))) - frames[(posy,posx,tmpl.getAttribute('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.getAttribute('width'))) - for tmpl in template.getElementsByTagName('pageGraphics'): - for n in tmpl.childNodes: + for tmpl in pt.findall('frame'): + posy = int(utils.unit_get(tmpl.get('y1'))) #+utils.unit_get(tmpl.get('height'))) + posx = int(utils.unit_get(tmpl.get('x1'))) + frames[(posy,posx,tmpl.get('id'))] = _rml_tmpl_frame(posx, utils.unit_get(tmpl.get('width'))) + for tmpl in node.findall('pageGraphics'): + for n in tmpl.getchildren(): if n.nodeType==n.ELEMENT_NODE: if n.localName in self._tags: t = self._tags[n.localName](n, self.style) @@ -480,21 +483,46 @@ class _rml_template(object): return result class _rml_doc(object): - def __init__(self, data): - self.dom = xml.dom.minidom.parseString(data) - self.filename = self.dom.documentElement.getAttribute('filename') + def __init__(self, node, localcontext, images={}, path='.', title=None): + self.localcontext = localcontext + self.etree = node + self.filename = self.etree.get('filename') self.result = '' def render(self, out): - template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0]) - f = _flowable(template, self.dom) - self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0]) - del f + #el = self.etree.findall('docinit') + #if el: + #self.docinit(el) + + #el = self.etree.findall('stylesheet') + #self.styles = _rml_styles(el,self.localcontext) + + el = self.etree.findall('template') + self.result ="" + if len(el): + pt_obj = _rml_template(self.localcontext, out, el[0], self) + stories = utils._child_get(self.etree, self, 'story') + for story in stories: + if self.result: + self.result += '\f' + f = _flowable(pt_obj,story,self.localcontext) + self.result += f.render(story) + del f + else: + self.result = "" self.result += '\n' out.write( self.result) -def parseString(data, fout=None): - r = _rml_doc(data) +def parseNode(rml, localcontext = {},fout=None, images={}, path='.',title=None): + node = etree.XML(rml) + r = _rml_doc(node, localcontext, images, path, title=title) + fp = StringIO.StringIO() + r.render(fp) + return fp.getvalue() + +def parseString(rml, localcontext = {},fout=None, images={}, path='.',title=None): + node = etree.XML(rml) + r = _rml_doc(node, localcontext, images, path, title=title) if fout: fp = file(fout,'wb') r.render(fp) diff --git a/bin/report/render/rml2txt/utils.py b/bin/report/render/rml2txt/utils.py index 7186cc1..789d79f 100644 --- a/bin/report/render/rml2txt/utils.py +++ b/bin/report/render/rml2txt/utils.py @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2008 Tiny SPRL (). All Rights Reserved +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved # $Id$ # # This program is free software: you can redistribute it and/or modify @@ -20,37 +20,110 @@ # ############################################################################## +# trml2pdf - An RML to PDF converter +# Copyright (C) 2003, Fabien Pinckaers, UCL, FSA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + import re import reportlab import reportlab.lib.units +from lxml import etree + +_regex = re.compile('\[\[(.+?)\]\]') + +def _child_get(node, self=None, tagname=None): + for n in node: + if self and self.localcontext and n.get('rml_loop', False): + oldctx = self.localcontext + for ctx in eval(n.get('rml_loop'),{}, self.localcontext): + self.localcontext.update(ctx) + if (tagname is None) or (n.tag==tagname): + if n.get('rml_except', False): + try: + eval(n.get('rml_except'), {}, self.localcontext) + except: + continue + if n.get('rml_tag'): + try: + (tag,attr) = eval(n.get('rml_tag'),{}, self.localcontext) + n2 = copy.copy(n) + n2.tag = tag + n2.attrib.update(attr) + yield n2 + except: + yield n + else: + yield n + self.localcontext = oldctx + continue + if self and self.localcontext and n.get('rml_except', False): + try: + eval(n.get('rml_except'), {}, self.localcontext) + except: + continue + if (tagname is None) or (n.tag==tagname): + yield n + +def _process_text(self, txt): + if not self.localcontext: + return txt + if not txt: + return '' + result = '' + sps = _regex.split(txt) + while sps: + # This is a simple text to translate + result += self.localcontext.get('translate', lambda x:x)(sps.pop(0)) + if sps: + try: + txt2 = eval(sps.pop(0),self.localcontext) + except: + txt2 = '' + if type(txt2) == type(0) or type(txt2) == type(0.0): + txt2 = str(txt2) + if type(txt2)==type('') or type(txt2)==type(u''): + result += txt2 + return result def text_get(node): rc = '' - for node in node.childNodes: - if node.nodeType == node.TEXT_NODE: - rc = rc + node.data + for node in node.getchildren(): + rc = rc + node.text return rc units = [ (re.compile('^(-?[0-9\.]+)\s*in$'), reportlab.lib.units.inch), - (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm), + (re.compile('^(-?[0-9\.]+)\s*cm$'), reportlab.lib.units.cm), (re.compile('^(-?[0-9\.]+)\s*mm$'), reportlab.lib.units.mm), - (re.compile('^(-?[0-9\.]+)\s*px$'), 0.7), (re.compile('^(-?[0-9\.]+)\s*$'), 1) ] def unit_get(size): global units - for unit in units: - res = unit[0].search(size, 0) - if res: - return int(unit[1]*float(res.group(1))*1.3) + if size: + for unit in units: + res = unit[0].search(size, 0) + if res: + return unit[1]*float(res.group(1)) return False def tuple_int_get(node, attr_name, default=None): - if not node.hasAttribute(attr_name): + if not node.get(attr_name): return default - res = [int(x) for x in node.getAttribute(attr_name).split(',')] + res = [int(x) for x in node.get(attr_name).split(',')] return res def bool_get(value): @@ -59,17 +132,18 @@ def bool_get(value): def attr_get(node, attrs, dict={}): res = {} for name in attrs: - if node.hasAttribute(name): - res[name] = unit_get(node.getAttribute(name)) + if node.get(name): + res[name] = unit_get(node.get(name)) for key in dict: - if node.hasAttribute(key): + if node.get(key): if dict[key]=='str': - res[key] = str(node.getAttribute(key)) + res[key] = str(node.get(key)) elif dict[key]=='bool': - res[key] = bool_get(node.getAttribute(key)) + res[key] = bool_get(node.get(key)) elif dict[key]=='int': - res[key] = int(node.getAttribute(key)) + res[key] = int(node.get(key)) + elif dict[key]=='unit': + res[key] = unit_get(node.get(key)) return res -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: - +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/bin/report/report_sxw.py b/bin/report/report_sxw.py index 426b738..c07f156 100644 --- a/bin/report/report_sxw.py +++ b/bin/report/report_sxw.py @@ -309,7 +309,7 @@ class rml_parse(object): head_dom = etree.XML(rml_head) for tag in head_dom.getchildren(): found = rml_dom.find('.//'+tag.tag) - if found: + if found is not None: if tag.get('position'): found.append(tag) else : @@ -359,12 +359,12 @@ class report_sxw(report_rml, preprocess.report): report_type = report_xml.report_type if report_type in ['sxw','odt']: fnct = self.create_source_odt - elif report_type in ['pdf','raw','html']: + elif report_type in ['pdf','raw','txt','html']: fnct = self.create_source_pdf elif report_type=='html2html': fnct = self.create_source_html2html else: - raise 'Unknown Report Type' + raise Exception('Unknown Report Type: '+report_type) return fnct(cr, uid, ids, data, report_xml, context) def create_source_odt(self, cr, uid, ids, data, report_xml, context=None):