[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