Source for org.jfree.report.structure.Element

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: Element.java 2791 2007-05-14 08:55:52Z taqua $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: 
  32: package org.jfree.report.structure;
  33: 
  34: import java.util.ArrayList;
  35: import java.util.Arrays;
  36: import java.util.HashMap;
  37: import java.util.Locale;
  38: import java.util.Map;
  39: import java.util.Iterator;
  40: import java.util.Collections;
  41: 
  42: import org.jfree.layouting.input.style.CSSStyleRule;
  43: import org.jfree.layouting.input.style.keys.box.BoxStyleKeys;
  44: import org.jfree.layouting.input.style.values.CSSConstant;
  45: import org.jfree.layouting.namespace.Namespaces;
  46: import org.jfree.layouting.util.AttributeMap;
  47: import org.jfree.layouting.util.LocaleUtility;
  48: import org.jfree.report.JFreeReportInfo;
  49: import org.jfree.report.expressions.Expression;
  50: 
  51: /**
  52:  * An element is a node that can have attributes. The 'id' and the 'name'
  53:  * attribute is defined for all elements.
  54:  * <p/>
  55:  * Both the name and the id attribute may be null.
  56:  * <p/>
  57:  * Properties in the 'http://jfreereport.sourceforge.net/namespaces/engine/flow'
  58:  * namespace and in the 'http://jfreereport.sourceforge.net/namespaces/engine/compatibility'
  59:  * namespace are considered internal. You should only touch them, if you really
  60:  * know what you are doing.
  61:  *
  62:  * @author Thomas Morgner
  63:  */
  64: public abstract class Element extends Node
  65: {
  66:   private static final Expression[] EMPTY_EXPRESSIONS = new Expression[0];
  67:   private static final String[] EMPTY_STRINGS = new String[0];
  68:   private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap());
  69:   public static final String NAME_ATTRIBUTE = "name";
  70:   public static final String ID_ATTRIBUTE = "id";
  71:   /**
  72:    * The type corresponds (somewhat) to the tagname of HTML.
  73:    */
  74:   public static final String TYPE_ATTRIBUTE = "type";
  75:   /**
  76:    * See XML-Namespaces for the idea of that one ...
  77:    */
  78:   public static final String NAMESPACE_ATTRIBUTE = "namespace";
  79:   public static final String VIRTUAL_ATTRIBUTE = "virtual";
  80: 
  81: 
  82:   /**
  83:    * The name of the element.
  84:    */
  85:   private AttributeMap attributes;
  86:   private CSSStyleRule style;
  87:   private ArrayList expressions;
  88:   private AttributeMap attributeExpressions;
  89:   private HashMap styleExpressions;
  90:   private boolean enabled;
  91:   private boolean virtual;
  92:   private Expression displayCondition;
  93: 
  94:   /**
  95:    * Constructs an element.
  96:    * <p/>
  97:    * The element inherits the element's defined default ElementStyleSheet to
  98:    * provide reasonable default values for common stylekeys. When the element is
  99:    * 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: }