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