| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| package com.sun.star.report.pentaho.output; |
| |
| import com.sun.star.report.pentaho.OfficeNamespaces; |
| import com.sun.star.report.pentaho.model.DataStyle; |
| import com.sun.star.report.pentaho.model.FontFaceDeclsSection; |
| import com.sun.star.report.pentaho.model.FontFaceElement; |
| import com.sun.star.report.pentaho.model.OfficeStyle; |
| import com.sun.star.report.pentaho.model.OfficeStyles; |
| import com.sun.star.report.pentaho.model.OfficeStylesCollection; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.jfree.report.ReportProcessingException; |
| import org.jfree.report.structure.Element; |
| import org.jfree.report.structure.Section; |
| import org.jfree.report.util.AttributeNameGenerator; |
| |
| |
| /** |
| * Todo: Document me! |
| * |
| * @author Thomas Morgner |
| * @since 13.03.2007 |
| */ |
| public class StyleUtilities |
| { |
| |
| private static final Log LOGGER = LogFactory.getLog(StyleUtilities.class); |
| private static final String STYLE = "style"; |
| |
| private StyleUtilities() |
| { |
| } |
| |
| /** |
| * Copies the specififed style (keyed by its family and name) into the current styles collection. This copies the |
| * style and all inherited styles into the target collection. Inherited common styles will be always be added to the |
| * common collection (which will be written into the 'styles.xml' later). |
| * <p/> |
| * This method does nothing if the specified style already exists in the styles collection. |
| * |
| * @param styleFamily the family of the style to copy |
| * @param styleName the unique name of the style. |
| * @param stylesCollection the current styles collection |
| * @param commonCollection the global styles collection |
| * @param predefCollection the predefined styles from where to copy the styles. |
| * @throws ReportProcessingException if the style copying failed. |
| */ |
| public static void copyStyle(final String styleFamily, |
| final String styleName, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection) |
| throws ReportProcessingException |
| { |
| copyStyle(styleFamily, styleName, stylesCollection, |
| commonCollection, predefCollection, new HashSet()); |
| } |
| |
| /** |
| * Copies the specififed style (keyed by its family and name) into the current styles collection. This copies the |
| * style and all inherited styles into the target collection. Inherited common styles will be always be added to the |
| * common collection (which will be written into the 'styles.xml' later). |
| * <p/> |
| * This method does nothing if the specified style already exists in the styles collection. |
| * |
| * @param styleFamily the family of the style to copy |
| * @param styleName the unique name of the style. |
| * @param stylesCollection the current styles collection |
| * @param commonCollection the global styles collection |
| * @param predefCollection the predefined styles from where to copy the styles. |
| * @param inheritanceTracker a collection of all styles that have been touched. This is used to prevent infinite |
| * loops and duplicates. |
| * @throws ReportProcessingException if the style copying failed. |
| */ |
| private static void copyStyle(final String styleFamily, |
| final String styleName, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection, |
| final Set inheritanceTracker) |
| throws ReportProcessingException |
| { |
| if (inheritanceTracker.contains(styleName)) |
| { |
| return; |
| } |
| inheritanceTracker.add(styleName); |
| |
| if (stylesCollection.containsStyle(styleFamily, styleName) || commonCollection.getCommonStyles().containsStyle(styleFamily, styleName)) |
| { |
| // fine, there's already a copy of the stylesheet. |
| return; |
| } |
| |
| final OfficeStyle predefCommonStyle = |
| predefCollection.getCommonStyles().getStyle(styleFamily, styleName); |
| if (predefCommonStyle != null) |
| { |
| // so we have an style from the predefined collection. |
| // copy it an add it to the current stylescollection |
| final OfficeStyles commonStyles = commonCollection.getCommonStyles(); |
| |
| copyStyleInternal(predefCommonStyle, commonStyles, stylesCollection, |
| commonCollection, predefCollection, styleFamily, inheritanceTracker); |
| return; |
| } |
| |
| final OfficeStyle predefAutoStyle = |
| predefCollection.getAutomaticStyles().getStyle(styleFamily, styleName); |
| if (predefAutoStyle != null) |
| { |
| // so we have an style from the predefined collection. |
| // copy it an add it to the current stylescollection |
| final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); |
| copyStyleInternal(predefAutoStyle, autoStyles, stylesCollection, |
| commonCollection, predefCollection, styleFamily, inheritanceTracker); |
| return; |
| } |
| |
| // There is no automatic style either. Now this means that someone |
| // messed up the fileformat. Lets create a new empty style for this. |
| final OfficeStyle autostyle = new OfficeStyle(); |
| autostyle.setNamespace(OfficeNamespaces.STYLE_NS); |
| autostyle.setType(STYLE); |
| autostyle.setStyleFamily(styleFamily); |
| autostyle.setStyleName(styleName); |
| |
| final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); |
| autoStyles.addStyle(autostyle); |
| } |
| |
| private static OfficeStyle copyStyleInternal( |
| final OfficeStyle predefCommonStyle, |
| final OfficeStyles styles, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection, |
| final String styleFamily, |
| final Set inheritanceTracker) |
| throws ReportProcessingException |
| { |
| try |
| { |
| final OfficeStyle preStyle = (OfficeStyle) predefCommonStyle.clone(); |
| styles.addStyle(preStyle); |
| performFontFaceProcessing(preStyle, stylesCollection, predefCollection); |
| performDataStyleProcessing(preStyle, stylesCollection, predefCollection); |
| |
| // Lookup the parent style .. |
| final String styleParent = preStyle.getStyleParent(); |
| final OfficeStyle inherited = |
| stylesCollection.getStyle(styleFamily, styleParent); |
| if (inherited != null) |
| { |
| // OK, recurse (and hope that we dont run into an infinite loop) .. |
| copyStyle(styleFamily, styleParent, stylesCollection, |
| commonCollection, predefCollection, inheritanceTracker); |
| } |
| else if (styleParent != null) |
| { |
| LOGGER.warn("Inconsistent styles: " + styleFamily + ":" + styleParent + " does not exist."); |
| } |
| return preStyle; |
| } |
| catch (CloneNotSupportedException e) |
| { |
| throw new ReportProcessingException("Failed to derive a stylesheet", e); |
| } |
| } |
| |
| private static void performFontFaceProcessing(final OfficeStyle style, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection predefCollection) |
| throws ReportProcessingException |
| { |
| final Element textProperties = style.getTextProperties(); |
| if (textProperties == null) |
| { |
| return; |
| } |
| |
| try |
| { |
| final FontFaceDeclsSection currentFonts = stylesCollection.getFontFaceDecls(); |
| final FontFaceDeclsSection predefFonts = predefCollection.getFontFaceDecls(); |
| |
| final String fontName = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, "font-name"); |
| if (fontName != null && !currentFonts.containsFont(fontName)) |
| { |
| final FontFaceElement element = predefFonts.getFontFace(fontName); |
| if (element != null) |
| { |
| currentFonts.addFontFace((FontFaceElement) element.clone()); |
| } |
| } |
| |
| final String fontNameAsian = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, |
| "font-name-asian"); |
| if (fontNameAsian != null && !currentFonts.containsFont(fontNameAsian)) |
| { |
| final FontFaceElement element = predefFonts.getFontFace( |
| fontNameAsian); |
| if (element != null) |
| { |
| currentFonts.addFontFace((FontFaceElement) element.clone()); |
| } |
| } |
| |
| final String fontNameComplex = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, |
| "font-name-complex"); |
| if (fontNameComplex != null && !currentFonts.containsFont(fontNameComplex)) |
| { |
| final FontFaceElement element = predefFonts.getFontFace( |
| fontNameComplex); |
| if (element != null) |
| { |
| currentFonts.addFontFace((FontFaceElement) element.clone()); |
| } |
| } |
| } |
| catch (CloneNotSupportedException e) |
| { |
| throw new ReportProcessingException("Failed to clone font-face element"); |
| } |
| } |
| |
| private static void performDataStyleProcessing(final OfficeStyle style, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection predefCollection) |
| throws ReportProcessingException |
| { |
| final Section derivedStyle = performDataStyleProcessing(style, stylesCollection, predefCollection, "data-style-name"); |
| if (derivedStyle != null) |
| { |
| try |
| { |
| final Section styleMap = (Section) derivedStyle.findFirstChild(OfficeNamespaces.STYLE_NS, "map"); |
| if (styleMap != null) |
| { |
| performDataStyleProcessing(styleMap, stylesCollection, predefCollection, "apply-style-name"); |
| } |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| } |
| |
| private static Section performDataStyleProcessing(final Section style, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection predefCollection, |
| final String attributeName) |
| throws ReportProcessingException |
| { |
| final Object attribute = style.getAttribute(OfficeNamespaces.STYLE_NS, attributeName); |
| final DataStyle derivedStyle; |
| if (attribute != null) |
| { |
| final String styleName = String.valueOf(attribute); |
| if (!stylesCollection.getAutomaticStyles().containsDataStyle(styleName) && !stylesCollection.getCommonStyles().containsDataStyle(styleName)) |
| { |
| try |
| { |
| final OfficeStyles automaticStyles = predefCollection.getAutomaticStyles(); |
| final DataStyle autoDataStyle = automaticStyles.getDataStyle(styleName); |
| if (autoDataStyle != null) |
| { |
| derivedStyle = (DataStyle) autoDataStyle.clone(); |
| stylesCollection.getAutomaticStyles().addDataStyle(derivedStyle); |
| } |
| else |
| { |
| final OfficeStyles commonStyles = predefCollection.getCommonStyles(); |
| final DataStyle commonDataStyle = commonStyles.getDataStyle(styleName); |
| if (commonDataStyle != null) |
| { |
| derivedStyle = (DataStyle) commonDataStyle.clone(); |
| stylesCollection.getCommonStyles().addDataStyle(derivedStyle); |
| } |
| else |
| { |
| LOGGER.warn("Dangling data style: " + styleName); |
| derivedStyle = null; |
| } |
| } |
| } |
| catch (CloneNotSupportedException e) |
| { |
| throw new ReportProcessingException("Failed to copy style. This should not have happened."); |
| } |
| } |
| else |
| { |
| derivedStyle = null; |
| } |
| } |
| else |
| { |
| derivedStyle = null; |
| } |
| return derivedStyle; |
| } |
| |
| /** |
| * Derives the named style. If the style is a common style, a new automatic style is generated and inserted into the |
| * given stylesCollection. If the named style is an automatic style, the style is copied and inserted as new automatic |
| * style. |
| * <p/> |
| * After the style has been created, the style's inheritance hierarchy will be copied as well. |
| * <p/> |
| * If there is no style with the given name and family, a new empty automatic style will be created. |
| * |
| * @param styleFamily the family of the style to copy |
| * @param styleName the unique name of the style. |
| * @param stylesCollection the current styles collection |
| * @param commonCollection the global styles collection |
| * @param predefCollection the predefined styles from where to copy the styles. |
| * @param generator the style-name-generator of the current report-target |
| * @return the derived style instance. |
| * @throws ReportProcessingException if the style copying failed. |
| */ |
| public static OfficeStyle deriveStyle(final String styleFamily, |
| final String styleName, |
| final OfficeStylesCollection stylesCollection, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection, |
| final AttributeNameGenerator generator) |
| throws ReportProcessingException |
| { |
| if (styleFamily == null) |
| { |
| throw new NullPointerException("StyleFamily must not be null"); |
| } |
| if (styleName != null) |
| { |
| |
| final OfficeStyle currentAuto = |
| stylesCollection.getAutomaticStyles().getStyle(styleFamily, |
| styleName); |
| if (currentAuto != null) |
| { |
| // handle an automatic style .. |
| final OfficeStyle derivedStyle = |
| deriveAutomaticStyle(currentAuto, styleFamily, styleName, |
| generator, commonCollection, predefCollection); |
| stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| return derivedStyle; |
| } |
| |
| final OfficeStyle currentCommon = |
| stylesCollection.getCommonStyles().getStyle(styleFamily, styleName); |
| if (currentCommon != null) |
| { |
| // handle an common style .. |
| final OfficeStyle derivedStyle = |
| deriveCommonStyle(currentCommon, styleFamily, styleName, |
| generator, commonCollection, predefCollection); |
| stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| return derivedStyle; |
| } |
| |
| // final OfficeStyle commonAuto = |
| // commonCollection.getAutomaticStyles().getStyle(styleFamily, |
| // styleName); |
| // if (commonAuto != null) |
| // { |
| // // handle an automatic style .. |
| // final OfficeStyle derivedStyle = |
| // deriveAutomaticStyle(commonAuto, styleFamily, styleName, |
| // generator, commonCollection, predefCollection); |
| // stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| // return derivedStyle; |
| // } |
| |
| final OfficeStyle commonCommon = |
| commonCollection.getCommonStyles().getStyle(styleFamily, styleName); |
| if (commonCommon != null) |
| { |
| // handle an common style .. |
| final OfficeStyle derivedStyle = |
| deriveCommonStyle(commonCommon, styleFamily, styleName, |
| generator, commonCollection, predefCollection); |
| stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| return derivedStyle; |
| } |
| |
| final OfficeStyle predefAuto = |
| predefCollection.getAutomaticStyles().getStyle(styleFamily, |
| styleName); |
| if (predefAuto != null) |
| { |
| // handle an automatic style .. |
| final OfficeStyle derivedStyle = |
| deriveAutomaticStyle(predefAuto, styleFamily, styleName, |
| generator, commonCollection, predefCollection); |
| stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| return derivedStyle; |
| } |
| |
| final OfficeStyle predefCommon = |
| predefCollection.getCommonStyles().getStyle(styleFamily, styleName); |
| if (predefCommon != null) |
| { |
| // handle an common style .. |
| final OfficeStyle derivedStyle = |
| deriveCommonStyle(predefCommon, styleFamily, styleName, |
| generator, commonCollection, predefCollection); |
| stylesCollection.getAutomaticStyles().addStyle(derivedStyle); |
| return derivedStyle; |
| } |
| } |
| |
| // No such style. Create a new one .. |
| final OfficeStyle autostyle = new OfficeStyle(); |
| autostyle.setNamespace(OfficeNamespaces.STYLE_NS); |
| autostyle.setType(STYLE); |
| autostyle.setStyleFamily(styleFamily); |
| if (styleName != null) |
| { |
| autostyle.setStyleName(styleName); |
| } |
| else |
| { |
| autostyle.setStyleName(generator.generateName("derived_anonymous")); |
| } |
| |
| final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); |
| autoStyles.addStyle(autostyle); |
| return autostyle; |
| } |
| |
| private static OfficeStyle deriveCommonStyle(final OfficeStyle commonStyle, |
| final String styleFamily, |
| final String styleName, |
| final AttributeNameGenerator nameGenerator, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection) |
| throws ReportProcessingException |
| { |
| final OfficeStyle autostyle = new OfficeStyle(); |
| autostyle.setNamespace(OfficeNamespaces.STYLE_NS); |
| autostyle.setType(STYLE); |
| autostyle.setStyleFamily(styleFamily); |
| autostyle.setStyleName(nameGenerator.generateName("derived_" + styleName)); |
| autostyle.setStyleParent(styleName); |
| |
| // now copy the common style .. |
| final OfficeStyles commonStyles = commonCollection.getCommonStyles(); |
| if (!commonStyles.containsStyle(styleFamily, styleName)) |
| { |
| copyStyleInternal(commonStyle, commonStyles, |
| commonCollection, commonCollection, predefCollection, |
| styleFamily, new HashSet()); |
| } |
| return autostyle; |
| } |
| |
| private static OfficeStyle deriveAutomaticStyle(final OfficeStyle commonStyle, |
| final String styleFamily, |
| final String styleName, |
| final AttributeNameGenerator nameGenerator, |
| final OfficeStylesCollection commonCollection, |
| final OfficeStylesCollection predefCollection) |
| throws ReportProcessingException |
| { |
| try |
| { |
| final OfficeStyle autostyle = (OfficeStyle) commonStyle.clone(); |
| autostyle.setNamespace(OfficeNamespaces.STYLE_NS); |
| autostyle.setType(STYLE); |
| autostyle.setStyleFamily(styleFamily); |
| autostyle.setStyleName(nameGenerator.generateName("derived_auto_" + styleName)); |
| |
| |
| final String parent = autostyle.getStyleParent(); |
| if (parent != null) |
| { |
| copyStyle(styleFamily, parent, commonCollection, commonCollection, |
| predefCollection); |
| } |
| return autostyle; |
| } |
| catch (CloneNotSupportedException e) |
| { |
| throw new ReportProcessingException( |
| "Deriving the style failed. Clone error: ", e); |
| } |
| } |
| |
| public static String queryStyle(final OfficeStylesCollection predefCollection, |
| final String styleFamily, |
| final String styleName, |
| final String sectionName, |
| final String propertyNamespace, |
| final String propertyName) |
| { |
| return queryStyle(predefCollection, styleFamily, |
| styleName, sectionName, propertyNamespace, propertyName, new HashSet()); |
| } |
| |
| public static OfficeStyle queryStyleByProperties(final OfficeStylesCollection predefCollection, |
| final String styleFamily, |
| final String sectionName, |
| final ArrayList propertyNamespace, |
| final ArrayList propertyName, |
| final ArrayList propertyValues) |
| { |
| if (propertyNamespace.size() != propertyName.size()) |
| { |
| return null; |
| } |
| final OfficeStyle[] styles = predefCollection.getAutomaticStyles().getAllStyles(); |
| for (int i = 0; i < styles.length; i++) |
| { |
| final OfficeStyle officeStyle = styles[i]; |
| if (officeStyle.getStyleFamily().equals(styleFamily)) |
| { |
| final Element section = officeStyle.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName); |
| if (section != null) |
| { |
| int j = 0; |
| for (; j < propertyNamespace.size(); j++) |
| { |
| final String ns = (String) propertyNamespace.get(j); |
| final String prop = (String) propertyName.get(j); |
| final Object obj = section.getAttribute(ns, prop); |
| final Object value = propertyValues.get(j); |
| if (obj == null || value == null) |
| { |
| continue; |
| } |
| if (!propertyValues.get(j).equals(obj)) |
| { |
| break; |
| } |
| } |
| if (j == propertyName.size()) |
| { |
| return officeStyle; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static String queryStyle(final OfficeStylesCollection predefCollection, |
| final String styleFamily, |
| final String styleName, |
| final String sectionName, |
| final String propertyNamespace, |
| final String propertyName, |
| final Set seenStyles) |
| { |
| if (seenStyles.contains(styleName)) |
| { |
| return null; |
| } |
| seenStyles.add(styleName); |
| |
| final OfficeStyle style = predefCollection.getStyle(styleFamily, styleName); |
| if (style == null) |
| { |
| return null; // no such style |
| |
| } |
| final Element section = style.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName); |
| if (section != null) |
| { |
| final Object attribute = section.getAttribute(propertyNamespace, propertyName); |
| if (attribute != null) |
| { |
| return String.valueOf(attribute); |
| } |
| } |
| final String parent = style.getStyleParent(); |
| if (parent == null) |
| { |
| return null; |
| } |
| return queryStyle(predefCollection, styleFamily, parent, sectionName, propertyNamespace, propertyName, seenStyles); |
| } |
| } |