Port txt report to new report engine.
authorP. Christeas <p_christ@hol.gr>
Thu, 7 May 2009 17:17:06 +0000 (20:17 +0300)
committerP. Christeas <p_christ@hol.gr>
Thu, 7 May 2009 17:17:06 +0000 (20:17 +0300)
bzr revid: p_christ@hol.gr-20090507171706-ozmwxiuwv5jf1q4p

bin/report/interface.py
bin/report/preprocess.py
bin/report/render/rml.py
bin/report/render/rml2html/rml2html.py
bin/report/render/rml2txt/__init__.py
bin/report/render/rml2txt/rml2txt.py
bin/report/render/rml2txt/utils.py
bin/report/report_sxw.py

index 486ba5e..bcbcd0f 100644 (file)
@@ -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')
 
index 441df89..dbb6f4c 100644 (file)
@@ -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__':
index e695cb3..d0b2d23 100644 (file)
@@ -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 = {}):
index 5e7bb5c..9987caa 100644 (file)
@@ -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
index b37936a..410b9f5 100644 (file)
@@ -20,7 +20,7 @@
 #
 ##############################################################################
 
-from rml2txt import parseString
+from rml2txt import parseString, parseNode
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
 
index ed99a3d..05fc547 100755 (executable)
@@ -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 = "<cannot render w/o template>"
         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)
index 7186cc1..789d79f 100644 (file)
@@ -1,8 +1,8 @@
 # -*- encoding: utf-8 -*-
 ##############################################################################
 #
-#    OpenERP, Open Source Management Solution  
-#    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
 #    $Id$
 #
 #    This program is free software: you can redistribute it and/or modify
 #
 ##############################################################################
 
+# 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
index 426b738..c07f156 100644 (file)
@@ -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):