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: */package org.jfree.report.structure;
031:
032: import java.util.ArrayList;
033: import java.util.Arrays;
034: import java.util.HashMap;
035: import java.util.Locale;
036: import java.util.Map;
037: import java.util.Iterator;
038: import java.util.Collections;
039:
040: import org.jfree.layouting.input.style.CSSStyleRule;
041: import org.jfree.layouting.input.style.keys.box.BoxStyleKeys;
042: import org.jfree.layouting.input.style.values.CSSConstant;
043: import org.jfree.layouting.namespace.Namespaces;
044: import org.jfree.layouting.util.AttributeMap;
045: import org.jfree.layouting.util.LocaleUtility;
046: import org.jfree.report.JFreeReportInfo;
047: import org.jfree.report.expressions.Expression;
048:
049: /**
050: * An element is a node that can have attributes. The 'id' and the 'name'
051: * attribute is defined for all elements.
052: * <p/>
053: * Both the name and the id attribute may be null.
054: * <p/>
055: * Properties in the 'http://jfreereport.sourceforge.net/namespaces/engine/flow'
056: * namespace and in the 'http://jfreereport.sourceforge.net/namespaces/engine/compatibility'
057: * namespace are considered internal. You should only touch them, if you really
058: * know what you are doing.
059: *
060: * @author Thomas Morgner
061: */
062: public abstract class Element extends Node {
063: private static final Expression[] EMPTY_EXPRESSIONS = new Expression[0];
064: private static final String[] EMPTY_STRINGS = new String[0];
065: private static final Map EMPTY_MAP = Collections
066: .unmodifiableMap(new HashMap());
067: public static final String NAME_ATTRIBUTE = "name";
068: public static final String ID_ATTRIBUTE = "id";
069: /**
070: * The type corresponds (somewhat) to the tagname of HTML.
071: */
072: public static final String TYPE_ATTRIBUTE = "type";
073: /**
074: * See XML-Namespaces for the idea of that one ...
075: */
076: public static final String NAMESPACE_ATTRIBUTE = "namespace";
077: public static final String VIRTUAL_ATTRIBUTE = "virtual";
078:
079: /**
080: * The name of the element.
081: */
082: private AttributeMap attributes;
083: private CSSStyleRule style;
084: private ArrayList expressions;
085: private AttributeMap attributeExpressions;
086: private HashMap styleExpressions;
087: private boolean enabled;
088: private boolean virtual;
089: private Expression displayCondition;
090:
091: /**
092: * Constructs an element.
093: * <p/>
094: * The element inherits the element's defined default ElementStyleSheet to
095: * provide reasonable default values for common stylekeys. When the element is
096: * added to the band, the bands stylesheet is set as parent to the element's
097: * stylesheet.
098: * <p/>
099: * A datasource is assigned with this element is set to a default source,
100: * which always returns null.
101: */
102: protected Element() {
103: this .style = new CSSStyleRule(null, null);
104: this .attributes = new AttributeMap();
105: this .enabled = true;
106: setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
107: }
108:
109: public String getNamespace() {
110: return (String) getAttribute(JFreeReportInfo.REPORT_NAMESPACE,
111: Element.NAMESPACE_ATTRIBUTE);
112: }
113:
114: public void setNamespace(final String id) {
115: setAttribute(JFreeReportInfo.REPORT_NAMESPACE,
116: Element.NAMESPACE_ATTRIBUTE, id);
117: }
118:
119: public String getId() {
120: return (String) getAttribute(Namespaces.XML_NAMESPACE,
121: Element.ID_ATTRIBUTE);
122: }
123:
124: public void setId(final String id) {
125: setAttribute(Namespaces.XML_NAMESPACE, Element.ID_ATTRIBUTE, id);
126: }
127:
128: public String getType() {
129: return (String) getAttribute(JFreeReportInfo.REPORT_NAMESPACE,
130: Element.TYPE_ATTRIBUTE);
131: }
132:
133: public void setType(final String type) {
134: setAttribute(JFreeReportInfo.REPORT_NAMESPACE,
135: Element.TYPE_ATTRIBUTE, type);
136: }
137:
138: /**
139: * Defines the name for this Element. The name must not be empty, or a
140: * NullPointerException is thrown.
141: * <p/>
142: * Names can be used to lookup an element within a band. There is no
143: * requirement for element names to be unique.
144: *
145: * @param name the name of this element
146: */
147: public void setName(final String name) {
148: setAttribute(Namespaces.XML_NAMESPACE, Element.NAME_ATTRIBUTE,
149: name);
150: }
151:
152: /**
153: * Returns the name of the Element. The name of the Element is never null.
154: *
155: * @return the name.
156: */
157: public String getName() {
158: return (String) getAttribute(Namespaces.XML_NAMESPACE,
159: Element.NAME_ATTRIBUTE);
160: }
161:
162: public void setAttribute(final String name, final Object value) {
163: setAttribute(getNamespace(), name, value);
164: }
165:
166: public void setAttribute(final String namespace, final String name,
167: final Object value) {
168: if (name == null) {
169: throw new NullPointerException();
170: }
171: if (attributes == null) {
172: this .attributes = new AttributeMap();
173: }
174: this .attributes.setAttribute(namespace, name, value);
175: }
176:
177: public Object getAttribute(final String name) {
178: return getAttribute(getNamespace(), name);
179: }
180:
181: public Object getAttribute(final String namespace, final String name) {
182: if (this .attributes == null) {
183: return null;
184: }
185: return this .attributes.getAttribute(namespace, name);
186: }
187:
188: public Map getAttributes(final String namespace) {
189: if (this .attributes == null) {
190: return null;
191: }
192: return this .attributes.getAttributes(namespace);
193: }
194:
195: public AttributeMap getAttributeMap() {
196: return new AttributeMap(this .attributes);
197: }
198:
199: public String[] getAttributeNameSpaces() {
200: if (this .attributes == null) {
201: return Element.EMPTY_STRINGS;
202: }
203: return this .attributes.getNameSpaces();
204: }
205:
206: /**
207: * Returns this elements private stylesheet. This sheet can be used to
208: * override the default values set in one of the parent-stylesheets.
209: *
210: * @return the Element's stylesheet
211: */
212: public CSSStyleRule getStyle() {
213: return style;
214: }
215:
216: public void setVisibility(final CSSConstant v) {
217: getStyle().setPropertyValue(BoxStyleKeys.VISIBILITY, v);
218: }
219:
220: public CSSConstant getVisibility() {
221: return (CSSConstant) getStyle().getPropertyCSSValue(
222: BoxStyleKeys.VISIBILITY);
223: }
224:
225: public void setAttributeExpression(final String attr,
226: final Expression function) {
227: setAttribute(getNamespace(), attr, function);
228: }
229:
230: /**
231: * Adds a function to the report's collection of expressions.
232: *
233: * @param namespace
234: * @param attr
235: * @param function the function.
236: */
237: public void setAttributeExpression(final String namespace,
238: final String attr, final Expression function) {
239:
240: if (attributeExpressions == null) {
241: if (function == null) {
242: return;
243: }
244: this .attributeExpressions = new AttributeMap();
245: }
246: attributeExpressions.setAttribute(namespace, attr, function);
247: }
248:
249: /**
250: * Returns the expressions for the report.
251: *
252: * @param attr
253: * @return the expressions.
254: */
255: public Expression getAttributeExpression(final String attr) {
256: return getAttributeExpression(getNamespace(), attr);
257: }
258:
259: public Expression getAttributeExpression(final String namespace,
260: final String attr) {
261: if (attributeExpressions == null) {
262: return null;
263: }
264: return (Expression) attributeExpressions.getAttribute(
265: namespace, attr);
266: }
267:
268: public Map getAttributeExpressions(final String namespace) {
269: if (attributeExpressions == null) {
270: return null;
271: }
272: return attributeExpressions.getAttributes(namespace);
273: }
274:
275: public AttributeMap getAttributeExpressionMap() {
276: if (this .attributeExpressions == null) {
277: return new AttributeMap();
278: }
279:
280: return new AttributeMap(this .attributeExpressions);
281: }
282:
283: /**
284: * Adds a function to the report's collection of expressions.
285: *
286: * @param function the function.
287: * @param property
288: */
289: public void setStyleExpression(final String property,
290: final Expression function) {
291: if (function == null) {
292: if (styleExpressions != null) {
293: styleExpressions.remove(property);
294: }
295: } else {
296: if (styleExpressions == null) {
297: styleExpressions = new HashMap();
298: }
299: styleExpressions.put(property, function);
300: }
301: }
302:
303: /**
304: * Returns the expressions for the report.
305: *
306: * @param property
307: * @return the expressions.
308: */
309: public Expression getStyleExpression(final String property) {
310: if (styleExpressions == null) {
311: return null;
312: }
313: return (Expression) styleExpressions.get(property);
314: }
315:
316: public Map getStyleExpressions() {
317: if (styleExpressions == null) {
318: return Element.EMPTY_MAP;
319: }
320: return Collections.unmodifiableMap(styleExpressions);
321: }
322:
323: /**
324: * Adds a function to the report's collection of expressions.
325: *
326: * @param function the function.
327: */
328: public void addExpression(final Expression function) {
329: if (expressions == null) {
330: expressions = new ArrayList();
331: }
332: expressions.add(function);
333: }
334:
335: /**
336: * Returns the expressions for the report.
337: *
338: * @return the expressions.
339: */
340: public Expression[] getExpressions() {
341: if (expressions == null) {
342: return Element.EMPTY_EXPRESSIONS;
343: }
344: return (Expression[]) expressions
345: .toArray(new Expression[expressions.size()]);
346: }
347:
348: /**
349: * Sets the expressions for the report.
350: *
351: * @param expressions the expressions (<code>null</code> not permitted).
352: */
353: public void setExpressions(final Expression[] expressions) {
354: if (expressions == null) {
355: throw new NullPointerException(
356: "JFreeReport.setExpressions(...) : null not permitted.");
357: }
358: if (this .expressions == null) {
359: this .expressions = new ArrayList(expressions.length);
360: } else {
361: this .expressions.clear();
362: }
363: this .expressions.addAll(Arrays.asList(expressions));
364: }
365:
366: /**
367: * Returns true, if the element is enabled.
368: *
369: * @return true or false
370: */
371: public boolean isEnabled() {
372: return enabled;
373: }
374:
375: /**
376: * Defines whether the element is enabled. Disabled elements will be fully
377: * ignored by the report processor. This is a design time property to exclude
378: * elements from the processing without actually having to deal with the other
379: * complex properties.
380: *
381: * @param enabled
382: */
383: public void setEnabled(final boolean enabled) {
384: this .enabled = enabled;
385: }
386:
387: public Expression getDisplayCondition() {
388: return displayCondition;
389: }
390:
391: public void setDisplayCondition(final Expression displayCondition) {
392: this .displayCondition = displayCondition;
393: }
394:
395: public Locale getLocale() {
396: final Locale locale = getLocaleFromAttributes();
397: if (locale != null) {
398: return locale;
399: }
400: return super .getLocale();
401: }
402:
403: protected Locale getLocaleFromAttributes() {
404: final Object mayBeXmlLang = getAttribute(
405: Namespaces.XML_NAMESPACE, "lang");
406: if (mayBeXmlLang instanceof String) {
407: return LocaleUtility.createLocale((String) mayBeXmlLang);
408: } else if (mayBeXmlLang instanceof Locale) {
409: return (Locale) mayBeXmlLang;
410: }
411:
412: final Object mayBeXhtmlLang = getAttribute(
413: Namespaces.XHTML_NAMESPACE, "lang");
414: if (mayBeXhtmlLang instanceof String) {
415: return LocaleUtility.createLocale((String) mayBeXhtmlLang);
416: } else if (mayBeXhtmlLang instanceof Locale) {
417: return (Locale) mayBeXhtmlLang;
418: }
419: //
420: // final Object mayBeHtmlLang = getAttribute(Namespaces.XHTML_NAMESPACE, "lang");
421: // if (mayBeHtmlLang instanceof String)
422: // {
423: // return LocaleUtility.createLocale((String) mayBeHtmlLang);
424: // }
425: // else if (mayBeHtmlLang instanceof Locale)
426: // {
427: // return (Locale) mayBeHtmlLang;
428: // }
429:
430: return null;
431: }
432:
433: public boolean isVirtual() {
434: return virtual;
435: }
436:
437: public void setVirtual(final boolean virtual) {
438: this .virtual = virtual;
439: }
440:
441: public Object clone() throws CloneNotSupportedException {
442: final Element element = (Element) super .clone();
443: element.style = (CSSStyleRule) style.clone();
444: if (attributes != null) {
445: element.attributes = (AttributeMap) attributes.clone();
446: }
447:
448: if (attributeExpressions != null) {
449: element.attributeExpressions = (AttributeMap) attributeExpressions
450: .clone();
451: final String[] namespaces = element.attributeExpressions
452: .getNameSpaces();
453: for (int i = 0; i < namespaces.length; i++) {
454: final String namespace = namespaces[i];
455: final Map attrsNs = element.attributeExpressions
456: .getAttributes(namespace);
457: final Iterator it = attrsNs.entrySet().iterator();
458: while (it.hasNext()) {
459: final Map.Entry entry = (Map.Entry) it.next();
460: final Expression exp = (Expression) entry
461: .getValue();
462: entry.setValue(exp.clone());
463: }
464: }
465: }
466:
467: if (expressions != null) {
468: element.expressions = (ArrayList) expressions.clone();
469: element.expressions.clear();
470: for (int i = 0; i < expressions.size(); i++) {
471: final Expression expression = (Expression) expressions
472: .get(i);
473: element.expressions.add(expression.clone());
474: }
475: }
476: if (styleExpressions != null) {
477: element.styleExpressions = (HashMap) styleExpressions
478: .clone();
479: final Iterator styleExpressionsIt = element.styleExpressions
480: .entrySet().iterator();
481: while (styleExpressionsIt.hasNext()) {
482: final Map.Entry entry = (Map.Entry) styleExpressionsIt
483: .next();
484: final Expression exp = (Expression) entry.getValue();
485: entry.setValue(exp.clone());
486: }
487: }
488:
489: if (displayCondition != null) {
490: element.displayCondition = (Expression) displayCondition
491: .clone();
492: }
493: return element;
494: }
495: }
|