11a37d047SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 31a37d047SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 41a37d047SAndrew Rist * or more contributor license agreements. See the NOTICE file 51a37d047SAndrew Rist * distributed with this work for additional information 61a37d047SAndrew Rist * regarding copyright ownership. The ASF licenses this file 71a37d047SAndrew Rist * to you under the Apache License, Version 2.0 (the 81a37d047SAndrew Rist * "License"); you may not use this file except in compliance 91a37d047SAndrew Rist * with the License. You may obtain a copy of the License at 101a37d047SAndrew Rist * 111a37d047SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 121a37d047SAndrew Rist * 131a37d047SAndrew Rist * Unless required by applicable law or agreed to in writing, 141a37d047SAndrew Rist * software distributed under the License is distributed on an 151a37d047SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 161a37d047SAndrew Rist * KIND, either express or implied. See the License for the 171a37d047SAndrew Rist * specific language governing permissions and limitations 181a37d047SAndrew Rist * under the License. 191a37d047SAndrew Rist * 201a37d047SAndrew Rist *************************************************************/ 211a37d047SAndrew Rist 221a37d047SAndrew Rist 23cdf0e10cSrcweir package com.sun.star.report.pentaho.layoutprocessor; 24cdf0e10cSrcweir 25cdf0e10cSrcweir import com.sun.star.report.OfficeToken; 26cdf0e10cSrcweir import com.sun.star.report.pentaho.OfficeNamespaces; 27cdf0e10cSrcweir import com.sun.star.report.pentaho.model.ImageElement; 28cdf0e10cSrcweir 29cdf0e10cSrcweir import org.apache.commons.logging.Log; 30cdf0e10cSrcweir import org.apache.commons.logging.LogFactory; 31cdf0e10cSrcweir 32cdf0e10cSrcweir import org.jfree.layouting.util.AttributeMap; 33cdf0e10cSrcweir import org.jfree.report.DataSourceException; 34cdf0e10cSrcweir import org.jfree.report.JFreeReportInfo; 35cdf0e10cSrcweir import org.jfree.report.ReportDataFactoryException; 36cdf0e10cSrcweir import org.jfree.report.ReportProcessingException; 37cdf0e10cSrcweir import org.jfree.report.data.GlobalMasterRow; 38cdf0e10cSrcweir import org.jfree.report.data.ReportDataRow; 39cdf0e10cSrcweir import org.jfree.report.expressions.FormulaExpression; 40cdf0e10cSrcweir import org.jfree.report.flow.FlowController; 41cdf0e10cSrcweir import org.jfree.report.flow.ReportTarget; 42cdf0e10cSrcweir import org.jfree.report.flow.layoutprocessor.LayoutController; 43cdf0e10cSrcweir import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; 44cdf0e10cSrcweir import org.jfree.report.structure.Element; 45cdf0e10cSrcweir import org.jfree.report.structure.Node; 46cdf0e10cSrcweir import org.jfree.report.structure.Section; 47cdf0e10cSrcweir import org.jfree.report.util.TextUtilities; 48cdf0e10cSrcweir 49cdf0e10cSrcweir import org.pentaho.reporting.libraries.base.util.ObjectUtilities; 50cdf0e10cSrcweir import org.pentaho.reporting.libraries.formula.Formula; 51cdf0e10cSrcweir import org.pentaho.reporting.libraries.formula.lvalues.LValue; 52cdf0e10cSrcweir import org.pentaho.reporting.libraries.formula.parser.ParseException; 53cdf0e10cSrcweir 54cdf0e10cSrcweir /** 55cdf0e10cSrcweir * Produces an image. The image-structures itself (draw:frame and so on) are not generated here. This element produces a 56cdf0e10cSrcweir * place-holder element and relies on the output target to compute a sensible position for the element. The report 57cdf0e10cSrcweir * definition does not give any hints about the size of the image, so we have to derive this from the surrounding 58cdf0e10cSrcweir * context. 59cdf0e10cSrcweir * 60cdf0e10cSrcweir * @author Thomas Morgner 61cdf0e10cSrcweir * @since 05.03.2007 62cdf0e10cSrcweir */ 63cdf0e10cSrcweir public class ImageElementLayoutController 64cdf0e10cSrcweir extends AbstractReportElementLayoutController 65cdf0e10cSrcweir { 66cdf0e10cSrcweir 67cdf0e10cSrcweir private static final Log LOGGER = LogFactory.getLog(ImageElementLayoutController.class); 68cdf0e10cSrcweir private ImageElementContext context; 69cdf0e10cSrcweir ImageElementLayoutController()70cdf0e10cSrcweir public ImageElementLayoutController() 71cdf0e10cSrcweir { 72cdf0e10cSrcweir } 73cdf0e10cSrcweir delegateContentGeneration(final ReportTarget target)74cdf0e10cSrcweir protected LayoutController delegateContentGeneration(final ReportTarget target) 75cdf0e10cSrcweir throws ReportProcessingException, ReportDataFactoryException, 76cdf0e10cSrcweir DataSourceException 77cdf0e10cSrcweir { 78cdf0e10cSrcweir final ImageElement imageElement = (ImageElement) getNode(); 79cdf0e10cSrcweir final FormulaExpression formulaExpression = imageElement.getFormula(); 80cdf0e10cSrcweir if (formulaExpression == null) 81cdf0e10cSrcweir { 82cdf0e10cSrcweir // A static image is easy. At least at this level. Dont ask about the weird things we have to do in the 83cdf0e10cSrcweir // output targets ... 84cdf0e10cSrcweir final String linkTarget = imageElement.getImageData(); 85cdf0e10cSrcweir generateImage(target, linkTarget, imageElement.getScaleMode(), imageElement.isPreserveIRI()); 86cdf0e10cSrcweir } 87cdf0e10cSrcweir else 88cdf0e10cSrcweir { 89cdf0e10cSrcweir final Object value = 90cdf0e10cSrcweir LayoutControllerUtil.evaluateExpression(getFlowController(), imageElement, formulaExpression); 91cdf0e10cSrcweir generateImage(target, value, imageElement.getScaleMode(), imageElement.isPreserveIRI()); 92cdf0e10cSrcweir } 93cdf0e10cSrcweir return join(getFlowController()); 94cdf0e10cSrcweir } 95cdf0e10cSrcweir generateImage(final ReportTarget target, final Object linkTarget, final String scale, final boolean preserveIri)96cdf0e10cSrcweir private void generateImage(final ReportTarget target, 97cdf0e10cSrcweir final Object linkTarget, 98cdf0e10cSrcweir final String scale, 99cdf0e10cSrcweir final boolean preserveIri) 100cdf0e10cSrcweir throws ReportProcessingException, DataSourceException 101cdf0e10cSrcweir { 102cdf0e10cSrcweir if (linkTarget == null) 103cdf0e10cSrcweir { 104cdf0e10cSrcweir return; 105cdf0e10cSrcweir } 106cdf0e10cSrcweir 107cdf0e10cSrcweir final AttributeMap image = new AttributeMap(); 108cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, JFreeReportInfo.REPORT_NAMESPACE); 109cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, OfficeToken.IMAGE); 110cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE, scale); 111cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.PRESERVE_IRI, String.valueOf(preserveIri)); 112cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "image-context", createContext()); 113cdf0e10cSrcweir image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA, linkTarget); 114cdf0e10cSrcweir target.startElement(image); 115cdf0e10cSrcweir target.endElement(image); 116cdf0e10cSrcweir } 117cdf0e10cSrcweir createContext()118cdf0e10cSrcweir protected ImageElementContext createContext() 119cdf0e10cSrcweir { 120cdf0e10cSrcweir if (context == null) 121cdf0e10cSrcweir { 122cdf0e10cSrcweir 123cdf0e10cSrcweir // Step 1: Find the parent cell. 124cdf0e10cSrcweir final LayoutController cellController = findParentCell(); 125cdf0e10cSrcweir if (cellController == null) 126cdf0e10cSrcweir { 127cdf0e10cSrcweir LOGGER.warn("Image is not contained in a table. Unable to calculate the image-size."); 128cdf0e10cSrcweir return null; 129cdf0e10cSrcweir } 130cdf0e10cSrcweir final Element tableCell = (Element) cellController.getNode(); 131cdf0e10cSrcweir final int rowSpan = TextUtilities.parseInt((String) tableCell.getAttribute(OfficeNamespaces.TABLE_NS, "number-rows-spanned"), 1); 132cdf0e10cSrcweir final int colSpan = TextUtilities.parseInt((String) tableCell.getAttribute(OfficeNamespaces.TABLE_NS, "number-columns-spanned"), 1); 133cdf0e10cSrcweir if (rowSpan < 1 || colSpan < 1) 134cdf0e10cSrcweir { 135cdf0e10cSrcweir LOGGER.warn("Rowspan or colspan for image-size calculation was invalid."); 136cdf0e10cSrcweir return null; 137cdf0e10cSrcweir } 138cdf0e10cSrcweir 139cdf0e10cSrcweir final LayoutController rowController = cellController.getParent(); 140cdf0e10cSrcweir if (rowController == null) 141cdf0e10cSrcweir { 142cdf0e10cSrcweir LOGGER.warn("Table-Cell has no parent. Unable to calculate the image-size."); 143cdf0e10cSrcweir return null; 144cdf0e10cSrcweir } 145cdf0e10cSrcweir final Section tableRow = (Section) rowController.getNode(); 146cdf0e10cSrcweir // we are now making the assumption, that the row is a section, that contains the table-cell. 147cdf0e10cSrcweir // This breaks the ability to return nodes or to construct reports on the fly, but the OO-report format 148*9f813b30Smseidel // is weird anyway and won't support such advanced techniques for the next few centuries... 149cdf0e10cSrcweir final int columnPos = findNodeInSection(tableRow, tableCell, OfficeToken.COVERED_TABLE_CELL); 150cdf0e10cSrcweir if (columnPos == -1) 151cdf0e10cSrcweir { 152cdf0e10cSrcweir LOGGER.warn("Table-Cell is not a direct child of the table-row. Unable to calculate the image-size."); 153cdf0e10cSrcweir return null; 154cdf0e10cSrcweir } 155cdf0e10cSrcweir 156cdf0e10cSrcweir final LayoutController tableController = rowController.getParent(); 157cdf0e10cSrcweir if (tableController == null) 158cdf0e10cSrcweir { 159cdf0e10cSrcweir LOGGER.warn("Table-Row has no Table. Unable to calculate the image-size."); 160cdf0e10cSrcweir return null; 161cdf0e10cSrcweir } 162cdf0e10cSrcweir 163cdf0e10cSrcweir final Section table = (Section) tableController.getNode(); 164cdf0e10cSrcweir // ok, we got a table, so as next we have to search for the columns now. 165cdf0e10cSrcweir final Section columns = (Section) table.findFirstChild(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMNS); 166cdf0e10cSrcweir if (columns.getNodeCount() <= columnPos + colSpan) 167cdf0e10cSrcweir { 168cdf0e10cSrcweir // the colspan is to large. The table definition is therefore invalid. We do not try to fix this. 169cdf0e10cSrcweir LOGGER.warn( 170cdf0e10cSrcweir "The Table's defined columns do not match the col-span or col-position. Unable to calculate the image-size."); 171cdf0e10cSrcweir return null; 172cdf0e10cSrcweir } 173cdf0e10cSrcweir 174cdf0e10cSrcweir final ImageElementContext context = new ImageElementContext(colSpan, rowSpan); 175cdf0e10cSrcweir addColumnStyles(context, columns, columnPos, colSpan); 176cdf0e10cSrcweir // finally search the styles for the row now. 177cdf0e10cSrcweir final int rowPos = findNodeInSection(table, tableRow, null); 178cdf0e10cSrcweir if (rowPos == -1) 179cdf0e10cSrcweir { 180cdf0e10cSrcweir LOGGER.warn("Table-Cell is not a direct child of the table-row. Unable to calculate the image-size."); 181cdf0e10cSrcweir return null; 182cdf0e10cSrcweir } 183cdf0e10cSrcweir 184cdf0e10cSrcweir addRowStyles(context, table, rowPos, rowSpan); 185cdf0e10cSrcweir this.context = context; 186cdf0e10cSrcweir } 187cdf0e10cSrcweir return this.context; 188cdf0e10cSrcweir } 189cdf0e10cSrcweir findNodeInSection(final Section tableRow, final Element tableCell, final String secondType)190cdf0e10cSrcweir private int findNodeInSection(final Section tableRow, 191cdf0e10cSrcweir final Element tableCell, 192cdf0e10cSrcweir final String secondType) 193cdf0e10cSrcweir { 194cdf0e10cSrcweir int retval = 0; 195cdf0e10cSrcweir final Node[] nodes = tableRow.getNodeArray(); 196cdf0e10cSrcweir final String namespace = tableCell.getNamespace(); 197cdf0e10cSrcweir final String type = tableCell.getType(); 198cdf0e10cSrcweir for (final Node node : nodes) 199cdf0e10cSrcweir { 200cdf0e10cSrcweir if (!(node instanceof Element)) 201cdf0e10cSrcweir { 202cdf0e10cSrcweir continue; 203cdf0e10cSrcweir } 204cdf0e10cSrcweir final Element child = (Element) node; 205cdf0e10cSrcweir /* 206cdf0e10cSrcweir if (! OfficeToken.COVERED_TABLE_CELL.equals(child.getType()) && 207cdf0e10cSrcweir (ObjectUtilities.equal(child.getNamespace(), namespace) == false || 208cdf0e10cSrcweir ObjectUtilities.equal(child.getType(), type) == false)) 209cdf0e10cSrcweir */ 210cdf0e10cSrcweir if (!ObjectUtilities.equal(child.getNamespace(), namespace) || (!ObjectUtilities.equal(child.getType(), type) && (secondType == null || !ObjectUtilities.equal(child.getType(), secondType)))) 211cdf0e10cSrcweir { 212cdf0e10cSrcweir continue; 213cdf0e10cSrcweir } 214cdf0e10cSrcweir 215cdf0e10cSrcweir if (node == tableCell) 216cdf0e10cSrcweir { 217cdf0e10cSrcweir return retval; 218cdf0e10cSrcweir } 219cdf0e10cSrcweir retval += 1; 220cdf0e10cSrcweir } 221cdf0e10cSrcweir return -1; 222cdf0e10cSrcweir } 223cdf0e10cSrcweir findParentCell()224cdf0e10cSrcweir private LayoutController findParentCell() 225cdf0e10cSrcweir { 226cdf0e10cSrcweir LayoutController parent = getParent(); 227cdf0e10cSrcweir while (parent != null) 228cdf0e10cSrcweir { 229cdf0e10cSrcweir final Object node = parent.getNode(); 230cdf0e10cSrcweir if (node instanceof Element) 231cdf0e10cSrcweir { 232cdf0e10cSrcweir final Element element = (Element) node; 233cdf0e10cSrcweir if (OfficeNamespaces.TABLE_NS.equals(element.getNamespace()) && "table-cell".equals(element.getType())) 234cdf0e10cSrcweir { 235cdf0e10cSrcweir return parent; 236cdf0e10cSrcweir } 237cdf0e10cSrcweir } 238cdf0e10cSrcweir parent = parent.getParent(); 239cdf0e10cSrcweir } 240cdf0e10cSrcweir return null; 241cdf0e10cSrcweir } 242cdf0e10cSrcweir isValueChanged()243cdf0e10cSrcweir protected boolean isValueChanged() 244cdf0e10cSrcweir { 245cdf0e10cSrcweir final ImageElement imageElement = (ImageElement) getNode(); 246cdf0e10cSrcweir final FormulaExpression formulaExpression = imageElement.getFormula(); 247cdf0e10cSrcweir if (formulaExpression == null) 248cdf0e10cSrcweir { 249cdf0e10cSrcweir final FlowController controller = getFlowController(); 250cdf0e10cSrcweir final GlobalMasterRow masterRow = controller.getMasterRow(); 251cdf0e10cSrcweir final ReportDataRow reportDataRow = masterRow.getReportDataRow(); 252cdf0e10cSrcweir return reportDataRow.getCursor() == 0; 253cdf0e10cSrcweir } 254cdf0e10cSrcweir 255cdf0e10cSrcweir try 256cdf0e10cSrcweir { 257cdf0e10cSrcweir final Formula formula = formulaExpression.getCompiledFormula(); 258cdf0e10cSrcweir final LValue lValue = formula.getRootReference(); 259cdf0e10cSrcweir return isReferenceChanged(lValue); 260cdf0e10cSrcweir } 261cdf0e10cSrcweir catch (ParseException e) 262cdf0e10cSrcweir { 263cdf0e10cSrcweir return false; 264cdf0e10cSrcweir } 265cdf0e10cSrcweir } 266cdf0e10cSrcweir addColumnStyles(final ImageElementContext context, final Section columns, final int columnPos, final int colSpan)267cdf0e10cSrcweir void addColumnStyles(final ImageElementContext context, final Section columns, final int columnPos, final int colSpan) 268cdf0e10cSrcweir { 269cdf0e10cSrcweir final Node[] columnDefs = columns.getNodeArray(); 270cdf0e10cSrcweir int columnCounter = 0; 271cdf0e10cSrcweir for (Node columnDef : columnDefs) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir final Element column = (Element) columnDef; 274cdf0e10cSrcweir 275cdf0e10cSrcweir if (!ObjectUtilities.equal(column.getNamespace(), OfficeNamespaces.TABLE_NS) || !ObjectUtilities.equal(column.getType(), OfficeToken.TABLE_COLUMN)) 276cdf0e10cSrcweir { 277cdf0e10cSrcweir continue; 278cdf0e10cSrcweir } 279cdf0e10cSrcweir if (columnCounter >= columnPos) 280cdf0e10cSrcweir { 281cdf0e10cSrcweir final String colStyle = (String) column.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); 282cdf0e10cSrcweir context.setColStyle(columnCounter - columnPos, colStyle); 283cdf0e10cSrcweir } 284cdf0e10cSrcweir 285cdf0e10cSrcweir columnCounter += 1; 286cdf0e10cSrcweir 287cdf0e10cSrcweir if (columnCounter >= (columnPos + colSpan)) 288cdf0e10cSrcweir { 289cdf0e10cSrcweir break; 290cdf0e10cSrcweir } 291cdf0e10cSrcweir 292cdf0e10cSrcweir } 293cdf0e10cSrcweir } 294cdf0e10cSrcweir addRowStyles(final ImageElementContext context, final Section table, final int rowPos, final int rowSpan)295cdf0e10cSrcweir void addRowStyles(final ImageElementContext context, final Section table, final int rowPos, final int rowSpan) 296cdf0e10cSrcweir { 297cdf0e10cSrcweir final Node[] rows = table.getNodeArray(); 298cdf0e10cSrcweir int rowCounter = 0; 299cdf0e10cSrcweir for (Node row1 : rows) 300cdf0e10cSrcweir { 301cdf0e10cSrcweir final Element row = (Element) row1; 302cdf0e10cSrcweir 303cdf0e10cSrcweir if (!ObjectUtilities.equal(row.getNamespace(), OfficeNamespaces.TABLE_NS) || !ObjectUtilities.equal(row.getType(), OfficeToken.TABLE_ROW)) 304cdf0e10cSrcweir { 305cdf0e10cSrcweir continue; 306cdf0e10cSrcweir } 307cdf0e10cSrcweir if (rowCounter >= rowPos) 308cdf0e10cSrcweir { 309cdf0e10cSrcweir final String rowStyle = (String) row.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); 310cdf0e10cSrcweir context.setRowStyle(rowCounter - rowPos, rowStyle); 311cdf0e10cSrcweir } 312cdf0e10cSrcweir 313cdf0e10cSrcweir rowCounter += 1; 314cdf0e10cSrcweir 315cdf0e10cSrcweir if (rowCounter >= (rowPos + rowSpan)) 316cdf0e10cSrcweir { 317cdf0e10cSrcweir break; 318cdf0e10cSrcweir } 319cdf0e10cSrcweir } 320cdf0e10cSrcweir } 321cdf0e10cSrcweir } 322