[Erp5-report] r26389 - in /erp5/trunk/products/ERP5OOo: ./ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Fri Apr 10 10:38:28 CEST 2009
Author: tatuya
Date: Fri Apr 10 10:38:26 2009
New Revision: 26389
URL: http://svn.erp5.org?rev=26389&view=rev
Log:
* Fix:
if listbox has no data line, must not have table rows
* Append:
ReportSection and ImageField mapping features
TODO: write their unit test
Modified:
erp5/trunk/products/ERP5OOo/FormPrintout.py
erp5/trunk/products/ERP5OOo/tests/testFormPrintout.py
Modified: erp5/trunk/products/ERP5OOo/FormPrintout.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/FormPrintout.py?rev=26389&r1=26388&r2=26389&view=diff
==============================================================================
--- erp5/trunk/products/ERP5OOo/FormPrintout.py [utf8] (original)
+++ erp5/trunk/products/ERP5OOo/FormPrintout.py [utf8] Fri Apr 10 10:38:26 2009
@@ -35,17 +35,20 @@
from Products.ERP5Form.ImageField import ImageField
from Products.ERP5OOo.OOoUtils import OOoBuilder
-from Acquisition import Implicit
+from Acquisition import Implicit, aq_base
from Globals import InitializeClass, DTMLFile, Persistent, get_request
from AccessControl import ClassSecurityInfo
from AccessControl.Role import RoleManager
from OFS.SimpleItem import Item, SimpleItem
-from urllib import quote
+from OFS.Image import File
+from urllib import quote, quote_plus
from copy import deepcopy
from lxml import etree
from zLOG import LOG, DEBUG, INFO, WARNING
from mimetypes import guess_extension
from DateTime import DateTime
+from decimal import Decimal
+import re
try:
from webdav.Lockable import ResourceLockedError
@@ -99,15 +102,16 @@
a form as a ODF document content, and a template as a document layout.
WARNING: The Form Printout currently supports only ODT format document.
- And the functions only supports paragraphs and tables.
-
- Fields <-> Paragraphs: supported
- ListBox <-> Table: supported
- Report Section <-> Tables: experimentally supported
- FormBox <-> Frame: experimentally supported
- Photo <-> Image: not supported yet
- Style group <-> styles.xml: supported
- Meta group <-> meta.xml: not supported yet
+
+ The functions status:
+
+ Fields -> Paragraphs: supported
+ ListBox -> Table: supported
+ Report Section -> Frames: experimentally supported
+ FormBox -> Frame: experimentally supported
+ ImageField -> Photo: supported
+ styles.xml: supported
+ meta.xml: not supported yet
"""
meta_type = "ERP5 Form Printout"
@@ -211,6 +215,8 @@
class ODFStrategy(Implicit):
"""ODFStrategy creates a ODF Document. """
+ odf_existent_name_list = []
+
def render(self, extra_context={}):
"""Render a odf document, form as a content, template as a template.
@@ -240,7 +246,8 @@
# Create a new builder instance
ooo_builder = OOoBuilder(ooo_document)
-
+ self.odf_existent_name_list = ooo_builder.getNameList()
+
# content.xml
ooo_builder = self._replaceContentXml(ooo_builder=ooo_builder, extra_context=extra_context)
# styles.xml
@@ -264,10 +271,12 @@
content_element_tree = self._replaceXmlByForm(element_tree=content_element_tree,
form=form,
here=here,
- extra_context=extra_context)
+ extra_context=extra_context,
+ ooo_builder=ooo_builder)
# mapping ERP5Report report method to ODF
content_element_tree = self._replaceXmlByReportSection(element_tree=content_element_tree,
- extra_context=extra_context)
+ extra_context=extra_context,
+ ooo_builder=ooo_builder)
content_xml = etree.tostring(content_element_tree, encoding='utf-8')
# Replace content.xml in master openoffice template
@@ -286,7 +295,8 @@
styles_element_tree = self._replaceXmlByForm(element_tree=styles_element_tree,
form=form,
here=here,
- extra_context=extra_context)
+ extra_context=extra_context,
+ ooo_builder=ooo_builder)
styles_xml = etree.tostring(styles_element_tree, encoding='utf-8')
ooo_builder.replace('styles.xml', styles_xml)
@@ -306,7 +316,7 @@
return ooo_builder
def _replaceXmlByForm(self, element_tree=None, form=None, here=None,
- extra_context=None, render_prefix=None):
+ extra_context=None, render_prefix=None, ooo_builder=None):
field_list = form.get_fields()
REQUEST = get_request()
for (count, field) in enumerate(field_list):
@@ -321,12 +331,13 @@
field_id=field.id,
form = sub_form,
REQUEST=REQUEST)
- #elif isinstance(field, ImageField):
- # element_tree = self._replaceXmlByImageField(element_tree=element_tree,
- # image_field=field)
+ elif isinstance(field, ImageField):
+ element_tree = self._replaceXmlByImageField(element_tree=element_tree,
+ image_field=field,
+ ooo_builder=ooo_builder)
else:
element_tree = self._replaceNodeViaReference(element_tree=element_tree,
- field=field)
+ field=field)
return element_tree
def _replaceNodeViaReference(self, element_tree=None, field=None):
@@ -377,7 +388,7 @@
node.tail = ''
return element_tree
- def _replaceXmlByReportSection(self, element_tree=None, extra_context=None):
+ def _replaceXmlByReportSection(self, element_tree=None, extra_context=None, ooo_builder=None):
if not extra_context.has_key('report_method') or extra_context['report_method'] is None:
return element_tree
report_method = extra_context['report_method']
@@ -386,6 +397,8 @@
REQUEST = get_request()
request = extra_context.get('REQUEST', REQUEST)
render_prefix = None
+
+ frame_paragraph_index_dict = {}
for (index, report_item) in enumerate(report_section_list):
if index > 0:
render_prefix = 'x%s' % index
@@ -393,14 +406,48 @@
here = report_item.getObject(portal_object)
form_id = report_item.getFormId()
form = getattr(here, form_id)
- element_tree = self._replaceXmlByForm(element_tree=element_tree,
- form=form,
- here=here,
- extra_context=extra_context,
- render_prefix=render_prefix)
+
+ report_section_frame_xpath = '//draw:frame[@draw:name="%s"]' % form_id
+ frame_list = element_tree.xpath(report_section_frame_xpath, namespaces=element_tree.nsmap)
+ if len(frame_list) is 0:
+ continue
+ frame = frame_list[0]
+ paragraph = frame.getparent()
+ parent = paragraph.getparent()
+ frame_paragraph_element_tree = deepcopy(paragraph)
+ if not form_id in frame_paragraph_index_dict:
+ frame_paragraph_index_dict[form_id] = parent.index(paragraph)
+ parent.remove(paragraph)
+ else:
+ self._setReportSectionFrameName(form_id=form_id,
+ frame_paragraph_index=frame_paragraph_index_dict[form_id],
+ frame_paragraph_element_tree=frame_paragraph_element_tree)
+
+ frame_paragraph_index = frame_paragraph_index_dict[form_id]
+ frame_paragraph_element_tree = self._replaceXmlByForm(element_tree=frame_paragraph_element_tree,
+ form=form,
+ here=here,
+ extra_context=extra_context,
+ ooo_builder=ooo_builder)
+
+
+ parent.insert(frame_paragraph_index, frame_paragraph_element_tree)
+ frame_paragraph_index_dict[form_id] = frame_paragraph_index + 1
report_item.popReport(portal_object, render_prefix = render_prefix)
return element_tree
+ def _setReportSectionFrameName(self,
+ form_id='',
+ frame_paragraph_index=0,
+ frame_paragraph_element_tree=None):
+ report_section_frame_name = "%s_%s" % (form_id, frame_paragraph_index)
+ draw_name_attribute = '{%s}name' % frame_paragraph_element_tree.nsmap['draw']
+ report_section_frame = frame_paragraph_element_tree.xpath('draw:frame[@draw:name="%s"]' % form_id,
+ namespaces=frame_paragraph_element_tree.nsmap)
+ if len(report_section_frame) is 0:
+ return
+ report_section_frame[0].set(draw_name_attribute, report_section_frame_name)
+
def _replaceXmlByFormbox(self, element_tree=None, field_id=None, form=None, REQUEST=None):
draw_xpath = '//draw:frame[@draw:name="%s"]/draw:text-box/*' % field_id
text_list = element_tree.xpath(draw_xpath, namespaces=element_tree.nsmap)
@@ -419,15 +466,68 @@
parent.append(child)
return element_tree
- def _replaceXmlByImageField(self, element_tree=None, image_field=None):
+ def _replaceXmlByImageField(self, element_tree=None, image_field=None, ooo_builder=None):
alt = image_field.get_value('description') or image_field.get_value('title')
image_xpath = '//draw:frame[@draw:name="%s"]/*' % image_field.id
image_list = element_tree.xpath(image_xpath, namespaces=element_tree.nsmap)
- if len(image_list) > 0:
- image_list[0].set("{%s}href" % element_tree.nsmap['xlink'], image_field.absolute_url())
-
+ if len(image_list) is 0:
+ return element_tree
+ path = image_field.get_value('default')
+ picture = self.getPortalObject().unrestrictedTraverse(path)
+ picture_data = getattr(aq_base(picture), 'data', None)
+ picture_type = picture.getContentType()
+ picture_path = self._createOdfUniqueFileName(path=path, picture_type=picture_type)
+ ooo_builder.addFileEntry(picture_path, media_type=picture_type, content=picture_data)
+ image_node = image_list[0]
+ picture_size = self._getPictureSize(picture, image_node)
+ image_node.set('{%s}href' % element_tree.nsmap['xlink'], picture_path)
+ image_frame = image_node.getparent()
+ image_frame.set('{%s}width' % element_tree.nsmap['svg'], picture_size[0])
+ image_frame.set('{%s}height' % element_tree.nsmap['svg'], picture_size[1])
return element_tree
+ def _createOdfUniqueFileName(self, path='', picture_type=''):
+ extension = guess_extension(picture_type)
+ picture_path = 'Pictures/%s%s' % (quote_plus(path), extension)
+ if picture_path not in self.odf_existent_name_list:
+ return picture_path
+ number = 0
+ while True:
+ picture_path = 'Pictures/%s_%s%s' % (path, number, extension)
+ if picture_path not in self.odf_existent_name_list:
+ return picture_path
+ number += 1
+
+ def _getPictureSize(self, picture=None, image_node=None):
+ if picture is None or image_node is None:
+ return ('0cm', '0cm')
+ draw_frame_node = image_node.getparent()
+ svg_width = draw_frame_node.attrib.get('{%s}width' % draw_frame_node.nsmap['svg'])
+ svg_height = draw_frame_node.attrib.get('{%s}height' % draw_frame_node.nsmap['svg'])
+ if svg_width is None or svg_height is None:
+ return ('0cm', '0cm')
+ # if not match causes exception
+ width_tuple = re.match("(\d[\d\.]*)(.*)", svg_width).groups()
+ height_tuple = re.match("(\d[\d\.]*)(.*)", svg_height).groups()
+ unit = width_tuple[1]
+ w = Decimal(width_tuple[0])
+ h = Decimal(height_tuple[0])
+ aspect_ratio = 1
+ try: # try image properties
+ aspect_ratio = Decimal(picture.width) / Decimal(picture.height)
+ except (TypeError, ZeroDivisionError):
+ try: # try ERP5.Document.Image API
+ height = Decimal(picture.getHeight())
+ if height:
+ aspect_ratio = Decimal(picture.getWidth()) / height
+ except AttributeError: # fallback to Photo API
+ height = float(picture.height())
+ if height:
+ aspect_ratio = Decimal(picture.width()) / height
+ w = h * aspect_ratio
+ return (str(w) + unit, str(h) + unit)
+
+
def _appendTableByListbox(self,
element_tree=None,
listbox=None,
@@ -484,7 +584,7 @@
row = self._updateColumnValue(row, listbox_column_list)
newtable.append(row)
is_top = False
- elif listboxline.isStatLine() or index is last_index:
+ elif listboxline.isStatLine() or (index is last_index and listboxline.isDataLine()):
row = deepcopy(row_bottom)
row = self._updateColumnStatValue(row, listbox_column_list, row_middle)
newtable.append(row)
Modified: erp5/trunk/products/ERP5OOo/tests/testFormPrintout.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/tests/testFormPrintout.py?rev=26389&r1=26388&r2=26389&view=diff
==============================================================================
--- erp5/trunk/products/ERP5OOo/tests/testFormPrintout.py [utf8] (original)
+++ erp5/trunk/products/ERP5OOo/tests/testFormPrintout.py [utf8] Fri Apr 10 10:38:26 2009
@@ -479,7 +479,6 @@
REQUEST = request)
self.assertEqual(len(listboxline_list), 4)
self.assertTrue(listboxline_list[1].getColumnProperty('title') == "foo_title_7")
- LOG('testFormPrintout start_date', INFO, listboxline_list[1].getColumnProperty('start_date'))
odf_document = foo_printout.index_html(REQUEST=request)
#test_output = open("/tmp/test_02_07_Table.odf", "w")
@@ -493,7 +492,6 @@
content = etree.XML(content_xml)
table_row_xpath = '//table:table[@table:name="listbox"]/table:table-row'
odf_table_rows = content.xpath(table_row_xpath, namespaces=content.nsmap)
- LOG('testFormPrintout odf_table_rows', INFO, odf_table_rows)
self.assertEqual(len(odf_table_rows), 3)
# to test ODF table cell number format
first_row = odf_table_rows[0]
@@ -502,7 +500,41 @@
date_value_attrib = "{%s}date-value" % content.nsmap['office']
self.assertTrue(date_column.attrib.has_key(date_value_attrib))
self.assertEqual(date_column.attrib[date_value_attrib], '2009-04-20')
-
+
+
+ def test_02_Table_08_Nodata(self, run=run_all_test):
+ """7. Normal case: list box has no data"""
+ if not run: return
+ # test target
+ test1 = self.portal.foo_module.test1
+ foo_printout = test1.Foo_viewAsPrintout
+ foo_form = test1.Foo_view
+ listbox = foo_form.listbox
+ request = self.app.REQUEST
+ request['here'] = test1
+
+ test1.foo_1.setTitle('foo_title_8')
+ message = listbox.ListBox_setPropertyList(
+ field_columns = 'id|ID\ntitle|Title\nquantity|Quantity\nstart_date|Date',)
+ self.failUnless('Set Successfully' in message)
+ listboxline_list = listbox.get_value('default', render_format = 'list',
+ REQUEST = request)
+ # title line only
+ self.assertEqual(len(listboxline_list), 1)
+
+ odf_document = foo_printout.index_html(REQUEST=request)
+ #test_output = open("/tmp/test_02_08_Table.odf", "w")
+ #test_output.write(odf_document)
+ self.assertTrue(odf_document is not None)
+ builder = OOoBuilder(odf_document)
+ content_xml = builder.extract("content.xml")
+
+ content = etree.XML(content_xml)
+ table_row_xpath = '//table:table[@table:name="listbox"]/table:table-row'
+ odf_table_rows = content.xpath(table_row_xpath, namespaces=content.nsmap)
+ # no rows
+ self.assertEqual(len(odf_table_rows), 0)
+
def _test_03_Frame(self, run=run_all_test):
"""
Frame not supported yet
More information about the Erp5-report
mailing list