cid#1607171 Data race condition
[LibreOffice.git] / reportbuilder / java / org / libreoffice / report / pentaho / output / StyleUtilities.java
blob6e7339171fd9c519bac5bfb5f4478cdcf5c854ec
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 package org.libreoffice.report.pentaho.output;
20 import org.libreoffice.report.pentaho.OfficeNamespaces;
21 import org.libreoffice.report.pentaho.model.DataStyle;
22 import org.libreoffice.report.pentaho.model.FontFaceDeclsSection;
23 import org.libreoffice.report.pentaho.model.FontFaceElement;
24 import org.libreoffice.report.pentaho.model.OfficeStyle;
25 import org.libreoffice.report.pentaho.model.OfficeStyles;
26 import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.Set;
31 import java.util.logging.Logger;
33 import org.jfree.report.ReportProcessingException;
34 import org.jfree.report.structure.Element;
35 import org.jfree.report.structure.Section;
36 import org.jfree.report.util.AttributeNameGenerator;
39 /**
40 * Todo: Document me!
42 * @since 13.03.2007
44 public class StyleUtilities
47 private static final Logger LOGGER = Logger.getLogger(StyleUtilities.class.getName());
48 private static final String STYLE = "style";
50 private StyleUtilities()
54 /**
55 * Copies the specified style (keyed by its family and name) into the current styles collection. This copies the
56 * style and all inherited styles into the target collection. Inherited common styles will be always be added to the
57 * common collection (which will be written into the 'styles.xml' later).
59 * <p>This method does nothing if the specified style already exists in the styles collection.</p>
61 * @param styleFamily the family of the style to copy
62 * @param styleName the unique name of the style.
63 * @param stylesCollection the current styles collection
64 * @param commonCollection the global styles collection
65 * @param predefCollection the predefined styles from where to copy the styles.
66 * @throws ReportProcessingException if the style copying failed.
68 public static void copyStyle(final String styleFamily,
69 final String styleName,
70 final OfficeStylesCollection stylesCollection,
71 final OfficeStylesCollection commonCollection,
72 final OfficeStylesCollection predefCollection)
73 throws ReportProcessingException
75 copyStyle(styleFamily, styleName, stylesCollection,
76 commonCollection, predefCollection, new HashSet<String>());
79 /**
80 * Copies the specified style (keyed by its family and name) into the current styles collection. This copies the
81 * style and all inherited styles into the target collection. Inherited common styles will be always be added to the
82 * common collection (which will be written into the 'styles.xml' later).
84 * <p>This method does nothing if the specified style already exists in the styles collection.</p>
86 * @param styleFamily the family of the style to copy
87 * @param styleName the unique name of the style.
88 * @param stylesCollection the current styles collection
89 * @param commonCollection the global styles collection
90 * @param predefCollection the predefined styles from where to copy the styles.
91 * @param inheritanceTracker a collection of all styles that have been touched. This is used to prevent infinite
92 * loops and duplicates.
93 * @throws ReportProcessingException if the style copying failed.
95 private static void copyStyle(final String styleFamily,
96 final String styleName,
97 final OfficeStylesCollection stylesCollection,
98 final OfficeStylesCollection commonCollection,
99 final OfficeStylesCollection predefCollection,
100 final Set<String> inheritanceTracker)
101 throws ReportProcessingException
103 if (inheritanceTracker.contains(styleName))
105 return;
107 inheritanceTracker.add(styleName);
109 if (stylesCollection.containsStyle(styleFamily, styleName) || commonCollection.getCommonStyles().containsStyle(styleFamily, styleName))
111 // fine, there's already a copy of the stylesheet.
112 return;
115 final OfficeStyle predefCommonStyle =
116 predefCollection.getCommonStyles().getStyle(styleFamily, styleName);
117 if (predefCommonStyle != null)
119 // so we have a style from the predefined collection.
120 // copy it an add it to the current stylescollection
121 final OfficeStyles commonStyles = commonCollection.getCommonStyles();
123 copyStyleInternal(predefCommonStyle, commonStyles, stylesCollection,
124 commonCollection, predefCollection, styleFamily, inheritanceTracker);
125 return;
128 final OfficeStyle predefAutoStyle =
129 predefCollection.getAutomaticStyles().getStyle(styleFamily, styleName);
130 if (predefAutoStyle != null)
132 // so we have a style from the predefined collection.
133 // copy it an add it to the current stylescollection
134 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
135 copyStyleInternal(predefAutoStyle, autoStyles, stylesCollection,
136 commonCollection, predefCollection, styleFamily, inheritanceTracker);
137 return;
140 // There is no automatic style either. Now this means that someone
141 // messed up the fileformat. Let's create a new empty style for this.
142 final OfficeStyle autostyle = new OfficeStyle();
143 autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
144 autostyle.setType(STYLE);
145 autostyle.setStyleFamily(styleFamily);
146 autostyle.setStyleName(styleName);
148 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
149 autoStyles.addStyle(autostyle);
152 private static OfficeStyle copyStyleInternal(
153 final OfficeStyle predefCommonStyle,
154 final OfficeStyles styles,
155 final OfficeStylesCollection stylesCollection,
156 final OfficeStylesCollection commonCollection,
157 final OfficeStylesCollection predefCollection,
158 final String styleFamily,
159 final Set<String> inheritanceTracker)
160 throws ReportProcessingException
164 final OfficeStyle preStyle = (OfficeStyle) predefCommonStyle.clone();
165 styles.addStyle(preStyle);
166 performFontFaceProcessing(preStyle, stylesCollection, predefCollection);
167 performDataStyleProcessing(preStyle, stylesCollection, predefCollection);
169 // Lookup the parent style ..
170 final String styleParent = preStyle.getStyleParent();
171 final OfficeStyle inherited =
172 stylesCollection.getStyle(styleFamily, styleParent);
173 if (inherited != null)
175 // OK, recurse (and hope that we don't run into an infinite loop) ..
176 copyStyle(styleFamily, styleParent, stylesCollection,
177 commonCollection, predefCollection, inheritanceTracker);
179 else if (styleParent != null)
181 LOGGER.warning("Inconsistent styles: " + styleFamily + ":" + styleParent + " does not exist.");
183 return preStyle;
185 catch (CloneNotSupportedException e)
187 throw new ReportProcessingException("Failed to derive a stylesheet", e);
191 private static void performFontFaceProcessing(final OfficeStyle style,
192 final OfficeStylesCollection stylesCollection,
193 final OfficeStylesCollection predefCollection)
194 throws ReportProcessingException
196 final Element textProperties = style.getTextProperties();
197 if (textProperties == null)
199 return;
204 final FontFaceDeclsSection currentFonts = stylesCollection.getFontFaceDecls();
205 final FontFaceDeclsSection predefFonts = predefCollection.getFontFaceDecls();
207 final String fontName = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, "font-name");
208 if (fontName != null && !currentFonts.containsFont(fontName))
210 final FontFaceElement element = predefFonts.getFontFace(fontName);
211 if (element != null)
213 currentFonts.addFontFace((FontFaceElement) element.clone());
217 final String fontNameAsian = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS,
218 "font-name-asian");
219 if (fontNameAsian != null && !currentFonts.containsFont(fontNameAsian))
221 final FontFaceElement element = predefFonts.getFontFace(
222 fontNameAsian);
223 if (element != null)
225 currentFonts.addFontFace((FontFaceElement) element.clone());
229 final String fontNameComplex = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS,
230 "font-name-complex");
231 if (fontNameComplex != null && !currentFonts.containsFont(fontNameComplex))
233 final FontFaceElement element = predefFonts.getFontFace(
234 fontNameComplex);
235 if (element != null)
237 currentFonts.addFontFace((FontFaceElement) element.clone());
241 catch (CloneNotSupportedException e)
243 throw new ReportProcessingException("Failed to clone font-face element", e);
247 private static void performDataStyleProcessing(final OfficeStyle style,
248 final OfficeStylesCollection stylesCollection,
249 final OfficeStylesCollection predefCollection)
250 throws ReportProcessingException
252 final Section derivedStyle = performDataStyleProcessing(style, stylesCollection, predefCollection, "data-style-name");
253 if (derivedStyle != null)
257 final Section styleMap = (Section) derivedStyle.findFirstChild(OfficeNamespaces.STYLE_NS, "map");
258 if (styleMap != null)
260 performDataStyleProcessing(styleMap, stylesCollection, predefCollection, "apply-style-name");
263 catch (Exception e)
269 private static Section performDataStyleProcessing(final Section style,
270 final OfficeStylesCollection stylesCollection,
271 final OfficeStylesCollection predefCollection,
272 final String attributeName)
273 throws ReportProcessingException
275 final Object attribute = style.getAttribute(OfficeNamespaces.STYLE_NS, attributeName);
276 final DataStyle derivedStyle;
277 if (attribute != null)
279 final String styleName = String.valueOf(attribute);
280 if (!stylesCollection.getAutomaticStyles().containsDataStyle(styleName) && !stylesCollection.getCommonStyles().containsDataStyle(styleName))
284 final OfficeStyles automaticStyles = predefCollection.getAutomaticStyles();
285 final DataStyle autoDataStyle = automaticStyles.getDataStyle(styleName);
286 if (autoDataStyle != null)
288 derivedStyle = (DataStyle) autoDataStyle.clone();
289 stylesCollection.getAutomaticStyles().addDataStyle(derivedStyle);
291 else
293 final OfficeStyles commonStyles = predefCollection.getCommonStyles();
294 final DataStyle commonDataStyle = commonStyles.getDataStyle(styleName);
295 if (commonDataStyle != null)
297 derivedStyle = (DataStyle) commonDataStyle.clone();
298 stylesCollection.getCommonStyles().addDataStyle(derivedStyle);
300 else
302 LOGGER.warning("Dangling data style: " + styleName);
303 derivedStyle = null;
307 catch (CloneNotSupportedException e)
309 throw new ReportProcessingException("Failed to copy style. This should not have happened.", e);
312 else
314 derivedStyle = null;
317 else
319 derivedStyle = null;
321 return derivedStyle;
325 * Derives the named style. If the style is a common style, a new automatic style is generated and inserted into the
326 * given stylesCollection. If the named style is an automatic style, the style is copied and inserted as new automatic
327 * style.
329 * <p>After the style has been created, the style's inheritance hierarchy will be copied as well.</p>
331 * <p>If there is no style with the given name and family, a new empty automatic style will be created.</p>
333 * @param styleFamily the family of the style to copy
334 * @param styleName the unique name of the style.
335 * @param stylesCollection the current styles collection
336 * @param commonCollection the global styles collection
337 * @param predefCollection the predefined styles from where to copy the styles.
338 * @param generator the style-name-generator of the current report-target
339 * @return the derived style instance.
340 * @throws ReportProcessingException if the style copying failed.
342 public static OfficeStyle deriveStyle(final String styleFamily,
343 final String styleName,
344 final OfficeStylesCollection stylesCollection,
345 final OfficeStylesCollection commonCollection,
346 final OfficeStylesCollection predefCollection,
347 final AttributeNameGenerator generator)
348 throws ReportProcessingException
350 if (styleFamily == null)
352 throw new NullPointerException("StyleFamily must not be null");
354 if (styleName != null)
357 final OfficeStyle currentAuto =
358 stylesCollection.getAutomaticStyles().getStyle(styleFamily,
359 styleName);
360 if (currentAuto != null)
362 // handle an automatic style ..
363 final OfficeStyle derivedStyle =
364 deriveAutomaticStyle(currentAuto, styleFamily, styleName,
365 generator, commonCollection, predefCollection);
366 stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
367 return derivedStyle;
370 final OfficeStyle currentCommon =
371 stylesCollection.getCommonStyles().getStyle(styleFamily, styleName);
372 if (currentCommon != null)
374 // handle a common style ..
375 final OfficeStyle derivedStyle =
376 deriveCommonStyle(currentCommon, styleFamily, styleName,
377 generator, commonCollection, predefCollection);
378 stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
379 return derivedStyle;
382 final OfficeStyle commonCommon =
383 commonCollection.getCommonStyles().getStyle(styleFamily, styleName);
384 if (commonCommon != null)
386 // handle a common style ..
387 final OfficeStyle derivedStyle =
388 deriveCommonStyle(commonCommon, styleFamily, styleName,
389 generator, commonCollection, predefCollection);
390 stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
391 return derivedStyle;
394 final OfficeStyle predefAuto =
395 predefCollection.getAutomaticStyles().getStyle(styleFamily,
396 styleName);
397 if (predefAuto != null)
399 // handle an automatic style ..
400 final OfficeStyle derivedStyle =
401 deriveAutomaticStyle(predefAuto, styleFamily, styleName,
402 generator, commonCollection, predefCollection);
403 stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
404 return derivedStyle;
407 final OfficeStyle predefCommon =
408 predefCollection.getCommonStyles().getStyle(styleFamily, styleName);
409 if (predefCommon != null)
411 // handle a common style ..
412 final OfficeStyle derivedStyle =
413 deriveCommonStyle(predefCommon, styleFamily, styleName,
414 generator, commonCollection, predefCollection);
415 stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
416 return derivedStyle;
420 // No such style. Create a new one ..
421 final OfficeStyle autostyle = new OfficeStyle();
422 autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
423 autostyle.setType(STYLE);
424 autostyle.setStyleFamily(styleFamily);
425 if (styleName != null)
427 autostyle.setStyleName(styleName);
429 else
431 autostyle.setStyleName(generator.generateName("derived_anonymous"));
434 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
435 autoStyles.addStyle(autostyle);
436 return autostyle;
439 private static OfficeStyle deriveCommonStyle(final OfficeStyle commonStyle,
440 final String styleFamily,
441 final String styleName,
442 final AttributeNameGenerator nameGenerator,
443 final OfficeStylesCollection commonCollection,
444 final OfficeStylesCollection predefCollection)
445 throws ReportProcessingException
447 final OfficeStyle autostyle = new OfficeStyle();
448 autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
449 autostyle.setType(STYLE);
450 autostyle.setStyleFamily(styleFamily);
451 autostyle.setStyleName(nameGenerator.generateName("derived_" + styleName));
452 autostyle.setStyleParent(styleName);
454 // now copy the common style ..
455 final OfficeStyles commonStyles = commonCollection.getCommonStyles();
456 if (!commonStyles.containsStyle(styleFamily, styleName))
458 copyStyleInternal(commonStyle, commonStyles,
459 commonCollection, commonCollection, predefCollection,
460 styleFamily, new HashSet<String>());
462 return autostyle;
465 private static OfficeStyle deriveAutomaticStyle(final OfficeStyle commonStyle,
466 final String styleFamily,
467 final String styleName,
468 final AttributeNameGenerator nameGenerator,
469 final OfficeStylesCollection commonCollection,
470 final OfficeStylesCollection predefCollection)
471 throws ReportProcessingException
475 final OfficeStyle autostyle = (OfficeStyle) commonStyle.clone();
476 autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
477 autostyle.setType(STYLE);
478 autostyle.setStyleFamily(styleFamily);
479 autostyle.setStyleName(nameGenerator.generateName("derived_auto_" + styleName));
482 final String parent = autostyle.getStyleParent();
483 if (parent != null)
485 copyStyle(styleFamily, parent, commonCollection, commonCollection,
486 predefCollection);
488 return autostyle;
490 catch (CloneNotSupportedException e)
492 throw new ReportProcessingException(
493 "Deriving the style failed. Clone error: ", e);
497 public static String queryStyle(final OfficeStylesCollection predefCollection,
498 final String styleFamily,
499 final String styleName,
500 final String sectionName,
501 final String propertyNamespace,
502 final String propertyName)
504 return queryStyle(predefCollection, styleFamily,
505 styleName, sectionName, propertyNamespace, propertyName, new HashSet<String>());
508 public static OfficeStyle queryStyleByProperties(final OfficeStylesCollection predefCollection,
509 final String styleFamily,
510 final String sectionName,
511 final ArrayList<?> propertyNamespace,
512 final ArrayList<?> propertyName,
513 final ArrayList<?> propertyValues)
515 if (propertyNamespace.size() != propertyName.size())
517 return null;
519 final OfficeStyle[] styles = predefCollection.getAutomaticStyles().getAllStyles();
520 for (int i = 0; i < styles.length; i++)
522 final OfficeStyle officeStyle = styles[i];
523 if (officeStyle.getStyleFamily().equals(styleFamily))
525 final Element section = officeStyle.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName);
526 if (section != null)
528 int j = 0;
529 for (; j < propertyNamespace.size(); j++)
531 final String ns = (String) propertyNamespace.get(j);
532 final String prop = (String) propertyName.get(j);
533 final Object obj = section.getAttribute(ns, prop);
534 final Object value = propertyValues.get(j);
535 if (obj == null || value == null)
537 continue;
539 if (!propertyValues.get(j).equals(obj))
541 break;
544 if (j == propertyName.size())
546 return officeStyle;
551 return null;
554 private static String queryStyle(final OfficeStylesCollection predefCollection,
555 final String styleFamily,
556 final String styleName,
557 final String sectionName,
558 final String propertyNamespace,
559 final String propertyName,
560 final Set<String> seenStyles)
562 if (seenStyles.contains(styleName))
564 return null;
566 seenStyles.add(styleName);
568 final OfficeStyle style = predefCollection.getStyle(styleFamily, styleName);
569 if (style == null)
571 return null; // no such style
574 final Element section = style.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName);
575 if (section != null)
577 final Object attribute = section.getAttribute(propertyNamespace, propertyName);
578 if (attribute != null)
580 return String.valueOf(attribute);
583 final String parent = style.getStyleParent();
584 if (parent == null)
586 return null;
588 return queryStyle(predefCollection, styleFamily, parent, sectionName, propertyNamespace, propertyName, seenStyles);