Commit e57cb147 authored by Tatuya Kamada's avatar Tatuya Kamada

* Clean up the code and the comments

* Append functions
  - styles.xml support
  - experimental FormBox support
  - experimental ReportSection support
* Fix 
  the table column attribute name was wrong



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@26306 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 407d2f8a
......@@ -30,6 +30,8 @@ from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.CMFCore.utils import _checkPermission, getToolByName
from Products.ERP5Type import PropertySheet, Permissions
from Products.ERP5Form.ListBox import ListBox
from Products.ERP5Form.FormBox import FormBox
from Products.ERP5Form.ImageField import ImageField
from Products.ERP5OOo.OOoUtils import OOoBuilder
from Acquisition import Implicit
......@@ -73,7 +75,7 @@ def add_and_edit(self, id, REQUEST):
'Add and Edit' button is pressed.
Keyword arguments:
id -- id of the object we just added
id -- the id of the object we just added
"""
if REQUEST is None:
return
......@@ -90,7 +92,7 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item):
The Form Printout enables to create a ODF document.
The Form Printout receives a name of a ERP5 form, and a template name.
The Form Printout receives an ERP5 form name, and a template name.
Using their parameters, the Form Printout genereate a ODF document,
a form as a ODF document content, and a template as a document layout.
......@@ -133,10 +135,6 @@ class FormPrintout(Implicit, Persistent, RoleManager, Item):
template = None
form_name = None
def __str__(self): return self.index_html()
def __len__(self): return 1
def __init__(self, id, title='', form_name='', template=''):
"""Initialize id, title, form_name, template.
......@@ -209,16 +207,17 @@ 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'}
'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 odt document, form as a content, template as a template.
"""Render a odf document, form as a content, template as a template.
Keyword arguments:
extra_context -- a dictionary, guess contains
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
......@@ -226,7 +225,6 @@ class ODFStrategy(Implicit):
"""
here = extra_context['here']
if here is None:
# This is a system error
raise ValueError, 'Can not create a ODF Document without a parent acquisition context'
form = extra_context['form']
if not extra_context.has_key('printout_template') or extra_context['printout_template'] is None:
......@@ -234,12 +232,12 @@ class ODFStrategy(Implicit):
odf_template = extra_context['printout_template']
# First, render a OOoTemplate itself with its style
# First, render the Template if it has a pt_render method
ooo_document = None
if hasattr(odf_template, 'pt_render'):
ooo_document = odf_template.pt_render(here, extra_context=extra_context)
else:
# File object, OOoBuilder directly support a file object
# File object can be a template
ooo_document = odf_template
# Create a new builder instance
......@@ -247,8 +245,9 @@ class ODFStrategy(Implicit):
# content.xml
ooo_builder = self._replace_content_xml(ooo_builder=ooo_builder, extra_context=extra_context)
# styles.xml and meta.xml are not supported yet
# ooo_builder = self._replace_styles_xml(ooo_builder=ooo_builder, extra_context=extra_context)
# styles.xml
ooo_builder = self._replace_styles_xml(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)
# Update the META informations
......@@ -258,25 +257,25 @@ class ODFStrategy(Implicit):
return ooo
def _replace_content_xml(self, ooo_builder=None, extra_context=None):
doc_xml = ooo_builder.extract('content.xml')
content_xml = ooo_builder.extract('content.xml')
# mapping ERP5Form to ODF
form = extra_context['form']
here = getattr(self, 'aq_parent', None)
ordinaly_group_list = [group for group in form.get_groups() if group not in ['meta','style']]
doc_xml = self._replace_xml_by_form(doc_xml=doc_xml,
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,
group_list=ordinaly_group_list)
extra_context=extra_context)
# mapping ERP5Report report method to ODF
doc_xml = self._replace_xml_by_report_section(doc_xml=doc_xml,
content_element_tree = self._replace_xml_by_report_section(element_tree=content_element_tree,
extra_context=extra_context)
if isinstance(doc_xml, unicode):
doc_xml = doc_xml.encode('utf-8')
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', doc_xml)
ooo_builder.replace('content.xml', content_xml)
return ooo_builder
# this method not supported yet
......@@ -284,19 +283,19 @@ class ODFStrategy(Implicit):
"""
replacing styles.xml file in a ODF document
"""
doc_xml = ooo_builder.extract('styles.xml')
styles_xml = ooo_builder.extract('styles.xml')
form = extra_context['form']
here = getattr(self, 'aq_parent', None)
doc_xml = self._replace_xml_by_form(doc_xml=doc_xml,
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,
group_list=['styles'])
if isinstance(doc_xml, unicode):
doc_xml = doc_xml.encode('utf-8')
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', doc_xml)
ooo_builder.replace('styles.xml', styles_xml)
return ooo_builder
# this method not implemented yet
......@@ -304,54 +303,60 @@ class ODFStrategy(Implicit):
"""
replacing meta.xml file in a ODF document
"""
doc_xml = ooo_builder.extract('meta.xml')
meta_xml = ooo_builder.extract('meta.xml')
if isinstance(doc_xml, unicode):
doc_xml = doc_xml.encode('utf-8')
meta_xml = meta_xml.encode('utf-8')
ooo_builder.replace('meta.xml', doc_xml)
ooo_builder.replace('meta.xml', meta_xml)
return ooo_builder
def _replace_xml_by_form(self, doc_xml=None, form=None, here=None,
group_list=[], extra_context=None):
field_list = [f for g in group_list for f in form.get_fields_in_group(g)]
content = etree.XML(doc_xml)
def _replace_xml_by_form(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):
for (count, field) in enumerate(field_list):
if isinstance(field, ListBox):
content = self._append_table_by_listbox(content=content,
element_tree = self._append_table_by_listbox(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)
#elif isinstance(field, ImageField):
# element_tree = self._replace_xml_by_image_field(element_tree=element_tree,
# image_field=field)
else:
field_value = field.get_value('default')
content = self._replace_node_via_reference(content=content,
field_id=field.id,
field_value=field_value)
return etree.tostring(content)
element_tree = self._replace_node_via_reference(element_tree=element_tree,
field=field)
return element_tree
def _replace_node_via_reference(self, content=None, field_id=None, field_value=None):
def _replace_node_via_reference(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 = content.xpath(reference_xpath, namespaces=NAME_SPACE_DICT)
reference_list = element_tree.xpath(reference_xpath, namespaces=NAME_SPACE_DICT)
if len(reference_list) > 0:
node = reference_list[0].getparent()
## remove such a "bbb"
## <text:p>aaa<br/>bbb</text:p>
# remove such a "bbb": <text:p>aaa<br/>bbb</text:p>
for child in node.getchildren():
child.tail = ''
node.text = field_value
return content
return element_tree
def _replace_xml_by_report_section(self, doc_xml=None, extra_context=None):
def _replace_xml_by_report_section(self, element_tree=None, extra_context=None):
if not extra_context.has_key('report_method') or extra_context['report_method'] is None:
return doc_xml
return element_tree
report_method = extra_context['report_method']
report_section_list = report_method()
portal_object = self.getPortalObject()
content = etree.XML(doc_xml)
REQUEST = get_request()
request = extra_context.get('REQUEST', REQUEST)
render_prefix = None
for (index, report_item) in enumerate(report_section_list):
if index > 0:
......@@ -360,31 +365,55 @@ class ODFStrategy(Implicit):
here = report_item.getObject(portal_object)
form_id = report_item.getFormId()
form = getattr(here, form_id)
for field in form.get_fields():
if field.meta_type == 'ListBox':
content = self._append_table_by_listbox(content=content,
listbox=field,
REQUEST=request,
element_tree = self._replace_xml_by_form(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):
draw_xpath = '//draw:frame[@draw:name="%s"]/draw:text-box/*' % field_id
text_list = element_tree.xpath(draw_xpath, namespaces=NAME_SPACE_DICT)
if len(text_list) == 0:
return element_tree
parent = text_list[0].getparent()
parent.clear()
# this form.__call__() possibly has a side effect,
# so must clear the 'here' context for listBox.get_value()
box = form(REQUEST=REQUEST);
REQUEST.set('here', None)
node = etree.XML(box)
# TODO style_copy
if node is not None:
for child in node.getchildren():
parent.append(child)
return element_tree
return etree.tostring(content)
def _replace_xml_by_image_field(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)
if len(image_list) > 0:
image_list[0].set("{%s}href" % NAME_SPACE_DICT['xlink'], image_field.absolute_url())
return element_tree
def _append_table_by_listbox(self,
content=None,
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 = content.xpath(table_xpath, namespaces=NAME_SPACE_DICT)
target_table_list = element_tree.xpath(table_xpath, namespaces=NAME_SPACE_DICT)
if len(target_table_list) is 0:
return content
return element_tree
target_table = target_table_list[0]
newtable = deepcopy(target_table)
# <table:table-header-rows>
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)
......@@ -392,7 +421,6 @@ class ODFStrategy(Implicit):
# copy row styles from ODF Document
has_header_rows = len(table_header_rows_list) > 0
LOG('FormPrintout has_header_rows', INFO, has_header_rows)
(row_top, row_middle, row_bottom) = self._copy_row_style(table_row_list,
has_header_rows=has_header_rows)
......@@ -411,8 +439,8 @@ class ODFStrategy(Implicit):
REQUEST=REQUEST,
render_prefix=render_prefix)
# if ODF table has heder rows, does not update the header rows
# if ODF table does not have header rows, insert the listbox title line
# if ODF table has header rows, does not update the header rows
# if does not have header rows, insert the listbox title line
is_top = True
for (index, listboxline) in enumerate(listboxline_list):
listbox_column_list = listboxline.getColumnItemList()
......@@ -441,9 +469,8 @@ class ODFStrategy(Implicit):
else:
# report section iteration
parent_paragraph.append(newtable)
# TODO: it would be better append a paragraph or linebreak
return content
return element_tree
def _copy_row_style(self, table_row_list=[], has_header_rows=False):
row_top = None
......@@ -490,7 +517,7 @@ class ODFStrategy(Implicit):
if listbox_column_index >= listbox_column_size:
break
value = listbox_column_list[listbox_column_index][1]
# if value is None, remaining ODF orinal text
# if value is None, remaining the ODF original text
if value is not None:
self._set_column_value(column, value)
column_span = self._get_column_span_size(column)
......@@ -502,7 +529,7 @@ class ODFStrategy(Implicit):
def _set_column_value(self, column, value):
if value is None:
# to eliminate a default value, remove "office:*" attributes.
# if remaining "office:*" attribetes, the column shows its default value,
# if remaining these attribetes, the column shows its default value,
# such as '0.0', '$0'
attrib = column.attrib
for key in attrib.keys():
......@@ -512,10 +539,24 @@ class ODFStrategy(Implicit):
column_value = unicode(str(value),'utf-8')
column.text = column_value
column_children = column.getchildren()
first_child = None
if len(column_children) > 0:
column_children[0].text = column_value
first_child = deepcopy(column_children[0])
first_child.text = column_value
for child in column_children:
column.remove(child)
column.append(first_child)
if column_value != '':
column.set("{%s}value" % NAME_SPACE_DICT['office'], column_value)
value_attribute = self._get_column_value_attribute(column)
if value_attribute is not None:
column.set(value_attribute, column_value)
def _get_column_value_attribute(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']
......@@ -538,7 +579,6 @@ class ODFStrategy(Implicit):
return []
odf_cell_list = row_middle.findall("{%s}table-cell" % NAME_SPACE_DICT['table'])
column_span_list = []
span_attribute = "{%s}number-columns-spanned" % NAME_SPACE_DICT['table']
for column in odf_cell_list:
column_span = self._get_column_span_size(column)
column_span_list.append(column_span)
......
......@@ -27,11 +27,8 @@
##############################################################################
import unittest
from threading import Thread
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Form.Selection import Selection
from Products.ERP5Form.SelectionTool import SelectionTool
from Products.ERP5OOo.OOoUtils import OOoBuilder
from zLOG import LOG , INFO
import os
......@@ -270,7 +267,7 @@ 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 have not a stat line, but table has a stat line
# 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()
......@@ -300,7 +297,7 @@ 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 of a form and the ODF table are same layout
# 5. Normal case: the listobx and the ODF table are same layout
foo_form.manage_renameObject('listbox', 'listbox2', REQUEST=request)
listbox2 = foo_form.listbox2
test1.foo_1.setTitle('foo_title_5')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment