001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, 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: * LevelList.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.util;
030:
031: import java.lang.reflect.Array;
032: import java.util.ArrayList;
033: import java.util.Arrays;
034: import java.util.Collections;
035: import java.util.Comparator;
036: import java.util.HashMap;
037: import java.util.Iterator;
038: import java.util.List;
039: import java.util.TreeSet;
040: import java.io.Serializable;
041:
042: /**
043: * A list that associates a level (instance of <code>Integer</code>) with each element in
044: * the list.
045: *
046: * @author Thomas Morgner
047: */
048: public class LevelList implements Cloneable {
049: /** A static object array of size zero. */
050: private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
051: /** A static object array of size zero. */
052: private static final Integer[] EMPTY_INTEGER_ARRAY = new Integer[0];
053:
054: /**
055: * Constant for level zero.
056: */
057: private static final Integer ZERO = new Integer(0);
058:
059: /**
060: * A treeset to build the iterator.
061: */
062: private transient TreeSet iteratorSetAsc;
063:
064: /**
065: * A treeset to build the iterator.
066: */
067: private transient TreeSet iteratorSetDesc;
068:
069: /**
070: * A treeset to cache the level iterator.
071: */
072: private HashMap iteratorCache;
073:
074: /**
075: * A comparator for levels in descending order.
076: */
077: private static final class DescendingComparator implements
078: Comparator, Serializable {
079: /**
080: * Default constructor.
081: */
082: private DescendingComparator() {
083: }
084:
085: /**
086: * Compares its two arguments for order. Returns a negative integer, zero, or a
087: * positive integer as the first argument is less than, equal to, or greater than the
088: * second.<p>
089: *
090: * @param o1 the first object to be compared.
091: * @param o2 the second object to be compared.
092: * @return a negative integer, zero, or a positive integer as the first argument is
093: * less than, equal to, or greater than the second.
094: *
095: * @throws ClassCastException if the arguments' types prevent them from being compared
096: * by this Comparator.
097: */
098: public int compare(final Object o1, final Object o2) {
099: if ((o1 instanceof Comparable) == false) {
100: throw new ClassCastException("Need comparable Elements");
101: }
102: if ((o2 instanceof Comparable) == false) {
103: throw new ClassCastException("Need comparable Elements");
104: }
105: final Comparable c1 = (Comparable) o1;
106: final Comparable c2 = (Comparable) o2;
107: return -1 * c1.compareTo(c2);
108: }
109: }
110:
111: /**
112: * An list that caches all elements for a certain level.
113: */
114: private static final class ElementLevelList {
115: /**
116: * The level list.
117: */
118: private Object[] data;
119:
120: /**
121: * Creates an iterator that provides access to all the elements in a list at the
122: * specified level.
123: *
124: * @param list the list (null not permitted).
125: * @param level the level.
126: */
127: private ElementLevelList(final LevelList list, final int level) {
128: if (list == null) {
129: throw new NullPointerException();
130: }
131:
132: final Object[] rawElements = list.getRawElements();
133: final Integer[] rawLevels = list.getRawLevels();
134:
135: final ArrayList datalist = new ArrayList(rawElements.length);
136: for (int i = 0; i < rawElements.length; i++) {
137: final Object iNext = rawElements[i];
138: final Integer iLevel = rawLevels[i];
139: if (iLevel.intValue() == level) {
140: datalist.add(iNext);
141: }
142: }
143: data = datalist.toArray();
144: }
145:
146: /**
147: * Returns the data for this level as object array.
148: *
149: * @return the data for this level as object array.
150: */
151: protected Object[] getData() {
152: return (Object[]) data.clone();
153: }
154:
155: /**
156: * Returns the data for this level as object array. Behaves like ArrayList.toArray(..)
157: *
158: * @param target object array that should receive the contents
159: * @return the data for this level as object array.
160: */
161: protected Object[] getData(Object[] target) {
162: if (target == null) {
163: target = new Object[data.length];
164: } else if (target.length < data.length) {
165: target = (Object[]) Array.newInstance(target.getClass()
166: .getComponentType(), data.length);
167: }
168: System.arraycopy(data, 0, target, 0, data.length);
169: if (target.length > data.length) {
170: target[data.length] = null;
171: }
172: return target;
173: }
174:
175: /**
176: * Returns the size if the list.
177: *
178: * @return the size.
179: */
180: protected int size() {
181: return data.length;
182: }
183: }
184:
185: /**
186: * The elements.
187: */
188: private ArrayList elements;
189:
190: /**
191: * The levels.
192: */
193: private ArrayList levels;
194:
195: /**
196: * Creates a new list (initially empty).
197: */
198: public LevelList() {
199: this .elements = new ArrayList();
200: this .levels = new ArrayList();
201: this .iteratorCache = new HashMap();
202: }
203:
204: /**
205: * Returns the number of elements in the list.
206: *
207: * @return the element count.
208: */
209: public int size() {
210: return elements.size();
211: }
212:
213: /**
214: * Returns an iterator that iterates through the levels in ascending order.
215: *
216: * @return an iterator.
217: */
218: public synchronized Iterator getLevelsAscending() {
219: if (iteratorSetAsc == null) {
220: iteratorSetAsc = new TreeSet();
221: final Integer[] ilevels = (Integer[]) levels
222: .toArray(new Integer[levels.size()]);
223: for (int i = 0; i < ilevels.length; i++) {
224: if (iteratorSetAsc.contains(ilevels[i]) == false) {
225: iteratorSetAsc.add(ilevels[i]);
226: }
227: }
228: }
229: return iteratorSetAsc.iterator();
230: }
231:
232: /**
233: * Returns the levels of the elements in the list in descending order.
234: *
235: * @return the levels in descending order.
236: */
237: public synchronized Integer[] getLevelsDescendingArray() {
238: if (levels.isEmpty()) {
239: return EMPTY_INTEGER_ARRAY;
240: }
241: if (iteratorSetDesc == null) {
242: final Integer[] ilevels = (Integer[]) levels
243: .toArray(new Integer[levels.size()]);
244: iteratorSetDesc = new TreeSet(new DescendingComparator());
245: for (int i = 0; i < ilevels.length; i++) {
246: if (iteratorSetDesc.contains(ilevels[i]) == false) {
247: iteratorSetDesc.add(ilevels[i]);
248: }
249: }
250: }
251: return (Integer[]) iteratorSetDesc
252: .toArray(new Integer[iteratorSetDesc.size()]);
253: }
254:
255: /**
256: * Returns an iterator that iterates through the levels in descending order.
257: *
258: * @return an iterator.
259: */
260: public synchronized Iterator getLevelsDescending() {
261: if (iteratorSetDesc == null) {
262: iteratorSetDesc = new TreeSet(new DescendingComparator());
263: final Integer[] ilevels = (Integer[]) levels
264: .toArray(new Integer[levels.size()]);
265: for (int i = 0; i < ilevels.length; i++) {
266: if (iteratorSetDesc.contains(ilevels[i]) == false) {
267: iteratorSetDesc.add(ilevels[i]);
268: }
269: }
270: }
271: return iteratorSetDesc.iterator();
272: }
273:
274: /**
275: * Returns the elements as an array.
276: *
277: * @return the array.
278: */
279: public synchronized Object[] toArray() {
280: return elements.toArray();
281: }
282:
283: /**
284: * Returns an iterator for all the elements at a given level.
285: *
286: * @param level the level.
287: * @param target the target array that should receive the contentes
288: * @return the data for the level as object array.
289: */
290: public Object[] getElementArrayForLevel(final int level,
291: final Object[] target) {
292: ElementLevelList it = (ElementLevelList) iteratorCache
293: .get(IntegerCache.getInteger(level));
294: if (it == null) {
295: it = new ElementLevelList(this , level);
296: iteratorCache.put(IntegerCache.getInteger(level), it);
297: }
298: if (target == null) {
299: return it.getData();
300: } else {
301: return it.getData(target);
302: }
303: }
304:
305: /**
306: * Returns an iterator for all the elements at a given level.
307: *
308: * @param level the level.
309: * @return the data for the level as object array.
310: */
311: public Object[] getElementArrayForLevel(final int level) {
312: return getElementArrayForLevel(level, null);
313: }
314:
315: /**
316: * Returns the numer of elements registered for an certain level.
317: *
318: * @param level the level that should be queried
319: * @return the numer of elements in that level
320: */
321: public int getElementCountForLevel(final int level) {
322: ElementLevelList it = (ElementLevelList) iteratorCache
323: .get(IntegerCache.getInteger(level));
324: if (it == null) {
325: it = new ElementLevelList(this , level);
326: iteratorCache.put(IntegerCache.getInteger(level), it);
327: }
328: return it.size();
329: }
330:
331: /**
332: * Creates an iterator for the elements in the list at the given level.
333: *
334: * @param level the level.
335: * @return An iterator.
336: *
337: * @deprecated use the array methods for best performance.
338: */
339: protected Iterator getElementsForLevel(final int level) {
340: final List list = Arrays.asList(getElementArrayForLevel(level));
341: return Collections.unmodifiableList(list).iterator();
342: }
343:
344: /**
345: * Returns the element with the given index.
346: *
347: * @param index the index.
348: * @return the element.
349: */
350: public synchronized Object get(final int index) {
351: return elements.get(index);
352: }
353:
354: /**
355: * Adds an element at level zero.
356: *
357: * @param o the element.
358: */
359: public synchronized void add(final Object o) {
360: elements.add(o);
361: levels.add(ZERO);
362: iteratorSetAsc = null;
363: iteratorSetDesc = null;
364: iteratorCache.remove(ZERO);
365: }
366:
367: /**
368: * Adds an element at a given level.
369: *
370: * @param o the element.
371: * @param level the level.
372: */
373: public synchronized void add(final Object o, final int level) {
374: elements.add(o);
375: final Integer i = IntegerCache.getInteger(level);
376: levels.add(i);
377: iteratorCache.remove(i);
378: iteratorSetAsc = null;
379: iteratorSetDesc = null;
380: }
381:
382: /**
383: * Sets the level for an element.
384: *
385: * @param index the element index.
386: * @param level the level.
387: */
388: public void setLevel(final int index, final int level) {
389: levels.set(index, IntegerCache.getInteger(level));
390: }
391:
392: /**
393: * Returns the level for an element.
394: *
395: * @param index the element index.
396: * @return the level.
397: */
398: public int getLevel(final int index) {
399: return ((Integer) levels.get(index)).intValue();
400: }
401:
402: /**
403: * Returns the index of an element.
404: *
405: * @param o the element.
406: * @return the index.
407: */
408: public int indexOf(final Object o) {
409: return elements.indexOf(o);
410: }
411:
412: /**
413: * Returns the level of an element.
414: *
415: * @param o the element.
416: * @return the level.
417: */
418: public int getLevel(final Object o) {
419: return getLevel(indexOf(o));
420: }
421:
422: /**
423: * Sets the level of an element.
424: *
425: * @param o the element.
426: * @param level the level.
427: */
428: public void setLevel(final Object o, final int level) {
429: setLevel(indexOf(o), level);
430: }
431:
432: /**
433: * Clones the list.
434: *
435: * @return the clone.
436: *
437: * @throws CloneNotSupportedException should never happen.
438: */
439: public Object clone() throws CloneNotSupportedException {
440: final LevelList l = (LevelList) super .clone();
441: l.elements = (ArrayList) elements.clone();
442: l.levels = (ArrayList) levels.clone();
443: l.iteratorCache = (HashMap) iteratorCache.clone();
444: return l;
445: }
446:
447: /**
448: * Clears the list.
449: */
450: public synchronized void clear() {
451: elements.clear();
452: levels.clear();
453: iteratorCache.clear();
454: iteratorSetAsc = null;
455: iteratorSetDesc = null;
456: }
457:
458: /**
459: * Returns all stored objects as object array.
460: *
461: * @return all elements as object array.
462: */
463: protected Object[] getRawElements() {
464: if (elements.isEmpty()) {
465: return EMPTY_OBJECT_ARRAY;
466: }
467: return elements.toArray(new Object[elements.size()]);
468: }
469:
470: /**
471: * Returns all active levels as java.lang.Integer array.
472: *
473: * @return all levels as Integer array.
474: */
475: protected Integer[] getRawLevels() {
476: if (levels.isEmpty()) {
477: return EMPTY_INTEGER_ARRAY;
478: }
479: return (Integer[]) levels.toArray(new Integer[levels.size()]);
480: }
481: }
|