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: * TotalGroupSumFunction.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.math.BigDecimal;
034: import java.util.HashMap;
035:
036: import org.jfree.report.event.ReportEvent;
037: import org.jfree.report.states.ReportStateKey;
038: import org.jfree.util.Log;
039:
040: /**
041: * A report function that calculates the sum of one field (column) from the Data-Row. This function produces a global
042: * total. The total sum of the group is known when the group processing starts and the report is not performing a
043: * prepare-run. The sum is calculated in the prepare run and recalled in the printing run.
044: * <p/>
045: * The function can be used in two ways: <ul> <li>to calculate a sum for the entire report;</li> <li>to calculate a sum
046: * within a particular group;</li> </ul> This function expects its input values to be either java.lang.Number instances
047: * or Strings that can be parsed to java.lang.Number instances using a java.text.DecimalFormat.
048: * <p/>
049: * The function undestands two parameters, the <code>field</code> parameter is required and denotes the name of an
050: * ItemBand-field which gets summed up.
051: * <p/>
052: * The parameter <code>group</code> denotes the name of a group. When this group is started, the counter gets reseted to
053: * null. This parameter is optional.
054: *
055: * @author Thomas Morgner
056: */
057: public class TotalGroupSumFunction extends AbstractFunction {
058: /**
059: * A map of results, keyed by the process-key.
060: */
061: private transient HashMap results;
062:
063: /**
064: * The field that should be evaluated.
065: */
066: private String field;
067: /**
068: * The name of the group on which to reset.
069: */
070: private String group;
071:
072: /**
073: * The currently computed result.
074: */
075: private transient BigDecimal result;
076: /**
077: * The global state key is used to store the result for the whole report.
078: */
079: private transient ReportStateKey globalStateKey;
080: /**
081: * The current group key is used to store the result for the current group.
082: */
083: private transient ReportStateKey groupStateKey;
084:
085: /**
086: * Constructs a new function. <P> Initially the function has no name...be sure to assign one before using the
087: * function.
088: */
089: public TotalGroupSumFunction() {
090: results = new HashMap();
091: }
092:
093: /**
094: * Receives notification that the report has started.
095: *
096: * @param event the event.
097: */
098: public void reportInitialized(final ReportEvent event) {
099: globalStateKey = event.getState().getProcessKey();
100: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event)) {
101: results.clear();
102: result = new BigDecimal(0);
103: results.put(globalStateKey, result);
104: } else {
105: result = (BigDecimal) results.get(globalStateKey);
106: }
107: }
108:
109: /**
110: * Receives notification that a group has started.
111: *
112: * @param event the event.
113: */
114: public void groupStarted(final ReportEvent event) {
115: if (FunctionUtilities.isDefinedGroup(getGroup(), event) == false) {
116: // wrong group ...
117: return;
118: }
119:
120: groupStateKey = event.getState().getProcessKey();
121: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event)) {
122: result = new BigDecimal(0);
123: results.put(globalStateKey, result);
124: results.put(groupStateKey, result);
125: } else {
126: // Activate the current group, which was filled in the prepare run.
127: result = (BigDecimal) results.get(groupStateKey);
128: }
129: }
130:
131: /**
132: * Receives notification that a row of data is being processed.
133: *
134: * @param event the event.
135: */
136: public void itemsAdvanced(final ReportEvent event) {
137: if (field == null) {
138: return;
139: }
140:
141: if (FunctionUtilities.isDefinedPrepareRunLevel(this , event) == false) {
142: return;
143: }
144:
145: final Object fieldValue = event.getDataRow().get(getField());
146: try {
147: final Number n = (Number) fieldValue;
148: if (n instanceof BigDecimal) {
149: final BigDecimal bd = (BigDecimal) n;
150: result = result.add(bd);
151: results.put(globalStateKey, result);
152: if (groupStateKey != null) {
153: results.put(groupStateKey, result);
154: }
155: } else if (n instanceof Number) {
156: result = result.add(new BigDecimal(String.valueOf(n)));
157: results.put(globalStateKey, result);
158: if (groupStateKey != null) {
159: results.put(groupStateKey, result);
160: }
161: }
162: } catch (Exception e) {
163: Log.error(
164: "TotalGroupSumFunction.itemsAdvanced(): problem adding number."
165: + fieldValue, e);
166: }
167: }
168:
169: /**
170: * Returns the name of the group to be totalled.
171: *
172: * @return the group name.
173: */
174: public String getGroup() {
175: return group;
176: }
177:
178: /**
179: * Defines the name of the group to be totalled. If the name is null, all groups are totalled.
180: *
181: * @param group the group name.
182: */
183: public void setGroup(final String group) {
184: this .group = group;
185: }
186:
187: /**
188: * Return the current function value. <P> The value depends (obviously) on the function implementation. For example,
189: * a page counting function will return the current page number.
190: *
191: * @return The value of the function.
192: */
193: public Object getValue() {
194: return result;
195: }
196:
197: /**
198: * Returns the field used by the function. The field name corresponds to a column name in the report's data-row.
199: *
200: * @return The field name.
201: */
202: public String getField() {
203: return field;
204: }
205:
206: /**
207: * Sets the field name for the function. The field name corresponds to a column name in the report's data-row.
208: *
209: * @param field the field name.
210: */
211: public void setField(final String field) {
212: this .field = field;
213: }
214:
215: /**
216: * Return a completly separated copy of this function. The copy does no longer share any changeable objects with the
217: * original function.
218: *
219: * @return a copy of this function.
220: */
221: public Expression getInstance() {
222: final TotalGroupSumFunction function = (TotalGroupSumFunction) super
223: .getInstance();
224: function.result = null;
225: function.results = new HashMap();
226: return function;
227: }
228:
229: /**
230: * Helper function for the serialization.
231: *
232: * @param in the input stream.
233: * @throws IOException if an IO error occured.
234: * @throws ClassNotFoundException if a required class could not be found.
235: */
236: private void readObject(final ObjectInputStream in)
237: throws IOException, ClassNotFoundException {
238: in.defaultReadObject();
239: this .results = new HashMap();
240: this.result = null;
241: }
242: }
|