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