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
;
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
;
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()
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
>());
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
))
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.
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
);
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
);
140 // There is no automatic style either. Now this means that someone
141 // messed up the fileformat. Lets 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.");
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)
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
);
213 currentFonts
.addFontFace((FontFaceElement
) element
.clone());
217 final String fontNameAsian
= (String
) textProperties
.getAttribute(OfficeNamespaces
.STYLE_NS
,
219 if (fontNameAsian
!= null && !currentFonts
.containsFont(fontNameAsian
))
221 final FontFaceElement element
= predefFonts
.getFontFace(
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(
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");
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
);
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
);
302 LOGGER
.warning("Dangling data style: " + styleName
);
307 catch (CloneNotSupportedException e
)
309 throw new ReportProcessingException("Failed to copy style. This should not have happened.", e
);
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
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
,
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
);
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
);
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
);
394 final OfficeStyle predefAuto
=
395 predefCollection
.getAutomaticStyles().getStyle(styleFamily
,
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
);
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
);
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
);
431 autostyle
.setStyleName(generator
.generateName("derived_anonymous"));
434 final OfficeStyles autoStyles
= stylesCollection
.getAutomaticStyles();
435 autoStyles
.addStyle(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
>());
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();
485 copyStyle(styleFamily
, parent
, commonCollection
, commonCollection
,
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())
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
);
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)
539 if (!propertyValues
.get(j
).equals(obj
))
544 if (j
== propertyName
.size())
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
))
566 seenStyles
.add(styleName
);
568 final OfficeStyle style
= predefCollection
.getStyle(styleFamily
, styleName
);
571 return null; // no such style
574 final Element section
= style
.findFirstChild(OfficeNamespaces
.STYLE_NS
, sectionName
);
577 final Object attribute
= section
.getAttribute(propertyNamespace
, propertyName
);
578 if (attribute
!= null)
580 return String
.valueOf(attribute
);
583 final String parent
= style
.getStyleParent();
588 return queryStyle(predefCollection
, styleFamily
, parent
, sectionName
, propertyNamespace
, propertyName
, seenStyles
);