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: * TotalItemMinFunction.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.function;
030:
031: import java.io.IOException;
032: import java.io.ObjectInputStream;
033: import java.util.HashMap;
034:
035: import org.jfree.report.event.ReportEvent;
036: import org.jfree.report.states.ReportStateKey;
037: import org.jfree.util.Log;
038:
039: /**
040: * A report function that pre-computes the smallest item in a group. The Items must be mutually comparable among each
041: * other or the function will fail. Comparing dates with strings will not work.
042: * <p/>
043: * Like all Total-Functions, this function produces a precomputed grand total. The function's result is precomputed once
044: * and will not change later. Printing the result of this function in a group header returns the same value as printed
045: * in the group-footer.
046: * <p/>
047: * The ItemMinFunction can be used to produce a running minimum for a group or report.
048: * <p/>
049: * A group can be defined using the property "group". If the group property is not set, the function will process the
050: * whole report.
051: *
052: * @author Thomas Morgner
053: */
054: public class TotalItemMinFunction extends AbstractFunction {
055: /**
056: * A map of results, keyed by the process-key.
057: */
058: private transient HashMap results;
059:
060: /**
061: * The name of the group on which to reset.
062: */
063: private String group;
064: /**
065: * The field that should be evaluated.
066: */
067: private String field;
068: /**
069: * The currently computed minimum value.
070: */
071: private transient Comparable min;
072: /**
073: * The global state key is used to store the result for the whole report.
074: */
075: private transient ReportStateKey globalStateKey;
076: /**
077: * The current group key is used to store the result for the current group.
078: */
079: private transient ReportStateKey groupStateKey;
080:
081: /**
082: * Default constructor.
083: */
084: public TotalItemMinFunction() {
085: results = new HashMap();
086: }
087:
088: /**
089: * Returns the field used by the function. The field name corresponds to a column name in the report's data-row.
090: *
091: * @return The field name.
092: */
093: public String getField() {
094: return field;
095: }
096:
097: /**
098: * Sets the field name for the function. The field name corresponds to a column name in the report's data-row.
099: *
100: * @param field the field name.
101: */
102: public void setField(final String field) {
103: this .field = field;
104: }
105:
106: /**
107: * Receives notification that the report has started.
108: *
109: * @param event the event.
110: */
111: public void reportInitialized(final ReportEvent event) {
112: globalStateKey = event.getState().getProcessKey();
113: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event)) {
114: results.clear();
115: this .min = null;
116: results.put(globalStateKey, null);
117: } else {
118: this .min = (Comparable) results.get(globalStateKey);
119: }
120: }
121:
122: /**
123: * Receives notification that a group has started.
124: *
125: * @param event the event.
126: */
127: public void groupStarted(final ReportEvent event) {
128: if (FunctionUtilities.isDefinedGroup(getGroup(), event) == false) {
129: // wrong group ...
130: return;
131: }
132:
133: groupStateKey = event.getState().getProcessKey();
134: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event)) {
135: this .min = null;
136: results.put(globalStateKey, min);
137: results.put(groupStateKey, min);
138: } else {
139: // Activate the current group, which was filled in the prepare run.
140: min = (Integer) results.get(groupStateKey);
141: }
142: }
143:
144: /**
145: * Receives notification that a row of data is being processed.
146: *
147: * @param event the event.
148: */
149: public void itemsAdvanced(final ReportEvent event) {
150: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event) == false) {
151: return;
152: }
153:
154: final Object fieldValue = event.getDataRow().get(getField());
155: if (fieldValue instanceof Comparable == false) {
156: return;
157: }
158: try {
159: final Comparable compare = (Comparable) fieldValue;
160: if (min == null) {
161: min = compare;
162: } else if (min.compareTo(compare) > 0) {
163: min = compare;
164: }
165: } catch (Exception e) {
166: Log
167: .error("TotalItemMinFunction.advanceItems(): problem comparing values.");
168: }
169:
170: results.put(globalStateKey, min);
171: if (groupStateKey != null) {
172: results.put(groupStateKey, min);
173: }
174: }
175:
176: /**
177: * Returns the name of the group for which the minimum should be computed.
178: *
179: * @return the group name.
180: */
181: public String getGroup() {
182: return group;
183: }
184:
185: /**
186: * Defines the name of the group to be totalled. If the name is null, the minimum for the whole report is computed.
187: *
188: * @param group the group name.
189: */
190: public void setGroup(final String group) {
191: this .group = group;
192: }
193:
194: /**
195: * Returns the computed minimum value.
196: *
197: * @return The computed minimum value.
198: */
199: public Object getValue() {
200: return min;
201: }
202:
203: /**
204: * Return a completly separated copy of this function. The copy does no longer share any changeable objects with the
205: * original function.
206: *
207: * @return a copy of this function.
208: */
209: public Expression getInstance() {
210: final TotalItemMinFunction function = (TotalItemMinFunction) super
211: .getInstance();
212: function.results = new HashMap();
213: return function;
214: }
215:
216: /**
217: * Helper function for the serialization.
218: *
219: * @param in the input stream.
220: * @throws IOException if an IO error occured.
221: * @throws ClassNotFoundException if a required class could not be found.
222: */
223: private void readObject(final ObjectInputStream in)
224: throws IOException, ClassNotFoundException {
225: in.defaultReadObject();
226: results = new HashMap();
227: }
228:
229: }
|