From 74cbe0850686a042a1115d373e41bd9285c75f6c Mon Sep 17 00:00:00 2001
From: Tatuya Kamada <tatuya@nexedi.com>
Date: Wed, 8 Apr 2009 07:08:33 +0000
Subject: [PATCH] * Fix   transform DateTime object into ODF acceptable format 
  '2009/04/20' -> '2009-04-20'

* Append
  test cases which confirm fixing the bugs

* Refactoring
  - change method name into mixedCase, according to
    the naming convention
  - using etree nsmap object instead of to define
    the namespace-dictionary constant
  - the long test method devide into appropriate
    some methods



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@26344 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5OOo/FormPrintout.py           | 232 +++++++++----------
 product/ERP5OOo/tests/testFormPrintout.py | 267 ++++++++++++++++------
 2 files changed, 312 insertions(+), 187 deletions(-)

diff --git a/product/ERP5OOo/FormPrintout.py b/product/ERP5OOo/FormPrintout.py
index a022f9b856..0124f6f3fd 100644
--- a/product/ERP5OOo/FormPrintout.py
+++ b/product/ERP5OOo/FormPrintout.py
@@ -45,6 +45,7 @@ from copy import deepcopy
 from lxml import etree
 from zLOG import LOG, DEBUG, INFO, WARNING
 from mimetypes import guess_extension
+from DateTime import DateTime
 
 try:
   from webdav.Lockable import ResourceLockedError
@@ -87,7 +88,7 @@ def add_and_edit(self, id, REQUEST):
   if REQUEST['submit'] == " Add and Edit ":
     u = "%s/%s" % (u, quote(id))
   REQUEST.RESPONSE.redirect(u+'/manage_main')
-  
+
 class FormPrintout(Implicit, Persistent, RoleManager, Item):
   """Form Printout
 
@@ -125,11 +126,10 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item):
   manage_options = ((
     {'label':'Edit', 'action':'manage_editFormPrintout'},
     {'label':'View', 'action': '' }, ) + Item.manage_options)
-                    
-
+  
   security.declareProtected('View management screens', 'manage_editFormPrintout')
   manage_editFormPrintout = PageTemplateFile('www/FormPrintout_manageEdit', globals(),
-                                  __name__='manage_editFormPrintout')
+                                             __name__='manage_editFormPrintout')
   manage_editFormPrintout._owner = None
   
   # default attributes
@@ -169,20 +169,20 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item):
     report_method = None
     if hasattr(form, 'report_method'):
       report_method = getattr(obj, form.report_method)
-    extra_context = dict( container=container,
-                          printout_template=printout_template,
-                          report_method=report_method,
-                          form=form,
-                          here=obj )
+    extra_context = dict(container=container,
+                         printout_template=printout_template,
+                         report_method=report_method,
+                         form=form,
+                         here=obj)
     # set property to aquisition
     content_type = printout_template.content_type
-    self.strategy = self._create_strategy(content_type)
+    self.strategy = self._createStrategy(content_type)
     printout = self.strategy.render(extra_context=extra_context)
     REQUEST.RESPONSE.setHeader('Content-Type','%s; charset=utf-8' % content_type)
     REQUEST.RESPONSE.setHeader('Content-disposition',
                                'inline;filename="%s%s"' % (self.title_or_id(), guess_extension(content_type)))
     return printout
- 
+
   security.declareProtected('Manage properties', 'doSettings')
   def doSettings(self, REQUEST, title='', form_name='', template=''):
     """Change title, form_name, template."""
@@ -197,32 +197,25 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item):
                 % '<br>'.join(self._v_warnings))
     return self.manage_editFormPrintout(manage_tabs_message=message)
 
-  def _create_strategy(slef, content_type=''):
+  def _createStrategy(slef, content_type=''):
     if guess_extension(content_type) == '.odt':
       return ODTStrategy()
     raise ValueError, 'Do not support the template type:%s' % content_type
 
 InitializeClass(FormPrintout)
 
-
-NAME_SPACE_DICT = {'draw':'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
-                   'table':'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
-                   'text':'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
-                   'office':'urn:oasis:names:tc:opendocument:xmlns:office:1.0',
-                   'xlink':'http://www.w3.org/1999/xlink'}
-
 class ODFStrategy(Implicit):
   """ODFStrategy creates a ODF Document. """
-  
+
   def render(self, extra_context={}):
     """Render a odf document, form as a content, template as a template.
 
     Keyword arguments:
     extra_context -- a dictionary, expected:
-                     'here' : where it call
-                     'printout_template' : the template object, tipically a OOoTemplate
-                     'container' : the object which has a form printout object
-                     'form' : the form as a content
+      'here' : where it call
+      'printout_template' : the template object, tipically a OOoTemplate
+      'container' : the object which has a form printout object
+      'form' : the form as a content
     """
     here = extra_context['here']
     if here is None:
@@ -232,7 +225,7 @@ class ODFStrategy(Implicit):
       raise ValueError, 'Can not create a ODF Document without a printout template'
 
     odf_template = extra_context['printout_template']
-    
+
     # First, render the Template if it has a pt_render method
     ooo_document = None
     if hasattr(odf_template, 'pt_render'):
@@ -245,42 +238,42 @@ class ODFStrategy(Implicit):
     ooo_builder = OOoBuilder(ooo_document)
 
     # content.xml
-    ooo_builder = self._replace_content_xml(ooo_builder=ooo_builder, extra_context=extra_context)
+    ooo_builder = self._replaceContentXml(ooo_builder=ooo_builder, extra_context=extra_context)
     # styles.xml
-    ooo_builder = self._replace_styles_xml(ooo_builder=ooo_builder, extra_context=extra_context)
+    ooo_builder = self._replaceStylesXml(ooo_builder=ooo_builder, extra_context=extra_context)
     # meta.xml is not supported yet
-    # ooo_builder = self._replace_meta_xml(ooo_builder=ooo_builder, extra_context=extra_context)
-        
+    # ooo_builder = self._replaceMetaXml(ooo_builder=ooo_builder, extra_context=extra_context)
+
     # Update the META informations
     ooo_builder.updateManifest()
 
     ooo = ooo_builder.render(name=odf_template.title or odf_template.id)
     return ooo
 
-  def _replace_content_xml(self, ooo_builder=None, extra_context=None):
+  def _replaceContentXml(self, ooo_builder=None, extra_context=None):
     content_xml = ooo_builder.extract('content.xml')
     # mapping ERP5Form to ODF
     form = extra_context['form']
     here = getattr(self, 'aq_parent', None)
 
     content_element_tree = etree.XML(content_xml)
-    content_element_tree = self._replace_xml_by_form(element_tree=content_element_tree,
-                                                     form=form,
-                                                     here=here,
-                                                     extra_context=extra_context)
+    content_element_tree = self._replaceXmlByForm(element_tree=content_element_tree,
+                                                  form=form,
+                                                  here=here,
+                                                  extra_context=extra_context)
     # mapping ERP5Report report method to ODF
-    content_element_tree = self._replace_xml_by_report_section(element_tree=content_element_tree,
-                                                               extra_context=extra_context)
+    content_element_tree = self._replaceXmlByReportSection(element_tree=content_element_tree,
+                                                           extra_context=extra_context)
     content_xml = etree.tostring(content_element_tree)
     if isinstance(content_xml, unicode):
       content_xml = content_xml.encode('utf-8')
- 
+
     # Replace content.xml in master openoffice template
     ooo_builder.replace('content.xml', content_xml)
     return ooo_builder
 
   # this method not supported yet
-  def _replace_styles_xml(self, ooo_builder=None, extra_context=None):
+  def _replaceStylesXml(self, ooo_builder=None, extra_context=None):
     """
     replacing styles.xml file in a ODF document
     """
@@ -288,19 +281,19 @@ class ODFStrategy(Implicit):
     form = extra_context['form']
     here = getattr(self, 'aq_parent', None)
     styles_element_tree = etree.XML(styles_xml)
-    styles_element_tree = self._replace_xml_by_form(element_tree=styles_element_tree,
-                                                    form=form,
-                                                    here=here,
-                                                    extra_context=extra_context)
+    styles_element_tree = self._replaceXmlByForm(element_tree=styles_element_tree,
+                                                 form=form,
+                                                 here=here,
+                                                 extra_context=extra_context)
     styles_xml = etree.tostring(styles_element_tree)
     if isinstance(styles_xml, unicode):
       styles_xml = styles_xml.encode('utf-8')
- 
+
     ooo_builder.replace('styles.xml', styles_xml)
     return ooo_builder
 
   # this method not implemented yet
-  def _replace_meta_xml(self, ooo_builder=None, extra_content=None):
+  def _replaceMetaXml(self, ooo_builder=None, extra_content=None):
     """
     replacing meta.xml file in a ODF document
     """
@@ -308,40 +301,40 @@ class ODFStrategy(Implicit):
 
     if isinstance(doc_xml, unicode):
       meta_xml = meta_xml.encode('utf-8')
- 
+
     ooo_builder.replace('meta.xml', meta_xml)
     return ooo_builder
 
-  def _replace_xml_by_form(self, element_tree=None, form=None, here=None,
+  def _replaceXmlByForm(self, element_tree=None, form=None, here=None,
                            extra_context=None, render_prefix=None):
     field_list = form.get_fields() 
     REQUEST = get_request()
     for (count, field) in enumerate(field_list):
       if isinstance(field, ListBox):
-        element_tree = self._append_table_by_listbox(element_tree=element_tree,
-                                                     listbox=field,
-                                                     REQUEST=REQUEST,
-                                                     render_prefix=render_prefix)
+        element_tree = self._appendTableByListbox(element_tree=element_tree,
+                                                  listbox=field,
+                                                  REQUEST=REQUEST,
+                                                  render_prefix=render_prefix)
       elif isinstance(field, FormBox):
         sub_form = getattr(here, field.get_value('formbox_target_id'))
-        content = self._replace_xml_by_formbox(element_tree=element_tree,
-                                               field_id=field.id,
-                                               form = sub_form,
-                                               REQUEST=REQUEST)
+        content = self._replaceXmlByFormbox(element_tree=element_tree,
+                                            field_id=field.id,
+                                            form = sub_form,
+                                            REQUEST=REQUEST)
       #elif isinstance(field, ImageField):
-      #  element_tree = self._replace_xml_by_image_field(element_tree=element_tree,
+      #  element_tree = self._replaceXmlByImageField(element_tree=element_tree,
       #                                                  image_field=field)
       else:
-        element_tree = self._replace_node_via_reference(element_tree=element_tree,
+        element_tree = self._replaceNodeViaReference(element_tree=element_tree,
                                                         field=field)
     return element_tree
-  
-  def _replace_node_via_reference(self, element_tree=None, field=None):
+
+  def _replaceNodeViaReference(self, element_tree=None, field=None):
     field_id = field.id
     field_value = field.get_value('default')
     # text:reference-mark text:name="invoice-date"
     reference_xpath = '//text:reference-mark[@text:name="%s"]' % field_id
-    reference_list = element_tree.xpath(reference_xpath, namespaces=NAME_SPACE_DICT)
+    reference_list = element_tree.xpath(reference_xpath, namespaces=element_tree.nsmap)
     if len(reference_list) > 0:
       node = reference_list[0].getparent()
       # remove such a "bbb": <text:p>aaa<br/>bbb</text:p>
@@ -349,8 +342,8 @@ class ODFStrategy(Implicit):
         child.tail = ''
       node.text = field_value
     return element_tree
-  
-  def _replace_xml_by_report_section(self, element_tree=None, extra_context=None):
+
+  def _replaceXmlByReportSection(self, element_tree=None, extra_context=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']
@@ -366,17 +359,17 @@ class ODFStrategy(Implicit):
       here = report_item.getObject(portal_object)
       form_id = report_item.getFormId()
       form = getattr(here, form_id)
-      element_tree = self._replace_xml_by_form(element_tree=element_tree,
-                                               form=form,
-                                               here=here,
-                                               extra_context=extra_context,
-                                               render_prefix=render_prefix)
+      element_tree = self._replaceXmlByForm(element_tree=element_tree,
+                                            form=form,
+                                            here=here,
+                                            extra_context=extra_context,
+                                            render_prefix=render_prefix)
       report_item.popReport(portal_object, render_prefix = render_prefix)
     return element_tree
 
-  def _replace_xml_by_formbox(self, element_tree=None, field_id=None, form=None, REQUEST=None):
+  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=NAME_SPACE_DICT)
+    text_list = element_tree.xpath(draw_xpath, namespaces=element_tree.nsmap)
     if len(text_list) == 0:
       return element_tree
     parent = text_list[0].getparent()
@@ -392,24 +385,24 @@ class ODFStrategy(Implicit):
         parent.append(child)
     return element_tree
 
-  def _replace_xml_by_image_field(self, element_tree=None, image_field=None):
+  def _replaceXmlByImageField(self, element_tree=None, image_field=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=NAME_SPACE_DICT)
+    image_list = element_tree.xpath(image_xpath, namespaces=element_tree.nsmap)
     if len(image_list) > 0:
-      image_list[0].set("{%s}href" % NAME_SPACE_DICT['xlink'], image_field.absolute_url())
-    
+      image_list[0].set("{%s}href" % element_tree.nsmap['xlink'], image_field.absolute_url())
+
     return element_tree
 
-  def _append_table_by_listbox(self,
-                               element_tree=None, 
-                               listbox=None,
-                               REQUEST=None,
-                               render_prefix=None):
+  def _appendTableByListbox(self,
+                            element_tree=None, 
+                            listbox=None,
+                            REQUEST=None,
+                            render_prefix=None):
     table_id = listbox.id
     table_xpath = '//table:table[@table:name="%s"]' % table_id
     # this list should be one item list
-    target_table_list = element_tree.xpath(table_xpath, namespaces=NAME_SPACE_DICT)
+    target_table_list = element_tree.xpath(table_xpath, namespaces=element_tree.nsmap)
     if len(target_table_list) is 0:
       return element_tree
 
@@ -418,13 +411,13 @@ class ODFStrategy(Implicit):
 
     table_header_rows_xpath = '%s/table:table-header-rows' % table_xpath
     table_row_xpath = '%s/table:table-row' % table_xpath
-    table_header_rows_list = newtable.xpath(table_header_rows_xpath,  namespaces=NAME_SPACE_DICT)
-    table_row_list = newtable.xpath(table_row_xpath,  namespaces=NAME_SPACE_DICT)
+    table_header_rows_list = newtable.xpath(table_header_rows_xpath,  namespaces=element_tree.nsmap)
+    table_row_list = newtable.xpath(table_row_xpath,  namespaces=element_tree.nsmap)
 
     # copy row styles from ODF Document
     has_header_rows = len(table_header_rows_list) > 0
-    (row_top, row_middle, row_bottom) = self._copy_row_style(table_row_list,
-                                                             has_header_rows=has_header_rows)
+    (row_top, row_middle, row_bottom) = self._copyRowStyle(table_row_list,
+                                                           has_header_rows=has_header_rows)
 
     # clear original table 
     parent_paragraph = target_table.getparent()
@@ -449,21 +442,21 @@ class ODFStrategy(Implicit):
       listbox_column_list = listboxline.getColumnItemList()
       if listboxline.isTitleLine() and not has_header_rows:
         row = deepcopy(row_top)
-        row = self._update_column_value(row, listbox_column_list)
+        row = self._updateColumnValue(row, listbox_column_list)
         newtable.append(row)
         is_top = False       
       elif listboxline.isDataLine() and is_top:
         row = deepcopy(row_top)
-        row = self._update_column_value(row, listbox_column_list)
+        row = self._updateColumnValue(row, listbox_column_list)
         newtable.append(row)
         is_top = False
       elif listboxline.isStatLine() or index is last_index:
         row = deepcopy(row_bottom)
-        row = self._update_column_stat_value(row, listbox_column_list, row_middle)
+        row = self._updateColumnStatValue(row, listbox_column_list, row_middle)
         newtable.append(row)
       elif index > 0 and listboxline.isDataLine():
         row = deepcopy(row_middle)
-        row = self._update_column_value(row, listbox_column_list)
+        row = self._updateColumnValue(row, listbox_column_list)
         newtable.append(row)
 
     # direct listbox mapping
@@ -472,10 +465,10 @@ class ODFStrategy(Implicit):
     else:
       # report section iteration
       parent_paragraph.append(newtable)
-      
+
     return element_tree
 
-  def _copy_row_style(self, table_row_list=[], has_header_rows=False):
+  def _copyRowStyle(self, table_row_list=[], has_header_rows=False):
     row_top = None
     row_middle = None
     row_bottom = None
@@ -497,42 +490,44 @@ class ODFStrategy(Implicit):
         row_middle = deepcopy(table_row_list[1])
         row_bottom = deepcopy(table_row_list[-1])
     return (row_top, row_middle, row_bottom)
-  
-  def _update_column_value(self, row=None, listbox_column_list=[]):
-    odf_cell_list = row.findall("{%s}table-cell" % NAME_SPACE_DICT['table'])
+
+  def _updateColumnValue(self, row=None, listbox_column_list=[]):
+    odf_cell_list = row.findall("{%s}table-cell" % row.nsmap['table'])
     odf_cell_list_size = len(odf_cell_list)
     listbox_column_size = len(listbox_column_list)
     for (column_index, column) in enumerate(odf_cell_list):
       if column_index >= listbox_column_size:
         break
       value = listbox_column_list[column_index][1]
-      self._set_column_value(column, value)
+      self._setColumnValue(column, value)
     return row
 
-  def _update_column_stat_value(self, row=None, listbox_column_list=[], row_middle=None):
+  def _updateColumnStatValue(self, row=None, listbox_column_list=[], row_middle=None):
     """stat line is capable of column span setting"""
     if row_middle is None:
       return row
-    odf_cell_list = row.findall("{%s}table-cell" % NAME_SPACE_DICT['table'])
-    odf_column_span_list = self._get_odf_column_span_list(row_middle)
+    odf_cell_list = row.findall("{%s}table-cell" % row.nsmap['table'])
+    odf_column_span_list = self._getOdfColumnSpanList(row_middle)
     listbox_column_size = len(listbox_column_list)
     listbox_column_index = 0
     for (column_index, column) in enumerate(odf_cell_list):
       if listbox_column_index >= listbox_column_size:
         break
       value = listbox_column_list[listbox_column_index][1]
-      self._set_column_value(column, value)
-      column_span = self._get_column_span_size(column)
-      listbox_column_index = self._next_listbox_column_index(column_span,
-                                                             listbox_column_index,
-                                                             odf_column_span_list)
+      self._setColumnValue(column, value)
+      column_span = self._getColumnSpanSize(column)
+      listbox_column_index = self._nextListboxColumnIndex(column_span,
+                                                          listbox_column_index,
+                                                          odf_column_span_list)
     return row
 
-  def _set_column_value(self, column, value):
-    self._clear_column_value(column)
+  def _setColumnValue(self, column, value):
+    self._clearColumnValue(column)
     if value is None:
       value = ''
-      self._remove_column_value(column)
+      self._removeColumnValue(column)
+    if isinstance(value, DateTime):
+      value = value.strftime('%Y-%m-%d')
     column_value = unicode(str(value),'utf-8')
     column.text = column_value
     column_children = column.getchildren()
@@ -545,47 +540,47 @@ class ODFStrategy(Implicit):
     if first_child is not None:
       column.append(first_child)
     if column_value != '':
-      value_attribute = self._get_column_value_attribute(column)
+      value_attribute = self._getColumnValueAttribute(column)
       if value_attribute is not None:
         column.set(value_attribute, column_value)
 
-  def _remove_column_value(self, column):
+  def _removeColumnValue(self, column):
     # to eliminate a default value, remove "office:*" attributes.
     # if remaining these attribetes, the column shows its default value,
     # such as '0.0', '$0'
     attrib = column.attrib
     for key in attrib.keys():
-      if key.startswith("{%s}" % NAME_SPACE_DICT['office']):
+      if key.startswith("{%s}" % column.nsmap['office']):
         del attrib[key]
     column_children = column.getchildren()
     for child in column_children:
       column.remove(child)
 
-  def _clear_column_value(self, column):
+  def _clearColumnValue(self, column):
     attrib = column.attrib
     for key in attrib.keys():
-      value_attribute = self._get_column_value_attribute(column)
+      value_attribute = self._getColumnValueAttribute(column)
       if value_attribute is not None:
         column.set(value_attribute, '')
     column_children = column.getchildren()
     for child in column_children:
       child.text = ''
 
-  def _get_column_value_attribute(self, column):
+  def _getColumnValueAttribute(self, column):
     attrib = column.attrib
     for key in attrib.keys():
       if key.endswith("value"):
         return key
     return None
-           
-  def _get_column_span_size(self, column=None):
-    span_attribute = "{%s}number-columns-spanned" % NAME_SPACE_DICT['table']
+
+  def _getColumnSpanSize(self, column=None):
+    span_attribute = "{%s}number-columns-spanned" % column.nsmap['table']
     column_span = 1
     if column.attrib.has_key(span_attribute):
       column_span = int(column.attrib[span_attribute])
     return column_span
-  
-  def _next_listbox_column_index(self, span=0, current_index=0, column_span_list=[]):
+
+  def _nextListboxColumnIndex(self, span=0, current_index=0, column_span_list=[]):
     hops = 0
     index = current_index
     while hops < span:
@@ -593,18 +588,17 @@ class ODFStrategy(Implicit):
       hops += column_span
       index += 1
     return index
-  
-  def _get_odf_column_span_list(self, row_middle=None):
+
+  def _getOdfColumnSpanList(self, row_middle=None):
     if row_middle is None:
       return []
-    odf_cell_list = row_middle.findall("{%s}table-cell" % NAME_SPACE_DICT['table'])
+    odf_cell_list = row_middle.findall("{%s}table-cell" % row_middle.nsmap['table'])
     column_span_list = []
     for column in odf_cell_list:
-      column_span = self._get_column_span_size(column)
+      column_span = self._getColumnSpanSize(column)
       column_span_list.append(column_span)
     return column_span_list
 
 class ODTStrategy(ODFStrategy):
   """ODTStrategy create a ODT Document from a form and a ODT template"""
   pass
-
diff --git a/product/ERP5OOo/tests/testFormPrintout.py b/product/ERP5OOo/tests/testFormPrintout.py
index 7ae0d4793b..ca5da1644a 100644
--- a/product/ERP5OOo/tests/testFormPrintout.py
+++ b/product/ERP5OOo/tests/testFormPrintout.py
@@ -31,10 +31,10 @@ from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
 from AccessControl.SecurityManagement import newSecurityManager
 from Products.ERP5OOo.OOoUtils import OOoBuilder
 from zLOG import LOG , INFO
+from lxml import etree
 import os
 
 class TestFormPrintout(ERP5TypeTestCase):
-  quiet = 1
   run_all_test = 1
 
   def getTitle(self):
@@ -67,7 +67,6 @@ class TestFormPrintout(ERP5TypeTestCase):
                              ooo_stylesheet='Foo_getODTStyleSheet')
     #Foo_viewAsOdt.pt_upload(request, file=foo_file)
     #render_result = Foo_viewAsOdt(REQUEST=request)
-    #LOG('testFormPrintout render_result:', INFO, render_result)
     builder = OOoBuilder(foo_file)
     content = builder.extract('content.xml')
     Foo_viewAsOdt.pt_edit(content, content_type='application/vnd.oasis.opendocument.text')
@@ -75,16 +74,30 @@ class TestFormPrintout(ERP5TypeTestCase):
       erp5OOo.addFormPrintout(id='Foo_viewAsPrintout', title='',
                               form_name='Foo_view', template='Foo_getODTStyleSheet')
 
+    ## append 'test1' data to a listbox
+    foo_module = self.portal.foo_module
+    if foo_module._getOb('test1', None) is None:
+      foo_module.newContent(id='test1', portal_type='Foo')
+    test1 =  foo_module.test1
+    if test1._getOb("foo_1", None) is None:
+      test1.newContent("foo_1", portal_type='Foo Line')
+    if test1._getOb("foo_2", None) is None:
+      test1.newContent("foo_2", portal_type='Foo Line')
+    get_transaction().commit()
+    self.tic()
+    
   def login(self):
     uf = self.getPortal().acl_users
     uf._doAddUser('tatuya', '', ['Manager'], [])
     user = uf.getUserById('tatuya').__of__(uf)
     newSecurityManager(None, user)
                           
-  def test_01_Paragraph(self, quiet=0, run=run_all_test):
+  def test_01_Paragraph(self, run=run_all_test):
     """
     mapping a field to a paragraph
     """
+    if not run: return
+    
     portal = self.getPortal()
     foo_module = self.portal.foo_module
     if foo_module._getOb('test1', None) is None:
@@ -139,63 +152,44 @@ class TestFormPrintout(ERP5TypeTestCase):
       self.assertTrue(True)
 
 
-  def test_02_Table(self, quiet=0, run=run_all_test):
-    """
-    To test mapping a listbox(Form) to a table(ODF)
+  def test_02_Table_01_Normal(self, run=run_all_test):
+    """To test listbox and ODF table mapping
+    
+     * Test Data Format
+    
+     ODF table named 'listbox':
+     +------------------------------+
+     |  ID | Title | Quantity |Date |
+     |-----+-------+----------+-----|
+     |     |       |          |     |
+     |-----+-------+----------+-----|
+     |   Total     |          |     |
+     +------------------------------+
     """
-    portal = self.getPortal()
-    ## append 'test1' data to a listbox
-    foo_module = self.portal.foo_module
-    if foo_module._getOb('test1', None) is None:
-      foo_module.newContent(id='test1', portal_type='Foo')
-    test1 =  foo_module.test1
-    if test1._getOb("foo_1", None) is None:
-      test1.newContent("foo_1", portal_type='Foo Line')
-    get_transaction().commit()
-    self.tic()
     # test target
-    foo_printout = portal.foo_module.test1.Foo_viewAsPrintout
-
-    # Test Data format
-    #
-    # * ODF table named 'listbox':
-    # +------------------------------+
-    # |  ID | Title | Quantity |Date |
-    # |-----+-------+----------+-----|
-    # |     |       |          |     |
-    # |-----+-------+----------+-----|
-    # |   Total     |          |     |
-    # +------------------------------+
-    #
-    # * ODF table named 'listbox2':
-    # +-------------------------------+
-    # |  A    |   B   |   C   |   D   |
-    # |-------+-------+-------+-------|
-    # |       |       |       |       |
-    # +-------+-------+-------+-------+
-    #
-    # * ODF table named 'listbox3':
-    # the table listbox3 has not table header.
-    # first row is table content, too.
-    # +-------------------------------+
-    # |  1    |   2   |   3   |   4   |
-    # |-------+-------+-------+-------|
-    # |       |       |       |       |
-    # +-------+-------+-------+-------+
-    # 
-
-    # 1. Normal Case: ODF table last row is stat line
-    test1.foo_1.setTitle('foo_title_1')
+    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
+    
+    # 1. Normal Case: ODF table last row is stat line
+    test1.foo_1.setTitle('foo_title_1')
+    message = listbox.ListBox_setPropertyList(
+      field_list_method = 'objectValues',
+      field_portal_types = 'Foo Line | Foo Line',
+      field_stat_method = 'portal_catalog',
+      field_stat_columns = 'quantity | Foo_statQuantity',
+      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)
-    self.assertEqual(len(listboxline_list), 3)
+    self.assertEqual(len(listboxline_list), 4)
     self.assertTrue(listboxline_list[0].isTitleLine())
     self.assertTrue(listboxline_list[1].isDataLine())
-    self.assertTrue(listboxline_list[2].isStatLine())
+    self.assertTrue(listboxline_list[2].isDataLine())
+    self.assertTrue(listboxline_list[3].isStatLine())
     column_list = listboxline_list[0].getColumnPropertyList()
     self.assertEqual(len(column_list), 4)
     self.assertTrue(listboxline_list[1].getColumnProperty('id') == "foo_1")
@@ -209,7 +203,17 @@ class TestFormPrintout(ERP5TypeTestCase):
     content_xml = builder.extract("content.xml")
     self.assertTrue(content_xml.find("foo_title_1") > 0)
 
-    # 2. Irregular case: listbox columns count smaller than table columns count
+  def test_02_Table_02_SmallerThanListboxColumns(self, run=run_all_test):
+    """2. Irregular case: listbox columns count smaller than table columns count"""
+    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_2')
     message = listbox.ListBox_setPropertyList(
       field_list_method = 'objectValues',
@@ -222,10 +226,11 @@ class TestFormPrintout(ERP5TypeTestCase):
                      [('id', 'ID'), ('title', 'Title'), ('quantity', 'Quantity')])
     listboxline_list = listbox.get_value('default', render_format = 'list',
                                          REQUEST = request)
-    self.assertEqual(len(listboxline_list), 3)
+    self.assertEqual(len(listboxline_list), 4)
     self.assertTrue(listboxline_list[0].isTitleLine())
     self.assertTrue(listboxline_list[1].isDataLine())
-    self.assertTrue(listboxline_list[2].isStatLine())
+    self.assertTrue(listboxline_list[2].isDataLine())
+    self.assertTrue(listboxline_list[3].isStatLine())
     self.assertTrue(listboxline_list[1].getColumnProperty('title') == "foo_title_2")
     
     column_list = listboxline_list[0].getColumnPropertyList()
@@ -240,7 +245,17 @@ class TestFormPrintout(ERP5TypeTestCase):
     self.assertFalse(content_xml.find("foo_title_1") > 0)
     self.assertTrue(content_xml.find("foo_title_2") > 0)
 
-    # 3. Irregular case: listbox columns count larger than table columns count
+  def test_02_Table_03_ListboxColumnsLargerThanTable(self, run=run_all_test):
+    """3. Irregular case: listbox columns count larger than table columns count"""
+    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_3')
     message = listbox.ListBox_setPropertyList(
       field_list_method = 'objectValues',
@@ -252,13 +267,12 @@ class TestFormPrintout(ERP5TypeTestCase):
     self.failUnless('Set Successfully' in message)
     listboxline_list = listbox.get_value('default', render_format = 'list',
                                          REQUEST = request)
-    self.assertEqual(len(listboxline_list), 3)
+    self.assertEqual(len(listboxline_list), 4)
     self.assertTrue(listboxline_list[1].getColumnProperty('title') == "foo_title_3")
     
     column_list = listboxline_list[0].getColumnPropertyList()
     self.assertEqual(len(column_list), 5)
     odf_document = foo_printout.index_html(REQUEST=request)
-    LOG('testFormPrintout', INFO, 'content:%s' % content_xml)
     #test_output = open("/tmp/test_02_03_Table.odf", "w")
     #test_output.write(odf_document)
     self.assertTrue(odf_document is not None)
@@ -267,13 +281,19 @@ class TestFormPrintout(ERP5TypeTestCase):
     self.assertFalse(content_xml.find("foo_title_2") > 0)
     self.assertTrue(content_xml.find("foo_title_3") > 0)
 
-    # 4. Irregular case: listbox has not a stat line, but table has a stat line
-    if test1._getOb("foo_2", None) is None:
-      test1.newContent("foo_2", portal_type='Foo Line')
-    get_transaction().commit()
-    self.tic()
+  def test_02_Table_04_ListboxHasNotStat(self, run=run_all_test):
+    """4. Irregular case: listbox has not a stat line, but table has a stat line"""
+    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_4')
+    test1.foo_1.setStartDate('2009-01-01')
     message = listbox.ListBox_setPropertyList(
       field_list_method = 'objectValues',
       field_portal_types = 'Foo Line | Foo Line',
@@ -297,7 +317,41 @@ class TestFormPrintout(ERP5TypeTestCase):
     self.assertFalse(content_xml.find("foo_title_3") > 0)
     self.assertTrue(content_xml.find("foo_title_4") > 0)
 
-    # 5. Normal case: the listobx and the ODF table are same layout
+    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)
+    self.assertEqual(len(odf_table_rows), 2)
+    # to test copying ODF table cell styles 
+    first_row = odf_table_rows[0]
+    first_row_columns = first_row.getchildren()
+    last_row = odf_table_rows[-1]
+    last_row_columns = last_row.getchildren()
+    span_attribute = "{%s}number-columns-spanned" % content.nsmap['table']
+    self.assertFalse(first_row_columns[0].attrib.has_key(span_attribute))
+    self.assertEqual(int(last_row_columns[0].attrib[span_attribute]), 2)
+
+  def test_02_Table_05_NormalSameLayout(self, run=run_all_test):
+    """5. Normal case: the listobx and the ODF table are same layout
+
+    * Test Data Format:
+    
+     ODF table named 'listbox2'
+     +-------------------------------+
+     |  A    |   B   |   C   |   D   |
+     |-------+-------+-------+-------|
+     |       |       |       |       |
+     +-------+-------+-------+-------+
+    """
+    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
+
     foo_form.manage_renameObject('listbox', 'listbox2', REQUEST=request)
     listbox2 = foo_form.listbox2
     test1.foo_1.setTitle('foo_title_5')
@@ -325,15 +379,44 @@ class TestFormPrintout(ERP5TypeTestCase):
     # put back the field name
     foo_form.manage_renameObject('listbox2', 'listbox', REQUEST=request)
 
-    # 6. Normal case: ODF table does not have a header
+    
+  def test_02_Table_06_TableDoesNotHaveAHeader(self, run=run_all_test):
+    """6. Normal case: ODF table does not have a header
+     * Test Data format:
+    
+     ODF table named 'listbox3'
+     the table listbox3 has not table header.
+     first row is a table content, too.
+     +-------------------------------+
+     |  1    |   2   |   3   |   4   |
+     |-------+-------+-------+-------|
+     |       |       |       |       |
+     +-------+-------+-------+-------+
+    """
+    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
+
     foo_form.manage_renameObject('listbox', 'listbox3', REQUEST=request)
     listbox3 = foo_form.listbox3
     test1.foo_1.setTitle('foo_title_6')
+    message = listbox3.ListBox_setPropertyList(
+      field_list_method = 'objectValues',
+      field_portal_types = 'Foo Line | Foo Line',
+      field_stat_method = 'portal_catalog',
+      field_stat_columns = 'quantity | Foo_statQuantity',
+      field_columns = 'id|ID\ntitle|Title\nquantity|Quantity\nstart_date|Date',)
+    self.failUnless('Set Successfully' in message)
     listboxline_list = listbox3.get_value('default', render_format = 'list',
                                          REQUEST = request)
     self.assertEqual(len(listboxline_list), 4)
     self.assertTrue(listboxline_list[1].getColumnProperty('title') == "foo_title_6")
-
+    
     odf_document = foo_printout.index_html(REQUEST=request)
     #test_output = open("/tmp/test_02_06_Table.odf", "w")
     #test_output.write(odf_document)
@@ -346,26 +429,74 @@ class TestFormPrintout(ERP5TypeTestCase):
     # put back the field name
     foo_form.manage_renameObject('listbox3', 'listbox', REQUEST=request)
 
-  def _test_03_Frame(self, quiet=0, run=run_all_test):
+  def test_02_Table_07_CellFormat(self, run=run_all_test):
+    """7. Normal case: cell format cetting"""
+    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_7')
+    test1.foo_1.setStartDate('2009-04-20')
+    message = listbox.ListBox_setPropertyList(
+      field_list_method = 'objectValues',
+      field_portal_types = 'Foo Line | Foo Line',
+      field_stat_method = 'portal_catalog',
+      field_stat_columns = 'quantity | Foo_statQuantity',
+      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)
+    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")
+    #test_output.write(odf_document)
+    self.assertTrue(odf_document is not None)
+    builder = OOoBuilder(odf_document)
+    content_xml = builder.extract("content.xml")
+    self.assertFalse(content_xml.find("foo_title_6") > 0)
+    self.assertTrue(content_xml.find("foo_title_7") > 0)
+
+    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]
+    first_row_columns = first_row.getchildren()
+    date_column = first_row_columns[3]
+    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_03_Frame(self, run=run_all_test):
     """
     Frame not supported yet
     """
     pass
 
-  def _test_04_Iteration(self, quiet=0, run=run_all_test):
+  def _test_04_Iteration(self, run=run_all_test):
     """
     Iteration(ReportSection) not supported yet.
     Probably to support *ReportBox* would be better.
     """
     pass
 
-  def _test_05_Styles(self, quiet=0, run=run_all_test):
+  def _test_05_Styles(self, run=run_all_test):
     """
     styles.xml not supported yet
     """
     pass
 
-  def _test_06_Meta(self, quiet=0, run=run_all_test):
+  def _test_06_Meta(self, run=run_all_test):
     """
     meta.xml not supported yet
     """
-- 
2.30.9