001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * Created Oct 31, 2005
014: * @author mbatchel
015: */
016: package org.pentaho.plugin.jfreereport.reportcharts;
017:
018: import java.util.ArrayList;
019: import java.util.Arrays;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.jfree.data.general.AbstractDataset;
026: import org.jfree.data.xy.XYSeries;
027: import org.jfree.data.xy.XYSeriesCollection;
028: import org.jfree.report.event.ReportEvent;
029: import org.jfree.report.function.Expression;
030: import org.jfree.report.function.FunctionUtilities;
031: import org.jfree.util.ObjectUtilities;
032: import org.pentaho.messages.Messages;
033:
034: /**
035: * Creation-Date: 02.07.2007
036: *
037: * @author Gretchen Moran
038: */
039: public class XYSeriesCollectorFunction extends BaseCollectorFunction {
040: private static final long serialVersionUID = -8138304452870844825L;
041:
042: private ArrayList seriesNames;
043: private ArrayList xValueColumns;
044: private ArrayList yValueColumns;
045:
046: private static final Log myLogger = LogFactory
047: .getLog(XYSeriesCollectorFunction.class);
048:
049: public XYSeriesCollectorFunction() {
050: super ();
051: this .seriesNames = new ArrayList();
052: this .xValueColumns = new ArrayList();
053: this .yValueColumns = new ArrayList();
054: }
055:
056: /*
057: * ------- Standard accessors - we use indexed properties for the series config.
058: */
059:
060: public void setSeriesName(final int index, final String field) {
061: if (seriesNames.size() == index) {
062: seriesNames.add(field);
063: } else {
064: seriesNames.set(index, field);
065: }
066: }
067:
068: public String getSeriesName(final int index) {
069: return (String) seriesNames.get(index);
070: }
071:
072: public int getSeriesNameCount() {
073: return seriesNames.size();
074: }
075:
076: public String[] getSeriesName() {
077: return (String[]) seriesNames.toArray(new String[seriesNames
078: .size()]);
079: }
080:
081: public void setSeriesName(final String[] fields) {
082: this .seriesNames.clear();
083: this .seriesNames.addAll(Arrays.asList(fields));
084: }
085:
086: public void setxValueColumn(final int index, final String field) {
087: if (xValueColumns.size() == index) {
088: xValueColumns.add(field);
089: } else {
090: xValueColumns.set(index, field);
091: }
092: }
093:
094: public void setyValueColumn(final int index, final String field) {
095: if (yValueColumns.size() == index) {
096: yValueColumns.add(field);
097: } else {
098: yValueColumns.set(index, field);
099: }
100: }
101:
102: public String getxValueColumn(final int index) {
103: return (String) xValueColumns.get(index);
104: }
105:
106: public int getxValueColumnCount() {
107: return xValueColumns.size();
108: }
109:
110: public String[] getxValueColumn() {
111: return (String[]) xValueColumns
112: .toArray(new String[xValueColumns.size()]);
113: }
114:
115: public void setxValueColumn(final String[] fields) {
116: this .xValueColumns.clear();
117: this .xValueColumns.addAll(Arrays.asList(fields));
118: }
119:
120: public String getyValueColumn(final int index) {
121: return (String) yValueColumns.get(index);
122: }
123:
124: public int getyValueColumnCount() {
125: return yValueColumns.size();
126: }
127:
128: public String[] getyValueColumn() {
129: return (String[]) yValueColumns
130: .toArray(new String[yValueColumns.size()]);
131: }
132:
133: public void setyValueColumn(final String[] fields) {
134: this .yValueColumns.clear();
135: this .yValueColumns.addAll(Arrays.asList(fields));
136: }
137:
138: /* ---------------------------------------------------------------- Now the function implementation ...
139: */
140:
141: public void itemsAdvanced(ReportEvent reportEvent) {
142: logger
143: .debug(Messages
144: .getString("CATEGORYSETCOLL.USER_DEBUG_ITEMS_ADVANCED")); //$NON-NLS-1$
145: if (FunctionUtilities.isDefinedPrepareRunLevel(this ,
146: reportEvent) == false) {
147: // we do not modify the created dataset if this is not the function
148: // computation run. (FunctionLevel '0')
149: return;
150: }
151: if (!isSummaryOnly()) {
152: buildDataset();
153: }
154: }
155:
156: public void groupFinished(ReportEvent reportEvent) {
157: logger
158: .debug(Messages
159: .getString("CATEGORYSETCOLL.USER_DEBUG_GROUPS_FINISHED")); //$NON-NLS-1$
160: if (FunctionUtilities.isDefinedPrepareRunLevel(this ,
161: reportEvent) == false) {
162: // we do not modify the created dataset if this is not the function
163: // computation run. (FunctionLevel '0')
164: return;
165: }
166:
167: if (isSummaryOnly()) {
168: if (FunctionUtilities.isDefinedGroup(getGroup(),
169: reportEvent)) {
170: // we can be sure that everything has been computed here. So
171: // grab the values and add them to the dataset.
172: buildDataset();
173: }
174: }
175: }
176:
177: protected void buildDataset() {
178:
179: XYSeriesCollection xySeriesDataset = null;
180: if (getDatasourceValue() instanceof XYSeriesCollection) {
181: xySeriesDataset = (XYSeriesCollection) getDatasourceValue();
182: }
183:
184: final int maxIndex = Math.min(this .seriesNames.size(),
185: this .xValueColumns.size());
186: for (int i = 0; i < maxIndex; i++) {
187: String seriesName = (String) seriesNames.get(i);
188: final String xColumn = (String) xValueColumns.get(i);
189: final String yColumn = (String) yValueColumns.get(i);
190: final Object xValueObject = getDataRow().get(xColumn);
191: final Object yValueObject = getDataRow().get(yColumn);
192:
193: if (isSeriesColumn()) {
194: Object tmp = getDataRow().get(seriesName);
195: if (tmp != null) {
196: seriesName = tmp.toString();
197: }
198: }
199:
200: Number xValue = (xValueObject instanceof Number) ? (Number) xValueObject
201: : null;
202: Number yValue = (yValueObject instanceof Number) ? (Number) yValueObject
203: : null;
204:
205: // TODO We are not aggregating here as we do in the
206: // standard function; should we be aggregating?
207:
208: boolean isThere = false;
209: Object series = null;
210: try {
211: for (Iterator iter = xySeriesDataset.getSeries()
212: .iterator(); iter.hasNext();) {
213: XYSeries element = (XYSeries) iter.next();
214: isThere = element.getKey().equals(seriesName);
215: series = isThere ? element : null;
216: if (series != null)
217: break;
218: }
219: } catch (Exception ignored) {
220: }
221: if (!isThere) {
222: series = new XYSeries(seriesName);
223: xySeriesDataset.addSeries((XYSeries) series);
224: }
225: ((XYSeries) series).add(xValue, yValue);
226: }
227: }
228:
229: public AbstractDataset getNewDataset() {
230: return new XYSeriesCollection();
231: }
232:
233: /**
234: * Return a completly separated copy of this function. The copy no longer
235: * shares any changeable objects with the original function.
236: * Also from Thomas:
237: * Should retain data from the report definition, but clear calculated data.
238: *
239: * @return a copy of this function.
240: */
241: public Expression getInstance() {
242: final XYSeriesCollectorFunction fn = (XYSeriesCollectorFunction) super
243: .getInstance();
244: try {
245: fn.seriesNames = (ArrayList) seriesNames.clone();
246: fn.xValueColumns = (ArrayList) xValueColumns.clone();
247: fn.yValueColumns = (ArrayList) yValueColumns.clone();
248: } catch (Exception ex) {
249: myLogger.error(ex);
250: throw new IllegalStateException(ex);
251: }
252: return fn;
253: }
254: }
|