1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 package com.sun.star.report.pentaho.output;
24 
25 import com.sun.star.report.DataSourceFactory;
26 import com.sun.star.report.ImageService;
27 import com.sun.star.report.InputRepository;
28 import com.sun.star.report.OfficeToken;
29 import com.sun.star.report.OutputRepository;
30 import com.sun.star.report.ReportEngineParameterNames;
31 import com.sun.star.report.SDBCReportDataFactory;
32 import com.sun.star.report.pentaho.OfficeNamespaces;
33 import com.sun.star.report.pentaho.layoutprocessor.ImageElementContext;
34 import com.sun.star.report.pentaho.model.OfficeDocument;
35 import com.sun.star.report.pentaho.model.OfficeStyle;
36 import com.sun.star.report.pentaho.model.OfficeStyles;
37 import com.sun.star.report.pentaho.model.OfficeStylesCollection;
38 import com.sun.star.report.pentaho.styles.LengthCalculator;
39 import com.sun.star.report.pentaho.styles.StyleMapper;
40 import com.sun.org.apache.xerces.internal.parsers.DOMParser;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 import javax.xml.transform.OutputKeys;
44 import javax.xml.transform.Transformer;
45 import javax.xml.transform.TransformerFactory;
46 import javax.xml.transform.dom.DOMSource;
47 import javax.xml.transform.stream.StreamResult;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.Node;
50 import org.w3c.dom.NodeList;
51 import org.xml.sax.InputSource;
52 
53 import java.awt.Image;
54 
55 import java.io.BufferedReader;
56 import java.io.ByteArrayInputStream;
57 import java.io.IOException;
58 import java.io.InputStreamReader;
59 import java.io.OutputStream;
60 import java.io.OutputStreamWriter;
61 import java.io.Reader;
62 import java.io.StringReader;
63 import java.io.StringWriter;
64 import java.io.Writer;
65 import java.io.InputStream;
66 
67 import java.util.ArrayList;
68 import java.util.Iterator;
69 import java.util.Map;
70 import java.util.zip.DeflaterOutputStream;
71 import java.util.zip.InflaterInputStream;
72 
73 import org.apache.commons.logging.Log;
74 import org.apache.commons.logging.LogFactory;
75 
76 import org.jfree.layouting.input.style.parser.CSSValueFactory;
77 import org.jfree.layouting.input.style.parser.StyleSheetParserUtil;
78 import org.jfree.layouting.input.style.values.CSSNumericType;
79 import org.jfree.layouting.input.style.values.CSSNumericValue;
80 import org.jfree.layouting.layouter.style.CSSValueResolverUtility;
81 import org.jfree.layouting.namespace.NamespaceDefinition;
82 import org.jfree.layouting.namespace.Namespaces;
83 import org.jfree.layouting.util.AttributeMap;
84 import org.jfree.layouting.util.LazyAttributeMap;
85 import org.jfree.report.DataFlags;
86 import org.jfree.report.DataSourceException;
87 import org.jfree.report.JFreeReportBoot;
88 import org.jfree.report.JFreeReportInfo;
89 import org.jfree.report.ReportProcessingException;
90 import org.jfree.report.flow.AbstractReportTarget;
91 import org.jfree.report.flow.ReportJob;
92 import org.jfree.report.flow.ReportStructureRoot;
93 import org.jfree.report.flow.ReportTargetUtil;
94 import org.jfree.report.structure.Element;
95 import org.jfree.report.structure.Section;
96 import org.jfree.report.util.AttributeNameGenerator;
97 import org.jfree.report.util.IntegerCache;
98 import org.jfree.report.util.MemoryByteArrayOutputStream;
99 
100 import org.pentaho.reporting.libraries.base.util.FastStack;
101 import org.pentaho.reporting.libraries.base.util.IOUtils;
102 import org.pentaho.reporting.libraries.resourceloader.ResourceException;
103 import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
104 import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
105 import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
106 import org.pentaho.reporting.libraries.xmlns.writer.DefaultTagDescription;
107 import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
108 import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
109 
110 import org.w3c.css.sac.LexicalUnit;
111 
112 /**
113  * Todo: Document me!
114  *
115  * @author Thomas Morgner
116  * @since 08.03.2007
117  */
118 public abstract class OfficeDocumentReportTarget extends AbstractReportTarget
119 {
120 
121     protected static final Log LOGGER = LogFactory.getLog(OfficeDocumentReportTarget.class);
122     public static final String HORIZONTAL_POS = "horizontal-pos";
123     public static final String TAG_DEF_PREFIX = "com.sun.star.report.pentaho.output.";
124     public static final int ROLE_NONE = 0;
125     public static final int ROLE_REPORT_HEADER = 1;
126     public static final int ROLE_REPORT_FOOTER = 2;
127     public static final int ROLE_GROUP_HEADER = 3;
128     public static final int ROLE_GROUP_FOOTER = 4;
129     public static final int ROLE_REPEATING_GROUP_HEADER = 5;
130     public static final int ROLE_REPEATING_GROUP_FOOTER = 6;
131     public static final int ROLE_PAGE_HEADER = 7;
132     public static final int ROLE_PAGE_FOOTER = 8;
133     public static final int ROLE_DETAIL = 9;
134     public static final int ROLE_VARIABLES = 10;
135     public static final int ROLE_TEMPLATE = 11;
136     public static final int ROLE_SPREADSHEET_PAGE_HEADER = 12;
137     public static final int ROLE_SPREADSHEET_PAGE_FOOTER = 13;
138     public static final int STATE_IN_DOCUMENT = 0;
139     public static final int STATE_IN_BODY = 1;
140     public static final int STATE_IN_CONTENT = 2;
141     public static final int STATE_IN_GROUP = 3;
142     public static final int STATE_IN_GROUP_BODY = 4;
143     public static final int STATE_IN_SECTION = 5;
144     public static final int STATE_IN_OTHER = 6;
145     public static final int STATE_IN_GROUP_INSTANCE = 7;
146     public static final String FAILED = "Failed";
147     public static final String VERTICAL_POS = "vertical-pos";
148     private static final String ZERO_CM = "0cm";
149     /** the version of the ODF specification to which generated documents
150      *  shall conform. */
151     public static final String ODF_VERSION = "1.2";
152 
153     protected static class BufferState
154     {
155 
156         private final XmlWriter xmlWriter;
157         private final MemoryByteArrayOutputStream xmlBuffer;
158         private final OfficeStylesCollection stylesCollection;
159 
BufferState(final XmlWriter xmlWriter, final MemoryByteArrayOutputStream xmlBuffer, final OfficeStylesCollection stylesCollection)160         protected BufferState(final XmlWriter xmlWriter,
161                 final MemoryByteArrayOutputStream xmlBuffer,
162                 final OfficeStylesCollection stylesCollection)
163         {
164             this.stylesCollection = stylesCollection;
165             this.xmlWriter = xmlWriter;
166             this.xmlBuffer = xmlBuffer;
167         }
168 
getStylesCollection()169         public OfficeStylesCollection getStylesCollection()
170         {
171             return stylesCollection;
172         }
173 
getXmlWriter()174         public XmlWriter getXmlWriter()
175         {
176             return xmlWriter;
177         }
178 
getXmlBuffer()179         public String getXmlBuffer() throws ReportProcessingException
180         {
181             try
182             {
183                 final byte[] zippedData = xmlBuffer.getRaw();
184                 final InputStreamReader reader = new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
185                 final StringWriter writer = new StringWriter((zippedData.length / 2) + 1);
186                 IOUtils.getInstance().copyWriter(reader, writer);
187                 return writer.toString();
188             }
189             catch (IOException e)
190             {
191                 throw new ReportProcessingException("Failed to copy buffer", e);
192             }
193         }
194 
getXmlAsReader()195         public Reader getXmlAsReader() throws ReportProcessingException
196         {
197             try
198             {
199                 final byte[] zippedData = xmlBuffer.getRaw();
200                 return new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
201             }
202             catch (IOException e)
203             {
204                 throw new ReportProcessingException("Failed to copy buffer", e);
205             }
206         }
207     }
208 
209     protected static class GroupContext
210     {
211 
212         private final GroupContext parent;
213         private int iterationCount;
214         private boolean groupWithRepeatingSection;
215 
GroupContext(final GroupContext parent)216         protected GroupContext(final GroupContext parent)
217         {
218             this.parent = parent;
219         }
220 
getParent()221         public GroupContext getParent()
222         {
223             return parent;
224         }
225 
getIterationCount()226         public int getIterationCount()
227         {
228             return iterationCount;
229         }
230 
setIterationCount(final int iterationCount)231         public void setIterationCount(final int iterationCount)
232         {
233             this.iterationCount = iterationCount;
234         }
235 
isGroupWithRepeatingSection()236         public boolean isGroupWithRepeatingSection()
237         {
238             return groupWithRepeatingSection;
239         }
240 
setGroupWithRepeatingSection(final boolean groupWithRepeatingSection)241         public void setGroupWithRepeatingSection(final boolean groupWithRepeatingSection)
242         {
243             this.groupWithRepeatingSection = groupWithRepeatingSection;
244         }
245 
toString()246         public String toString()
247         {
248             return "GroupContext{" + "parent=" + parent + ", iterationCount=" + iterationCount + ", groupWithRepeatingSection=" + groupWithRepeatingSection + '}';
249         }
250     }
251     private final FastStack states;
252     private int currentRole;
253     private final FastStack xmlWriters;
254     private XmlWriter rootXmlWriter;
255     /**
256      * This styles-collection contains all styles that were predefined in the report definition file. The common styles
257      * and the master-styles will be written unmodified, the automatic styles will be ignored.
258      */
259     private OfficeStylesCollection predefinedStylesCollection;
260     /**
261      * This styles-collection contains all master-styles that have been generated by the report definition process. It
262      * also contains all automatic styles that have been generated for the page-bands (and the pagebands as well).
263      */
264     private OfficeStylesCollection globalStylesCollection;
265     /**
266      * The content styles collection contains all automatic styles that have been generated for the normal-flow content.
267      */
268     private OfficeStylesCollection contentStylesCollection;
269     private final OutputRepository outputRepository;
270     private final InputRepository inputRepository;
271     private final AttributeNameGenerator tableNameGenerator;
272     private final AttributeNameGenerator frameNameGenerator;
273     private final AttributeNameGenerator autoStyleNameGenerator;
274     private final String target;
275     private static final int INITIAL_BUFFER_SIZE = 40960;
276     private StyleMapper styleMapper;
277     private StyleSheetParserUtil styleSheetParserUtil;
278     private final AttributeNameGenerator imageNames;
279     private final ImageProducer imageProducer;
280     private final OleProducer oleProducer;
281     private GroupContext groupContext;
282     private static final boolean DEBUG_ELEMENTS =
283             JFreeReportBoot.getInstance().getExtendedConfig().getBoolProperty("com.sun.star.report.pentaho.output.DebugElements");
284 
OfficeDocumentReportTarget(final ReportJob reportJob, final ResourceManager resourceManager, final ResourceKey baseResource, final InputRepository inputRepository, final OutputRepository outputRepository, final String target, final ImageService imageService, final DataSourceFactory datasourcefactory)285     protected OfficeDocumentReportTarget(final ReportJob reportJob,
286             final ResourceManager resourceManager,
287             final ResourceKey baseResource,
288             final InputRepository inputRepository,
289             final OutputRepository outputRepository,
290             final String target,
291             final ImageService imageService,
292             final DataSourceFactory datasourcefactory)
293             throws ReportProcessingException
294     {
295         super(reportJob, resourceManager, baseResource);
296         if (imageService == null)
297         {
298             throw new NullPointerException("ImageService must not be null");
299         }
300         if (target == null)
301         {
302             throw new NullPointerException("Target-Name must not be null");
303         }
304 
305         this.target = target;
306 
307         this.tableNameGenerator = new AttributeNameGenerator();
308         this.frameNameGenerator = new AttributeNameGenerator();
309         this.autoStyleNameGenerator = new AttributeNameGenerator();
310         this.outputRepository = outputRepository;
311         this.inputRepository = inputRepository;
312         this.states = new FastStack();
313         this.xmlWriters = new FastStack();
314         this.imageNames = new AttributeNameGenerator();
315 
316         this.imageProducer = new ImageProducer(inputRepository, outputRepository, imageService);
317         this.oleProducer = new OleProducer(inputRepository, outputRepository, imageService, datasourcefactory, (Integer) reportJob.getParameters().get(ReportEngineParameterNames.MAXROWS));
318 
319         try
320         {
321             final ResourceManager realResourceManager = getResourceManager();
322             styleMapper = StyleMapper.loadInstance(realResourceManager);
323         }
324         catch (ResourceException e)
325         {
326             throw new ReportProcessingException("Failed to load style-mapper", e);
327         }
328     }
329 
getTargetMimeType()330     protected abstract String getTargetMimeType();
331 
getOutputRepository()332     protected OutputRepository getOutputRepository()
333     {
334         return outputRepository;
335     }
336 
getInputRepository()337     protected InputRepository getInputRepository()
338     {
339         return inputRepository;
340     }
341 
342     /**
343      * Starts the output of a new office document. This method writes the generic 'office:document-content' tag along with
344      * all known namespace declarations.
345      *
346      * @param report the report object.
347      * @throws DataSourceException       if there was an error accessing the datasource
348      * @throws ReportProcessingException if some other error occurred.
349      */
startReport(final ReportStructureRoot report)350     public void startReport(final ReportStructureRoot report)
351             throws DataSourceException, ReportProcessingException
352     {
353         imageNames.reset();
354         this.groupContext = new GroupContext(null);
355 
356         final DefaultTagDescription tagDescription = createTagDescription();
357         try
358         {
359             final OutputStream outputStream = outputRepository.createOutputStream(target, "text/xml");
360             final Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
361 
362             this.rootXmlWriter = new XmlWriter(writer, tagDescription);
363             this.rootXmlWriter.setAlwaysAddNamespace(true);
364 
365             final AttributeList rootAttributes = new AttributeList();
366             rootAttributes.addNamespaceDeclaration("office", OfficeNamespaces.OFFICE_NS);
367             rootAttributes.addNamespaceDeclaration("style", OfficeNamespaces.STYLE_NS);
368             rootAttributes.addNamespaceDeclaration("text", OfficeNamespaces.TEXT_NS);
369             rootAttributes.addNamespaceDeclaration("table", OfficeNamespaces.TABLE_NS);
370             rootAttributes.addNamespaceDeclaration("draw", OfficeNamespaces.DRAWING_NS);
371             rootAttributes.addNamespaceDeclaration("fo", OfficeNamespaces.FO_NS);
372             rootAttributes.addNamespaceDeclaration("xlink", OfficeNamespaces.XLINK_NS);
373             rootAttributes.addNamespaceDeclaration("dc", OfficeNamespaces.PURL_NS);
374             rootAttributes.addNamespaceDeclaration("meta", OfficeNamespaces.META_NS);
375             rootAttributes.addNamespaceDeclaration("number", OfficeNamespaces.DATASTYLE_NS);
376             rootAttributes.addNamespaceDeclaration("svg", OfficeNamespaces.SVG_NS);
377             rootAttributes.addNamespaceDeclaration("chart", OfficeNamespaces.CHART_NS);
378             rootAttributes.addNamespaceDeclaration("chartooo", OfficeNamespaces.CHARTOOO_NS);
379             rootAttributes.addNamespaceDeclaration("dr3d", OfficeNamespaces.DR3D_NS);
380             rootAttributes.addNamespaceDeclaration("math", OfficeNamespaces.MATHML_NS);
381             rootAttributes.addNamespaceDeclaration("form", OfficeNamespaces.FORM_NS);
382             rootAttributes.addNamespaceDeclaration("script", OfficeNamespaces.SCRIPT_NS);
383             rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
384             rootAttributes.addNamespaceDeclaration("ooow", OfficeNamespaces.OOW2004_NS);
385             rootAttributes.addNamespaceDeclaration("oooc", OfficeNamespaces.OOC2004_NS);
386             rootAttributes.addNamespaceDeclaration("dom", OfficeNamespaces.XML_EVENT_NS);
387             rootAttributes.addNamespaceDeclaration("xforms", OfficeNamespaces.XFORMS_NS);
388             rootAttributes.addNamespaceDeclaration("xsd", OfficeNamespaces.XSD_NS);
389             rootAttributes.addNamespaceDeclaration("xsi", OfficeNamespaces.XSI_NS);
390             rootAttributes.addNamespaceDeclaration("grddl", OfficeNamespaces.GRDDL_NS);
391             rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version",
392                     ODF_VERSION);
393 
394             this.rootXmlWriter.writeXmlDeclaration("UTF-8");
395             this.rootXmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "document-content", rootAttributes, XmlWriterSupport.OPEN);
396 
397             states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_DOCUMENT));
398 
399             autoStyleNameGenerator.reset();
400             tableNameGenerator.reset();
401             frameNameGenerator.reset();
402 
403             final OfficeDocument reportDoc = (OfficeDocument) report;
404             predefinedStylesCollection = reportDoc.getStylesCollection();
405 
406             final OfficeStyles commonStyles = predefinedStylesCollection.getCommonStyles();
407             if (!commonStyles.containsStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS))
408             {
409                 final OfficeStyle graphicsDefaultStyle = new OfficeStyle();
410                 graphicsDefaultStyle.setStyleFamily(OfficeToken.GRAPHIC);
411                 graphicsDefaultStyle.setStyleName(OfficeToken.GRAPHICS);
412                 final Element graphicProperties = produceFirstChild(graphicsDefaultStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
413                 graphicProperties.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH);
414                 graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "x", ZERO_CM);
415                 graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "y", ZERO_CM);
416                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap", "dynamic");
417                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "number-wrapped-paragraphs", "no-limit");
418                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap-contour", OfficeToken.FALSE);
419                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, VERTICAL_POS, "from-top"); // changed for chart
420 
421                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", OfficeToken.PARAGRAPH);
422                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, HORIZONTAL_POS, "from-left"); // changed for chart
423 
424                 graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", OfficeToken.PARAGRAPH);
425                 commonStyles.addStyle(graphicsDefaultStyle);
426             }
427 
428             // Make sure that later generated styles do not overwrite existing styles.
429             fillStyleNameGenerator(predefinedStylesCollection);
430 
431             contentStylesCollection = new OfficeStylesCollection();
432             globalStylesCollection = new OfficeStylesCollection();
433 
434             startBuffering(contentStylesCollection, true);
435         }
436         catch (IOException e)
437         {
438             throw new ReportProcessingException(FAILED, e);
439         }
440     }
441 
getAutoStyleNameGenerator()442     protected AttributeNameGenerator getAutoStyleNameGenerator()
443     {
444         return autoStyleNameGenerator;
445     }
446 
fillStyleNameGenerator(final OfficeStylesCollection stylesCollection)447     private void fillStyleNameGenerator(final OfficeStylesCollection stylesCollection)
448     {
449         final OfficeStyles commonStyles = stylesCollection.getCommonStyles();
450         final OfficeStyle[] allCommonStyles = commonStyles.getAllStyles();
451         for (int i = 0; i < allCommonStyles.length; i++)
452         {
453             final OfficeStyle style = allCommonStyles[i];
454             autoStyleNameGenerator.generateName(style.getStyleName());
455         }
456 
457         final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
458         final OfficeStyle[] allAutoStyles = autoStyles.getAllStyles();
459         for (int i = 0; i < allAutoStyles.length; i++)
460         {
461             final OfficeStyle style = allAutoStyles[i];
462             autoStyleNameGenerator.generateName(style.getStyleName());
463         }
464     }
465 
getPredefinedStylesCollection()466     public OfficeStylesCollection getPredefinedStylesCollection()
467     {
468         return predefinedStylesCollection;
469     }
470 
getGlobalStylesCollection()471     public OfficeStylesCollection getGlobalStylesCollection()
472     {
473         return globalStylesCollection;
474     }
475 
getContentStylesCollection()476     public OfficeStylesCollection getContentStylesCollection()
477     {
478         return contentStylesCollection;
479     }
480 
481     /**
482      * Returns the XML-Writer tag description. This description defines whether an element can have character data inside.
483      * Such element will disable the indention, as in that case the additional whitespaces might alter the meaning of the
484      * element's contents.
485      *
486      * @return the tag description library.
487      */
createTagDescription()488     protected DefaultTagDescription createTagDescription()
489     {
490         final DefaultTagDescription tagDescription = new DefaultTagDescription();
491         tagDescription.configure(JFreeReportBoot.getInstance().getGlobalConfig(),
492                 OfficeDocumentReportTarget.TAG_DEF_PREFIX);
493         return tagDescription;
494     }
495 
496     /**
497      * Returns the current processing state.
498      *
499      * @return the processing state.
500      */
getCurrentState()501     protected int getCurrentState()
502     {
503         if (states.isEmpty())
504         {
505             throw new IllegalStateException();
506         }
507         final Integer o = (Integer) states.peek();
508         return o;
509     }
510 
511     /**
512      * Starts the processing of an element and updates the processing state. This will select an appropriate handler method
513      * for the call and will call one of the start* methods.
514      *
515      * @param roAttrs the attribute map for the current element
516      * @throws DataSourceException
517      * @throws ReportProcessingException
518      */
startElement(final AttributeMap roAttrs)519     public final void startElement(final AttributeMap roAttrs)
520             throws DataSourceException, ReportProcessingException
521     {
522         final AttributeMap attrs = new LazyAttributeMap(roAttrs);
523         // todo
524         if (DEBUG_ELEMENTS)
525         {
526             LOGGER.debug("Starting " + getCurrentState() + '/' + states.size() + ' ' + ReportTargetUtil.getNamespaceFromAttribute(attrs) + " -> " + ReportTargetUtil.getElemenTypeFromAttribute(attrs));
527         }
528         try
529         {
530             switch (getCurrentState())
531             {
532                 case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
533                 {
534                     if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "body", attrs))
535                     {
536                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_BODY));
537                         startBody(attrs);
538                     }
539                     else
540                     {
541                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
542                         if (!isFilteredNamespace(ReportTargetUtil.getNamespaceFromAttribute(attrs)))
543                         {
544                             startOther(attrs);
545                         }
546                     }
547                     break;
548                 }
549                 case OfficeDocumentReportTarget.STATE_IN_BODY:
550                 {
551                     if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "report", attrs))
552                     {
553                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_CONTENT));
554                         startContent(attrs);
555                     }
556                     else
557                     {
558                         throw new IllegalStateException("The 'office:body' element must have exactly one child of type 'report'");
559                     }
560                     break;
561                 }
562                 case OfficeDocumentReportTarget.STATE_IN_CONTENT:
563                 {
564                     // Either a ordinary section or a group ..
565                     // A group.
566                     if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "report-body", attrs))
567                     {
568                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
569                         startGroupBody(attrs);
570                     }
571                     else
572                     {
573                         // Either a template-section, page-header, page-footer, report-header, report-footer
574                         // or variables-section
575                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
576                         if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "template", attrs))
577                         {
578                             currentRole = OfficeDocumentReportTarget.ROLE_TEMPLATE;
579                         }
580                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-header", attrs))
581                         {
582                             if ("spreadsheet-section".equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "role")))
583                             {
584                                 currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER;
585                             }
586                             else
587                             {
588                                 currentRole = OfficeDocumentReportTarget.ROLE_PAGE_HEADER;
589                             }
590                         }
591                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-footer", attrs))
592                         {
593                             if ("spreadsheet-section".equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "role")))
594                             {
595                                 currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER;
596                             }
597                             else
598                             {
599                                 currentRole = OfficeDocumentReportTarget.ROLE_PAGE_FOOTER;
600                             }
601                         }
602                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-header", attrs))
603                         {
604                             currentRole = OfficeDocumentReportTarget.ROLE_REPORT_HEADER;
605                         }
606                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-footer", attrs))
607                         {
608                             currentRole = OfficeDocumentReportTarget.ROLE_REPORT_FOOTER;
609                         }
610                         else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
611                         {
612                             currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
613                         }
614                         else
615                         {
616                             throw new IllegalStateException("Expected either 'template', 'report-body', " + "'report-header', 'report-footer', 'variables-section', 'page-header' or 'page-footer'");
617                         }
618                         startReportSection(attrs, currentRole);
619                     }
620                     break;
621                 }
622                 case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
623                 {
624                     // We now expect either an other group or a detail band.
625 
626                     if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group", attrs))
627                     {
628                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP));
629                         groupContext = new GroupContext(groupContext);
630                         startGroup(attrs);
631                     }
632                     else
633                     {
634                         // Either a variables-section, or a detail-band
635                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
636                         if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "detail", attrs))
637                         {
638                             currentRole = OfficeDocumentReportTarget.ROLE_DETAIL;
639                         }
640                         else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
641                         {
642                             currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
643                         }
644                         else
645                         {
646                             throw new IllegalStateException("Expected either 'group', 'detail' or 'variables-section'");
647                         }
648                         startReportSection(attrs, currentRole);
649                     }
650                     break;
651                 }
652                 case OfficeDocumentReportTarget.STATE_IN_GROUP:
653                 {
654                     // A group can carry a repeating group header/footer or a group-instance section.
655                     if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "group-instance", attrs))
656                     {
657                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE));
658                         startGroupInstance(attrs);
659                     }
660                     else
661                     {
662                         // repeating group header/footer, but *no* variables section
663                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
664                         if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section")))
665                         {
666                             currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER;
667                         }
668                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section")))
669                         {
670                             currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER;
671                         }
672                         else
673                         {
674                             throw new IllegalStateException("Expected either 'group-instance', " + "'repeating group-header' or 'repeating group-footer'");
675                         }
676                         startReportSection(attrs, currentRole);
677                     }
678                     break;
679                 }
680                 case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
681                 {
682                     if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "group-body", attrs))
683                     {
684                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
685                         startGroupBody(attrs);
686                     }
687                     else
688                     {
689                         // Either a group-header or group-footer or variables-section
690                         states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
691                         if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs))
692                         {
693                             currentRole = OfficeDocumentReportTarget.ROLE_GROUP_HEADER;
694                         }
695                         else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs))
696                         {
697                             currentRole = OfficeDocumentReportTarget.ROLE_GROUP_FOOTER;
698                         }
699                         else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
700                         {
701                             currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
702                         }
703                         else
704                         {
705                             throw new IllegalStateException("Expected either 'group-body', 'group-header', 'group-footer' or 'variables-section'");
706                         }
707                         startReportSection(attrs, currentRole);
708                     }
709                     break;
710                 }
711                 case OfficeDocumentReportTarget.STATE_IN_SECTION:
712                 {
713                     states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
714                     startOther(attrs);
715                     break;
716                 }
717                 case OfficeDocumentReportTarget.STATE_IN_OTHER:
718                 {
719                     states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
720                     startOther(attrs);
721                     break;
722                 }
723                 default:
724                     throw new IllegalStateException("Failure: " + getCurrentState());
725             }
726         }
727         catch (IOException ioe)
728         {
729             LOGGER.error("ReportProcessing failed", ioe);
730             throw new ReportProcessingException("Failed to write content", ioe);
731         }
732 //    finally
733 //    {
734 //      LOGGER.debug ("Started " + getNamespaceFromAttribute(attrs) + ":" +
735 //                 getElemenTypeFromAttribute(attrs) + " -> " + getCurrentState());
736 //    }
737     }
738 
getGroupContext()739     protected GroupContext getGroupContext()
740     {
741         return groupContext;
742     }
743 
performStyleProcessing(final AttributeMap attrs)744     protected void performStyleProcessing(final AttributeMap attrs)
745             throws ReportProcessingException
746     {
747         final OfficeStylesCollection stylesCollection = getStylesCollection();
748         final OfficeStylesCollection predefCollection = getPredefinedStylesCollection();
749         final OfficeStylesCollection globalStylesCollection = getGlobalStylesCollection();
750 
751         final String elementNamespace =
752                 ReportTargetUtil.getNamespaceFromAttribute(attrs);
753         final String elementName =
754                 ReportTargetUtil.getElemenTypeFromAttribute(attrs);
755 
756         final String[] namespaces = attrs.getNameSpaces();
757         for (int i = 0; i < namespaces.length; i++)
758         {
759             final String attrNamespace = namespaces[i];
760             if (isFilteredNamespace(attrNamespace))
761             {
762                 continue;
763             }
764 
765             final Map attributes = attrs.getAttributes(attrNamespace);
766             final Iterator iterator = attributes.entrySet().iterator();
767             while (iterator.hasNext())
768             {
769                 final Map.Entry entry = (Map.Entry) iterator.next();
770                 final String attrName = (String) entry.getKey();
771                 final String attrValue = String.valueOf(entry.getValue());
772 
773                 final String styleFamily = styleMapper.getStyleFamilyFor(elementNamespace, elementName, attrNamespace, attrName);
774                 if (styleFamily == null)
775                 {
776                     // None of the known style attributes.
777                     continue;
778                 }
779 
780                 if (styleMapper.isListOfStyles(elementNamespace, elementName, attrNamespace, attrName))
781                 {
782                     // ignored for now.
783                     LOGGER.warn("List of styles is not yet implemented.");
784                     continue;
785                 }
786 
787                 // Copy styles is only called once per style.
788                 StyleUtilities.copyStyle(styleFamily, attrValue, stylesCollection, globalStylesCollection, predefCollection);
789             }
790         }
791     }
792 
startBody(final AttributeMap attrs)793     protected void startBody(final AttributeMap attrs)
794             throws IOException
795     {
796         getXmlWriter().writeTag(OfficeNamespaces.OFFICE_NS, "body", XmlWriterSupport.OPEN);
797     }
798 
allowBuffering(final int role)799     private final boolean allowBuffering(final int role)
800     {
801         return (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER || role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_TEMPLATE);
802     }
803 
startReportSection(final AttributeMap attrs, final int role)804     protected void startReportSection(final AttributeMap attrs, final int role)
805             throws IOException, DataSourceException, ReportProcessingException
806     {
807         if (allowBuffering(role))
808         {
809             startBuffering(new OfficeStylesCollection(), true);
810         }
811     }
812 
startContent(final AttributeMap attrs)813     protected abstract void startContent(final AttributeMap attrs)
814             throws IOException, DataSourceException, ReportProcessingException;
815 
startGroup(final AttributeMap attrs)816     protected void startGroup(final AttributeMap attrs)
817             throws IOException, DataSourceException, ReportProcessingException
818     {
819         final Object repeatingHeaderOrFooter = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeating-header-or-footer");
820         if (OfficeToken.TRUE.equals(repeatingHeaderOrFooter))
821         {
822             getGroupContext().setGroupWithRepeatingSection(true);
823         }
824 
825         final Object iterationCount = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "iteration-count");
826         if (iterationCount instanceof Number)
827         {
828             final Number itNumber = (Number) iterationCount;
829             getGroupContext().setIterationCount(itNumber.intValue());
830         }
831     }
832 
startGroupInstance(final AttributeMap attrs)833     protected void startGroupInstance(final AttributeMap attrs)
834             throws IOException, DataSourceException, ReportProcessingException
835     {
836     }
837 
startGroupBody(final AttributeMap attrs)838     protected void startGroupBody(final AttributeMap attrs)
839             throws IOException, DataSourceException, ReportProcessingException
840     {
841     }
842 
startOther(final AttributeMap attrs)843     protected abstract void startOther(final AttributeMap attrs)
844             throws IOException, DataSourceException, ReportProcessingException;
845 
processText(final String text)846     public void processText(final String text)
847             throws DataSourceException, ReportProcessingException
848     {
849         try
850         {
851             final XmlWriter xmlWriter = getXmlWriter();
852             final BufferedReader br = new BufferedReader(new StringReader(text));
853             String line = br.readLine();
854             while (line != null)
855             {
856                 xmlWriter.writeTextNormalized(line, false);
857                 line = br.readLine();
858                 if (line != null)
859                 {
860                     xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
861                 }
862             }
863         }
864         catch (IOException e)
865         {
866             throw new ReportProcessingException(FAILED, e);
867         }
868     }
869 
isFilteredNamespace(final String namespace)870     protected boolean isFilteredNamespace(final String namespace)
871     {
872         if (Namespaces.LIBLAYOUT_NAMESPACE.equals(namespace))
873         {
874             return true;
875         }
876         if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
877         {
878             return true;
879         }
880         if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
881         {
882             return true;
883         }
884         if (JFreeReportInfo.COMPATIBILITY_NAMESPACE.equals(namespace))
885         {
886             return true;
887         }
888         if (OfficeNamespaces.OOREPORT_NS.equals(namespace))
889         {
890             return true;
891         }
892         return false;
893     }
894 
processContent(final DataFlags value)895     public void processContent(final DataFlags value)
896             throws DataSourceException, ReportProcessingException
897     {
898         final Object rawvalue = value.getValue();
899         if (rawvalue == null)
900         {
901             return;
902         }
903 
904         // special handler for image (possibly also for URL ..)
905         if (rawvalue instanceof Image)
906         {
907             // do nothing yet. We should define something for that later ..
908             return;
909         }
910 
911         final XmlWriter xmlWriter = getXmlWriter();
912         final String text = String.valueOf(rawvalue);
913         try
914         {
915             final BufferedReader br = new BufferedReader(new StringReader(text));
916             String line = br.readLine();
917             while (line != null)
918             {
919                 xmlWriter.writeTextNormalized(line, false);
920                 line = br.readLine();
921                 if (line != null)
922                 {
923                     xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
924                 }
925             }
926         }
927         catch (IOException e)
928         {
929             throw new ReportProcessingException(FAILED, e);
930         }
931     }
932 
endElement(final AttributeMap roAttrs)933     public final void endElement(final AttributeMap roAttrs)
934             throws DataSourceException, ReportProcessingException
935     {
936         final AttributeMap attrs = new LazyAttributeMap(roAttrs);
937         // final int oldState = getCurrentState();
938         try
939         {
940 
941             switch (getCurrentState())
942             {
943                 case OfficeDocumentReportTarget.STATE_IN_OTHER:
944                 {
945                     endOther(attrs);
946                     break;
947                 }
948                 case OfficeDocumentReportTarget.STATE_IN_SECTION:
949                 {
950                     endReportSection(attrs, currentRole);
951                     currentRole = OfficeDocumentReportTarget.ROLE_NONE;
952                     break;
953                 }
954                 case OfficeDocumentReportTarget.STATE_IN_GROUP:
955                 {
956                     endGroup(attrs);
957                     groupContext = groupContext.getParent();
958                     break;
959                 }
960                 case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
961                 {
962                     endGroupInstance(attrs);
963                     break;
964                 }
965                 case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
966                 {
967                     endGroupBody(attrs);
968                     break;
969                 }
970                 case OfficeDocumentReportTarget.STATE_IN_CONTENT:
971                 {
972                     endContent(attrs);
973                     break;
974                 }
975                 case OfficeDocumentReportTarget.STATE_IN_BODY:
976                 {
977                     endBody(attrs);
978                     break;
979                 }
980                 case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
981                 {
982                     throw new IllegalStateException("This cannot be.");
983                 }
984                 default:
985                 {
986                     throw new IllegalStateException("Invalid state encountered.");
987                 }
988             }
989         }
990         catch (IOException ioe)
991         {
992             throw new ReportProcessingException("IO Error while writing content",
993                     ioe);
994         } finally
995         {
996             states.pop();
997 
998             if (DEBUG_ELEMENTS)
999             {
1000                 LOGGER.debug("Finished " + getCurrentState() + "/" + states.size() + " " + ReportTargetUtil.getNamespaceFromAttribute(attrs) + ":" + ReportTargetUtil.getElemenTypeFromAttribute(attrs));
1001             }
1002 
1003         }
1004     }
1005 
endGroupBody(final AttributeMap attrs)1006     protected void endGroupBody(final AttributeMap attrs)
1007             throws IOException, DataSourceException, ReportProcessingException
1008     {
1009     }
1010 
endGroupInstance(final AttributeMap attrs)1011     protected void endGroupInstance(final AttributeMap attrs)
1012             throws IOException, DataSourceException, ReportProcessingException
1013     {
1014     }
1015 
getCurrentRole()1016     public int getCurrentRole()
1017     {
1018         return currentRole;
1019     }
1020 
endOther(final AttributeMap attrs)1021     protected abstract void endOther(final AttributeMap attrs)
1022             throws IOException, DataSourceException, ReportProcessingException;
1023 
endReportSection(final AttributeMap attrs, final int role)1024     protected void endReportSection(final AttributeMap attrs,
1025             final int role)
1026             throws IOException, DataSourceException, ReportProcessingException
1027     {
1028         if (allowBuffering(role))
1029         {
1030             finishBuffering();
1031         }
1032     }
1033 
endGroup(final AttributeMap attrs)1034     protected void endGroup(final AttributeMap attrs)
1035             throws IOException, DataSourceException, ReportProcessingException
1036     {
1037     }
1038 
endContent(final AttributeMap attrs)1039     protected abstract void endContent(final AttributeMap attrs)
1040             throws IOException, DataSourceException, ReportProcessingException;
1041 
endBody(final AttributeMap attrs)1042     protected void endBody(final AttributeMap attrs)
1043             throws IOException, DataSourceException, ReportProcessingException
1044     {
1045         getXmlWriter().writeCloseTag();
1046     }
1047 
copyMeta()1048     public void copyMeta()
1049     {
1050         // now copy the meta.xml
1051         if (getInputRepository().isReadable("meta.xml"))
1052         {
1053             InputStream inputStream = null;
1054             try
1055             {
1056                 inputStream = getInputRepository().createInputStream("meta.xml");
1057                 DOMParser dOMParser = new DOMParser();
1058                 dOMParser.parse(new InputSource(inputStream));
1059                 Document document = dOMParser.getDocument();
1060                 NodeList nl = document.getElementsByTagName("document-meta/meta/generator");
1061                 Node node = document.getFirstChild().getFirstChild().getFirstChild().getFirstChild();
1062                 String creator = node.getNodeValue();
1063                 node.setNodeValue(creator + "/report_builder");
1064                 Transformer transformer = TransformerFactory.newInstance().newTransformer();
1065                 transformer.setOutputProperty(OutputKeys.METHOD, "xml");
1066 
1067                 final OutputStream outputMetaStream = getOutputRepository().createOutputStream("meta.xml", "text/xml");
1068                 StreamResult result = new StreamResult(outputMetaStream);
1069                 DOMSource source = new DOMSource(document);
1070                 transformer.transform(source, result);
1071 
1072                 //IOUtils.getInstance().copyStreams(inputStream, outputMetaStream);
1073                 outputMetaStream.flush();
1074                 outputMetaStream.close();
1075             }
1076             catch (java.lang.Exception ex)
1077             {
1078             } finally
1079             {
1080                 if (inputStream != null)
1081                 {
1082                     try
1083                     {
1084                         inputStream.close();
1085                     }
1086                     catch (IOException ex)
1087                     {
1088                         Logger.getLogger(OfficeDocumentReportTarget.class.getName()).log(Level.SEVERE, null, ex);
1089                     }
1090                 }
1091             }
1092         }
1093     }
1094 
endReport(final ReportStructureRoot report)1095     public void endReport(final ReportStructureRoot report)
1096             throws DataSourceException, ReportProcessingException
1097     {
1098         if (xmlWriters.size() != 1)
1099         {
1100             throw new IllegalStateException("Invalid writer-stack state");
1101         }
1102 
1103         try
1104         {
1105             final StylesWriter inlineStylesWriter = new StylesWriter(rootXmlWriter);
1106             inlineStylesWriter.writeContentStyles(predefinedStylesCollection, contentStylesCollection);
1107 
1108             final BufferState state = finishBuffering();
1109             this.rootXmlWriter.writeStream(state.getXmlAsReader());
1110 
1111             final OutputStream stylesOutStream =
1112                     outputRepository.createOutputStream("styles.xml", "text/xml");
1113             final OutputStreamWriter osw =
1114                     new OutputStreamWriter(stylesOutStream, "UTF-8");
1115             final StylesWriter stylesWriter = new StylesWriter(osw);
1116             stylesWriter.writeGlobalStyles(predefinedStylesCollection, globalStylesCollection);
1117             stylesWriter.close();
1118 
1119             this.rootXmlWriter.writeCloseTag();
1120             this.rootXmlWriter.close();
1121         }
1122         catch (IOException e)
1123         {
1124             throw new ReportProcessingException(FAILED, e);
1125         }
1126     }
1127 
getXmlWriter()1128     public XmlWriter getXmlWriter()
1129     {
1130         final BufferState bufferState = (BufferState) xmlWriters.peek();
1131         return bufferState.getXmlWriter();
1132     }
1133 
getStylesCollection()1134     public OfficeStylesCollection getStylesCollection()
1135     {
1136         final BufferState bufferState = (BufferState) xmlWriters.peek();
1137         return bufferState.getStylesCollection();
1138     }
1139 
startBuffering(final OfficeStylesCollection stylesCollection, final boolean indent)1140     public void startBuffering(final OfficeStylesCollection stylesCollection,
1141             final boolean indent) throws ReportProcessingException
1142     {
1143         final XmlWriter currentWriter;
1144         if (xmlWriters.isEmpty())
1145         {
1146             currentWriter = rootXmlWriter;
1147         }
1148         else
1149         {
1150             final BufferState bufferState = (BufferState) xmlWriters.peek();
1151             currentWriter = bufferState.getXmlWriter();
1152         }
1153 
1154         try
1155         {
1156             final MemoryByteArrayOutputStream out =
1157                     new MemoryByteArrayOutputStream(INITIAL_BUFFER_SIZE, 256 * INITIAL_BUFFER_SIZE);
1158             final DeflaterOutputStream deflateOut = new DeflaterOutputStream(out);
1159             final OutputStreamWriter xmlBuffer = new OutputStreamWriter(deflateOut, "UTF-16");
1160             //    final StringWriter xmlBuffer = new StringWriter
1161             //        (OfficeDocumentReportTarget.INITIAL_BUFFER_SIZE);
1162             final XmlWriter contentXmlWriter = new XmlWriter(xmlBuffer, createTagDescription());
1163             contentXmlWriter.copyNamespaces(currentWriter);
1164             if (indent)
1165             {
1166                 contentXmlWriter.setAdditionalIndent(currentWriter.getCurrentIndentLevel());
1167                 contentXmlWriter.setWriteFinalLinebreak(true);
1168             }
1169             else
1170             {
1171                 contentXmlWriter.setWriteFinalLinebreak(false);
1172             }
1173             contentXmlWriter.setAlwaysAddNamespace(true);
1174             xmlWriters.push(new BufferState(contentXmlWriter, out, stylesCollection));
1175         }
1176         catch (IOException ioe)
1177         {
1178             throw new ReportProcessingException("Unable to create the buffer", ioe);
1179         }
1180     }
1181 
finishBuffering()1182     public BufferState finishBuffering() throws ReportProcessingException
1183     {
1184         final BufferState state = (BufferState) xmlWriters.pop();
1185         try
1186         {
1187             state.getXmlWriter().close();
1188         }
1189         catch (IOException e)
1190         {
1191             LOGGER.error("ReportProcessing failed", e);
1192         }
1193         return state;
1194     }
1195 
commit()1196     public void commit()
1197             throws ReportProcessingException
1198     {
1199         // do not call flush before the report is fully finished. Every flush
1200         // causes the Office-Backend to fully ZIP all contents (it acts like a
1201         // 'Save' call from the UI) and that's expensive like hell
1202     }
1203 
getNamespaceByUri(final String uri)1204     public NamespaceDefinition getNamespaceByUri(final String uri)
1205     {
1206         return null;
1207     }
1208 
buildAttributeList(final AttributeMap attrs)1209     protected AttributeList buildAttributeList(final AttributeMap attrs)
1210     {
1211         final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
1212         final AttributeList attrList = new AttributeList();
1213         final String[] namespaces = attrs.getNameSpaces();
1214         for (int i = 0; i < namespaces.length; i++)
1215         {
1216             final String attrNamespace = namespaces[i];
1217             if (isFilteredNamespace(attrNamespace))
1218             {
1219                 continue;
1220             }
1221 
1222             final Map localAttributes = attrs.getAttributes(attrNamespace);
1223             final Iterator entries = localAttributes.entrySet().iterator();
1224             while (entries.hasNext())
1225             {
1226                 final Map.Entry entry = (Map.Entry) entries.next();
1227                 final String key = String.valueOf(entry.getKey());
1228                 if (OfficeNamespaces.TABLE_NS.equals(attrNamespace) && "name".equals(key))
1229                 {
1230                     final String tableName = String.valueOf(entry.getValue());
1231                     final String saneName = sanitizeName(tableName);
1232                     attrList.setAttribute(attrNamespace, key,
1233                             tableNameGenerator.generateName(saneName));
1234                 }
1235                 else if (OfficeNamespaces.DRAWING_NS.equals(attrNamespace) && "name".equals(key) && !"equation".equals(elementType))
1236                 {
1237                     final String objectName = String.valueOf(entry.getValue());
1238                     attrList.setAttribute(attrNamespace, key,
1239                             frameNameGenerator.generateName(objectName));
1240                 }
1241                 else
1242                 {
1243                     attrList.setAttribute(attrNamespace, key, String.valueOf(entry.getValue()));
1244                 }
1245             }
1246         }
1247         return attrList;
1248     }
1249 
sanitizeName(final String name)1250     protected String sanitizeName(final String name)
1251     {
1252         // A table name cannot contain spaces and should only contain
1253         // ascii-characters.
1254         if (name == null)
1255         {
1256             return "";
1257         }
1258         final char[] chars = name.toCharArray();
1259         final StringBuffer buffer = new StringBuffer();
1260         for (int i = 0; i < chars.length; i++)
1261         {
1262             final char aChar = chars[i];
1263             if (Character.isWhitespace(aChar))
1264             {
1265                 buffer.append('_');
1266             }
1267             else
1268             {
1269                 buffer.append(aChar);
1270             }
1271         }
1272         return buffer.toString();
1273     }
1274 
1275     /**
1276      * Returns the length in point. This method is f**king slow, it eats half of the processing time. I surely should
1277      * replace it with something more efficient later.
1278      *
1279      * @param text
1280      * @return
1281      */
parseLength(final String text)1282     protected CSSNumericValue parseLength(final String text)
1283     {
1284         if (styleSheetParserUtil == null)
1285         {
1286             styleSheetParserUtil = StyleSheetParserUtil.getInstance();
1287         }
1288 
1289         final LexicalUnit cssValue = styleSheetParserUtil.parseLexicalStyleValue(
1290                 text);
1291         return CSSValueFactory.createLengthValue(cssValue);
1292     }
1293 
isRepeatingSection()1294     protected boolean isRepeatingSection()
1295     {
1296         return (currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER || currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER || currentRole == OfficeDocumentReportTarget.ROLE_PAGE_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_VARIABLES);
1297 
1298     }
1299 
deriveStyle(final String styleFamily, final String styleName)1300     protected OfficeStyle deriveStyle(final String styleFamily, final String styleName)
1301             throws ReportProcessingException
1302     {
1303         // autogenerate a style. The style has already been added to the current
1304         // auto-collection.
1305         final OfficeStyle style = StyleUtilities.deriveStyle(styleFamily, styleName,
1306                 getStylesCollection(), getGlobalStylesCollection(),
1307                 getPredefinedStylesCollection(), getAutoStyleNameGenerator());
1308         return style;
1309     }
1310 
startImageProcessing(final AttributeMap attrs)1311     protected void startImageProcessing(final AttributeMap attrs)
1312             throws ReportProcessingException
1313     {
1314         final Object imageData = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA);
1315         final boolean preserveIRI = OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.PRESERVE_IRI));
1316 
1317         // for the first shot, do nothing fancy ..
1318         final ImageProducer.OfficeImage image = imageProducer.produceImage(imageData, preserveIRI);
1319         if (image != null)
1320         {
1321             final ImageElementContext imageContext = (ImageElementContext) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "image-context");
1322 
1323             // When scaling, we have to create an image-style.
1324             final CSSNumericValue width = image.getWidth(); // always in 100th of a mm
1325 
1326             final CSSNumericValue height = image.getHeight(); // always in 100th of a mm
1327 
1328             LOGGER.debug("Image " + imageData + " Width: " + width + ", Height: " + height);
1329             if (width == null || height == null)
1330             {
1331                 return;
1332             }
1333 
1334             CSSNumericValue imageAreaWidthVal;
1335             CSSNumericValue imageAreaHeightVal;
1336             CSSNumericValue posX = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
1337             CSSNumericValue posY = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
1338 
1339             String styleName = null;
1340             if (imageContext != null)
1341             {
1342                 imageAreaWidthVal = computeImageWidth(imageContext);
1343                 imageAreaHeightVal = computeImageHeight(imageContext);
1344 
1345                 if (imageAreaWidthVal == null || imageAreaHeightVal == null)
1346                 {
1347                     LOGGER.debug("Image data returned from context is invalid. Maybe this is not an image?");
1348                     return;
1349                 }
1350                 else
1351                 {
1352                     // compute the clip-area ..
1353                     final CSSNumericValue normalizedImageWidth =
1354                             CSSValueResolverUtility.convertLength(width, imageAreaWidthVal.getType());
1355                     final CSSNumericValue normalizedImageHeight =
1356                             CSSValueResolverUtility.convertLength(height, imageAreaHeightVal.getType());
1357 
1358                     final String scale = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE);
1359                     if (OfficeToken.NONE.equals(scale) && normalizedImageWidth.getValue() > 0 && normalizedImageHeight.getValue() > 0)
1360                     {
1361                         final double clipWidth = normalizedImageWidth.getValue() - imageAreaWidthVal.getValue();
1362                         final double clipHeight = normalizedImageHeight.getValue() - imageAreaHeightVal.getValue();
1363                         if (clipWidth > 0 && clipHeight > 0)
1364                         {
1365                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1366                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1367                             final StringBuffer buffer = new StringBuffer();
1368                             buffer.append("rect(");
1369                             buffer.append(clipHeight / 2);
1370                             buffer.append(imageAreaHeightVal.getType().getType());
1371                             buffer.append(' ');
1372                             buffer.append(clipWidth / 2);
1373                             buffer.append(imageAreaWidthVal.getType().getType());
1374                             buffer.append(' ');
1375                             buffer.append(clipHeight / 2);
1376                             buffer.append(imageAreaHeightVal.getType().getType());
1377                             buffer.append(' ');
1378                             buffer.append(clipWidth / 2);
1379                             buffer.append(imageAreaWidthVal.getType().getType());
1380                             buffer.append(')');
1381                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1382 
1383                             styleName = imageStyle.getStyleName();
1384                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1385                         }
1386                         else if (clipWidth > 0)
1387                         {
1388                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1389                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1390                             final StringBuffer buffer = new StringBuffer();
1391                             buffer.append("rect(0cm ");
1392                             buffer.append(clipWidth / 2);
1393                             buffer.append(imageAreaWidthVal.getType().getType());
1394                             buffer.append(" 0cm ");
1395                             buffer.append(clipWidth / 2);
1396                             buffer.append(imageAreaWidthVal.getType().getType());
1397                             buffer.append(')');
1398                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1399 
1400                             styleName = imageStyle.getStyleName();
1401                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1402                             imageAreaHeightVal = normalizedImageHeight;
1403                         }
1404                         else if (clipHeight > 0)
1405                         {
1406                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1407                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1408                             final StringBuffer buffer = new StringBuffer();
1409                             buffer.append("rect(");
1410                             buffer.append(clipHeight / 2);
1411                             buffer.append(imageAreaHeightVal.getType().getType());
1412                             buffer.append(" 0cm ");
1413                             buffer.append(clipHeight / 2);
1414                             buffer.append(imageAreaHeightVal.getType().getType());
1415                             buffer.append(" 0cm)");
1416                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1417 
1418                             styleName = imageStyle.getStyleName();
1419                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1420                             imageAreaWidthVal = normalizedImageWidth;
1421                         }
1422                         else
1423                         {
1424                             imageAreaWidthVal = normalizedImageWidth;
1425                             imageAreaHeightVal = normalizedImageHeight;
1426                         }
1427                     }
1428                     else if (OfficeToken.ISOTROPIC.equals(scale))
1429                     {
1430                         final double[] ret = calcPaintSize(imageAreaWidthVal, imageAreaHeightVal, normalizedImageWidth, normalizedImageHeight);
1431 
1432                         posX = CSSNumericValue.createValue(imageAreaWidthVal.getType(), (imageAreaWidthVal.getValue() - ret[0]) * 0.5);
1433                         posY = CSSNumericValue.createValue(imageAreaHeightVal.getType(), (imageAreaHeightVal.getValue() - ret[1]) * 0.5);
1434 
1435                         imageAreaWidthVal = CSSNumericValue.createValue(imageAreaWidthVal.getType(), ret[0]);
1436                         imageAreaHeightVal = CSSNumericValue.createValue(imageAreaHeightVal.getType(), ret[1]);
1437                     }
1438                 }
1439                 // If we do scale, then we simply use the given image-area-size as valid image size and dont
1440                 // care about the image itself ..
1441             }
1442             else
1443             {
1444                 LOGGER.debug("There is no image-context, so we have to rely on the image's natural bounds. " + "This may go awfully wrong.");
1445                 imageAreaWidthVal = image.getWidth();
1446                 imageAreaHeightVal = image.getHeight();
1447             }
1448 
1449             final AttributeList frameList = new AttributeList();
1450             frameList.setAttribute(OfficeNamespaces.DRAWING_NS, "name", imageNames.generateName("Image"));
1451             if (styleName != null)
1452             {
1453                 frameList.setAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME, styleName);
1454             }
1455             frameList.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH);
1456             frameList.setAttribute(OfficeNamespaces.SVG_NS, "z-index", "0");
1457             frameList.setAttribute(OfficeNamespaces.SVG_NS, "x", posX.getValue() + posX.getType().getType());
1458             frameList.setAttribute(OfficeNamespaces.SVG_NS, "y", posY.getValue() + posY.getType().getType());
1459 
1460 
1461             LOGGER.debug("Image " + imageData + " A-Width: " + imageAreaWidthVal + ", A-Height: " + imageAreaHeightVal);
1462 
1463             if (imageAreaWidthVal != null)
1464             {
1465                 frameList.setAttribute(OfficeNamespaces.SVG_NS,
1466                         "width", imageAreaWidthVal.getValue() + imageAreaWidthVal.getType().getType());
1467             }
1468 
1469             if (imageAreaHeightVal != null)
1470             {
1471                 frameList.setAttribute(OfficeNamespaces.SVG_NS,
1472                         "height", imageAreaHeightVal.getValue() + imageAreaHeightVal.getType().getType());
1473             }
1474 
1475 
1476             final AttributeList imageList = new AttributeList();
1477             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "href", image.getEmbeddableLink());
1478             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
1479             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
1480             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
1481 
1482 
1483             try
1484             {
1485                 getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, "frame", frameList, XmlWriterSupport.OPEN);
1486                 getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.IMAGE, imageList, XmlWriterSupport.CLOSE);
1487                 getXmlWriter().writeCloseTag();
1488             }
1489             catch (IOException ioe)
1490             {
1491                 throw new ReportProcessingException(FAILED, ioe);
1492             }
1493         }
1494     }
1495 
computeImageWidth(final ImageElementContext imageElementContext)1496     private CSSNumericValue computeImageWidth(final ImageElementContext imageElementContext)
1497     {
1498         final LengthCalculator calculator = new LengthCalculator();
1499         final String[] strings = imageElementContext.getColStyles();
1500         for (int i = 0; i < strings.length; i++)
1501         {
1502             final String styleName = strings[i];
1503             final CSSNumericValue value = computeColumnWidth(styleName);
1504             if (value != null)
1505             {
1506                 calculator.add(value);
1507             }
1508         }
1509         return calculator.getResult();
1510     }
1511 
computeImageHeight(final ImageElementContext imageElementContext)1512     private CSSNumericValue computeImageHeight(final ImageElementContext imageElementContext)
1513     {
1514         final LengthCalculator calculator = new LengthCalculator();
1515         final String[] strings = imageElementContext.getRowStyles();
1516         for (int i = 0; i < strings.length; i++)
1517         {
1518             final String styleName = strings[i];
1519             final CSSNumericValue value = computeRowHeight(styleName);
1520             if (value != null)
1521             {
1522                 calculator.add(value);
1523             }
1524         }
1525         return calculator.getResult();
1526     }
1527 
computeRowHeight(final String rowStyle)1528     protected CSSNumericValue computeRowHeight(final String rowStyle)
1529     {
1530         final OfficeStylesCollection contentStyles = getContentStylesCollection();
1531         final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1532         if (style != null)
1533         {
1534             final Element element = style.getTableRowProperties();
1535             if (element != null)
1536             {
1537                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1538                 if (height != null)
1539                 {
1540                     return parseLength(height);
1541                 }
1542             }
1543 
1544             final String styleParent = style.getStyleParent();
1545             if (styleParent != null)
1546             {
1547                 return computeRowHeight(styleParent);
1548             }
1549         }
1550 
1551         final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
1552         final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1553         if (globalStyle != null)
1554         {
1555             final Element element = globalStyle.getTableRowProperties();
1556             if (element != null)
1557             {
1558                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1559                 if (height != null)
1560                 {
1561                     return parseLength(height);
1562                 }
1563             }
1564             final String styleParent = globalStyle.getStyleParent();
1565             if (styleParent != null)
1566             {
1567                 return computeRowHeight(styleParent);
1568             }
1569         }
1570 
1571         final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
1572         final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1573         if (predefStyle != null)
1574         {
1575             final Element element = predefStyle.getTableRowProperties();
1576             if (element != null)
1577             {
1578                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1579                 if (height != null)
1580                 {
1581                     return parseLength(height);
1582                 }
1583             }
1584             final String styleParent = predefStyle.getStyleParent();
1585             if (styleParent != null)
1586             {
1587                 return computeRowHeight(styleParent);
1588             }
1589         }
1590         // not found.
1591         return null;
1592     }
1593 
computeColumnWidth(final String colStyle)1594     protected CSSNumericValue computeColumnWidth(final String colStyle)
1595     {
1596         final OfficeStylesCollection contentStyles = getContentStylesCollection();
1597         final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1598         if (style != null)
1599         {
1600             final Element element = style.getTableColumnProperties();
1601             if (element != null)
1602             {
1603                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1604                 if (height != null)
1605                 {
1606                     return parseLength(height);
1607                 }
1608             }
1609 
1610             final String styleParent = style.getStyleParent();
1611             if (styleParent != null)
1612             {
1613                 return computeRowHeight(styleParent);
1614             }
1615         }
1616 
1617         final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
1618         final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1619         if (globalStyle != null)
1620         {
1621             final Element element = globalStyle.getTableColumnProperties();
1622             if (element != null)
1623             {
1624                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1625                 if (height != null)
1626                 {
1627                     return parseLength(height);
1628                 }
1629             }
1630             final String styleParent = globalStyle.getStyleParent();
1631             if (styleParent != null)
1632             {
1633                 return computeRowHeight(styleParent);
1634             }
1635         }
1636 
1637         final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
1638         final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1639         if (predefStyle != null)
1640         {
1641             final Element element = predefStyle.getTableColumnProperties();
1642             if (element != null)
1643             {
1644                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1645                 if (height != null)
1646                 {
1647                     return parseLength(height);
1648                 }
1649             }
1650             final String styleParent = predefStyle.getStyleParent();
1651             if (styleParent != null)
1652             {
1653                 return computeRowHeight(styleParent);
1654             }
1655         }
1656         // not found.
1657         return null;
1658     }
1659 
produceFirstChild(final Section style, final String nameSpace, final String type)1660     protected Element produceFirstChild(final Section style,
1661             final String nameSpace,
1662             final String type)
1663     {
1664         Element paragraphProps = style.findFirstChild(nameSpace, type);
1665         if (paragraphProps == null)
1666         {
1667             paragraphProps = new Section();
1668             paragraphProps.setNamespace(nameSpace);
1669             paragraphProps.setType(type);
1670             style.addNode(paragraphProps);
1671         }
1672         return paragraphProps;
1673     }
1674 
startChartProcessing(final AttributeMap attrs)1675     protected void startChartProcessing(final AttributeMap attrs)
1676             throws ReportProcessingException
1677     {
1678         final String classId = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "class-id");
1679         final String chartUrl = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "href");
1680         final ArrayList masterColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_COLUMNS);
1681         final ArrayList masterValues = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_VALUES);
1682         final ArrayList detailColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.DETAIL_COLUMNS);
1683         final String href = oleProducer.produceOle(chartUrl, masterColumns, masterValues, detailColumns);
1684 
1685         final AttributeList oleList = new AttributeList();
1686         oleList.setAttribute(OfficeNamespaces.DRAWING_NS, "class-id", classId);
1687         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "href", "./" + href);
1688         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
1689         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
1690         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
1691 
1692         try
1693         {
1694             getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.OBJECT_OLE, oleList, XmlWriterSupport.CLOSE);
1695         }
1696         catch (IOException ioe)
1697         {
1698             throw new ReportProcessingException(FAILED, ioe);
1699         }
1700     }
1701 
calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight, final CSSNumericValue imageWidth, final CSSNumericValue imageHeight)1702     static private double[] calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight,
1703             final CSSNumericValue imageWidth, final CSSNumericValue imageHeight)
1704     {
1705 
1706         final double ratioX = areaWidth.getValue() / imageWidth.getValue();
1707         final double ratioY = areaHeight.getValue() / imageHeight.getValue();
1708         final double ratioMin = Math.min(ratioX, ratioY);
1709 
1710         double[] ret = new double[2];
1711         ret[0] = imageWidth.getValue() * ratioMin;
1712         ret[1] = imageHeight.getValue() * ratioMin;
1713         return ret;
1714     }
1715 
writeNullDate()1716     protected void writeNullDate() throws IOException
1717     {
1718         // write NULL DATE
1719         final XmlWriter xmlWriter = getXmlWriter();
1720         xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "calculation-settings", null, XmlWriterSupport.OPEN);
1721         final AttributeMap nullDateAttributes = new AttributeMap();
1722         nullDateAttributes.setAttribute(OfficeNamespaces.TABLE_NS, "date-value", "1900-01-01");
1723         xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "null-date", buildAttributeList(nullDateAttributes), XmlWriterSupport.CLOSE);
1724         xmlWriter.writeCloseTag();
1725     }
1726 }
1727