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,v 1.13 2007/05/14 08:55:52 taqua Exp $
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 }