Developments for report designer
base_report_designer module allows you to create your own reports reports and images are stored in the database custom report may override base reports RML modification You can now select to put the image in the RML instead than in a separate file bzr revid: fp@tinyerp.com-d15a6508d4dc07abfa294fc980649935816cd60f
This commit is contained in:
parent
19aa5fdc18
commit
ac95d32a22
|
@ -59,12 +59,14 @@
|
|||
model="res.partner"
|
||||
name="account.rappel"
|
||||
rml="account/report/rappel.rml"
|
||||
sxw="account/report/rappel.sxw"
|
||||
auto="False" />
|
||||
<report id="account_invoices"
|
||||
string="Invoices"
|
||||
model="account.invoice"
|
||||
name="account.invoice"
|
||||
rml="account/report/invoice.rml"
|
||||
sxw="account/report/invoice.sxw"
|
||||
auto="False"/>
|
||||
<report id="account_transfers"
|
||||
string="Transfers"
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import account_simulation
|
||||
import wizard
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name" : "Report designer interface module",
|
||||
"description" : """
|
||||
This module adds wizards to import/export documents to be edited in
|
||||
OpenOffice.
|
||||
""",
|
||||
"version" : "1.0",
|
||||
"depends" : ["account"],
|
||||
"author" : "Tiny",
|
||||
"website" : "http://tinyerp.com",
|
||||
"category" : "Generic Modules/Base",
|
||||
"init_xml" : [ ],
|
||||
"demo_xml" : [ ],
|
||||
"update_xml" : [ "base_report_designer_wizard.xml" ],
|
||||
# "translations" : {
|
||||
# "fr": "i18n/french_fr.csv"
|
||||
# },
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<terp>
|
||||
<data>
|
||||
|
||||
<wizard
|
||||
string="Modify an existing report"
|
||||
model="ir.actions.report.xml"
|
||||
name="base_report_designer.modify"
|
||||
id="wizard_report_designer_modify"/>
|
||||
|
||||
<menuitem
|
||||
name="Administration/Custom/Report designer"
|
||||
action="wizard_report_designer_modify"
|
||||
type="wizard"
|
||||
id="menu_wizard_report_designer_modify"/>
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
</terp>
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import base_report_designer_modify
|
|
@ -0,0 +1,221 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import wizard
|
||||
import osv
|
||||
import pooler
|
||||
import urllib
|
||||
import base64
|
||||
import tools
|
||||
|
||||
intro_form = '''<?xml version="1.0"?>
|
||||
<form string="Report designer">
|
||||
<separator string="Report designer introduction" colspan="4"/>
|
||||
<field name="text" colspan="4" nolabel="1"/>
|
||||
</form>'''
|
||||
|
||||
intro_fields = {
|
||||
'text': {
|
||||
'string':'Introduction',
|
||||
'type':'text',
|
||||
'readonly':True,
|
||||
'default': lambda *args: """
|
||||
This system must be used with the Tiny OpenOffice plugin. If you
|
||||
did not installed yet, you can find this package on:
|
||||
http://tinyerp.com
|
||||
|
||||
This wizard will provide you the .SXW report that you can modify
|
||||
in OpenOffice. After having modified it, you will be able to reupload
|
||||
it to the Tiny ERP server.
|
||||
"""},
|
||||
'operation': {
|
||||
'string':'Operation',
|
||||
'type':'selection',
|
||||
'selection':[('create','Create a new report'),('modify','Modify an existing report')],
|
||||
'size':32,
|
||||
'required':True,
|
||||
'default':lambda *args: 'create'
|
||||
},
|
||||
}
|
||||
|
||||
get_form = '''<?xml version="1.0"?>
|
||||
<form string="Get a report">
|
||||
<separator string="Select your report" colspan="4"/>
|
||||
<field name="report_id"/>
|
||||
</form>'''
|
||||
|
||||
get_fields = {
|
||||
'report_id': {
|
||||
'string':'Report',
|
||||
'type':'many2one',
|
||||
'relation':'ir.actions.report.xml',
|
||||
'required':True,
|
||||
'domain': [('report_sxw_content','<>',False)]
|
||||
},
|
||||
}
|
||||
|
||||
get_form_result = '''<?xml version="1.0"?>
|
||||
<form string="Get a report">
|
||||
<separator string="The .SXW report" colspan="4"/>
|
||||
<field name="report_id"/>
|
||||
<newline/>
|
||||
<field name="file_sxw"/>
|
||||
<newline/>
|
||||
<label colspan="4" string="This is the template of your requested report.\nSave it as a .SXW file and open it with OpenOffice.\nDon't forget to install the Tiny OpenOffice package to modify it.\nOnce it is modified, re-upload it in Tiny ERP using this wizard." align="0.0"/>
|
||||
</form>'''
|
||||
|
||||
get_form_fields = {
|
||||
'report_id': {
|
||||
'string':'Report',
|
||||
'type':'many2one',
|
||||
'relation':'ir.actions.report.xml',
|
||||
'readonly':True,
|
||||
},
|
||||
'file_sxw': {
|
||||
'string':'Your .SXW file',
|
||||
'type':'binary',
|
||||
'readonly':True
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
send_form_result_arch = '''<?xml version="1.0"?>
|
||||
<form string="Report modified">
|
||||
<separator string="Report modified" colspan="4"/>
|
||||
<label string="Your report has been modified."/>
|
||||
</form>'''
|
||||
|
||||
send_form_result_fields = {
|
||||
}
|
||||
|
||||
|
||||
send_form_arch = '''<?xml version="1.0"?>
|
||||
<form string="Get a report">
|
||||
<separator string="Upload your modified report" colspan="4"/>
|
||||
<field name="report_id"/>
|
||||
<newline/>
|
||||
<field name="file_sxw"/>
|
||||
</form>'''
|
||||
|
||||
send_form_fields = {
|
||||
'report_id': {
|
||||
'string':'Report',
|
||||
'type':'many2one',
|
||||
'relation':'ir.actions.report.xml',
|
||||
'required':True,
|
||||
'domain': [('report_sxw_content','<>',False)]
|
||||
},
|
||||
'file_sxw': {
|
||||
'string':'Your .SXW file',
|
||||
'type':'binary',
|
||||
'required':True
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class base_report_designer_modify(wizard.interface):
|
||||
def _upload_report_clear(self, cr, uid, data, context):
|
||||
return {'file_sxw': False}
|
||||
def _upload_report(self, cr, uid, data, context):
|
||||
import tiny_sxw2rml
|
||||
import StringIO
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
sxwval = StringIO.StringIO(base64.decodestring(data['form']['file_sxw']))
|
||||
fp = tools.file_open('normalized_oo2rml.xsl',subdir='addons/base_report_designer/wizard/tiny_sxw2rml')
|
||||
report = pool.get('ir.actions.report.xml').write(cr, uid, [data['form']['report_id']], {
|
||||
'report_sxw_content': base64.decodestring(data['form']['file_sxw']),
|
||||
'report_rml_content': str(tiny_sxw2rml.sxw2rml(sxwval, xsl=fp.read()))
|
||||
})
|
||||
return {}
|
||||
def _get_report(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
report = pool.get('ir.actions.report.xml').browse(cr, uid, data['form']['report_id'], context)
|
||||
return {'file_sxw': base64.encodestring(report.report_sxw_content)}
|
||||
states = {
|
||||
'init': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':intro_form,
|
||||
'fields':intro_fields,
|
||||
'state':[
|
||||
('end','Cancel'),
|
||||
('get_form','Get a .SXW')
|
||||
]
|
||||
}
|
||||
},
|
||||
'get_form': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':get_form,
|
||||
'fields':get_fields,
|
||||
'state':[
|
||||
('end','Cancel'),
|
||||
('get_form_result', 'Continue'),
|
||||
]
|
||||
}
|
||||
},
|
||||
'get_form_result': {
|
||||
'actions': [_get_report],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':get_form_result,
|
||||
'fields':get_form_fields,
|
||||
'state':[
|
||||
('end','Close'),
|
||||
('send_form', 'Upload the modified report'),
|
||||
]
|
||||
}
|
||||
},
|
||||
'send_form': {
|
||||
'actions': [_upload_report_clear],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':send_form_arch,
|
||||
'fields':send_form_fields,
|
||||
'state':[
|
||||
('end','Close'),
|
||||
('send_form_result', 'Update the report'),
|
||||
]
|
||||
}
|
||||
},
|
||||
'send_form_result': {
|
||||
'actions': [_upload_report],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':send_form_result_arch,
|
||||
'fields':send_form_result_fields,
|
||||
'state':[
|
||||
('end','Close'),
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
base_report_designer_modify('base_report_designer.modify')
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
|
||||
# Fabien Pinckaers <fp@tiny.Be>
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from tiny_sxw2rml import sxw2rml
|
|
@ -0,0 +1,644 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet
|
||||
version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xmlns:office="http://openoffice.org/2000/office"
|
||||
xmlns:style="http://openoffice.org/2000/style"
|
||||
xmlns:text="http://openoffice.org/2000/text"
|
||||
xmlns:table="http://openoffice.org/2000/table"
|
||||
xmlns:draw="http://openoffice.org/2000/drawing"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:number="http://openoffice.org/2000/datastyle"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:chart="http://openoffice.org/2000/chart"
|
||||
xmlns:dr3d="http://openoffice.org/2000/dr3d"
|
||||
xmlns:math="http://www.w3.org/1998/Math/MathML"
|
||||
xmlns:form="http://openoffice.org/2000/form"
|
||||
xmlns:script="http://openoffice.org/2000/script"
|
||||
office:class="text" office:version="1.0"
|
||||
exclude-result-prefixes = "xsl fo office style text table draw xlink number svg chart dr3d math form script">
|
||||
|
||||
<!--TODO's: indent, picture cache (trml2pdf) -->
|
||||
|
||||
<xsl:output method="xml" indent="yes" />
|
||||
<xsl:strip-space elements="*"/>
|
||||
|
||||
<xsl:key name="text_style" match="style:style[@style:family='text']" use="@style:name" />
|
||||
<xsl:key name="page_break_before" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-before='page']" use="@style:name" />
|
||||
<xsl:key name="page_break_after" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-after='page']" use="@style:name" />
|
||||
<xsl:key name="table_column_style" match="style:style[@style:family='table-column']" use="@style:name" />
|
||||
<xsl:key name="table_cell_style" match="style:style[@style:family='table-cell']" use="@style:name" />
|
||||
<xsl:key name="paragraph_style" match="style:style[@style:family='paragraph']" use="@style:name" />
|
||||
|
||||
<xsl:template match="office:document-content">
|
||||
<document filename="test.pdf">
|
||||
<xsl:apply-templates select="office:automatic-styles" />
|
||||
<xsl:apply-templates select="office:body" />
|
||||
</document>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="page_size">
|
||||
<xsl:attribute name="pageSize">
|
||||
<xsl:text>(</xsl:text>
|
||||
<xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
|
||||
<xsl:text>,</xsl:text>
|
||||
<xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" />
|
||||
<xsl:text>)</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="fixed_frame">
|
||||
<xsl:for-each select="//draw:text-box">
|
||||
<frame>
|
||||
<xsl:attribute name="id"><xsl:value-of select="./@draw:name" /></xsl:attribute>
|
||||
<xsl:attribute name="x1"><xsl:value-of select="./@svg:x" /></xsl:attribute>
|
||||
<xsl:attribute name="y1">
|
||||
<xsl:value-of
|
||||
select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height - ./@svg:y - ./@fo:min-height" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="width">
|
||||
<xsl:value-of select="./@svg:width" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="height">
|
||||
<xsl:value-of select="./@fo:min-height" />
|
||||
</xsl:attribute>
|
||||
</frame>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="margin_sizes">
|
||||
<xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" />
|
||||
<xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" />
|
||||
<xsl:variable name="margin_top" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-top" />
|
||||
<xsl:variable name="margin_bottom" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-bottom" />
|
||||
<xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
|
||||
<xsl:variable name="page_height" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" />
|
||||
<xsl:attribute name="x1"><xsl:value-of select="$margin_left" /></xsl:attribute>
|
||||
<xsl:attribute name="y1"><xsl:value-of select="$margin_bottom" /></xsl:attribute>
|
||||
<xsl:attribute name="width"><xsl:value-of select="$page_width - $margin_left - $margin_right"/></xsl:attribute>
|
||||
<xsl:attribute name="height"><xsl:value-of select="$page_height - $margin_bottom - $margin_top"/></xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="text_width">
|
||||
<!-- You need this for the workaround to make primitive outlines-->
|
||||
<xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" />
|
||||
<xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" />
|
||||
<xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
|
||||
<xsl:value-of select="$page_width - $margin_left - $margin_right - 18"/>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template match="office:automatic-styles">
|
||||
<!--<template pageSize="(21cm, 29.7cm)" leftMargin="1.0cm" rightMargin="2.0cm" topMargin="1.0cm" bottomMargin="1.0cm" title="Test" author="Martin Simon" allowSplitting="20">-->
|
||||
<template pageSize="(21cm, 29.7cm)" title="Test" author="Martin Simon" allowSplitting="20">
|
||||
<xsl:call-template name="page_size" />
|
||||
<pageTemplate id="first">
|
||||
<xsl:call-template name="fixed_frame" />
|
||||
<frame id="first" x1="2cm" y1="2cm" width="17cm" height="26cm">
|
||||
<xsl:call-template name="margin_sizes" />
|
||||
</frame>
|
||||
</pageTemplate>
|
||||
</template>
|
||||
<stylesheet>
|
||||
<!--A table style to simulate primitive outlines -till the <addOutline> tag is implemented in trml2pdf -->
|
||||
<blockTableStyle id="Standard_Outline">
|
||||
<blockAlignment value="LEFT"/>
|
||||
<blockValign value="TOP"/>
|
||||
</blockTableStyle>
|
||||
<!--use two standard table grid styles like PyOpenOffice "Old Way": with and without a grid-->
|
||||
<!--TODO insert table cell colors here, not within the <td> tag - otherwise
|
||||
it will not work with flowables as cell content-->
|
||||
<xsl:call-template name="make_blocktablestyle" />
|
||||
<initialize>
|
||||
<paraStyle name="all" alignment="justify" />
|
||||
</initialize>
|
||||
<xsl:apply-templates select="style:style" />
|
||||
</stylesheet>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_blocktablestyle">
|
||||
<xsl:for-each select="//table:table">
|
||||
<xsl:variable name="test">
|
||||
<xsl:value-of select="./@table:name" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not(boolean(count(preceding-sibling::table:table[@table:name=$test])))">
|
||||
<!--Test if this is the first table with this style, nested tables not counted-->
|
||||
<blockTableStyle id="{@table:name}">
|
||||
<xsl:if test=".//draw:image">
|
||||
<blockTopPadding value="0"/>
|
||||
<blockBottomPadding value="0"/>
|
||||
</xsl:if>
|
||||
<blockAlignment value="LEFT" />
|
||||
<blockValign value="TOP" />
|
||||
<xsl:call-template name="make_tablegrid" />
|
||||
<xsl:call-template name="make_tablebackground" />
|
||||
</blockTableStyle>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_tablegrid">
|
||||
<xsl:variable name="test_grid">
|
||||
<xsl:call-template name="test_grid" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="contains($test_grid,'has_grid')">
|
||||
<lineStyle kind="GRID" colorName="black" />
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<!-- Was needed to simulate bulleted lists:
|
||||
<xsl:template match="text:ordered-list|text:unordered-list">
|
||||
<xsl:variable name = "text_width">
|
||||
<xsl:call-template name="text_width" />
|
||||
</xsl:variable>
|
||||
<blockTable style="Standard_Outline" colWidths="18,{$text_width}">
|
||||
<xsl:apply-templates match="text:list-item" />
|
||||
</blockTable>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text:list-item">
|
||||
<tr>
|
||||
<td><para><font face="Helvetica-Bold" size="10">*</font></para></td>
|
||||
<td>
|
||||
<xsl:apply-templates />
|
||||
</td>
|
||||
</tr>
|
||||
</xsl:template>
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<xsl:template match="office:body">
|
||||
<story>
|
||||
<xsl:apply-templates />
|
||||
<xsl:for-each select="//draw:text-box">
|
||||
<currentFrame>
|
||||
<xsl:attribute name="name">
|
||||
<xsl:value-of select="./@draw:name" />
|
||||
</xsl:attribute>
|
||||
</currentFrame>
|
||||
<xsl:apply-templates>
|
||||
<xsl:with-param name="skip_draw" select="0" />
|
||||
</xsl:apply-templates>
|
||||
<frameEnd />
|
||||
</xsl:for-each>
|
||||
</story>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="table:table">
|
||||
<blockTable>
|
||||
<xsl:attribute name="colWidths">
|
||||
<xsl:call-template name="make_columns" />
|
||||
</xsl:attribute>
|
||||
<xsl:call-template name="make_tableheaders" />
|
||||
<xsl:attribute name="style">
|
||||
<xsl:value-of select="@table:name" />
|
||||
</xsl:attribute>
|
||||
<xsl:apply-templates />
|
||||
</blockTable>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_tableheaders">
|
||||
<xsl:if test="boolean(count(table:table-header-rows))">
|
||||
<xsl:attribute name="repeatRows">1</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_tablebackground">
|
||||
<xsl:for-each select=".//table:table-row">
|
||||
<!--Be careful when there are table:table-header-rows as
|
||||
parent node of table:table-row -->
|
||||
<xsl:variable name="row" select="position() - 1" />
|
||||
<xsl:for-each select="./table:table-cell">
|
||||
<xsl:variable name="col" select="position() - 1" />
|
||||
<xsl:variable name="background">
|
||||
<xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:background-color" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($background='') and boolean(key('table_cell_style',@table:style-name)/style:properties/@fo:background-color) and starts-with($background,'#')">
|
||||
<!--only RGB hexcolors are accepted -->
|
||||
<blockBackground colorName="{$background}" start="{$col},{$row}" stop="{$col},{$row}" />
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="test_grid">
|
||||
<!--very primitive: if at last one cell has a border,
|
||||
the whole table style is set to GRID.-->
|
||||
<xsl:for-each select=".//table:table-cell">
|
||||
<xsl:for-each select="key('table_cell_style',@table:style-name)/style:properties" >
|
||||
<!--Test all table cell styles if there is at least one border line -->
|
||||
<xsl:variable name="border">
|
||||
<xsl:value-of select="@fo:border" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($border='none') and not($border='') and boolean(@fo:border)">
|
||||
<xsl:text>has_grid</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_columns">
|
||||
<xsl:variable name="columns" >
|
||||
<xsl:for-each select="table:table-column">
|
||||
<xsl:value-of select="key('table_column_style',@table:style-name)/style:properties/@style:column-width" />
|
||||
<xsl:text>,</xsl:text>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="substring($columns,1,string-length($columns) - 1)" />
|
||||
<!--strip the last comma-->
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="table:table-row">
|
||||
<tr>
|
||||
<xsl:apply-templates />
|
||||
</tr>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="table:table-cell">
|
||||
<td>
|
||||
<xsl:apply-templates />
|
||||
</td>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text:section">
|
||||
<section>
|
||||
<xsl:apply-templates />
|
||||
</section>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="text:span">
|
||||
<font>
|
||||
<xsl:call-template name="make_fontnames_span" />
|
||||
<xsl:call-template name="make_fontsize_span" />
|
||||
<xsl:apply-templates />
|
||||
</font>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_fontsize_span">
|
||||
<xsl:variable name ="fontsize">
|
||||
<xsl:value-of select="key('text_style',@text:style-name)/style:properties/@fo:font-size" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($fontsize='') and boolean(key('text_style',@text:style-name)/style:properties/@fo:font-size)" >
|
||||
<xsl:attribute name="size">
|
||||
<xsl:value-of select="$fontsize" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_fontnames_span">
|
||||
<xsl:attribute name="face">
|
||||
<xsl:call-template name="make_fontnames">
|
||||
<xsl:with-param name="fontName" select="key('text_style',@text:style-name)/style:properties/@style:font-name" />
|
||||
<xsl:with-param name="fontWeight" select="key('text_style',@text:style-name)/style:properties/@fo:font-weight" />
|
||||
<xsl:with-param name="fontStyle" select="key('text_style',@text:style-name)/style:properties/@fo:font-style" />
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_image">
|
||||
<illustration height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}">
|
||||
<image x="0" y="0" file="{substring-after(.//draw:image/@xlink:href,'#Pictures/')}" height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}" />
|
||||
</illustration>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="empty_paragraph">
|
||||
<xsl:if test="not(boolean(count(descendant::node())))">
|
||||
<xsl:call-template name="distance_point">
|
||||
<xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" />
|
||||
</xsl:call-template>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="distance_point">
|
||||
<xsl:param name="background" />
|
||||
<xsl:param name="tab_stop"></xsl:param>
|
||||
<xsl:variable name="local_back">
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(boolean($background)) or not(contains($background,'#'))">
|
||||
<!-- Do not accept OO colors like "transparent", only hex-colors -->
|
||||
<xsl:text>white</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="$background" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<font color="{$local_back}">
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:if test="boolean($tab_stop)">
|
||||
<!-- simulate a tabstop with white/background-color points -->
|
||||
<xsl:text>.........</xsl:text>
|
||||
</xsl:if>
|
||||
</font>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text:ordered-list">
|
||||
<xsl:apply-templates />
|
||||
<para><seqreset id="ordered_list" /></para>
|
||||
<!-- Reset the counter. seqreset is not a trml2pdf tag, but a Platypus Intra Paragraph Markup,
|
||||
so it needs a dummy paragraph to enclose it -->
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_listitem">
|
||||
<xsl:if test="(name(..)='text:list-item')">
|
||||
<xsl:attribute name="leftIndent">15</xsl:attribute>
|
||||
<xsl:attribute name="bulletIndent">0</xsl:attribute>
|
||||
<xsl:choose>
|
||||
<xsl:when test="(name(../..)='text:unordered-list')">
|
||||
<xsl:variable name="fontsize">
|
||||
<xsl:value-of select="number(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)" />
|
||||
</xsl:variable>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$fontsize='NaN'">
|
||||
<!-- you should exclude non-numerical values for bulletFontSize. <== Sometimes the preprocessing went wrong.-->
|
||||
<!--use a default bullet font size-->
|
||||
<xsl:attribute name="bulletFontSize">6</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="bulletFontSize"><xsl:value-of select="floor(($fontsize div 2) + 1)" /></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:attribute name="bulletFontName">ZapfDingbats</xsl:attribute>
|
||||
<xsl:attribute name="bulletText">l</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!-- Generate the numbers for an ordered list -->
|
||||
<xsl:variable name="size">
|
||||
<xsl:value-of select="key('paragraph_style',@text:style-name)/style:properties/@fo:font-size" />
|
||||
</xsl:variable>
|
||||
<!-- For ordered lists we use the bullet tag from Platypus Intra Paragraph Markup -->
|
||||
<bullet>
|
||||
<xsl:if test="not($size='') and boolean(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)">
|
||||
<xsl:attribute name="size">
|
||||
<!-- adapt the fontsize to the fontsize of the current paragraph -->
|
||||
<xsl:value-of select="$size" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
<seq id="ordered_list" />.</bullet>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text:p|text:h">
|
||||
<xsl:param name="skip_draw" select="1" />
|
||||
<xsl:if test="boolean(key('page_break_before',@text:style-name))" >
|
||||
<pageBreak />
|
||||
</xsl:if>
|
||||
<xsl:choose>
|
||||
<xsl:when test="boolean(.//draw:image)">
|
||||
<xsl:call-template name="make_image" />
|
||||
</xsl:when>
|
||||
<xsl:when test="boolean(name(..) = 'draw:text-box') and boolean($skip_draw)">
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<para>
|
||||
<xsl:attribute name="style">
|
||||
<xsl:value-of select="@text:style-name" />
|
||||
</xsl:attribute>
|
||||
<xsl:call-template name="make_listitem" />
|
||||
<xsl:apply-templates />
|
||||
<xsl:call-template name="empty_paragraph" />
|
||||
</para>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:if test="boolean(key('page_break_after',@text:style-name))" >
|
||||
<pageBreak />
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="text:p/text:tab-stop">
|
||||
<!-- simulate a tabstop -->
|
||||
<xsl:call-template name="distance_point">
|
||||
<xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" />
|
||||
<xsl:with-param name="tab_stop">yes</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- experimental - switched off
|
||||
<xsl:template match="text:h">
|
||||
<para>
|
||||
<xsl:attribute name="style">
|
||||
<xsl:value-of select="@text:style-name" />
|
||||
</xsl:attribute>
|
||||
<xsl:call-template name="make_number" />
|
||||
<xsl:apply-templates />
|
||||
<xsl:call-template name="empty_paragraph" />
|
||||
</para>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_number">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@text:level='1'">
|
||||
<xsl:number format="1. " />
|
||||
</xsl:when>
|
||||
<xsl:when test="@text:level='2'">
|
||||
<xsl:number count="text:h[@text:level='1']|text:h[text:level='2']" level="any" format="1.1." />
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
-->
|
||||
|
||||
<xsl:template match="style:style[@style:family='paragraph']">
|
||||
<paraStyle>
|
||||
<xsl:attribute name="name">
|
||||
<xsl:value-of select="@style:name" />
|
||||
</xsl:attribute>
|
||||
<xsl:call-template name="make_indent_paragraph" />
|
||||
<xsl:call-template name="make_fontnames_paragraph" />
|
||||
<xsl:call-template name="make_fontsize" />
|
||||
<!--<xsl:call-template name="make_parent" /> not necessary -
|
||||
parent styles processed by PyOpenOffice -->
|
||||
<xsl:call-template name="make_alignment" />
|
||||
<xsl:call-template name="make_background" />
|
||||
<xsl:call-template name="make_space_beforeafter" />
|
||||
</paraStyle>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_indent_paragraph">
|
||||
<xsl:variable name="right_indent"><xsl:value-of select="style:properties/@fo:margin-right" /></xsl:variable>
|
||||
<xsl:variable name="left_indent"><xsl:value-of select="style:properties/@fo:margin-left" /></xsl:variable>
|
||||
<xsl:if test="not($right_indent='') and boolean(style:properties/@fo:margin-right)">
|
||||
<xsl:attribute name="rightIndent">
|
||||
<xsl:value-of select="$right_indent" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:if test="not($left_indent='') and boolean(style:properties/@fo:margin-left)">
|
||||
<xsl:attribute name="leftIndent">
|
||||
<xsl:value-of select="$left_indent" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_background">
|
||||
<xsl:variable name="background">
|
||||
<xsl:value-of select="style:properties/@fo:background-color" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($background='') and boolean(style:properties/@fo:background-color) and starts-with($background,'#')" >
|
||||
<xsl:attribute name="backColor">
|
||||
<xsl:value-of select="$background" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_space_beforeafter">
|
||||
<xsl:variable name="before">
|
||||
<xsl:value-of select="style:properties/@fo:margin-top" />
|
||||
</xsl:variable>
|
||||
<xsl:variable name="after">
|
||||
<xsl:value-of select="style:properties/@fo:margin-bottom" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($before='') and boolean(style:properties/@fo:margin-top)" >
|
||||
<xsl:attribute name="spaceBefore">
|
||||
<xsl:value-of select="$before" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:if test="not($after='') and boolean(style:properties/@fo:margin-bottom)" >
|
||||
<xsl:attribute name="spaceAfter">
|
||||
<xsl:value-of select="$after" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_fontsize">
|
||||
<xsl:variable name="fontSize">
|
||||
<xsl:value-of select="style:properties/@fo:font-size" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($fontSize='') and boolean(style:properties/@fo:font-size)">
|
||||
<xsl:attribute name="fontSize">
|
||||
<xsl:value-of select="$fontSize" />
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="leading">
|
||||
<xsl:value-of select="$fontSize + floor($fontSize div 5) + 1" />
|
||||
<!--use a standard leading related to the font size -->
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<!--this template is not needed anymore for "normalized" sxw files -->
|
||||
<xsl:template name="make_parent">
|
||||
<xsl:variable name="parent">
|
||||
<xsl:value-of select="@style:parent-style-name" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($parent='') and boolean(@style:parent-style-name)">
|
||||
<xsl:attribute name="parent">
|
||||
<xsl:value-of select="$parent" />
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_alignment">
|
||||
<xsl:variable name="alignment">
|
||||
<xsl:value-of select="style:properties/@fo:text-align" />
|
||||
</xsl:variable>
|
||||
<xsl:if test="not($alignment='') and boolean(style:properties/@fo:text-align)">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$alignment='start'">
|
||||
<xsl:attribute name="alignment">LEFT</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$alignment='center'">
|
||||
<xsl:attribute name="alignment">CENTER</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$alignment='end'">
|
||||
<xsl:attribute name="alignment">RIGHT</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$alignment='justify'">
|
||||
<xsl:attribute name="alignment">JUSTIFY</xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_fontnames_paragraph">
|
||||
<xsl:attribute name="fontName">
|
||||
<xsl:call-template name="make_fontnames">
|
||||
<xsl:with-param name="fontName" select="style:properties/@style:font-name" />
|
||||
<xsl:with-param name="fontWeight" select="style:properties/@fo:font-weight" />
|
||||
<xsl:with-param name="fontStyle" select="style:properties/@fo:font-style" />
|
||||
</xsl:call-template>
|
||||
</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="make_fontnames">
|
||||
<!--much too verbose, needs improvement-->
|
||||
<xsl:param name="fontName" />
|
||||
<xsl:param name="fontWeight" />
|
||||
<xsl:param name="fontStyle" />
|
||||
<xsl:choose>
|
||||
<xsl:when test="not($fontName='') and boolean($fontName)">
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains($fontName,'Courier')">
|
||||
<xsl:choose>
|
||||
<xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Courier-BoldOblique</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
|
||||
<xsl:text>Courier-Bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Courier-Oblique</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>Courier</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($fontName,'Helvetica') or contains($fontName,'Arial') or contains($fontName,'Sans')">
|
||||
<xsl:choose>
|
||||
<xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Helvetica-BoldOblique</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
|
||||
<xsl:text>Helvetica-Bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Helvetica-Oblique</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>Helvetica</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:choose>
|
||||
<xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Times-BoldItalic</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
|
||||
<xsl:text>Times-Bold</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
|
||||
<xsl:text>Times-Italic</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>Times-Roman</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!--Use this as default -->
|
||||
<xsl:text>Times-Roman</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!--
|
||||
This stylesheet is part of:
|
||||
PyOpenOffice Version 0.4
|
||||
Copyright (C) 2005: Martin Simon
|
||||
Homepage: www.bezirksreiter.de
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999
|
||||
-->
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
#!/usr/bin/python
|
||||
#coding: latin-1
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c):
|
||||
#
|
||||
# 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
|
||||
# 2005 Fabien Pinckaers, TINY SPRL. (http://tiny.be)
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contact a Free Software
|
||||
# Service Company
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""
|
||||
Tiny SXW2RML - The Tiny ERP's report engine
|
||||
|
||||
Tiny SXW2RMLis part of the Tiny report project.
|
||||
Tiny Report is a module that allows you to render high quality PDF document
|
||||
from an OpenOffice template (.sxw) and any relationnal database.
|
||||
|
||||
The whole source code is distributed under the terms of the
|
||||
GNU Public Licence.
|
||||
|
||||
(c) 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
|
||||
(c) 2005-TODAY, Fabien Pinckaers - Tiny sprl
|
||||
"""
|
||||
__version__ = '0.9'
|
||||
|
||||
|
||||
import re
|
||||
import string
|
||||
import os
|
||||
import zipfile
|
||||
import xml.dom.minidom
|
||||
from reportlab.lib.units import toLength
|
||||
import base64
|
||||
|
||||
class DomApiGeneral:
|
||||
"""General DOM API utilities."""
|
||||
def __init__(self,content_string="",file=""):
|
||||
self.content_string = content_string
|
||||
self.re_digits = re.compile(r"(.*?\d)(pt|cm|mm|inch|in)")
|
||||
|
||||
def _unitTuple(self,string):
|
||||
"""Split values and units to a tuple."""
|
||||
temp = self.re_digits.findall(string)
|
||||
if not temp:
|
||||
return (string,"")
|
||||
else:
|
||||
return (temp[0])
|
||||
|
||||
def stringPercentToFloat(self,string):
|
||||
temp = string.replace("""%""","")
|
||||
return float(temp)/100
|
||||
|
||||
def findChildrenByName(self,parent,name,attr_dict={}):
|
||||
"""Helper functions. Does not work recursively.
|
||||
Optional: also test for certain attribute/value pairs."""
|
||||
children = []
|
||||
for c in parent.childNodes:
|
||||
if c.nodeType == c.ELEMENT_NODE and c.nodeName == name:
|
||||
children.append(c)
|
||||
if attr_dict == {}:
|
||||
return children
|
||||
else:
|
||||
return self._selectForAttributes(nodelist=children,attr_dict=attr_dict)
|
||||
|
||||
def _selectForAttributes(self,nodelist,attr_dict):
|
||||
"Helper function."""
|
||||
selected_nodes = []
|
||||
for n in nodelist:
|
||||
check = 1
|
||||
for a in attr_dict.keys():
|
||||
if n.getAttribute(a) != attr_dict[a]:
|
||||
# at least one incorrect attribute value?
|
||||
check = 0
|
||||
if check:
|
||||
selected_nodes.append(n)
|
||||
return selected_nodes
|
||||
|
||||
def _stringToTuple(self,s):
|
||||
"""Helper function."""
|
||||
try:
|
||||
temp = string.split(s,",")
|
||||
return int(temp[0]),int(temp[1])
|
||||
except:
|
||||
return None
|
||||
|
||||
def _tupleToString(self,t):
|
||||
try:
|
||||
return self.openOfficeStringUtf8("%s,%s" % (t[0],t[1]))
|
||||
except:
|
||||
return None
|
||||
|
||||
def _lengthToFloat(self,value):
|
||||
v = value
|
||||
if not self.re_digits.search(v):
|
||||
return v
|
||||
try:
|
||||
if v[-4:] == "inch":
|
||||
# OO files use "inch" instead of "in" in Reportlab units
|
||||
v = v[:-2]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
c = round(toLength(v))
|
||||
return c
|
||||
except:
|
||||
return v
|
||||
|
||||
def openOfficeStringUtf8(self,string):
|
||||
if type(string) == unicode:
|
||||
return string.encode("utf-8")
|
||||
tempstring = unicode(string,"cp1252").encode("utf-8")
|
||||
return tempstring
|
||||
|
||||
class DomApi(DomApiGeneral):
|
||||
"""This class provides a DOM-API for XML-Files from an SXW-Archive."""
|
||||
def __init__(self,xml_content,xml_styles):
|
||||
DomApiGeneral.__init__(self)
|
||||
self.content_dom = xml.dom.minidom.parseString(xml_content)
|
||||
self.styles_dom = xml.dom.minidom.parseString(xml_styles)
|
||||
body = self.content_dom.getElementsByTagName("office:body")
|
||||
self.body = body and body[0]
|
||||
|
||||
# TODO:
|
||||
self.style_dict = {}
|
||||
self.style_properties_dict = {}
|
||||
|
||||
# ******** always use the following order:
|
||||
self.buildStyleDict()
|
||||
self.buildStylePropertiesDict()
|
||||
|
||||
self.page_master = self.styles_dom.getElementsByTagName("style:page-master")[0]
|
||||
self.document = self.content_dom.getElementsByTagName("office:document-content")[0]
|
||||
|
||||
def buildStylePropertiesDict(self):
|
||||
for s in self.style_dict.keys():
|
||||
self.style_properties_dict[s] = self.getStylePropertiesDict(s)
|
||||
|
||||
def updateWithPercents(self,dict,updatedict):
|
||||
"""Sometimes you find values like "115%" in the style hierarchy."""
|
||||
if not updatedict:
|
||||
# no style hierarchies for this style? =>
|
||||
return
|
||||
new_updatedict = copy.copy(updatedict)
|
||||
for u in new_updatedict.keys():
|
||||
try:
|
||||
if new_updatedict[u].find("""%""") != -1 and dict.has_key(u):
|
||||
number = float(self.re_digits.search(dict[u]).group(1))
|
||||
unit = self.re_digits.search(dict[u]).group(2)
|
||||
new_number = self.stringPercentToFloat(new_updatedict[u]) * number
|
||||
if unit == "pt":
|
||||
new_number = int(new_number)
|
||||
# no floats allowed for "pt"
|
||||
# OOo just takes the int, does not round (try it out!)
|
||||
new_updatedict[u] = "%s%s" % (new_number,unit)
|
||||
else:
|
||||
dict[u] = new_updatedict[u]
|
||||
except:
|
||||
dict[u] = new_updatedict[u]
|
||||
dict.update(new_updatedict)
|
||||
|
||||
def normalizeStyleProperties(self):
|
||||
"""Transfer all style:style-properties attributes from the
|
||||
self.style_properties_hierarchical dict to the automatic-styles
|
||||
from content.xml. Use this function to preprocess content.xml for
|
||||
XSLT transformations etc.Do not try to implement this function
|
||||
with XSlT - believe me, it's a terrible task..."""
|
||||
styles_styles = self.styles_dom.getElementsByTagName("style:style")
|
||||
automatic_styles = self.content_dom.getElementsByTagName("office:automatic-styles")[0]
|
||||
for s in styles_styles:
|
||||
automatic_styles.appendChild(s.cloneNode(deep=1))
|
||||
content_styles = self.content_dom.getElementsByTagName("style:style")
|
||||
# these are the content_styles with styles_styles added!!!
|
||||
for s in content_styles:
|
||||
c = self.findChildrenByName(s,"style:properties")
|
||||
if c == []:
|
||||
# some derived automatic styles do not have "style:properties":
|
||||
temp = self.content_dom.createElement("style:properties")
|
||||
s.appendChild(temp)
|
||||
c = self.findChildrenByName(s,"style:properties")
|
||||
c = c[0]
|
||||
dict = self.style_properties_dict[(s.getAttribute("style:name")).encode("latin-1")] or {}
|
||||
for attribute in dict.keys():
|
||||
c.setAttribute(self.openOfficeStringUtf8(attribute),self.openOfficeStringUtf8(dict[attribute]))
|
||||
|
||||
def transferStylesXml(self):
|
||||
"""Transfer certain sub-trees from styles.xml to the normalized content.xml
|
||||
(see above). It is not necessary to do this - for example - with paragraph styles.
|
||||
the "normalized" style properties contain all information needed for
|
||||
further processing."""
|
||||
# TODO: What about table styles etc.?
|
||||
page_master = self.page_master
|
||||
outline_styles = self.styles_dom.getElementsByTagName("text:outline-style")
|
||||
t = self.content_dom.createElement("transferredfromstylesxml")
|
||||
self.document.insertBefore(t,self.body)
|
||||
t_new = self.body.previousSibling
|
||||
try:
|
||||
t_new.appendChild(page_master.cloneNode(deep=1))
|
||||
t_new.appendChild(outline_styles[0].cloneNode(deep=1))
|
||||
except:
|
||||
pass
|
||||
|
||||
def normalizeLength(self):
|
||||
"""Normalize all lengthes to floats (i.e: 1 inch = 72).
|
||||
Always use this after "normalizeContent" and "transferStyles"!"""
|
||||
# TODO: The complex attributes of table cell styles are not transferred yet.
|
||||
#all_styles = self.content_dom.getElementsByTagName("style:properties")
|
||||
#all_styles += self.content_dom.getElementsByTagName("draw:image")
|
||||
all_styles = self.content_dom.getElementsByTagName("*")
|
||||
for s in all_styles:
|
||||
for x in s._attrs.keys():
|
||||
v = s.getAttribute(x)
|
||||
s.setAttribute(x,"%s" % self._lengthToFloat(v))
|
||||
# convert float to string first!
|
||||
|
||||
def normalizeTableColumns(self):
|
||||
"""Handle this strange table:number-columns-repeated attribute."""
|
||||
columns = self.content_dom.getElementsByTagName("table:table-column")
|
||||
for c in columns:
|
||||
if c.hasAttribute("table:number-columns-repeated"):
|
||||
number = int(c.getAttribute("table:number-columns-repeated"))
|
||||
c.removeAttribute("table:number-columns-repeated")
|
||||
for i in range(number-1):
|
||||
(c.parentNode).insertBefore(c.cloneNode(deep=1),c)
|
||||
|
||||
def buildStyleDict(self):
|
||||
"""Store all style:style-nodes from content.xml and styles.xml in self.style_dict.
|
||||
Caution: in this dict the nodes from two dom apis are merged!"""
|
||||
for st in (self.styles_dom,self.content_dom):
|
||||
for s in st.getElementsByTagName("style:style"):
|
||||
name = s.getAttribute("style:name").encode("latin-1")
|
||||
self.style_dict[name] = s
|
||||
return True
|
||||
|
||||
def toxml(self):
|
||||
return self.content_dom.toxml(encoding="utf-8")
|
||||
|
||||
def getStylePropertiesDict(self,style_name):
|
||||
res = {}
|
||||
|
||||
if self.style_dict[style_name].hasAttribute("style:parent-style-name"):
|
||||
parent = self.style_dict[style_name].getAttribute("style:parent-style-name").encode("latin-1")
|
||||
res = self.getStylePropertiesDict(parent)
|
||||
|
||||
childs = self.style_dict[style_name].childNodes
|
||||
for c in childs:
|
||||
if c.nodeType == c.ELEMENT_NODE and c.nodeName == "style:properties":
|
||||
for attr in c._attrs.keys():
|
||||
res[attr] = c.getAttribute(attr).encode("latin-1")
|
||||
return res
|
||||
|
||||
class PyOpenOffice(object):
|
||||
"""This is the main class which provides all functionality."""
|
||||
def __init__(self, path='.', save_pict=False):
|
||||
self.path = path
|
||||
self.save_pict = save_pict
|
||||
self.images = {}
|
||||
|
||||
def oo_read(self,fname):
|
||||
z = zipfile.ZipFile(fname,"r")
|
||||
content = z.read('content.xml')
|
||||
style = z.read('styles.xml')
|
||||
all = z.namelist()
|
||||
for a in all:
|
||||
if a[:9]=='Pictures/' and len(a)>10:
|
||||
pic_content = z.read(a)
|
||||
self.images[a[9:]] = pic_content
|
||||
if self.save_pict:
|
||||
f=open(os.path.join(self.path, os.path.basename(a)),"wb")
|
||||
f.write(pic_content)
|
||||
f.close()
|
||||
z.close()
|
||||
return content,style
|
||||
|
||||
def oo_replace(self,content):
|
||||
regex = [
|
||||
(r"<para[^>]*/>", ""),
|
||||
#(r"<text:ordered-list.*?>(.*?)</text:ordered-list>", "$1"),
|
||||
#(r"<text:unordered-list.*?>(.*?)</text:unordered-list>", "$1"),
|
||||
(r"<para(.*)>(.*?)<text:line-break[^>]*/>", "<para$1>$2</para><para$1>"),
|
||||
]
|
||||
for key,val in regex:
|
||||
content = re.sub(key, val, content)
|
||||
return content
|
||||
|
||||
def unpackNormalize(self,sourcefile):
|
||||
c,s = self.oo_read(sourcefile)
|
||||
c = self.oo_replace(c)
|
||||
dom = DomApi(c,s)
|
||||
dom.normalizeStyleProperties()
|
||||
dom.transferStylesXml()
|
||||
dom.normalizeLength()
|
||||
dom.normalizeTableColumns()
|
||||
new_c = dom.toxml()
|
||||
return new_c
|
||||
|
||||
def sxw2rml(sxw_file, xsl, output='.', save_pict=False):
|
||||
import libxslt
|
||||
import libxml2
|
||||
tool = PyOpenOffice(output, save_pict = save_pict)
|
||||
res = tool.unpackNormalize(sxw_file)
|
||||
styledoc = libxml2.parseDoc(xsl)
|
||||
style = libxslt.parseStylesheetDoc(styledoc)
|
||||
doc = libxml2.parseMemory(res,len(res))
|
||||
result = style.applyStylesheet(doc, None)
|
||||
|
||||
root = result.xpathEval("/document/stylesheet")
|
||||
if root:
|
||||
root=root[0]
|
||||
images = libxml2.newNode("images")
|
||||
for img in tool.images:
|
||||
node = libxml2.newNode('image')
|
||||
node.setProp('name', img)
|
||||
node.setContent( base64.encodestring(tool.images[img]))
|
||||
images.addChild(node)
|
||||
root.addNextSibling(images)
|
||||
|
||||
xml = style.saveResultToString(result)
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
import optparse
|
||||
parser = optparse.OptionParser(
|
||||
version="Tiny Report v%s" % __version__,
|
||||
usage = 'tiny_sxw2rml.py [options] file.sxw')
|
||||
parser.add_option("-v", "--verbose", default=False, dest="verbose", help="enable basic debugging")
|
||||
parser.add_option("-o", "--output", dest="output", default='.', help="directory of image output")
|
||||
(opt, args) = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.error("incorrect number of arguments")
|
||||
|
||||
import sys
|
||||
import StringIO
|
||||
|
||||
fname = sys.argv[1]
|
||||
f = StringIO.StringIO(file(fname).read())
|
||||
|
||||
xsl = file('normalized_oo2rml.xsl').read()
|
||||
result = sxw2rml(f, xsl, output=opt.output, save_pict=False)
|
||||
|
||||
print result
|
Loading…
Reference in New Issue