diff --git a/ext/custom-addons/web_printscreen_zb/__init__.py b/ext/custom-addons/web_printscreen_zb/__init__.py
new file mode 100644
index 00000000..63149b13
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/__init__.py
@@ -0,0 +1,27 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd.
+# (http://wwww.zbeanztech.com)
+# contact@zbeanztech.com
+# prajul@zbeanztech.com
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import trml2pdf
+import controllers
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/ext/custom-addons/web_printscreen_zb/__openerp__.py b/ext/custom-addons/web_printscreen_zb/__openerp__.py
new file mode 100644
index 00000000..b074cd8e
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/__openerp__.py
@@ -0,0 +1,41 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd.
+# (http://wwww.zbeanztech.com)
+# contact@zbeanztech.com
+# prajul@zbeanztech.com
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+{
+ 'name': 'Web Printscreen ZB',
+ 'version': '1.0',
+ 'category': 'Web',
+ 'description': """
+ Module to export current active tree view in to excel report
+ """,
+ 'author': 'Zesty Beanz Technologies',
+ 'website': 'http://www.zbeanztech.com',
+ 'depends': ['web'],
+ 'data': ['views/web_printscreen_zb.xml'],
+ 'qweb': ['static/src/xml/web_printscreen_export.xml'],
+ 'installable': True,
+ 'auto_install': False,
+ 'web_preload': False,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/ext/custom-addons/web_printscreen_zb/controllers.py b/ext/custom-addons/web_printscreen_zb/controllers.py
new file mode 100644
index 00000000..8c383af8
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/controllers.py
@@ -0,0 +1,185 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd.
+# (http://wwww.zbeanztech.com)
+# contact@zbeanztech.com
+# prajul@zbeanztech.com
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+import openerp.addons.web.http as openerpweb
+from openerp.addons.web.controllers.main import ExcelExport
+from openerp.addons.web.controllers.main import Export
+import re
+from cStringIO import StringIO
+from lxml import etree
+import trml2pdf
+import time, os
+import locale
+import openerp.tools as tools
+try:
+ import xlwt
+except ImportError:
+ xlwt = None
+
+class ZbExcelExport(ExcelExport):
+ _cp_path = '/web/export/zb_excel_export'
+
+ def from_data(self, fields, rows):
+ workbook = xlwt.Workbook()
+ worksheet = workbook.add_sheet('Sheet 1')
+ style = xlwt.easyxf('align: wrap yes')
+ font = xlwt.Font()
+ font.bold = True
+ style.font = font
+ ignore_index = []
+ count = 0
+ for i, fieldname in enumerate(fields):
+ if fieldname.get('header_data_id', False):
+ field_name = fieldname.get('header_name', '')
+ worksheet.write(0, i-count, field_name, style)
+ worksheet.col(i).width = 8000
+ else:
+ count += 1
+ ignore_index.append(i)
+ style = xlwt.easyxf('align: wrap yes')
+ bold_style = xlwt.easyxf('align: wrap yes')
+ font = xlwt.Font()
+ font.bold = True
+ bold_style.font = font
+ for row_index, row in enumerate(rows):
+ count = 0
+ for cell_index, cell_value in enumerate(row):
+ if cell_index not in ignore_index:
+ cell_style = style
+ if cell_value.get('bold', False):
+ cell_style = bold_style
+ cellvalue = cell_value.get('data', '')
+ if isinstance(cellvalue, basestring):
+ cellvalue = re.sub("\r", " ", cellvalue)
+ if cell_value.get('number', False) and cellvalue:
+ cellvalue = float(cellvalue)
+ if cellvalue is False: cellvalue = None
+ worksheet.write(row_index + 1, cell_index - count, cellvalue, cell_style)
+ else:
+ count += 1
+ fp = StringIO()
+ workbook.save(fp)
+ fp.seek(0)
+ data = fp.read()
+ fp.close()
+ return data
+
+ @openerpweb.httprequest
+ def index(self, req, data, token):
+ data = json.loads(data)
+ return req.make_response(
+ self.from_data(data.get('headers', []), data.get('rows', [])),
+ headers=[
+ ('Content-Disposition', 'attachment; filename="%s"'
+ % data.get('model', 'Export.xls')),
+ ('Content-Type', self.content_type)
+ ],
+ cookies={'fileToken': token}
+ )
+
+class ExportPdf(Export):
+ _cp_path = '/web/export/zb_pdf'
+ fmt = {
+ 'tag': 'pdf',
+ 'label': 'PDF',
+ 'error': None
+ }
+
+ @property
+ def content_type(self):
+ return 'application/pdf'
+
+ def filename(self, base):
+ return base + '.pdf'
+
+ def from_data(self, uid, fields, rows, company_name):
+ pageSize=[210.0,297.0]
+ new_doc = etree.Element("report")
+ config = etree.SubElement(new_doc, 'config')
+ def _append_node(name, text):
+ n = etree.SubElement(config, name)
+ n.text = text
+ _append_node('date', time.strftime(str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'))))
+ _append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
+ _append_node('PageWidth', '%.2f' % (pageSize[0] * 2.8346,))
+ _append_node('PageHeight', '%.2f' %(pageSize[1] * 2.8346,))
+ _append_node('PageFormat', 'a4')
+ _append_node('header-date', time.strftime(str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y'))))
+ _append_node('company', company_name)
+ l = []
+ t = 0
+ temp = []
+ tsum = []
+ skip_index = []
+ header = etree.SubElement(new_doc, 'header')
+ i = 0
+ for f in fields:
+ if f.get('header_data_id', False):
+ value = f.get('header_name', "")
+ field = etree.SubElement(header, 'field')
+ field.text = tools.ustr(value)
+ else:
+ skip_index.append(i)
+ i += 1
+ lines = etree.SubElement(new_doc, 'lines')
+ for row_lines in rows:
+ node_line = etree.SubElement(lines, 'row')
+ j = 0
+ for row in row_lines:
+ if not j in skip_index:
+ para = "yes"
+ tree = "no"
+ value = row.get('data', '')
+ if row.get('bold', False):
+ para = "group"
+ if row.get('number', False):
+ tree = "float"
+ col = etree.SubElement(node_line, 'col', para=para, tree=tree)
+ col.text = tools.ustr(value)
+ j += 1
+ transform = etree.XSLT(
+ etree.parse(os.path.join(tools.config['root_path'],
+ 'addons/base/report/custom_new.xsl')))
+ rml = etree.tostring(transform(new_doc))
+ self.obj = trml2pdf.parseNode(rml, title='Printscreen')
+ return self.obj
+
+class ZbPdfExport(ExportPdf):
+ _cp_path = '/web/export/zb_pdf_export'
+
+ @openerpweb.httprequest
+ def index(self, req, data, token):
+ data = json.loads(data)
+ uid = data.get('uid', False)
+ return req.make_response(self.from_data(uid, data.get('headers', []), data.get('rows', []),
+ data.get('company_name','')),
+ headers=[('Content-Disposition',
+ 'attachment; filename=PDF Export'),
+ ('Content-Type', self.content_type)])
+# cookies={'fileToken': long(token)})
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js b/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js
new file mode 100644
index 00000000..dfcbe0a2
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/static/src/js/web_printscreen_export.js
@@ -0,0 +1,122 @@
+openerp.web_printscreen_zb = function(instance, m) {
+
+ var _t = instance.web._t;
+ var QWeb = instance.web.qweb;
+
+ instance.web.ListView.include({
+ load_list: function () {
+ var self = this;
+ this._super.apply(this, arguments);
+ self.$pager.find(".oe_list_button_import_excel").unbind('click').click(function(event){self.export_to_excel("excel")})
+ self.$pager.find(".oe_list_button_import_pdf").unbind('click').click(function(event){self.export_to_excel("pdf")})
+ },
+ export_to_excel: function(export_type) {
+ var self = this
+ var export_type = export_type
+ view = this.getParent()
+ // Find Header Element
+ header_eles = self.$el.find('.oe_list_header_columns')
+ header_name_list = []
+ $.each(header_eles,function(){
+ $header_ele = $(this)
+ header_td_elements = $header_ele.find('th')
+ $.each(header_td_elements,function(){
+ $header_td = $(this)
+ text = $header_td.text().trim() || ""
+ data_id = $header_td.attr('data-id')
+ if (text && !data_id){
+ data_id = 'group_name'
+ }
+ header_name_list.push({'header_name': text.trim(), 'header_data_id': data_id})
+ // }
+ });
+ });
+
+ //Find Data Element
+ data_eles = self.$el.find('.oe_list_content > tbody > tr')
+ export_data = []
+ $.each(data_eles,function(){
+ data = []
+ $data_ele = $(this)
+ is_analysis = false
+ if ($data_ele.text().trim()){
+ //Find group name
+ group_th_eles = $data_ele.find('th')
+ $.each(group_th_eles,function(){
+ $group_th_ele = $(this)
+ text = $group_th_ele.text().trim() || ""
+ is_analysis = true
+ data.push({'data': text, 'bold': true})
+ });
+ data_td_eles = $data_ele.find('td')
+ $.each(data_td_eles,function(){
+ $data_td_ele = $(this)
+ text = $data_td_ele.text().trim() || ""
+ if ($data_td_ele && $data_td_ele[0].classList.contains('oe_number') && !$data_td_ele[0].classList.contains('oe_list_field_float_time')){
+ text = text.replace('%', '')
+ text = instance.web.parse_value(text, { type:"float" })
+ data.push({'data': text || "", 'number': true})
+ }
+ else{
+ data.push({'data': text})
+ }
+ });
+ export_data.push(data)
+ }
+ });
+
+ //Find Footer Element
+
+ footer_eles = self.$el.find('.oe_list_content > tfoot> tr')
+ $.each(footer_eles,function(){
+ data = []
+ $footer_ele = $(this)
+ footer_td_eles = $footer_ele.find('td')
+ $.each(footer_td_eles,function(){
+ $footer_td_ele = $(this)
+ text = $footer_td_ele.text().trim() || ""
+ if ($footer_td_ele && $footer_td_ele[0].classList.contains('oe_number')){
+ text = instance.web.parse_value(text, { type:"float" })
+ data.push({'data': text || "", 'bold': true, 'number': true})
+ }
+ else{
+ data.push({'data': text, 'bold': true})
+ }
+ });
+ export_data.push(data)
+ });
+
+ //Export to excel
+ $.blockUI();
+ if (export_type === 'excel'){
+ view.session.get_file({
+ url: '/web/export/zb_excel_export',
+ data: {data: JSON.stringify({
+ model : view.model,
+ headers : header_name_list,
+ rows : export_data,
+ })},
+ complete: $.unblockUI
+ });
+ }
+ else{
+ console.log(view)
+ new instance.web.Model("res.users").get_func("read")(this.session.uid, ["company_id"]).then(function(res) {
+ new instance.web.Model("res.company").get_func("read")(res['company_id'][0], ["name"]).then(function(result) {
+ view.session.get_file({
+ url: '/web/export/zb_pdf_export',
+ data: {data: JSON.stringify({
+ uid: view.session.uid,
+ model : view.model,
+ headers : header_name_list,
+ rows : export_data,
+ company_name: result['name']
+ })},
+ complete: $.unblockUI
+ });
+ });
+ });
+ }
+ },
+ });
+};
diff --git a/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml b/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml
new file mode 100644
index 00000000..7af23f9e
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/static/src/xml/web_printscreen_export.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ PDF
+
+ Excel
+
+
+
diff --git a/ext/custom-addons/web_printscreen_zb/trml2pdf.py b/ext/custom-addons/web_printscreen_zb/trml2pdf.py
new file mode 100644
index 00000000..5a29c331
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/trml2pdf.py
@@ -0,0 +1,1044 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2013 ZestyBeanz Technologies Pvt. Ltd.
+# (http://wwww.zbeanztech.com)
+# contact@zbeanztech.com
+# prajul@zbeanztech.com
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+import sys
+import copy
+import reportlab
+import re
+from reportlab.pdfgen import canvas
+from reportlab import platypus
+from openerp.report.render.rml2pdf import utils
+from openerp.report.render.rml2pdf import color
+import os
+import logging
+from lxml import etree
+import base64
+from reportlab.platypus.doctemplate import ActionFlowable
+from openerp.tools.safe_eval import safe_eval as eval
+from reportlab.lib.units import inch,cm,mm
+from openerp.tools.misc import file_open
+from reportlab.pdfbase import pdfmetrics
+from reportlab.lib.pagesizes import A4, letter
+
+try:
+ from cStringIO import StringIO
+ _hush_pyflakes = [ StringIO ]
+except ImportError:
+ from StringIO import StringIO
+
+_logger = logging.getLogger(__name__)
+
+encoding = 'utf-8'
+
+def _open_image(filename, path=None):
+ """Attempt to open a binary file and return the descriptor
+ """
+ if os.path.isfile(filename):
+ return open(filename, 'rb')
+ for p in (path or []):
+ if p and os.path.isabs(p):
+ fullpath = os.path.join(p, filename)
+ if os.path.isfile(fullpath):
+ return open(fullpath, 'rb')
+ try:
+ if p:
+ fullpath = os.path.join(p, filename)
+ else:
+ fullpath = filename
+ return file_open(fullpath)
+ except IOError:
+ pass
+ raise IOError("File %s cannot be found in image path" % filename)
+
+class NumberedCanvas(canvas.Canvas):
+ def __init__(self, *args, **kwargs):
+ canvas.Canvas.__init__(self, *args, **kwargs)
+ self._codes = []
+ self._flag=False
+ self._pageCount=0
+ self._currentPage =0
+ self._pageCounter=0
+ self.pages={}
+
+ def showPage(self):
+ self._currentPage +=1
+ if not self._flag:
+ self._pageCount += 1
+ else:
+ self.pages.update({self._currentPage:self._pageCount})
+ self._codes.append({'code': self._code, 'stack': self._codeStack})
+ self._startPage()
+ self._flag=False
+
+ def pageCount(self):
+ if self.pages.get(self._pageCounter,False):
+ self._pageNumber=0
+ self._pageCounter +=1
+ key=self._pageCounter
+ if not self.pages.get(key,False):
+ while not self.pages.get(key,False):
+ key += 1
+ self.setFont("Helvetica", 8)
+ self.drawRightString((self._pagesize[0]-30), (self._pagesize[1]-40),
+ " %(this)i / %(total)i" % {
+ 'this': self._pageNumber+1,
+ 'total': self.pages.get(key,False),
+ }
+ )
+
+ def save(self):
+ """add page info to each page (page x of y)"""
+ # reset page counter
+ self._pageNumber = 0
+ for code in self._codes:
+ self._code = code['code']
+ self._codeStack = code['stack']
+ self.pageCount()
+ canvas.Canvas.showPage(self)
+# self.restoreState()
+ self._doc.SaveToFile(self._filename, self)
+
+class PageCount(platypus.Flowable):
+ def __init__(self, story_count=0):
+ platypus.Flowable.__init__(self)
+ self.story_count = story_count
+
+ def draw(self):
+ self.canv.beginForm("pageCount%d" % self.story_count)
+ self.canv.setFont("Helvetica", utils.unit_get(str(8)))
+ self.canv.drawString(0, 0, str(self.canv.getPageNumber()))
+ self.canv.endForm()
+
+class PageReset(platypus.Flowable):
+ def draw(self):
+ self.canv._doPageReset = True
+class PageReset(platypus.Flowable):
+ def draw(self):
+ self.canv._doPageReset = True
+
+class _rml_styles(object,):
+ def __init__(self, nodes, localcontext):
+ self.localcontext = localcontext
+ self.styles = {}
+ self.styles_obj = {}
+ self.names = {}
+ self.table_styles = {}
+ self.default_style = reportlab.lib.styles.getSampleStyleSheet()
+
+ for node in nodes:
+ for style in node.findall('blockTableStyle'):
+ self.table_styles[style.get('id')] = self._table_style_get(style)
+ for style in node.findall('paraStyle'):
+ sname = style.get('name')
+ self.styles[sname] = self._para_style_update(style)
+
+ self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname])
+
+ for variable in node.findall('initialize'):
+ for name in variable.findall('name'):
+ self.names[ name.get('id')] = name.get('value')
+
+ def _para_style_update(self, node):
+ data = {}
+ for attr in ['textColor', 'backColor', 'bulletColor', 'borderColor']:
+ if node.get(attr):
+ data[attr] = color.get(node.get(attr))
+ for attr in ['fontName', 'bulletFontName', 'bulletText']:
+ if node.get(attr):
+ data[attr] = node.get(attr)
+ for attr in ['fontSize', 'leftIndent', 'rightIndent', 'spaceBefore', 'spaceAfter',
+ 'firstLineIndent', 'bulletIndent', 'bulletFontSize', 'leading',
+ 'borderWidth','borderPadding','borderRadius']:
+ if node.get(attr):
+ data[attr] = utils.unit_get(node.get(attr))
+ if node.get('alignment'):
+ align = {
+ 'right':reportlab.lib.enums.TA_RIGHT,
+ 'center':reportlab.lib.enums.TA_CENTER,
+ 'justify':reportlab.lib.enums.TA_JUSTIFY
+ }
+ data['alignment'] = align.get(node.get('alignment').lower(), reportlab.lib.enums.TA_LEFT)
+ return data
+
+ def _table_style_get(self, style_node):
+ styles = []
+ for node in style_node:
+ start = utils.tuple_int_get(node, 'start', (0,0) )
+ stop = utils.tuple_int_get(node, 'stop', (-1,-1) )
+ if node.tag=='blockValign':
+ styles.append(('VALIGN', start, stop, str(node.get('value'))))
+ elif node.tag=='blockFont':
+ styles.append(('FONT', start, stop, str(node.get('name'))))
+ elif node.tag=='blockTextColor':
+ styles.append(('TEXTCOLOR', start, stop, color.get(str(node.get('colorName')))))
+ elif node.tag=='blockLeading':
+ styles.append(('LEADING', start, stop, utils.unit_get(node.get('length'))))
+ elif node.tag=='blockAlignment':
+ styles.append(('ALIGNMENT', start, stop, str(node.get('value'))))
+ elif node.tag=='blockSpan':
+ styles.append(('SPAN', start, stop))
+ elif node.tag=='blockLeftPadding':
+ styles.append(('LEFTPADDING', start, stop, utils.unit_get(node.get('length'))))
+ elif node.tag=='blockRightPadding':
+ styles.append(('RIGHTPADDING', start, stop, utils.unit_get(node.get('length'))))
+ elif node.tag=='blockTopPadding':
+ styles.append(('TOPPADDING', start, stop, utils.unit_get(node.get('length'))))
+ elif node.tag=='blockBottomPadding':
+ styles.append(('BOTTOMPADDING', start, stop, utils.unit_get(node.get('length'))))
+ elif node.tag=='blockBackground':
+ styles.append(('BACKGROUND', start, stop, color.get(node.get('colorName'))))
+ if node.get('size'):
+ styles.append(('FONTSIZE', start, stop, utils.unit_get(node.get('size'))))
+ elif node.tag=='lineStyle':
+ kind = node.get('kind')
+ kind_list = [ 'GRID', 'BOX', 'OUTLINE', 'INNERGRID', 'LINEBELOW', 'LINEABOVE','LINEBEFORE', 'LINEAFTER' ]
+ assert kind in kind_list
+ thick = 1
+ if node.get('thickness'):
+ thick = float(node.get('thickness'))
+ styles.append((kind, start, stop, thick, color.get(node.get('colorName'))))
+ return platypus.tables.TableStyle(styles)
+
+ def para_style_get(self, node):
+ style = False
+ sname = node.get('style')
+ if sname:
+ if sname in self.styles_obj:
+ style = self.styles_obj[sname]
+ else:
+ _logger.warning('Warning: style not found, %s - setting default!\n' % (node.get('style'),) )
+ if not style:
+ style = self.default_style['Normal']
+ para_update = self._para_style_update(node)
+ if para_update:
+ # update style only is necessary
+ style = copy.deepcopy(style)
+ style.__dict__.update(para_update)
+ return style
+
+class _rml_doc(object):
+ def __init__(self, node, localcontext=None, images=None, path='.', title=None):
+ if images is None:
+ images = {}
+ if localcontext is None:
+ localcontext = {}
+ self.localcontext = localcontext
+ self.etree = node
+ self.filename = self.etree.get('filename')
+ self.images = images
+ self.path = path
+ self.title = title
+
+ def docinit(self, els):
+ from reportlab.lib.fonts import addMapping
+ from reportlab.pdfbase import pdfmetrics
+ from reportlab.pdfbase.ttfonts import TTFont
+
+ for node in els:
+ for font in node.findall('registerFont'):
+ name = font.get('fontName').encode('ascii')
+ fname = font.get('fontFile').encode('ascii')
+ if name not in pdfmetrics._fonts:
+ pdfmetrics.registerFont(TTFont(name, fname))
+ addMapping(name, 0, 0, name) #normal
+ addMapping(name, 0, 1, name) #italic
+ addMapping(name, 1, 0, name) #bold
+ addMapping(name, 1, 1, name) #italic and bold
+
+ def setTTFontMapping(self,face, fontname, filename, mode='all'):
+ from reportlab.lib.fonts import addMapping
+ from reportlab.pdfbase import pdfmetrics
+ from reportlab.pdfbase.ttfonts import TTFont
+
+ if fontname not in pdfmetrics._fonts:
+ pdfmetrics.registerFont(TTFont(fontname, filename))
+ if mode == 'all':
+ addMapping(face, 0, 0, fontname) #normal
+ addMapping(face, 0, 1, fontname) #italic
+ addMapping(face, 1, 0, fontname) #bold
+ addMapping(face, 1, 1, fontname) #italic and bold
+ elif (mode== 'normal') or (mode == 'regular'):
+ addMapping(face, 0, 0, fontname) #normal
+ elif mode == 'italic':
+ addMapping(face, 0, 1, fontname) #italic
+ elif mode == 'bold':
+ addMapping(face, 1, 0, fontname) #bold
+ elif mode == 'bolditalic':
+ addMapping(face, 1, 1, fontname) #italic and bold
+
+ def _textual_image(self, node):
+ rc = ''
+ for n in node:
+ rc +=( etree.tostring(n) or '') + n.tail
+ return base64.decodestring(node.tostring())
+
+ def _images(self, el):
+ result = {}
+ for node in el.findall('.//image'):
+ rc =( node.text or '')
+ result[node.get('name')] = base64.decodestring(rc)
+ return result
+
+ def render(self, out):
+ 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('.//images')
+ if el:
+ self.images.update( self._images(el[0]) )
+
+ el = self.etree.findall('.//template')
+ if len(el):
+ pt_obj = _rml_template(self.localcontext, out, el[0], self, images=self.images, path=self.path, title=self.title)
+ el = utils._child_get(self.etree, self, 'story')
+ pt_obj.render(el)
+ else:
+ self.canvas = canvas.Canvas(out)
+ pd = self.etree.find('pageDrawing')[0]
+ pd_obj = _rml_canvas(self.canvas, self.localcontext, None, self, self.images, path=self.path, title=self.title)
+ pd_obj.render(pd)
+
+ self.canvas.showPage()
+ self.canvas.save()
+
+class _rml_canvas(object):
+ def __init__(self, canvas, localcontext, doc_tmpl=None, doc=None, images=None, path='.', title=None):
+ if images is None:
+ images = {}
+ self.localcontext = localcontext
+ self.canvas = canvas
+ self.styles = doc.styles
+ self.doc_tmpl = doc_tmpl
+ self.doc = doc
+ self.images = images
+ self.path = path
+ self.title = title
+ if self.title:
+ self.canvas.setTitle(self.title)
+
+ def _textual(self, node, x=0, y=0):
+ text = node.text and node.text.encode('utf-8') or ''
+ rc = utils._process_text(self, text)
+ for n in node:
+ if n.tag == 'seq':
+ from reportlab.lib.sequencer import getSequencer
+ seq = getSequencer()
+ rc += str(seq.next(n.get('id')))
+ if n.tag == 'pageCount':
+ if x or y:
+ self.canvas.translate(x,y)
+ self.canvas.doForm('pageCount%s' % (self.canvas._storyCount,))
+ if x or y:
+ self.canvas.translate(-x,-y)
+ if n.tag == 'pageNumber':
+ rc += str(self.canvas.getPageNumber())
+ rc += utils._process_text(self, n.tail)
+ return rc.replace('\n','')
+
+ def _drawString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ text=self._textual(node, **v)
+ text = utils.xml2str(text)
+ self.canvas.drawString(text=text, **v)
+
+ def _drawCenteredString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ text=self._textual(node, **v)
+ text = utils.xml2str(text)
+ self.canvas.drawCentredString(text=text, **v)
+
+ def _drawRightString(self, node):
+ v = utils.attr_get(node, ['x','y'])
+ text=self._textual(node, **v)
+ text = utils.xml2str(text)
+ self.canvas.drawRightString(text=text, **v)
+
+ def _rect(self, node):
+ if node.get('round'):
+ self.canvas.roundRect(radius=utils.unit_get(node.get('round')), **utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
+ else:
+ self.canvas.rect(**utils.attr_get(node, ['x','y','width','height'], {'fill':'bool','stroke':'bool'}))
+
+ def _ellipse(self, node):
+ x1 = utils.unit_get(node.get('x'))
+ x2 = utils.unit_get(node.get('width'))
+ y1 = utils.unit_get(node.get('y'))
+ y2 = utils.unit_get(node.get('height'))
+
+ self.canvas.ellipse(x1,y1,x2,y2, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+
+ def _curves(self, node):
+ line_str = node.text.split()
+ lines = []
+ while len(line_str)>7:
+ self.canvas.bezier(*[utils.unit_get(l) for l in line_str[0:8]])
+ line_str = line_str[8:]
+
+ def _lines(self, node):
+ line_str = node.text.split()
+ lines = []
+ while len(line_str)>3:
+ lines.append([utils.unit_get(l) for l in line_str[0:4]])
+ line_str = line_str[4:]
+ self.canvas.lines(lines)
+
+ def _grid(self, node):
+ xlist = [utils.unit_get(s) for s in node.get('xs').split(',')]
+ ylist = [utils.unit_get(s) for s in node.get('ys').split(',')]
+
+ self.canvas.grid(xlist, ylist)
+
+ def _translate(self, node):
+ dx = utils.unit_get(node.get('dx')) or 0
+ dy = utils.unit_get(node.get('dy')) or 0
+ self.canvas.translate(dx,dy)
+
+ def _circle(self, node):
+ self.canvas.circle(x_cen=utils.unit_get(node.get('x')), y_cen=utils.unit_get(node.get('y')), r=utils.unit_get(node.get('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+
+ def _place(self, node):
+ flows = _rml_flowable(self.doc, self.localcontext, images=self.images, path=self.path, title=self.title).render(node)
+ infos = utils.attr_get(node, ['x','y','width','height'])
+
+ infos['y']+=infos['height']
+ for flow in flows:
+ w,h = flow.wrap(infos['width'], infos['height'])
+ if w<=infos['width'] and h<=infos['height']:
+ infos['y']-=h
+ flow.drawOn(self.canvas,infos['x'],infos['y'])
+ infos['height']-=h
+ else:
+ raise ValueError("Not enough space")
+
+ def _line_mode(self, node):
+ ljoin = {'round':1, 'mitered':0, 'bevelled':2}
+ lcap = {'default':0, 'round':1, 'square':2}
+
+ if node.get('width'):
+ self.canvas.setLineWidth(utils.unit_get(node.get('width')))
+ if node.get('join'):
+ self.canvas.setLineJoin(ljoin[node.get('join')])
+ if node.get('cap'):
+ self.canvas.setLineCap(lcap[node.get('cap')])
+ if node.get('miterLimit'):
+ self.canvas.setDash(utils.unit_get(node.get('miterLimit')))
+ if node.get('dash'):
+ dashes = node.get('dash').split(',')
+ for x in range(len(dashes)):
+ dashes[x]=utils.unit_get(dashes[x])
+ self.canvas.setDash(node.get('dash').split(','))
+
+ def _image(self, node):
+ import urllib
+ import urlparse
+ from reportlab.lib.utils import ImageReader
+ nfile = node.get('file')
+ if not nfile:
+ if node.get('name'):
+ image_data = self.images[node.get('name')]
+ _logger.debug("Image %s used", node.get('name'))
+ s = StringIO(image_data)
+ else:
+ newtext = node.text
+ if self.localcontext:
+ res = utils._regex.findall(newtext)
+ for key in res:
+ newtext = eval(key, {}, self.localcontext) or ''
+ image_data = None
+ if newtext:
+ image_data = base64.decodestring(newtext)
+ if image_data:
+ s = StringIO(image_data)
+ else:
+ _logger.debug("No image data!")
+ return False
+ else:
+ if nfile in self.images:
+ s = StringIO(self.images[nfile])
+ else:
+ try:
+ up = urlparse.urlparse(str(nfile))
+ except ValueError:
+ up = False
+ if up and up.scheme:
+ # RFC: do we really want to open external URLs?
+ # Are we safe from cross-site scripting or attacks?
+ _logger.debug("Retrieve image from %s", nfile)
+ u = urllib.urlopen(str(nfile))
+ s = StringIO(u.read())
+ else:
+ _logger.debug("Open image file %s ", nfile)
+ s = _open_image(nfile, path=self.path)
+ try:
+ img = ImageReader(s)
+ (sx,sy) = img.getSize()
+ _logger.debug("Image is %dx%d", sx, sy)
+ args = { 'x': 0.0, 'y': 0.0, 'mask': 'auto'}
+ for tag in ('width','height','x','y'):
+ if node.get(tag):
+ args[tag] = utils.unit_get(node.get(tag))
+ if ('width' in args) and (not 'height' in args):
+ args['height'] = sy * args['width'] / sx
+ elif ('height' in args) and (not 'width' in args):
+ args['width'] = sx * args['height'] / sy
+ elif ('width' in args) and ('height' in args):
+ if (float(args['width'])/args['height'])>(float(sx)>sy):
+ args['width'] = sx * args['height'] / sy
+ else:
+ args['height'] = sy * args['width'] / sx
+ self.canvas.drawImage(img, **args)
+ finally:
+ s.close()
+# self.canvas._doc.SaveToFile(self.canvas._filename, self.canvas)
+
+ def _path(self, node):
+ self.path = self.canvas.beginPath()
+ self.path.moveTo(**utils.attr_get(node, ['x','y']))
+ for n in utils._child_get(node, self):
+ if not n.text :
+ if n.tag=='moveto':
+ vals = utils.text_get(n).split()
+ self.path.moveTo(utils.unit_get(vals[0]), utils.unit_get(vals[1]))
+ elif n.tag=='curvesto':
+ vals = utils.text_get(n).split()
+ while len(vals)>5:
+ pos=[]
+ while len(pos)<6:
+ pos.append(utils.unit_get(vals.pop(0)))
+ self.path.curveTo(*pos)
+ elif n.text:
+ data = n.text.split() # Not sure if I must merge all TEXT_NODE ?
+ while len(data)>1:
+ x = utils.unit_get(data.pop(0))
+ y = utils.unit_get(data.pop(0))
+ self.path.lineTo(x,y)
+ if (not node.get('close')) or utils.bool_get(node.get('close')):
+ self.path.close()
+ self.canvas.drawPath(self.path, **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'}))
+
+ def setFont(self, node):
+ fontname = node.get('name')
+ if fontname not in pdfmetrics.getRegisteredFontNames()\
+ or fontname not in pdfmetrics.standardFonts:
+ # let reportlab attempt to find it
+ try:
+ pdfmetrics.getFont(fontname)
+ except Exception:
+ _logger.debug('Could not locate font %s, substituting default: %s',
+ fontname,
+ self.canvas._fontname)
+ fontname = self.canvas._fontname
+ return self.canvas.setFont(fontname, utils.unit_get(node.get('size')))
+
+ def render(self, node):
+ tags = {
+ 'drawCentredString': self._drawCenteredString,
+ 'drawRightString': self._drawRightString,
+ 'drawString': self._drawString,
+ 'rect': self._rect,
+ 'ellipse': self._ellipse,
+ 'lines': self._lines,
+ 'grid': self._grid,
+ 'curves': self._curves,
+ 'fill': lambda node: self.canvas.setFillColor(color.get(node.get('color'))),
+ 'stroke': lambda node: self.canvas.setStrokeColor(color.get(node.get('color'))),
+ 'setFont': self.setFont ,
+ 'place': self._place,
+ 'circle': self._circle,
+ 'lineMode': self._line_mode,
+ 'path': self._path,
+ 'rotate': lambda node: self.canvas.rotate(float(node.get('degrees'))),
+ 'translate': self._translate,
+ 'image': self._image
+ }
+ for n in utils._child_get(node, self):
+ if n.tag in tags:
+ tags[n.tag](n)
+
+class _rml_draw(object):
+ def __init__(self, localcontext, node, styles, images=None, path='.', title=None):
+ if images is None:
+ images = {}
+ self.localcontext = localcontext
+ self.node = node
+ self.styles = styles
+ self.canvas = None
+ self.images = images
+ self.path = path
+ self.canvas_title = title
+
+ def render(self, canvas, doc):
+ canvas.saveState()
+ cnv = _rml_canvas(canvas, self.localcontext, doc, self.styles, images=self.images, path=self.path, title=self.canvas_title)
+ cnv.render(self.node)
+ canvas.restoreState()
+
+class _rml_Illustration(platypus.flowables.Flowable):
+ def __init__(self, node, localcontext, styles, self2):
+ self.localcontext = (localcontext or {}).copy()
+ self.node = node
+ self.styles = styles
+ self.width = utils.unit_get(node.get('width'))
+ self.height = utils.unit_get(node.get('height'))
+ self.self2 = self2
+ def wrap(self, *args):
+ return self.width, self.height
+ def draw(self):
+ drw = _rml_draw(self.localcontext ,self.node,self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title)
+ drw.render(self.canv, None)
+
+class _rml_flowable(object):
+ def __init__(self, doc, localcontext, images=None, path='.', title=None):
+ if images is None:
+ images = {}
+ self.localcontext = localcontext
+ self.doc = doc
+ self.styles = doc.styles
+ self.images = images
+ self.path = path
+ self.title = title
+
+ def _textual(self, node):
+ rc1 = utils._process_text(self, node.text or '')
+ for n in utils._child_get(node,self):
+ txt_n = copy.deepcopy(n)
+ for key in txt_n.attrib.keys():
+ if key in ('rml_except', 'rml_loop', 'rml_tag'):
+ del txt_n.attrib[key]
+ if not n.tag == 'bullet':
+ txt_n.text = utils.xml2str(self._textual(n))
+ txt_n.tail = n.tail and utils.xml2str(utils._process_text(self, n.tail.replace('\n',''))) or ''
+ rc1 += etree.tostring(txt_n)
+ return rc1
+
+ def _table(self, node):
+ children = utils._child_get(node,self,'tr')
+ if not children:
+ return None
+ length = 0
+ colwidths = None
+ rowheights = None
+ data = []
+ styles = []
+ posy = 0
+ for tr in children:
+ paraStyle = None
+ if tr.get('style'):
+ st = copy.deepcopy(self.styles.table_styles[tr.get('style')])
+ for si in range(len(st._cmds)):
+ s = list(st._cmds[si])
+ s[1] = (s[1][0],posy)
+ s[2] = (s[2][0],posy)
+ st._cmds[si] = tuple(s)
+ styles.append(st)
+ if tr.get('paraStyle'):
+ paraStyle = self.styles.styles[tr.get('paraStyle')]
+ data2 = []
+ posx = 0
+ for td in utils._child_get(tr, self,'td'):
+ if td.get('style'):
+ st = copy.deepcopy(self.styles.table_styles[td.get('style')])
+ for s in st._cmds:
+ s[1][1] = posy
+ s[2][1] = posy
+ s[1][0] = posx
+ s[2][0] = posx
+ styles.append(st)
+ if td.get('paraStyle'):
+ # TODO: merge styles
+ paraStyle = self.styles.styles[td.get('paraStyle')]
+ posx += 1
+
+ flow = []
+ for n in utils._child_get(td, self):
+ if n.tag == etree.Comment:
+ n.text = ''
+ continue
+ fl = self._flowable(n, extra_style=paraStyle)
+ if isinstance(fl,list):
+ flow += fl
+ else:
+ flow.append( fl )
+
+ if not len(flow):
+ flow = self._textual(td)
+ data2.append( flow )
+ if len(data2)>length:
+ length=len(data2)
+ for ab in data:
+ while len(ab) tag:
+ # - we reset page number to 0
+ # - we add an new PageCount flowable (relative to the current
+ # story number), but not for NumeredCanvas at is handle page
+ # count itself)
+ # NOTE: _rml_template render() method add a PageReset flowable at end
+ # of each story, so we're sure to pass here at least once per story.
+ if not isinstance(self.canv, NumberedCanvas):
+ self.handle_flowable([ PageCount(story_count=self.canv._storyCount) ])
+ self.canv._pageCount = self.page
+ self.page = 0
+ self.canv._flag = True
+ self.canv._pageNumber = 0
+ self.canv._doPageReset = False
+ self.canv._storyCount += 1
+
+class _rml_template(object):
+ def __init__(self, localcontext, out, node, doc, images=None, path='.', title=None):
+ if images is None:
+ images = {}
+ if not localcontext:
+ localcontext={'internal_header':True}
+ self.localcontext = localcontext
+ self.images= images
+ self.path = path
+ self.title = title
+
+ pagesize_map = {'a4': A4,
+ 'us_letter': letter
+ }
+ pageSize = (841.8897637795275, 595.275590551181)
+ self.doc_tmpl = TinyDocTemplate(out, pagesize=pageSize, **utils.attr_get(node, ['leftMargin','rightMargin','topMargin','bottomMargin'], {'allowSplitting':'int','showBoundary':'bool','rotation':'int','title':'str','author':'str'}))
+ self.page_templates = []
+ self.styles = doc.styles
+ self.doc = doc
+ self.image=[]
+ pts = node.findall('pageTemplate')
+ for pt in pts:
+ frames = []
+ for frame_el in pt.findall('frame'):
+ frame = platypus.Frame( **(utils.attr_get(frame_el, ['x1','y1', 'width','height', 'leftPadding', 'rightPadding', 'bottomPadding', 'topPadding'], {'id':'str', 'showBoundary':'bool'})) )
+ if utils.attr_get(frame_el, ['last']):
+ frame.lastFrame = True
+ frames.append( frame )
+ try :
+ gr = pt.findall('pageGraphics')\
+ or pt[1].findall('pageGraphics')
+ except Exception: # FIXME: be even more specific, perhaps?
+ gr=''
+ if len(gr):
+# self.image=[ n for n in utils._child_get(gr[0], self) if n.tag=='image' or not self.localcontext]
+ drw = _rml_draw(self.localcontext,gr[0], self.doc, images=images, path=self.path, title=self.title)
+ self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) ))
+ else:
+ drw = _rml_draw(self.localcontext,node,self.doc,title=self.title)
+ self.page_templates.append( platypus.PageTemplate(frames=frames,onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) ))
+ self.doc_tmpl.addPageTemplates(self.page_templates)
+
+ def render(self, node_stories):
+ if self.localcontext and not self.localcontext.get('internal_header',False):
+ del self.localcontext['internal_header']
+ fis = []
+ r = _rml_flowable(self.doc,self.localcontext, images=self.images, path=self.path, title=self.title)
+ story_cnt = 0
+ for node_story in node_stories:
+ if story_cnt > 0:
+ fis.append(platypus.PageBreak())
+ fis += r.render(node_story)
+ # Reset Page Number with new story tag
+ fis.append(PageReset())
+ story_cnt += 1
+ if self.localcontext and self.localcontext.get('internal_header',False):
+ self.doc_tmpl.afterFlowable(fis)
+ self.doc_tmpl.build(fis,canvasmaker=NumberedCanvas)
+ else:
+ self.doc_tmpl.build(fis)
+
+def parseNode(rml, localcontext=None, fout=None, images=None, path='.', title=None):
+ node = etree.XML(rml)
+ r = _rml_doc(node, localcontext, images, path, title=title)
+ #try to override some font mappings
+ try:
+ from customfonts import SetCustomFonts
+ SetCustomFonts(r)
+ except ImportError:
+ # means there is no custom fonts mapping in this system.
+ pass
+ except Exception:
+ _logger.warning('Cannot set font mapping', exc_info=True)
+ pass
+ fp = StringIO()
+ r.render(fp)
+ return fp.getvalue()
+
+def parseString(rml, localcontext=None, fout=None, images=None, path='.', title=None):
+ node = etree.XML(rml)
+ r = _rml_doc(node, localcontext, images, path, title=title)
+
+ #try to override some font mappings
+ try:
+ from customfonts import SetCustomFonts
+ SetCustomFonts(r)
+ except Exception:
+ pass
+
+ if fout:
+ fp = file(fout,'wb')
+ r.render(fp)
+ fp.close()
+ return fout
+ else:
+ fp = StringIO()
+ r.render(fp)
+ return fp.getvalue()
+
+def trml2pdf_help():
+ print 'Usage: trml2pdf input.rml >output.pdf'
+ print 'Render the standard input (RML) and output a PDF file'
+ sys.exit(0)
+
+if __name__=="__main__":
+ if len(sys.argv)>1:
+ if sys.argv[1]=='--help':
+ trml2pdf_help()
+ print parseString(file(sys.argv[1], 'r').read()),
+ else:
+ print 'Usage: trml2pdf input.rml >output.pdf'
+ print 'Try \'trml2pdf --help\' for more information.'
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml b/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml
new file mode 100644
index 00000000..0386b7d2
--- /dev/null
+++ b/ext/custom-addons/web_printscreen_zb/views/web_printscreen_zb.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/setup/lib/config_at.py b/setup/lib/config_at.py
index e46f6261..64e727b3 100644
--- a/setup/lib/config_at.py
+++ b/setup/lib/config_at.py
@@ -117,7 +117,8 @@ class Config():
'cam_custom',
'cam_reports',
'account_cancel',
- 'cam_invoice_skonto',
+ 'cam_invoice_skonto',
+ #'web_printscreen_zb',
#'crm',
#'sale',
#'cam_hr_overtime',