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: /*
014: * Copyright 2006 Pentaho Corporation. All rights reserved.
015: * This software was developed by Pentaho Corporation and is provided under the terms
016: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
017: * this file except in compliance with the license. If you need a copy of the license,
018: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
019: * BI Platform. The Initial Developer is Pentaho Corporation.
020: *
021: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
022: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
023: * the license for the specific language governing your rights and limitations.
024: *
025: * Created Jun 26, 2006
026: * @author Ron Troyer
027: */
028:
029: package org.pentaho.ui.component.charting;
030:
031: import java.io.IOException;
032: import java.io.PrintWriter;
033: import java.io.StringWriter;
034: import java.io.UnsupportedEncodingException;
035: import java.net.URLEncoder;
036: import java.util.ArrayList;
037: import java.util.Iterator;
038: import java.util.List;
039:
040: import org.dom4j.Document;
041: import org.dom4j.DocumentHelper;
042: import org.dom4j.Element;
043: import org.dom4j.Node;
044: import org.jfree.chart.ChartRenderingInfo;
045: import org.jfree.chart.entity.ChartEntity;
046: import org.jfree.chart.entity.StandardEntityCollection;
047: import org.jfree.chart.entity.XYItemEntity;
048: import org.jfree.chart.imagemap.ImageMapUtilities;
049: import org.jfree.data.general.Dataset;
050: import org.jfree.data.time.RegularTimePeriod;
051: import org.jfree.data.time.TimeSeriesCollection;
052: import org.pentaho.commons.connection.IPentahoResultSet;
053: import org.pentaho.core.solution.ActionResource;
054: import org.pentaho.core.solution.IActionResource;
055: import org.pentaho.core.system.PentahoSystem;
056: import org.pentaho.core.ui.IPentahoUrlFactory;
057: import org.pentaho.core.util.TemplateUtil;
058: import org.pentaho.messages.Messages;
059: import org.pentaho.messages.util.LocaleHelper;
060: import org.pentaho.plugin.jfreechart.JFreeChartEngine;
061: import org.pentaho.plugin.jfreechart.TimeSeriesCollectionChartDefinition;
062:
063: public class TimeSeriesCollectionChartComponent extends
064: AbstractJFreeChartComponent {
065: private static final long serialVersionUID = -6268840271596447555L;
066:
067: protected String seriesName = null;
068:
069: public TimeSeriesCollectionChartComponent(int chartType,
070: String definitionPath, int width, int height,
071: IPentahoUrlFactory urlFactory, List messages) {
072: super (chartType, definitionPath, width, height, urlFactory,
073: messages);
074: }
075:
076: public TimeSeriesCollectionChartComponent(String definitionPath,
077: IPentahoUrlFactory urlFactory, ArrayList messages) {
078: super (definitionPath, urlFactory, messages);
079: }
080:
081: public TimeSeriesCollectionChartComponent(
082: IPentahoUrlFactory urlFactory, List messages) {
083: super (urlFactory, messages);
084: }
085:
086: public void setSeriesName(String seriesName) {
087: this .seriesName = seriesName;
088: }
089:
090: public Dataset createChart(Document doc) {
091: if (solution != null) { // if we have a solution then get the values
092: values = getActionData();
093: } else {
094: // TODO support other methods of getting data
095: }
096:
097: if (values == null) {
098: // we could not get any data
099: return null;
100: }
101: // get the chart node from the document
102: Node chartAttributes = doc
103: .selectSingleNode("//" + CHART_NODE_NAME); //$NON-NLS-1$
104: // create the definition
105: TimeSeriesCollectionChartDefinition chartDefinition = new TimeSeriesCollectionChartDefinition(
106: (IPentahoResultSet) values, byRow, chartAttributes,
107: getSession());
108:
109: // set the misc values from chartDefinition
110: setChartType(chartDefinition.getChartType());
111: setTitle(chartDefinition.getTitle());
112:
113: // get the URL template
114: Node urlTemplateNode = chartAttributes
115: .selectSingleNode(URLTEMPLE_NODE_NAME);
116: if (urlTemplateNode != null) {
117: setUrlTemplate(urlTemplateNode.getText());
118: }
119:
120: // get the additional parameter
121: Node paramName2Node = chartAttributes
122: .selectSingleNode(PARAM2_NODE_NAME);
123: if (paramName2Node != null) {
124: seriesName = paramName2Node.getText();
125: }
126:
127: if (chartDefinition.getWidth() != -1 && (width == -1)) {
128: setWidth(chartDefinition.getWidth());
129: }
130: if (chartDefinition.getHeight() != -1 && (height == -1)) {
131: setHeight(chartDefinition.getHeight());
132: }
133:
134: return chartDefinition;
135: }
136:
137: public Document getXmlContent() {
138:
139: // Create a document that describes the result
140: Document result = DocumentHelper.createDocument();
141: String baseUrl = PentahoSystem.getApplicationContext()
142: .getBaseUrl();
143: setXslProperty("baseUrl", baseUrl); //$NON-NLS-1$
144:
145: // load the XML document that defines the pie
146: ActionResource resource = new ActionResource(title,
147: IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$
148: definitionPath);
149: Document chartDefinition = null;
150: String mapName = "chart" + chartCount++; //$NON-NLS-1$
151: try {
152: chartDefinition = getResourceAsDocument(getSession(),
153: resource);
154: } catch (IOException e) {
155: }
156:
157: if (chartDefinition == null) {
158: Element errorElement = result.addElement("error"); //$NON-NLS-1$
159: errorElement
160: .addElement("title").setText(Messages.getString("ABSTRACTCHARTEXPRESSION.ERROR_0001_ERROR_GENERATING_CHART")); //$NON-NLS-1$ //$NON-NLS-2$
161: String message = Messages
162: .getString(
163: "CHARTS.ERROR_0001_CHART_DEFINIION_MISSING", definitionPath); //$NON-NLS-1$
164: errorElement.addElement("message").setText(message); //$NON-NLS-1$
165: error(message);
166: return result;
167: }
168: // create a pie definition from the XML definition
169: dataDefinition = createChart(chartDefinition);
170:
171: if (dataDefinition == null) {
172: Element errorElement = result.addElement("error"); //$NON-NLS-1$
173: errorElement
174: .addElement("title").setText(Messages.getString("ABSTRACTCHARTEXPRESSION.ERROR_0001_ERROR_GENERATING_CHART")); //$NON-NLS-1$ //$NON-NLS-2$
175: String message = Messages
176: .getString(
177: "CHARTS.ERROR_0002_CHART_DATA_MISSING", solution + "/" + actionPath + "/" + actionName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
178: errorElement.addElement("message").setText(message); //$NON-NLS-1$
179: // System .out.println( result.asXML() );
180: return result;
181: }
182:
183: // create an image for the dial using the JFreeChart engine
184: PrintWriter printWriter = new PrintWriter(new StringWriter());
185: // we'll dispay the title in HTML so that the dial image does not have
186: // to
187: // accommodate it
188: String chartTitle = ""; //$NON-NLS-1$
189: try {
190: if (width == -1) {
191: width = Integer.parseInt(chartDefinition
192: .selectSingleNode("/chart/width").getText()); //$NON-NLS-1$
193: }
194: if (height == -1) {
195: height = Integer.parseInt(chartDefinition
196: .selectSingleNode("/chart/height").getText()); //$NON-NLS-1$
197: }
198: } catch (Exception e) {
199: // go with the default
200: }
201: if (chartDefinition
202: .selectSingleNode("/chart/" + URLTEMPLE_NODE_NAME) != null) { //$NON-NLS-1$
203: urlTemplate = chartDefinition.selectSingleNode(
204: "/chart/" + URLTEMPLE_NODE_NAME).getText(); //$NON-NLS-1$
205: }
206:
207: if (chartDefinition.selectSingleNode("/chart/paramName") != null) { //$NON-NLS-1$
208: paramName = chartDefinition.selectSingleNode(
209: "/chart/paramName").getText(); //$NON-NLS-1$
210: }
211:
212: Element root = result.addElement("charts"); //$NON-NLS-1$
213: TimeSeriesCollection chartDataDefinition = (TimeSeriesCollection) dataDefinition;
214: if (chartDataDefinition.getSeriesCount() > 0) {
215: // create temporary file names
216: String[] tempFileInfo = createTempFile();
217: String fileName = tempFileInfo[AbstractChartComponent.FILENAME_INDEX];
218: String filePathWithoutExtension = tempFileInfo[AbstractChartComponent.FILENAME_WITHOUT_EXTENSION_INDEX];
219:
220: ChartRenderingInfo info = new ChartRenderingInfo(
221: new StandardEntityCollection());
222: JFreeChartEngine
223: .saveChart(
224: chartDataDefinition,
225: chartTitle,
226: "", filePathWithoutExtension, width, height, JFreeChartEngine.OUTPUT_PNG, printWriter, info, this ); //$NON-NLS-1$
227: applyOuterURLTemplateParam();
228: populateInfo(info);
229: Element chartElement = root.addElement("chart"); //$NON-NLS-1$
230: chartElement.addElement("mapName").setText(mapName); //$NON-NLS-1$
231: chartElement
232: .addElement("width").setText(Integer.toString(width)); //$NON-NLS-1$
233: chartElement
234: .addElement("height").setText(Integer.toString(height)); //$NON-NLS-1$
235: for (int row = 0; row < chartDataDefinition
236: .getSeriesCount(); row++) {
237: for (int column = 0; column < chartDataDefinition
238: .getItemCount(row); column++) {
239: Number value = chartDataDefinition
240: .getY(row, column);
241: Comparable rowKey = chartDataDefinition
242: .getSeriesKey(row);
243: RegularTimePeriod columnKey = chartDataDefinition
244: .getSeries(row).getTimePeriod(column);
245: Element valueElement = chartElement
246: .addElement("value2D"); //$NON-NLS-1$
247: valueElement
248: .addElement("value").setText(value.toString()); //$NON-NLS-1$
249: valueElement
250: .addElement("row-key").setText(rowKey.toString()); //$NON-NLS-1$
251: valueElement
252: .addElement("column-key").setText(columnKey.toString()); //$NON-NLS-1$
253: }
254: }
255: String mapString = ImageMapUtilities.getImageMap(mapName,
256: info);
257: chartElement.addElement("imageMap").setText(mapString); //$NON-NLS-1$
258: chartElement.addElement("image").setText(fileName); //$NON-NLS-1$
259: }
260: return result;
261: }
262:
263: private void populateInfo(ChartRenderingInfo info) {
264: if (urlTemplate == null) {
265: return;
266: }
267: Iterator iter = info.getEntityCollection().iterator();
268: while (iter.hasNext()) {
269: ChartEntity entity = (ChartEntity) iter.next();
270: if (entity instanceof XYItemEntity) {
271: if (urlTemplate != null) {
272: XYItemEntity xyItemEntity = (XYItemEntity) entity;
273: if (paramName == null) {
274: xyItemEntity.setURLText(urlTemplate);
275: } else {
276: try {
277: int seriesIndex = xyItemEntity
278: .getSeriesIndex();
279: int itemIndex = xyItemEntity.getItem();
280: String xySeriesKey = (String) ((TimeSeriesCollection) xyItemEntity
281: .getDataset())
282: .getSeriesKey(seriesIndex);
283: String encodedVal = URLEncoder.encode(
284: xySeriesKey, LocaleHelper
285: .getSystemEncoding());
286: String drillURL = TemplateUtil
287: .applyTemplate(urlTemplate,
288: paramName, encodedVal);
289: String itemValueStr = ((TimeSeriesCollection) xyItemEntity
290: .getDataset()).getX(seriesIndex,
291: itemIndex).toString();
292: encodedVal = URLEncoder.encode(
293: itemValueStr, LocaleHelper
294: .getSystemEncoding());
295: if (seriesName == null) {
296: drillURL = TemplateUtil.applyTemplate(
297: drillURL, "SERIES", encodedVal); //$NON-NLS-1$
298: } else {
299: drillURL = TemplateUtil.applyTemplate(
300: drillURL, seriesName,
301: encodedVal);
302: }
303: xyItemEntity.setURLText(drillURL);
304: } catch (UnsupportedEncodingException e) {
305: // TODO Auto-generated catch block
306: e.printStackTrace();
307: }
308: }
309: }
310: }
311: }
312: }
313:
314: public boolean validate() {
315: // TODO Auto-generated method stub
316: return true;
317: }
318:
319: }
|