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: * GroupList.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report;
030:
031: import java.io.Serializable;
032: import java.util.ArrayList;
033: import java.util.Collection;
034: import java.util.Iterator;
035:
036: import org.jfree.report.util.ReadOnlyIterator;
037:
038: /**
039: * The group list is used to store groups in a ordered way. The less specific groups are guaranteed to be listed before
040: * the more specific subgroups.
041: * <p/>
042: * Groups are ordered by comparing the declared fieldnames for the groups. A subgroup of an group must contain all
043: * fields from its parent plus at least one new field.
044: * <p/>
045: * This implementation is not synchronized.
046: * <p/>
047: * The group list cannot be empty. JFreeReport needs at least one group instance to work as expected. By default, this
048: * default instance does not define any fields (and therefore contains the complete report) and has no Bands defined
049: * (rendering it invisible). You cannot remove that group. Every attempt to remove the last group will recreates a new
050: * default group.
051: *
052: * @author Thomas Morgner
053: */
054: public class GroupList implements Cloneable, Serializable {
055: /**
056: * A unique identifier for long term persistance.
057: */
058: private static final long serialVersionUID = 2193162824440886046L;
059:
060: /**
061: * Cache.
062: */
063: private transient Group[] cache;
064:
065: /**
066: * The backend to store the groups.
067: */
068: private ArrayList backend;
069:
070: /**
071: * The report definition to which this group list is assigned to.
072: */
073: private ReportDefinition reportDefinition;
074:
075: /**
076: * The name of the automaticly created default group.
077: */
078: public static final String DEFAULT_GROUP_NAME = "default";
079:
080: /**
081: * Constructs a new group list, with only a default group inside.
082: */
083: public GroupList() {
084: backend = new ArrayList();
085: createDefaultGroup();
086: }
087:
088: /**
089: * Creates a default group. The default group has no fields defined and spans all fields of the report.
090: */
091: private void createDefaultGroup() {
092: final Group defaultGroup = new Group();
093: defaultGroup.setName(DEFAULT_GROUP_NAME);
094: add(defaultGroup);
095: }
096:
097: /**
098: * Creates a new group list and copies the contents of the given grouplist. If the given group list was assigned with
099: * a report definition, then the new group list will share that registration.
100: *
101: * @param list groups to add to the list.
102: */
103: protected GroupList(final GroupList list) {
104: backend = new ArrayList();
105: backend.addAll(list.backend);
106: }
107:
108: /**
109: * Returns the group at a given position in the list.
110: *
111: * @param i the position index (zero-based).
112: * @return the report group.
113: */
114: public Group get(final int i) {
115: if (cache == null) {
116: cache = (Group[]) backend
117: .toArray(new Group[backend.size()]);
118: }
119: return cache[i];
120: }
121:
122: /**
123: * Removes an group from the list.
124: *
125: * @param o the group that should be removed.
126: * @return a boolean indicating whether or not the object was removed.
127: * @throws NullPointerException if the given group object is null.
128: */
129: public boolean remove(final Group o) {
130: if (o == null) {
131: throw new NullPointerException();
132: }
133: cache = null;
134: final int idxOf = backend.indexOf(o);
135: if (idxOf == -1) {
136: // the object was not in the list ...
137: return false;
138: }
139:
140: // it might as well be a group that looks like the one we have in the list
141: // so be sure that you modify the one, that was removed, and not the one given
142: // to us.
143: final Group g = (Group) backend.remove(idxOf);
144: g.setReportDefinition(null);
145:
146: if (backend.isEmpty()) {
147: createDefaultGroup();
148: }
149: return true;
150: }
151:
152: /**
153: * Clears the list.
154: */
155: public void clear() {
156: backend.clear();
157: createDefaultGroup();
158: cache = null;
159: }
160:
161: /**
162: * Adds a group to the list.
163: *
164: * @param o the group object.
165: */
166: public void add(final Group o) {
167: if (o == null) {
168: throw new NullPointerException("Try to add null");
169: }
170: cache = null;
171: final int idxOf = backend.indexOf(o);
172: if (idxOf != -1) {
173: // it might as well be a group that looks like the one we have in the list
174: // so be sure that you modify the one, that was removed, and not the one given
175: // to us.
176: final Group g = (Group) backend.remove(idxOf);
177: g.setReportDefinition(null);
178: }
179:
180: // this is a linear search to find the correct insertation point ..
181: for (int i = 0; i < backend.size(); i++) {
182: final Group compareGroup = (Group) backend.get(i);
183: // if the current group at index i is greater than the new group
184: if (compareGroup.compareTo(o) > 0) {
185: // then insert the new one before the current group ..
186: backend.add(i, o);
187: o.setReportDefinition(reportDefinition);
188: return;
189: }
190: }
191: // finally, if this group is the smallest group ...
192: backend.add(o);
193: o.setReportDefinition(reportDefinition);
194: }
195:
196: /**
197: * Adds all groups of the collection to this group list. This method will result in a ClassCastException if the
198: * collection does not contain Group objects.
199: *
200: * @param c the collection that contains the groups.
201: * @throws NullPointerException if the given collection is null.
202: * @throws ClassCastException if the collection does not contain groups.
203: */
204: public void addAll(final Collection c) {
205: final Iterator it = c.iterator();
206: while (it.hasNext()) {
207: add((Group) it.next());
208: }
209: }
210:
211: /**
212: * Clones the group list and all contained groups.
213: *
214: * @return a clone of this list.
215: * @throws CloneNotSupportedException if cloning the element failed.
216: * @see Cloneable
217: */
218: public Object clone() throws CloneNotSupportedException {
219: final GroupList l = (GroupList) super .clone();
220: final Group[] groups = getGroupCache();
221:
222: l.backend = new ArrayList();
223: l.reportDefinition = null;
224: final int length = groups.length;
225: l.cache = new Group[length];
226: for (int i = 0; i < length; i++) {
227: final Group group = (Group) groups[i].clone();
228: group.setReportDefinition(null);
229: l.backend.add(group);
230: l.cache[i] = group;
231: }
232: return l;
233: }
234:
235: /**
236: * Returns an iterator for the groups of the list.
237: *
238: * @return An iterator over all groups of the list.
239: */
240: public Iterator iterator() {
241: return new ReadOnlyIterator(backend.iterator());
242: }
243:
244: /**
245: * Returns the number of groups in the list.
246: *
247: * @return The number of groups in the list.
248: */
249: public int size() {
250: return backend.size();
251: }
252:
253: /**
254: * Returns a string representation of the list (useful for debugging).
255: *
256: * @return A string.
257: */
258: public String toString() {
259: final StringBuffer b = new StringBuffer();
260: b.append("GroupList={backend='");
261: b.append(backend);
262: b.append("'} ");
263: return b.toString();
264: }
265:
266: /**
267: * Returns a direct reference to the group cache.
268: *
269: * @return the groups of this list as array.
270: */
271: protected Group[] getGroupCache() {
272: if (cache == null) {
273: cache = (Group[]) backend
274: .toArray(new Group[backend.size()]);
275: }
276: return cache;
277: }
278:
279: /**
280: * Searches a group by its defined name. This method returns null, if the group was not found.
281: *
282: * @param name the name of the group.
283: * @return the group or null if not found.
284: */
285: public Group getGroupByName(final String name) {
286: if (name == null) {
287: // Groups cannot have a null-name
288: return null;
289: }
290:
291: final Group[] cache = getGroupCache();
292: final int length = cache.length;
293: for (int i = 0; i < length; i++) {
294: if (name.equals(cache[i].getName())) {
295: return cache[i];
296: }
297: }
298: return null;
299: }
300:
301: /**
302: * Assigns the report definition to all groups in the list.
303: *
304: * @param reportDefinition the report definition (maybe null).
305: */
306: public void setReportDefinition(
307: final ReportDefinition reportDefinition) {
308: this .reportDefinition = reportDefinition;
309: for (int i = 0; i < backend.size(); i++) {
310: final Group group = (Group) backend.get(i);
311: group.setReportDefinition(reportDefinition);
312: }
313: }
314:
315: /**
316: * Returns the assigned report definition of the group.
317: *
318: * @return the report definition (maybe null).
319: */
320: public ReportDefinition getReportDefinition() {
321: return reportDefinition;
322: }
323:
324: }
|