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.pentaho.OfficeNamespaces; 26 import com.sun.star.report.pentaho.model.DataStyle; 27 import com.sun.star.report.pentaho.model.FontFaceDeclsSection; 28 import com.sun.star.report.pentaho.model.FontFaceElement; 29 import com.sun.star.report.pentaho.model.OfficeStyle; 30 import com.sun.star.report.pentaho.model.OfficeStyles; 31 import com.sun.star.report.pentaho.model.OfficeStylesCollection; 32 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.Set; 36 37 import org.apache.commons.logging.Log; 38 import org.apache.commons.logging.LogFactory; 39 40 import org.jfree.report.ReportProcessingException; 41 import org.jfree.report.structure.Element; 42 import org.jfree.report.structure.Section; 43 import org.jfree.report.util.AttributeNameGenerator; 44 45 46 /** 47 * Todo: Document me! 48 * 49 * @author Thomas Morgner 50 * @since 13.03.2007 51 */ 52 public class StyleUtilities 53 { 54 55 private static final Log LOGGER = LogFactory.getLog(StyleUtilities.class); 56 private static final String STYLE = "style"; 57 StyleUtilities()58 private StyleUtilities() 59 { 60 } 61 62 /** 63 * Copies the specififed style (keyed by its family and name) into the current styles collection. This copies the 64 * style and all inherited styles into the target collection. Inherited common styles will be always be added to the 65 * common collection (which will be written into the 'styles.xml' later). 66 * <p/> 67 * This method does nothing if the specified style already exists in the styles collection. 68 * 69 * @param styleFamily the family of the style to copy 70 * @param styleName the unique name of the style. 71 * @param stylesCollection the current styles collection 72 * @param commonCollection the global styles collection 73 * @param predefCollection the predefined styles from where to copy the styles. 74 * @throws ReportProcessingException if the style copying failed. 75 */ copyStyle(final String styleFamily, final String styleName, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection)76 public static void copyStyle(final String styleFamily, 77 final String styleName, 78 final OfficeStylesCollection stylesCollection, 79 final OfficeStylesCollection commonCollection, 80 final OfficeStylesCollection predefCollection) 81 throws ReportProcessingException 82 { 83 copyStyle(styleFamily, styleName, stylesCollection, 84 commonCollection, predefCollection, new HashSet()); 85 } 86 87 /** 88 * Copies the specififed style (keyed by its family and name) into the current styles collection. This copies the 89 * style and all inherited styles into the target collection. Inherited common styles will be always be added to the 90 * common collection (which will be written into the 'styles.xml' later). 91 * <p/> 92 * This method does nothing if the specified style already exists in the styles collection. 93 * 94 * @param styleFamily the family of the style to copy 95 * @param styleName the unique name of the style. 96 * @param stylesCollection the current styles collection 97 * @param commonCollection the global styles collection 98 * @param predefCollection the predefined styles from where to copy the styles. 99 * @param inheritanceTracker a collection of all styles that have been touched. This is used to prevent infinite 100 * loops and duplicates. 101 * @throws ReportProcessingException if the style copying failed. 102 */ copyStyle(final String styleFamily, final String styleName, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection, final Set inheritanceTracker)103 private static void copyStyle(final String styleFamily, 104 final String styleName, 105 final OfficeStylesCollection stylesCollection, 106 final OfficeStylesCollection commonCollection, 107 final OfficeStylesCollection predefCollection, 108 final Set inheritanceTracker) 109 throws ReportProcessingException 110 { 111 if (inheritanceTracker.contains(styleName)) 112 { 113 return; 114 } 115 inheritanceTracker.add(styleName); 116 117 if (stylesCollection.containsStyle(styleFamily, styleName) || commonCollection.getCommonStyles().containsStyle(styleFamily, styleName)) 118 { 119 // fine, there's already a copy of the stylesheet. 120 return; 121 } 122 123 final OfficeStyle predefCommonStyle = 124 predefCollection.getCommonStyles().getStyle(styleFamily, styleName); 125 if (predefCommonStyle != null) 126 { 127 // so we have an style from the predefined collection. 128 // copy it an add it to the current stylescollection 129 final OfficeStyles commonStyles = commonCollection.getCommonStyles(); 130 131 copyStyleInternal(predefCommonStyle, commonStyles, stylesCollection, 132 commonCollection, predefCollection, styleFamily, inheritanceTracker); 133 return; 134 } 135 136 final OfficeStyle predefAutoStyle = 137 predefCollection.getAutomaticStyles().getStyle(styleFamily, styleName); 138 if (predefAutoStyle != null) 139 { 140 // so we have an style from the predefined collection. 141 // copy it an add it to the current stylescollection 142 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); 143 copyStyleInternal(predefAutoStyle, autoStyles, stylesCollection, 144 commonCollection, predefCollection, styleFamily, inheritanceTracker); 145 return; 146 } 147 148 // There is no automatic style either. Now this means that someone 149 // messed up the fileformat. Lets create a new empty style for this. 150 final OfficeStyle autostyle = new OfficeStyle(); 151 autostyle.setNamespace(OfficeNamespaces.STYLE_NS); 152 autostyle.setType(STYLE); 153 autostyle.setStyleFamily(styleFamily); 154 autostyle.setStyleName(styleName); 155 156 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); 157 autoStyles.addStyle(autostyle); 158 } 159 copyStyleInternal( final OfficeStyle predefCommonStyle, final OfficeStyles styles, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection, final String styleFamily, final Set inheritanceTracker)160 private static OfficeStyle copyStyleInternal( 161 final OfficeStyle predefCommonStyle, 162 final OfficeStyles styles, 163 final OfficeStylesCollection stylesCollection, 164 final OfficeStylesCollection commonCollection, 165 final OfficeStylesCollection predefCollection, 166 final String styleFamily, 167 final Set inheritanceTracker) 168 throws ReportProcessingException 169 { 170 try 171 { 172 final OfficeStyle preStyle = (OfficeStyle) predefCommonStyle.clone(); 173 styles.addStyle(preStyle); 174 performFontFaceProcessing(preStyle, stylesCollection, predefCollection); 175 performDataStyleProcessing(preStyle, stylesCollection, predefCollection); 176 177 // Lookup the parent style .. 178 final String styleParent = preStyle.getStyleParent(); 179 final OfficeStyle inherited = 180 stylesCollection.getStyle(styleFamily, styleParent); 181 if (inherited != null) 182 { 183 // OK, recurse (and hope that we dont run into an infinite loop) .. 184 copyStyle(styleFamily, styleParent, stylesCollection, 185 commonCollection, predefCollection, inheritanceTracker); 186 } 187 else if (styleParent != null) 188 { 189 LOGGER.warn("Inconsistent styles: " + styleFamily + ":" + styleParent + " does not exist."); 190 } 191 return preStyle; 192 } 193 catch (CloneNotSupportedException e) 194 { 195 throw new ReportProcessingException("Failed to derive a stylesheet", e); 196 } 197 } 198 performFontFaceProcessing(final OfficeStyle style, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection predefCollection)199 private static void performFontFaceProcessing(final OfficeStyle style, 200 final OfficeStylesCollection stylesCollection, 201 final OfficeStylesCollection predefCollection) 202 throws ReportProcessingException 203 { 204 final Element textProperties = style.getTextProperties(); 205 if (textProperties == null) 206 { 207 return; 208 } 209 210 try 211 { 212 final FontFaceDeclsSection currentFonts = stylesCollection.getFontFaceDecls(); 213 final FontFaceDeclsSection predefFonts = predefCollection.getFontFaceDecls(); 214 215 final String fontName = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, "font-name"); 216 if (fontName != null && !currentFonts.containsFont(fontName)) 217 { 218 final FontFaceElement element = predefFonts.getFontFace(fontName); 219 if (element != null) 220 { 221 currentFonts.addFontFace((FontFaceElement) element.clone()); 222 } 223 } 224 225 final String fontNameAsian = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, 226 "font-name-asian"); 227 if (fontNameAsian != null && !currentFonts.containsFont(fontNameAsian)) 228 { 229 final FontFaceElement element = predefFonts.getFontFace( 230 fontNameAsian); 231 if (element != null) 232 { 233 currentFonts.addFontFace((FontFaceElement) element.clone()); 234 } 235 } 236 237 final String fontNameComplex = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, 238 "font-name-complex"); 239 if (fontNameComplex != null && !currentFonts.containsFont(fontNameComplex)) 240 { 241 final FontFaceElement element = predefFonts.getFontFace( 242 fontNameComplex); 243 if (element != null) 244 { 245 currentFonts.addFontFace((FontFaceElement) element.clone()); 246 } 247 } 248 } 249 catch (CloneNotSupportedException e) 250 { 251 throw new ReportProcessingException("Failed to clone font-face element"); 252 } 253 } 254 performDataStyleProcessing(final OfficeStyle style, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection predefCollection)255 private static void performDataStyleProcessing(final OfficeStyle style, 256 final OfficeStylesCollection stylesCollection, 257 final OfficeStylesCollection predefCollection) 258 throws ReportProcessingException 259 { 260 final Section derivedStyle = performDataStyleProcessing(style, stylesCollection, predefCollection, "data-style-name"); 261 if (derivedStyle != null) 262 { 263 try 264 { 265 final Section styleMap = (Section) derivedStyle.findFirstChild(OfficeNamespaces.STYLE_NS, "map"); 266 if (styleMap != null) 267 { 268 performDataStyleProcessing(styleMap, stylesCollection, predefCollection, "apply-style-name"); 269 } 270 } 271 catch (Exception e) 272 { 273 } 274 } 275 } 276 performDataStyleProcessing(final Section style, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection predefCollection, final String attributeName)277 private static Section performDataStyleProcessing(final Section style, 278 final OfficeStylesCollection stylesCollection, 279 final OfficeStylesCollection predefCollection, 280 final String attributeName) 281 throws ReportProcessingException 282 { 283 final Object attribute = style.getAttribute(OfficeNamespaces.STYLE_NS, attributeName); 284 final DataStyle derivedStyle; 285 if (attribute != null) 286 { 287 final String styleName = String.valueOf(attribute); 288 if (!stylesCollection.getAutomaticStyles().containsDataStyle(styleName) && !stylesCollection.getCommonStyles().containsDataStyle(styleName)) 289 { 290 try 291 { 292 final OfficeStyles automaticStyles = predefCollection.getAutomaticStyles(); 293 final DataStyle autoDataStyle = automaticStyles.getDataStyle(styleName); 294 if (autoDataStyle != null) 295 { 296 derivedStyle = (DataStyle) autoDataStyle.clone(); 297 stylesCollection.getAutomaticStyles().addDataStyle(derivedStyle); 298 } 299 else 300 { 301 final OfficeStyles commonStyles = predefCollection.getCommonStyles(); 302 final DataStyle commonDataStyle = commonStyles.getDataStyle(styleName); 303 if (commonDataStyle != null) 304 { 305 derivedStyle = (DataStyle) commonDataStyle.clone(); 306 stylesCollection.getCommonStyles().addDataStyle(derivedStyle); 307 } 308 else 309 { 310 LOGGER.warn("Dangling data style: " + styleName); 311 derivedStyle = null; 312 } 313 } 314 } 315 catch (CloneNotSupportedException e) 316 { 317 throw new ReportProcessingException("Failed to copy style. This should not have happened."); 318 } 319 } 320 else 321 { 322 derivedStyle = null; 323 } 324 } 325 else 326 { 327 derivedStyle = null; 328 } 329 return derivedStyle; 330 } 331 332 /** 333 * Derives the named style. If the style is a common style, a new automatic style is generated and inserted into the 334 * given stylesCollection. If the named style is an automatic style, the style is copied and inserted as new automatic 335 * style. 336 * <p/> 337 * After the style has been created, the style's inheritance hierarchy will be copied as well. 338 * <p/> 339 * If there is no style with the given name and family, a new empty automatic style will be created. 340 * 341 * @param styleFamily the family of the style to copy 342 * @param styleName the unique name of the style. 343 * @param stylesCollection the current styles collection 344 * @param commonCollection the global styles collection 345 * @param predefCollection the predefined styles from where to copy the styles. 346 * @param generator the style-name-generator of the current report-target 347 * @return the derived style instance. 348 * @throws ReportProcessingException if the style copying failed. 349 */ deriveStyle(final String styleFamily, final String styleName, final OfficeStylesCollection stylesCollection, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection, final AttributeNameGenerator generator)350 public static OfficeStyle deriveStyle(final String styleFamily, 351 final String styleName, 352 final OfficeStylesCollection stylesCollection, 353 final OfficeStylesCollection commonCollection, 354 final OfficeStylesCollection predefCollection, 355 final AttributeNameGenerator generator) 356 throws ReportProcessingException 357 { 358 if (styleFamily == null) 359 { 360 throw new NullPointerException("StyleFamily must not be null"); 361 } 362 if (styleName != null) 363 { 364 365 final OfficeStyle currentAuto = 366 stylesCollection.getAutomaticStyles().getStyle(styleFamily, 367 styleName); 368 if (currentAuto != null) 369 { 370 // handle an automatic style .. 371 final OfficeStyle derivedStyle = 372 deriveAutomaticStyle(currentAuto, styleFamily, styleName, 373 generator, commonCollection, predefCollection); 374 stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 375 return derivedStyle; 376 } 377 378 final OfficeStyle currentCommon = 379 stylesCollection.getCommonStyles().getStyle(styleFamily, styleName); 380 if (currentCommon != null) 381 { 382 // handle an common style .. 383 final OfficeStyle derivedStyle = 384 deriveCommonStyle(currentCommon, styleFamily, styleName, 385 generator, commonCollection, predefCollection); 386 stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 387 return derivedStyle; 388 } 389 390 // final OfficeStyle commonAuto = 391 // commonCollection.getAutomaticStyles().getStyle(styleFamily, 392 // styleName); 393 // if (commonAuto != null) 394 // { 395 // // handle an automatic style .. 396 // final OfficeStyle derivedStyle = 397 // deriveAutomaticStyle(commonAuto, styleFamily, styleName, 398 // generator, commonCollection, predefCollection); 399 // stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 400 // return derivedStyle; 401 // } 402 403 final OfficeStyle commonCommon = 404 commonCollection.getCommonStyles().getStyle(styleFamily, styleName); 405 if (commonCommon != null) 406 { 407 // handle an common style .. 408 final OfficeStyle derivedStyle = 409 deriveCommonStyle(commonCommon, styleFamily, styleName, 410 generator, commonCollection, predefCollection); 411 stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 412 return derivedStyle; 413 } 414 415 final OfficeStyle predefAuto = 416 predefCollection.getAutomaticStyles().getStyle(styleFamily, 417 styleName); 418 if (predefAuto != null) 419 { 420 // handle an automatic style .. 421 final OfficeStyle derivedStyle = 422 deriveAutomaticStyle(predefAuto, styleFamily, styleName, 423 generator, commonCollection, predefCollection); 424 stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 425 return derivedStyle; 426 } 427 428 final OfficeStyle predefCommon = 429 predefCollection.getCommonStyles().getStyle(styleFamily, styleName); 430 if (predefCommon != null) 431 { 432 // handle an common style .. 433 final OfficeStyle derivedStyle = 434 deriveCommonStyle(predefCommon, styleFamily, styleName, 435 generator, commonCollection, predefCollection); 436 stylesCollection.getAutomaticStyles().addStyle(derivedStyle); 437 return derivedStyle; 438 } 439 } 440 441 // No such style. Create a new one .. 442 final OfficeStyle autostyle = new OfficeStyle(); 443 autostyle.setNamespace(OfficeNamespaces.STYLE_NS); 444 autostyle.setType(STYLE); 445 autostyle.setStyleFamily(styleFamily); 446 if (styleName != null) 447 { 448 autostyle.setStyleName(styleName); 449 } 450 else 451 { 452 autostyle.setStyleName(generator.generateName("derived_anonymous")); 453 } 454 455 final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles(); 456 autoStyles.addStyle(autostyle); 457 return autostyle; 458 } 459 deriveCommonStyle(final OfficeStyle commonStyle, final String styleFamily, final String styleName, final AttributeNameGenerator nameGenerator, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection)460 private static OfficeStyle deriveCommonStyle(final OfficeStyle commonStyle, 461 final String styleFamily, 462 final String styleName, 463 final AttributeNameGenerator nameGenerator, 464 final OfficeStylesCollection commonCollection, 465 final OfficeStylesCollection predefCollection) 466 throws ReportProcessingException 467 { 468 final OfficeStyle autostyle = new OfficeStyle(); 469 autostyle.setNamespace(OfficeNamespaces.STYLE_NS); 470 autostyle.setType(STYLE); 471 autostyle.setStyleFamily(styleFamily); 472 autostyle.setStyleName(nameGenerator.generateName("derived_" + styleName)); 473 autostyle.setStyleParent(styleName); 474 475 // now copy the common style .. 476 final OfficeStyles commonStyles = commonCollection.getCommonStyles(); 477 if (!commonStyles.containsStyle(styleFamily, styleName)) 478 { 479 copyStyleInternal(commonStyle, commonStyles, 480 commonCollection, commonCollection, predefCollection, 481 styleFamily, new HashSet()); 482 } 483 return autostyle; 484 } 485 deriveAutomaticStyle(final OfficeStyle commonStyle, final String styleFamily, final String styleName, final AttributeNameGenerator nameGenerator, final OfficeStylesCollection commonCollection, final OfficeStylesCollection predefCollection)486 private static OfficeStyle deriveAutomaticStyle(final OfficeStyle commonStyle, 487 final String styleFamily, 488 final String styleName, 489 final AttributeNameGenerator nameGenerator, 490 final OfficeStylesCollection commonCollection, 491 final OfficeStylesCollection predefCollection) 492 throws ReportProcessingException 493 { 494 try 495 { 496 final OfficeStyle autostyle = (OfficeStyle) commonStyle.clone(); 497 autostyle.setNamespace(OfficeNamespaces.STYLE_NS); 498 autostyle.setType(STYLE); 499 autostyle.setStyleFamily(styleFamily); 500 autostyle.setStyleName(nameGenerator.generateName("derived_auto_" + styleName)); 501 502 503 final String parent = autostyle.getStyleParent(); 504 if (parent != null) 505 { 506 copyStyle(styleFamily, parent, commonCollection, commonCollection, 507 predefCollection); 508 } 509 return autostyle; 510 } 511 catch (CloneNotSupportedException e) 512 { 513 throw new ReportProcessingException( 514 "Deriving the style failed. Clone error: ", e); 515 } 516 } 517 queryStyle(final OfficeStylesCollection predefCollection, final String styleFamily, final String styleName, final String sectionName, final String propertyNamespace, final String propertyName)518 public static String queryStyle(final OfficeStylesCollection predefCollection, 519 final String styleFamily, 520 final String styleName, 521 final String sectionName, 522 final String propertyNamespace, 523 final String propertyName) 524 { 525 return queryStyle(predefCollection, styleFamily, 526 styleName, sectionName, propertyNamespace, propertyName, new HashSet()); 527 } 528 queryStyleByProperties(final OfficeStylesCollection predefCollection, final String styleFamily, final String sectionName, final ArrayList propertyNamespace, final ArrayList propertyName, final ArrayList propertyValues)529 public static OfficeStyle queryStyleByProperties(final OfficeStylesCollection predefCollection, 530 final String styleFamily, 531 final String sectionName, 532 final ArrayList propertyNamespace, 533 final ArrayList propertyName, 534 final ArrayList propertyValues) 535 { 536 if (propertyNamespace.size() != propertyName.size()) 537 { 538 return null; 539 } 540 final OfficeStyle[] styles = predefCollection.getAutomaticStyles().getAllStyles(); 541 for (int i = 0; i < styles.length; i++) 542 { 543 final OfficeStyle officeStyle = styles[i]; 544 if (officeStyle.getStyleFamily().equals(styleFamily)) 545 { 546 final Element section = officeStyle.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName); 547 if (section != null) 548 { 549 int j = 0; 550 for (; j < propertyNamespace.size(); j++) 551 { 552 final String ns = (String) propertyNamespace.get(j); 553 final String prop = (String) propertyName.get(j); 554 final Object obj = section.getAttribute(ns, prop); 555 final Object value = propertyValues.get(j); 556 if (obj == null || value == null) 557 { 558 continue; 559 } 560 if (!propertyValues.get(j).equals(obj)) 561 { 562 break; 563 } 564 } 565 if (j == propertyName.size()) 566 { 567 return officeStyle; 568 } 569 } 570 } 571 } 572 return null; 573 } 574 queryStyle(final OfficeStylesCollection predefCollection, final String styleFamily, final String styleName, final String sectionName, final String propertyNamespace, final String propertyName, final Set seenStyles)575 private static String queryStyle(final OfficeStylesCollection predefCollection, 576 final String styleFamily, 577 final String styleName, 578 final String sectionName, 579 final String propertyNamespace, 580 final String propertyName, 581 final Set seenStyles) 582 { 583 if (seenStyles.contains(styleName)) 584 { 585 return null; 586 } 587 seenStyles.add(styleName); 588 589 final OfficeStyle style = predefCollection.getStyle(styleFamily, styleName); 590 if (style == null) 591 { 592 return null; // no such style 593 594 } 595 final Element section = style.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName); 596 if (section != null) 597 { 598 final Object attribute = section.getAttribute(propertyNamespace, propertyName); 599 if (attribute != null) 600 { 601 return String.valueOf(attribute); 602 } 603 } 604 final String parent = style.getStyleParent(); 605 if (parent == null) 606 { 607 return null; 608 } 609 return queryStyle(predefCollection, styleFamily, parent, sectionName, propertyNamespace, propertyName, seenStyles); 610 } 611 } 612