001 /** 002 * ======================================== 003 * JFreeReport : a free Java report library 004 * ======================================== 005 * 006 * Project Info: http://reporting.pentaho.org/ 007 * 008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 009 * 010 * This library is free software; you can redistribute it and/or modify it under the terms 011 * of the GNU Lesser General Public License as published by the Free Software Foundation; 012 * either version 2.1 of the License, or (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 016 * See the GNU Lesser General Public License for more details. 017 * 018 * You should have received a copy of the GNU Lesser General Public License along with this 019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 020 * Boston, MA 02111-1307, USA. 021 * 022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 023 * in the United States and other countries.] 024 * 025 * ------------ 026 * $Id: Element.java 3048 2007-07-28 18:02:42Z tmorgner $ 027 * ------------ 028 * (C) Copyright 2000-2005, by Object Refinery Limited. 029 * (C) Copyright 2005-2007, by Pentaho Corporation. 030 */ 031 032 package org.jfree.report.structure; 033 034 import java.util.ArrayList; 035 import java.util.Arrays; 036 import java.util.HashMap; 037 import java.util.Locale; 038 import java.util.Map; 039 import java.util.Iterator; 040 import java.util.Collections; 041 042 import org.jfree.layouting.input.style.CSSStyleRule; 043 import org.jfree.layouting.input.style.keys.box.BoxStyleKeys; 044 import org.jfree.layouting.input.style.values.CSSConstant; 045 import org.jfree.layouting.namespace.Namespaces; 046 import org.jfree.layouting.util.AttributeMap; 047 import org.jfree.layouting.util.LocaleUtility; 048 import org.jfree.report.JFreeReportInfo; 049 import org.jfree.report.expressions.Expression; 050 051 /** 052 * An element is a node that can have attributes. The 'id' and the 'name' 053 * attribute is defined for all elements. 054 * <p/> 055 * Both the name and the id attribute may be null. 056 * <p/> 057 * Properties in the 'http://jfreereport.sourceforge.net/namespaces/engine/flow' 058 * namespace and in the 'http://jfreereport.sourceforge.net/namespaces/engine/compatibility' 059 * namespace are considered internal. You should only touch them, if you really 060 * know what you are doing. 061 * 062 * @author Thomas Morgner 063 */ 064 public abstract class Element extends Node 065 { 066 private static final Expression[] EMPTY_EXPRESSIONS = new Expression[0]; 067 private static final String[] EMPTY_STRINGS = new String[0]; 068 private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap()); 069 public static final String NAME_ATTRIBUTE = "name"; 070 public static final String ID_ATTRIBUTE = "id"; 071 /** 072 * The type corresponds (somewhat) to the tagname of HTML. 073 */ 074 public static final String TYPE_ATTRIBUTE = "type"; 075 /** 076 * See XML-Namespaces for the idea of that one ... 077 */ 078 public static final String NAMESPACE_ATTRIBUTE = "namespace"; 079 public static final String VIRTUAL_ATTRIBUTE = "virtual"; 080 081 082 /** 083 * The name of the element. 084 */ 085 private AttributeMap attributes; 086 private CSSStyleRule style; 087 private ArrayList expressions; 088 private AttributeMap attributeExpressions; 089 private HashMap styleExpressions; 090 private boolean enabled; 091 private boolean virtual; 092 private Expression displayCondition; 093 094 /** 095 * Constructs an element. 096 * <p/> 097 * The element inherits the element's defined default ElementStyleSheet to 098 * provide reasonable default values for common stylekeys. When the element is 099 * added to the band, the bands stylesheet is set as parent to the element's 100 * stylesheet. 101 * <p/> 102 * A datasource is assigned with this element is set to a default source, 103 * which always returns null. 104 */ 105 protected Element() 106 { 107 this.style = new CSSStyleRule(null, null); 108 this.attributes = new AttributeMap(); 109 this.enabled = true; 110 setNamespace(JFreeReportInfo.REPORT_NAMESPACE); 111 } 112 113 public String getNamespace() 114 { 115 return (String) getAttribute 116 (JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE); 117 } 118 119 public void setNamespace(final String id) 120 { 121 setAttribute 122 (JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, id); 123 } 124 125 public String getId() 126 { 127 return (String) getAttribute 128 (Namespaces.XML_NAMESPACE, Element.ID_ATTRIBUTE); 129 } 130 131 public void setId(final String id) 132 { 133 setAttribute(Namespaces.XML_NAMESPACE, Element.ID_ATTRIBUTE, id); 134 } 135 136 public String getType() 137 { 138 return (String) getAttribute 139 (JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE); 140 } 141 142 public void setType(final String type) 143 { 144 setAttribute 145 (JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, type); 146 } 147 148 /** 149 * Defines the name for this Element. The name must not be empty, or a 150 * NullPointerException is thrown. 151 * <p/> 152 * Names can be used to lookup an element within a band. There is no 153 * requirement for element names to be unique. 154 * 155 * @param name the name of this element 156 */ 157 public void setName(final String name) 158 { 159 setAttribute(Namespaces.XML_NAMESPACE, Element.NAME_ATTRIBUTE, name); 160 } 161 162 163 /** 164 * Returns the name of the Element. The name of the Element is never null. 165 * 166 * @return the name. 167 */ 168 public String getName() 169 { 170 return (String) getAttribute 171 (Namespaces.XML_NAMESPACE, Element.NAME_ATTRIBUTE); 172 } 173 174 public void setAttribute(final String name, final Object value) 175 { 176 setAttribute(getNamespace(), name, value); 177 } 178 179 public void setAttribute(final String namespace, 180 final String name, 181 final Object value) 182 { 183 if (name == null) 184 { 185 throw new NullPointerException(); 186 } 187 if (attributes == null) 188 { 189 this.attributes = new AttributeMap(); 190 } 191 this.attributes.setAttribute(namespace, name, value); 192 } 193 194 public Object getAttribute(final String name) 195 { 196 return getAttribute(getNamespace(), name); 197 } 198 199 public Object getAttribute(final String namespace, final String name) 200 { 201 if (this.attributes == null) 202 { 203 return null; 204 } 205 return this.attributes.getAttribute(namespace, name); 206 } 207 208 public Map getAttributes(final String namespace) 209 { 210 if (this.attributes == null) 211 { 212 return null; 213 } 214 return this.attributes.getAttributes(namespace); 215 } 216 217 public AttributeMap getAttributeMap() 218 { 219 return new AttributeMap(this.attributes); 220 } 221 222 public String[] getAttributeNameSpaces() 223 { 224 if (this.attributes == null) 225 { 226 return Element.EMPTY_STRINGS; 227 } 228 return this.attributes.getNameSpaces(); 229 } 230 231 /** 232 * Returns this elements private stylesheet. This sheet can be used to 233 * override the default values set in one of the parent-stylesheets. 234 * 235 * @return the Element's stylesheet 236 */ 237 public CSSStyleRule getStyle() 238 { 239 return style; 240 } 241 242 public void setVisibility(final CSSConstant v) 243 { 244 getStyle().setPropertyValue(BoxStyleKeys.VISIBILITY, v); 245 } 246 247 248 public CSSConstant getVisibility() 249 { 250 return (CSSConstant) getStyle().getPropertyCSSValue(BoxStyleKeys.VISIBILITY); 251 } 252 253 public void setAttributeExpression(final String attr, 254 final Expression function) 255 { 256 setAttribute(getNamespace(), attr, function); 257 } 258 259 /** 260 * Adds a function to the report's collection of expressions. 261 * 262 * @param namespace 263 * @param attr 264 * @param function the function. 265 */ 266 public void setAttributeExpression(final String namespace, 267 final String attr, 268 final Expression function) 269 { 270 271 if (attributeExpressions == null) 272 { 273 if (function == null) 274 { 275 return; 276 } 277 this.attributeExpressions = new AttributeMap(); 278 } 279 attributeExpressions.setAttribute(namespace, attr, function); 280 } 281 282 /** 283 * Returns the expressions for the report. 284 * 285 * @param attr 286 * @return the expressions. 287 */ 288 public Expression getAttributeExpression(final String attr) 289 { 290 return getAttributeExpression(getNamespace(), attr); 291 } 292 293 public Expression getAttributeExpression(final String namespace, 294 final String attr) 295 { 296 if (attributeExpressions == null) 297 { 298 return null; 299 } 300 return (Expression) attributeExpressions.getAttribute(namespace, attr); 301 } 302 303 public Map getAttributeExpressions(final String namespace) 304 { 305 if (attributeExpressions == null) 306 { 307 return null; 308 } 309 return attributeExpressions.getAttributes(namespace); 310 } 311 312 public AttributeMap getAttributeExpressionMap() 313 { 314 if (this.attributeExpressions == null) 315 { 316 return new AttributeMap(); 317 } 318 319 return new AttributeMap(this.attributeExpressions); 320 } 321 322 323 /** 324 * Adds a function to the report's collection of expressions. 325 * 326 * @param function the function. 327 * @param property 328 */ 329 public void setStyleExpression(final String property, 330 final Expression function) 331 { 332 if (function == null) 333 { 334 if (styleExpressions != null) 335 { 336 styleExpressions.remove(property); 337 } 338 } 339 else 340 { 341 if (styleExpressions == null) 342 { 343 styleExpressions = new HashMap(); 344 } 345 styleExpressions.put(property, function); 346 } 347 } 348 349 /** 350 * Returns the expressions for the report. 351 * 352 * @param property 353 * @return the expressions. 354 */ 355 public Expression getStyleExpression(final String property) 356 { 357 if (styleExpressions == null) 358 { 359 return null; 360 } 361 return (Expression) styleExpressions.get(property); 362 } 363 364 public Map getStyleExpressions() 365 { 366 if (styleExpressions == null) 367 { 368 return Element.EMPTY_MAP; 369 } 370 return Collections.unmodifiableMap(styleExpressions); 371 } 372 373 /** 374 * Adds a function to the report's collection of expressions. 375 * 376 * @param function the function. 377 */ 378 public void addExpression(final Expression function) 379 { 380 if (expressions == null) 381 { 382 expressions = new ArrayList(); 383 } 384 expressions.add(function); 385 } 386 387 /** 388 * Returns the expressions for the report. 389 * 390 * @return the expressions. 391 */ 392 public Expression[] getExpressions() 393 { 394 if (expressions == null) 395 { 396 return Element.EMPTY_EXPRESSIONS; 397 } 398 return (Expression[]) expressions.toArray 399 (new Expression[expressions.size()]); 400 } 401 402 /** 403 * Sets the expressions for the report. 404 * 405 * @param expressions the expressions (<code>null</code> not permitted). 406 */ 407 public void setExpressions(final Expression[] expressions) 408 { 409 if (expressions == null) 410 { 411 throw new NullPointerException( 412 "JFreeReport.setExpressions(...) : null not permitted."); 413 } 414 if (this.expressions == null) 415 { 416 this.expressions = new ArrayList(expressions.length); 417 } 418 else 419 { 420 this.expressions.clear(); 421 } 422 this.expressions.addAll(Arrays.asList(expressions)); 423 } 424 425 /** 426 * Returns true, if the element is enabled. 427 * 428 * @return true or false 429 */ 430 public boolean isEnabled() 431 { 432 return enabled; 433 } 434 435 /** 436 * Defines whether the element is enabled. Disabled elements will be fully 437 * ignored by the report processor. This is a design time property to exclude 438 * elements from the processing without actually having to deal with the other 439 * complex properties. 440 * 441 * @param enabled 442 */ 443 public void setEnabled(final boolean enabled) 444 { 445 this.enabled = enabled; 446 } 447 448 public Expression getDisplayCondition() 449 { 450 return displayCondition; 451 } 452 453 public void setDisplayCondition(final Expression displayCondition) 454 { 455 this.displayCondition = displayCondition; 456 } 457 458 public Locale getLocale() 459 { 460 final Locale locale = getLocaleFromAttributes(); 461 if (locale != null) 462 { 463 return locale; 464 } 465 return super.getLocale(); 466 } 467 468 protected Locale getLocaleFromAttributes() 469 { 470 final Object mayBeXmlLang = getAttribute(Namespaces.XML_NAMESPACE, "lang"); 471 if (mayBeXmlLang instanceof String) 472 { 473 return LocaleUtility.createLocale((String) mayBeXmlLang); 474 } 475 else if (mayBeXmlLang instanceof Locale) 476 { 477 return (Locale) mayBeXmlLang; 478 } 479 480 final Object mayBeXhtmlLang = getAttribute(Namespaces.XHTML_NAMESPACE, 481 "lang"); 482 if (mayBeXhtmlLang instanceof String) 483 { 484 return LocaleUtility.createLocale((String) mayBeXhtmlLang); 485 } 486 else if (mayBeXhtmlLang instanceof Locale) 487 { 488 return (Locale) mayBeXhtmlLang; 489 } 490 // 491 // final Object mayBeHtmlLang = getAttribute(Namespaces.XHTML_NAMESPACE, "lang"); 492 // if (mayBeHtmlLang instanceof String) 493 // { 494 // return LocaleUtility.createLocale((String) mayBeHtmlLang); 495 // } 496 // else if (mayBeHtmlLang instanceof Locale) 497 // { 498 // return (Locale) mayBeHtmlLang; 499 // } 500 501 return null; 502 } 503 504 public boolean isVirtual() 505 { 506 return virtual; 507 } 508 509 public void setVirtual(final boolean virtual) 510 { 511 this.virtual = virtual; 512 } 513 514 515 public Object clone() 516 throws CloneNotSupportedException 517 { 518 final Element element = (Element) super.clone(); 519 element.style = (CSSStyleRule) style.clone(); 520 if (attributes != null) 521 { 522 element.attributes = (AttributeMap) attributes.clone(); 523 } 524 525 if (attributeExpressions != null) 526 { 527 element.attributeExpressions = (AttributeMap) attributeExpressions.clone(); 528 final String[] namespaces = element.attributeExpressions.getNameSpaces(); 529 for (int i = 0; i < namespaces.length; i++) 530 { 531 final String namespace = namespaces[i]; 532 final Map attrsNs = element.attributeExpressions.getAttributes( 533 namespace); 534 final Iterator it = 535 attrsNs.entrySet().iterator(); 536 while (it.hasNext()) 537 { 538 final Map.Entry entry = (Map.Entry) it.next(); 539 final Expression exp = (Expression) entry.getValue(); 540 entry.setValue(exp.clone()); 541 } 542 } 543 } 544 545 if (expressions != null) 546 { 547 element.expressions = (ArrayList) expressions.clone(); 548 element.expressions.clear(); 549 for (int i = 0; i < expressions.size(); i++) 550 { 551 final Expression expression = (Expression) expressions.get(i); 552 element.expressions.add(expression.clone()); 553 } 554 } 555 if (styleExpressions != null) 556 { 557 element.styleExpressions = (HashMap) styleExpressions.clone(); 558 final Iterator styleExpressionsIt = 559 element.styleExpressions.entrySet().iterator(); 560 while (styleExpressionsIt.hasNext()) 561 { 562 final Map.Entry entry = (Map.Entry) styleExpressionsIt.next(); 563 final Expression exp = (Expression) entry.getValue(); 564 entry.setValue(exp.clone()); 565 } 566 } 567 568 if (displayCondition != null) 569 { 570 element.displayCondition = (Expression) displayCondition.clone(); 571 } 572 return element; 573 } 574 }