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