xref: /trunk/main/reportbuilder/java/com/sun/star/report/pentaho/output/OfficeDocumentReportTarget.java (revision fb60cf8910e0804448d3318ffd78f75bb7989c47)
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 java.util.logging.Level;
41 import java.util.logging.Logger;
42 import javax.xml.transform.OutputKeys;
43 import javax.xml.transform.Transformer;
44 import javax.xml.transform.TransformerFactory;
45 import javax.xml.transform.dom.DOMSource;
46 import javax.xml.transform.stream.StreamResult;
47 import javax.xml.parsers.DocumentBuilderFactory;
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                 Document document = DocumentBuilderFactory.newInstance()
1058                         .newDocumentBuilder().parse(new InputSource(inputStream));
1059                 NodeList nl = document.getElementsByTagName("document-meta/meta/generator");
1060                 Node node = document.getFirstChild().getFirstChild().getFirstChild().getFirstChild();
1061                 String creator = node.getNodeValue();
1062                 node.setNodeValue(creator + "/report_builder");
1063                 Transformer transformer = TransformerFactory.newInstance().newTransformer();
1064                 transformer.setOutputProperty(OutputKeys.METHOD, "xml");
1065 
1066                 final OutputStream outputMetaStream = getOutputRepository().createOutputStream("meta.xml", "text/xml");
1067                 StreamResult result = new StreamResult(outputMetaStream);
1068                 DOMSource source = new DOMSource(document);
1069                 transformer.transform(source, result);
1070 
1071                 //IOUtils.getInstance().copyStreams(inputStream, outputMetaStream);
1072                 outputMetaStream.flush();
1073                 outputMetaStream.close();
1074             }
1075             catch (java.lang.Exception ex)
1076             {
1077             } finally
1078             {
1079                 if (inputStream != null)
1080                 {
1081                     try
1082                     {
1083                         inputStream.close();
1084                     }
1085                     catch (IOException ex)
1086                     {
1087                         Logger.getLogger(OfficeDocumentReportTarget.class.getName()).log(Level.SEVERE, null, ex);
1088                     }
1089                 }
1090             }
1091         }
1092     }
1093 
endReport(final ReportStructureRoot report)1094     public void endReport(final ReportStructureRoot report)
1095             throws DataSourceException, ReportProcessingException
1096     {
1097         if (xmlWriters.size() != 1)
1098         {
1099             throw new IllegalStateException("Invalid writer-stack state");
1100         }
1101 
1102         try
1103         {
1104             final StylesWriter inlineStylesWriter = new StylesWriter(rootXmlWriter);
1105             inlineStylesWriter.writeContentStyles(predefinedStylesCollection, contentStylesCollection);
1106 
1107             final BufferState state = finishBuffering();
1108             this.rootXmlWriter.writeStream(state.getXmlAsReader());
1109 
1110             final OutputStream stylesOutStream =
1111                     outputRepository.createOutputStream("styles.xml", "text/xml");
1112             final OutputStreamWriter osw =
1113                     new OutputStreamWriter(stylesOutStream, "UTF-8");
1114             final StylesWriter stylesWriter = new StylesWriter(osw);
1115             stylesWriter.writeGlobalStyles(predefinedStylesCollection, globalStylesCollection);
1116             stylesWriter.close();
1117 
1118             this.rootXmlWriter.writeCloseTag();
1119             this.rootXmlWriter.close();
1120         }
1121         catch (IOException e)
1122         {
1123             throw new ReportProcessingException(FAILED, e);
1124         }
1125     }
1126 
getXmlWriter()1127     public XmlWriter getXmlWriter()
1128     {
1129         final BufferState bufferState = (BufferState) xmlWriters.peek();
1130         return bufferState.getXmlWriter();
1131     }
1132 
getStylesCollection()1133     public OfficeStylesCollection getStylesCollection()
1134     {
1135         final BufferState bufferState = (BufferState) xmlWriters.peek();
1136         return bufferState.getStylesCollection();
1137     }
1138 
startBuffering(final OfficeStylesCollection stylesCollection, final boolean indent)1139     public void startBuffering(final OfficeStylesCollection stylesCollection,
1140             final boolean indent) throws ReportProcessingException
1141     {
1142         final XmlWriter currentWriter;
1143         if (xmlWriters.isEmpty())
1144         {
1145             currentWriter = rootXmlWriter;
1146         }
1147         else
1148         {
1149             final BufferState bufferState = (BufferState) xmlWriters.peek();
1150             currentWriter = bufferState.getXmlWriter();
1151         }
1152 
1153         try
1154         {
1155             final MemoryByteArrayOutputStream out =
1156                     new MemoryByteArrayOutputStream(INITIAL_BUFFER_SIZE, 256 * INITIAL_BUFFER_SIZE);
1157             final DeflaterOutputStream deflateOut = new DeflaterOutputStream(out);
1158             final OutputStreamWriter xmlBuffer = new OutputStreamWriter(deflateOut, "UTF-16");
1159             //    final StringWriter xmlBuffer = new StringWriter
1160             //        (OfficeDocumentReportTarget.INITIAL_BUFFER_SIZE);
1161             final XmlWriter contentXmlWriter = new XmlWriter(xmlBuffer, createTagDescription());
1162             contentXmlWriter.copyNamespaces(currentWriter);
1163             if (indent)
1164             {
1165                 contentXmlWriter.setAdditionalIndent(currentWriter.getCurrentIndentLevel());
1166                 contentXmlWriter.setWriteFinalLinebreak(true);
1167             }
1168             else
1169             {
1170                 contentXmlWriter.setWriteFinalLinebreak(false);
1171             }
1172             contentXmlWriter.setAlwaysAddNamespace(true);
1173             xmlWriters.push(new BufferState(contentXmlWriter, out, stylesCollection));
1174         }
1175         catch (IOException ioe)
1176         {
1177             throw new ReportProcessingException("Unable to create the buffer", ioe);
1178         }
1179     }
1180 
finishBuffering()1181     public BufferState finishBuffering() throws ReportProcessingException
1182     {
1183         final BufferState state = (BufferState) xmlWriters.pop();
1184         try
1185         {
1186             state.getXmlWriter().close();
1187         }
1188         catch (IOException e)
1189         {
1190             LOGGER.error("ReportProcessing failed", e);
1191         }
1192         return state;
1193     }
1194 
commit()1195     public void commit()
1196             throws ReportProcessingException
1197     {
1198         // do not call flush before the report is fully finished. Every flush
1199         // causes the Office-Backend to fully ZIP all contents (it acts like a
1200         // 'Save' call from the UI) and that's expensive like hell
1201     }
1202 
getNamespaceByUri(final String uri)1203     public NamespaceDefinition getNamespaceByUri(final String uri)
1204     {
1205         return null;
1206     }
1207 
buildAttributeList(final AttributeMap attrs)1208     protected AttributeList buildAttributeList(final AttributeMap attrs)
1209     {
1210         final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
1211         final AttributeList attrList = new AttributeList();
1212         final String[] namespaces = attrs.getNameSpaces();
1213         for (int i = 0; i < namespaces.length; i++)
1214         {
1215             final String attrNamespace = namespaces[i];
1216             if (isFilteredNamespace(attrNamespace))
1217             {
1218                 continue;
1219             }
1220 
1221             final Map localAttributes = attrs.getAttributes(attrNamespace);
1222             final Iterator entries = localAttributes.entrySet().iterator();
1223             while (entries.hasNext())
1224             {
1225                 final Map.Entry entry = (Map.Entry) entries.next();
1226                 final String key = String.valueOf(entry.getKey());
1227                 if (OfficeNamespaces.TABLE_NS.equals(attrNamespace) && "name".equals(key))
1228                 {
1229                     final String tableName = String.valueOf(entry.getValue());
1230                     final String saneName = sanitizeName(tableName);
1231                     attrList.setAttribute(attrNamespace, key,
1232                             tableNameGenerator.generateName(saneName));
1233                 }
1234                 else if (OfficeNamespaces.DRAWING_NS.equals(attrNamespace) && "name".equals(key) && !"equation".equals(elementType))
1235                 {
1236                     final String objectName = String.valueOf(entry.getValue());
1237                     attrList.setAttribute(attrNamespace, key,
1238                             frameNameGenerator.generateName(objectName));
1239                 }
1240                 else
1241                 {
1242                     attrList.setAttribute(attrNamespace, key, String.valueOf(entry.getValue()));
1243                 }
1244             }
1245         }
1246         return attrList;
1247     }
1248 
sanitizeName(final String name)1249     protected String sanitizeName(final String name)
1250     {
1251         // A table name cannot contain spaces and should only contain
1252         // ascii-characters.
1253         if (name == null)
1254         {
1255             return "";
1256         }
1257         final char[] chars = name.toCharArray();
1258         final StringBuffer buffer = new StringBuffer();
1259         for (int i = 0; i < chars.length; i++)
1260         {
1261             final char aChar = chars[i];
1262             if (Character.isWhitespace(aChar))
1263             {
1264                 buffer.append('_');
1265             }
1266             else
1267             {
1268                 buffer.append(aChar);
1269             }
1270         }
1271         return buffer.toString();
1272     }
1273 
1274     /**
1275      * Returns the length in point. This method is f**king slow, it eats half of the processing time. I surely should
1276      * replace it with something more efficient later.
1277      *
1278      * @param text
1279      * @return
1280      */
parseLength(final String text)1281     protected CSSNumericValue parseLength(final String text)
1282     {
1283         if (styleSheetParserUtil == null)
1284         {
1285             styleSheetParserUtil = StyleSheetParserUtil.getInstance();
1286         }
1287 
1288         final LexicalUnit cssValue = styleSheetParserUtil.parseLexicalStyleValue(
1289                 text);
1290         return CSSValueFactory.createLengthValue(cssValue);
1291     }
1292 
isRepeatingSection()1293     protected boolean isRepeatingSection()
1294     {
1295         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);
1296 
1297     }
1298 
deriveStyle(final String styleFamily, final String styleName)1299     protected OfficeStyle deriveStyle(final String styleFamily, final String styleName)
1300             throws ReportProcessingException
1301     {
1302         // autogenerate a style. The style has already been added to the current
1303         // auto-collection.
1304         final OfficeStyle style = StyleUtilities.deriveStyle(styleFamily, styleName,
1305                 getStylesCollection(), getGlobalStylesCollection(),
1306                 getPredefinedStylesCollection(), getAutoStyleNameGenerator());
1307         return style;
1308     }
1309 
startImageProcessing(final AttributeMap attrs)1310     protected void startImageProcessing(final AttributeMap attrs)
1311             throws ReportProcessingException
1312     {
1313         final Object imageData = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA);
1314         final boolean preserveIRI = OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.PRESERVE_IRI));
1315 
1316         // for the first shot, do nothing fancy ..
1317         final ImageProducer.OfficeImage image = imageProducer.produceImage(imageData, preserveIRI);
1318         if (image != null)
1319         {
1320             final ImageElementContext imageContext = (ImageElementContext) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "image-context");
1321 
1322             // When scaling, we have to create an image-style.
1323             final CSSNumericValue width = image.getWidth(); // always in 100th of a mm
1324 
1325             final CSSNumericValue height = image.getHeight(); // always in 100th of a mm
1326 
1327             LOGGER.debug("Image " + imageData + " Width: " + width + ", Height: " + height);
1328             if (width == null || height == null)
1329             {
1330                 return;
1331             }
1332 
1333             CSSNumericValue imageAreaWidthVal;
1334             CSSNumericValue imageAreaHeightVal;
1335             CSSNumericValue posX = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
1336             CSSNumericValue posY = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
1337 
1338             String styleName = null;
1339             if (imageContext != null)
1340             {
1341                 imageAreaWidthVal = computeImageWidth(imageContext);
1342                 imageAreaHeightVal = computeImageHeight(imageContext);
1343 
1344                 if (imageAreaWidthVal == null || imageAreaHeightVal == null)
1345                 {
1346                     LOGGER.debug("Image data returned from context is invalid. Maybe this is not an image?");
1347                     return;
1348                 }
1349                 else
1350                 {
1351                     // compute the clip-area ..
1352                     final CSSNumericValue normalizedImageWidth =
1353                             CSSValueResolverUtility.convertLength(width, imageAreaWidthVal.getType());
1354                     final CSSNumericValue normalizedImageHeight =
1355                             CSSValueResolverUtility.convertLength(height, imageAreaHeightVal.getType());
1356 
1357                     final String scale = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE);
1358                     if (OfficeToken.NONE.equals(scale) && normalizedImageWidth.getValue() > 0 && normalizedImageHeight.getValue() > 0)
1359                     {
1360                         final double clipWidth = normalizedImageWidth.getValue() - imageAreaWidthVal.getValue();
1361                         final double clipHeight = normalizedImageHeight.getValue() - imageAreaHeightVal.getValue();
1362                         if (clipWidth > 0 && clipHeight > 0)
1363                         {
1364                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1365                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1366                             final StringBuffer buffer = new StringBuffer();
1367                             buffer.append("rect(");
1368                             buffer.append(clipHeight / 2);
1369                             buffer.append(imageAreaHeightVal.getType().getType());
1370                             buffer.append(' ');
1371                             buffer.append(clipWidth / 2);
1372                             buffer.append(imageAreaWidthVal.getType().getType());
1373                             buffer.append(' ');
1374                             buffer.append(clipHeight / 2);
1375                             buffer.append(imageAreaHeightVal.getType().getType());
1376                             buffer.append(' ');
1377                             buffer.append(clipWidth / 2);
1378                             buffer.append(imageAreaWidthVal.getType().getType());
1379                             buffer.append(')');
1380                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1381 
1382                             styleName = imageStyle.getStyleName();
1383                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1384                         }
1385                         else if (clipWidth > 0)
1386                         {
1387                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1388                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1389                             final StringBuffer buffer = new StringBuffer();
1390                             buffer.append("rect(0cm ");
1391                             buffer.append(clipWidth / 2);
1392                             buffer.append(imageAreaWidthVal.getType().getType());
1393                             buffer.append(" 0cm ");
1394                             buffer.append(clipWidth / 2);
1395                             buffer.append(imageAreaWidthVal.getType().getType());
1396                             buffer.append(')');
1397                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1398 
1399                             styleName = imageStyle.getStyleName();
1400                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1401                             imageAreaHeightVal = normalizedImageHeight;
1402                         }
1403                         else if (clipHeight > 0)
1404                         {
1405                             final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
1406                             final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
1407                             final StringBuffer buffer = new StringBuffer();
1408                             buffer.append("rect(");
1409                             buffer.append(clipHeight / 2);
1410                             buffer.append(imageAreaHeightVal.getType().getType());
1411                             buffer.append(" 0cm ");
1412                             buffer.append(clipHeight / 2);
1413                             buffer.append(imageAreaHeightVal.getType().getType());
1414                             buffer.append(" 0cm)");
1415                             graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
1416 
1417                             styleName = imageStyle.getStyleName();
1418                             getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
1419                             imageAreaWidthVal = normalizedImageWidth;
1420                         }
1421                         else
1422                         {
1423                             imageAreaWidthVal = normalizedImageWidth;
1424                             imageAreaHeightVal = normalizedImageHeight;
1425                         }
1426                     }
1427                     else if (OfficeToken.ISOTROPIC.equals(scale))
1428                     {
1429                         final double[] ret = calcPaintSize(imageAreaWidthVal, imageAreaHeightVal, normalizedImageWidth, normalizedImageHeight);
1430 
1431                         posX = CSSNumericValue.createValue(imageAreaWidthVal.getType(), (imageAreaWidthVal.getValue() - ret[0]) * 0.5);
1432                         posY = CSSNumericValue.createValue(imageAreaHeightVal.getType(), (imageAreaHeightVal.getValue() - ret[1]) * 0.5);
1433 
1434                         imageAreaWidthVal = CSSNumericValue.createValue(imageAreaWidthVal.getType(), ret[0]);
1435                         imageAreaHeightVal = CSSNumericValue.createValue(imageAreaHeightVal.getType(), ret[1]);
1436                     }
1437                 }
1438                 // If we do scale, then we simply use the given image-area-size as valid image size and dont
1439                 // care about the image itself ..
1440             }
1441             else
1442             {
1443                 LOGGER.debug("There is no image-context, so we have to rely on the image's natural bounds. " + "This may go awfully wrong.");
1444                 imageAreaWidthVal = image.getWidth();
1445                 imageAreaHeightVal = image.getHeight();
1446             }
1447 
1448             final AttributeList frameList = new AttributeList();
1449             frameList.setAttribute(OfficeNamespaces.DRAWING_NS, "name", imageNames.generateName("Image"));
1450             if (styleName != null)
1451             {
1452                 frameList.setAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME, styleName);
1453             }
1454             frameList.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH);
1455             frameList.setAttribute(OfficeNamespaces.SVG_NS, "z-index", "0");
1456             frameList.setAttribute(OfficeNamespaces.SVG_NS, "x", posX.getValue() + posX.getType().getType());
1457             frameList.setAttribute(OfficeNamespaces.SVG_NS, "y", posY.getValue() + posY.getType().getType());
1458 
1459 
1460             LOGGER.debug("Image " + imageData + " A-Width: " + imageAreaWidthVal + ", A-Height: " + imageAreaHeightVal);
1461 
1462             if (imageAreaWidthVal != null)
1463             {
1464                 frameList.setAttribute(OfficeNamespaces.SVG_NS,
1465                         "width", imageAreaWidthVal.getValue() + imageAreaWidthVal.getType().getType());
1466             }
1467 
1468             if (imageAreaHeightVal != null)
1469             {
1470                 frameList.setAttribute(OfficeNamespaces.SVG_NS,
1471                         "height", imageAreaHeightVal.getValue() + imageAreaHeightVal.getType().getType());
1472             }
1473 
1474 
1475             final AttributeList imageList = new AttributeList();
1476             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "href", image.getEmbeddableLink());
1477             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
1478             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
1479             imageList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
1480 
1481 
1482             try
1483             {
1484                 getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, "frame", frameList, XmlWriterSupport.OPEN);
1485                 getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.IMAGE, imageList, XmlWriterSupport.CLOSE);
1486                 getXmlWriter().writeCloseTag();
1487             }
1488             catch (IOException ioe)
1489             {
1490                 throw new ReportProcessingException(FAILED, ioe);
1491             }
1492         }
1493     }
1494 
computeImageWidth(final ImageElementContext imageElementContext)1495     private CSSNumericValue computeImageWidth(final ImageElementContext imageElementContext)
1496     {
1497         final LengthCalculator calculator = new LengthCalculator();
1498         final String[] strings = imageElementContext.getColStyles();
1499         for (int i = 0; i < strings.length; i++)
1500         {
1501             final String styleName = strings[i];
1502             final CSSNumericValue value = computeColumnWidth(styleName);
1503             if (value != null)
1504             {
1505                 calculator.add(value);
1506             }
1507         }
1508         return calculator.getResult();
1509     }
1510 
computeImageHeight(final ImageElementContext imageElementContext)1511     private CSSNumericValue computeImageHeight(final ImageElementContext imageElementContext)
1512     {
1513         final LengthCalculator calculator = new LengthCalculator();
1514         final String[] strings = imageElementContext.getRowStyles();
1515         for (int i = 0; i < strings.length; i++)
1516         {
1517             final String styleName = strings[i];
1518             final CSSNumericValue value = computeRowHeight(styleName);
1519             if (value != null)
1520             {
1521                 calculator.add(value);
1522             }
1523         }
1524         return calculator.getResult();
1525     }
1526 
computeRowHeight(final String rowStyle)1527     protected CSSNumericValue computeRowHeight(final String rowStyle)
1528     {
1529         final OfficeStylesCollection contentStyles = getContentStylesCollection();
1530         final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1531         if (style != null)
1532         {
1533             final Element element = style.getTableRowProperties();
1534             if (element != null)
1535             {
1536                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1537                 if (height != null)
1538                 {
1539                     return parseLength(height);
1540                 }
1541             }
1542 
1543             final String styleParent = style.getStyleParent();
1544             if (styleParent != null)
1545             {
1546                 return computeRowHeight(styleParent);
1547             }
1548         }
1549 
1550         final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
1551         final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1552         if (globalStyle != null)
1553         {
1554             final Element element = globalStyle.getTableRowProperties();
1555             if (element != null)
1556             {
1557                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1558                 if (height != null)
1559                 {
1560                     return parseLength(height);
1561                 }
1562             }
1563             final String styleParent = globalStyle.getStyleParent();
1564             if (styleParent != null)
1565             {
1566                 return computeRowHeight(styleParent);
1567             }
1568         }
1569 
1570         final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
1571         final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
1572         if (predefStyle != null)
1573         {
1574             final Element element = predefStyle.getTableRowProperties();
1575             if (element != null)
1576             {
1577                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
1578                 if (height != null)
1579                 {
1580                     return parseLength(height);
1581                 }
1582             }
1583             final String styleParent = predefStyle.getStyleParent();
1584             if (styleParent != null)
1585             {
1586                 return computeRowHeight(styleParent);
1587             }
1588         }
1589         // not found.
1590         return null;
1591     }
1592 
computeColumnWidth(final String colStyle)1593     protected CSSNumericValue computeColumnWidth(final String colStyle)
1594     {
1595         final OfficeStylesCollection contentStyles = getContentStylesCollection();
1596         final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1597         if (style != null)
1598         {
1599             final Element element = style.getTableColumnProperties();
1600             if (element != null)
1601             {
1602                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1603                 if (height != null)
1604                 {
1605                     return parseLength(height);
1606                 }
1607             }
1608 
1609             final String styleParent = style.getStyleParent();
1610             if (styleParent != null)
1611             {
1612                 return computeRowHeight(styleParent);
1613             }
1614         }
1615 
1616         final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
1617         final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1618         if (globalStyle != null)
1619         {
1620             final Element element = globalStyle.getTableColumnProperties();
1621             if (element != null)
1622             {
1623                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1624                 if (height != null)
1625                 {
1626                     return parseLength(height);
1627                 }
1628             }
1629             final String styleParent = globalStyle.getStyleParent();
1630             if (styleParent != null)
1631             {
1632                 return computeRowHeight(styleParent);
1633             }
1634         }
1635 
1636         final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
1637         final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
1638         if (predefStyle != null)
1639         {
1640             final Element element = predefStyle.getTableColumnProperties();
1641             if (element != null)
1642             {
1643                 final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
1644                 if (height != null)
1645                 {
1646                     return parseLength(height);
1647                 }
1648             }
1649             final String styleParent = predefStyle.getStyleParent();
1650             if (styleParent != null)
1651             {
1652                 return computeRowHeight(styleParent);
1653             }
1654         }
1655         // not found.
1656         return null;
1657     }
1658 
produceFirstChild(final Section style, final String nameSpace, final String type)1659     protected Element produceFirstChild(final Section style,
1660             final String nameSpace,
1661             final String type)
1662     {
1663         Element paragraphProps = style.findFirstChild(nameSpace, type);
1664         if (paragraphProps == null)
1665         {
1666             paragraphProps = new Section();
1667             paragraphProps.setNamespace(nameSpace);
1668             paragraphProps.setType(type);
1669             style.addNode(paragraphProps);
1670         }
1671         return paragraphProps;
1672     }
1673 
startChartProcessing(final AttributeMap attrs)1674     protected void startChartProcessing(final AttributeMap attrs)
1675             throws ReportProcessingException
1676     {
1677         final String classId = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "class-id");
1678         final String chartUrl = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "href");
1679         final ArrayList masterColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_COLUMNS);
1680         final ArrayList masterValues = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_VALUES);
1681         final ArrayList detailColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.DETAIL_COLUMNS);
1682         final String href = oleProducer.produceOle(chartUrl, masterColumns, masterValues, detailColumns);
1683 
1684         final AttributeList oleList = new AttributeList();
1685         oleList.setAttribute(OfficeNamespaces.DRAWING_NS, "class-id", classId);
1686         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "href", "./" + href);
1687         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
1688         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
1689         oleList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
1690 
1691         try
1692         {
1693             getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.OBJECT_OLE, oleList, XmlWriterSupport.CLOSE);
1694         }
1695         catch (IOException ioe)
1696         {
1697             throw new ReportProcessingException(FAILED, ioe);
1698         }
1699     }
1700 
calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight, final CSSNumericValue imageWidth, final CSSNumericValue imageHeight)1701     static private double[] calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight,
1702             final CSSNumericValue imageWidth, final CSSNumericValue imageHeight)
1703     {
1704 
1705         final double ratioX = areaWidth.getValue() / imageWidth.getValue();
1706         final double ratioY = areaHeight.getValue() / imageHeight.getValue();
1707         final double ratioMin = Math.min(ratioX, ratioY);
1708 
1709         double[] ret = new double[2];
1710         ret[0] = imageWidth.getValue() * ratioMin;
1711         ret[1] = imageHeight.getValue() * ratioMin;
1712         return ret;
1713     }
1714 
writeNullDate()1715     protected void writeNullDate() throws IOException
1716     {
1717         // write NULL DATE
1718         final XmlWriter xmlWriter = getXmlWriter();
1719         xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "calculation-settings", null, XmlWriterSupport.OPEN);
1720         final AttributeMap nullDateAttributes = new AttributeMap();
1721         nullDateAttributes.setAttribute(OfficeNamespaces.TABLE_NS, "date-value", "1900-01-01");
1722         xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "null-date", buildAttributeList(nullDateAttributes), XmlWriterSupport.CLOSE);
1723         xmlWriter.writeCloseTag();
1724     }
1725 }
1726