001: /*
002: * Copyright 2005 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 May 1, 2006
014: * @author James Dixon
015: */
016:
017: package org.pentaho.ui.component.charting;
018:
019: import java.io.File;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.io.Writer;
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.dom4j.Document;
029: import org.dom4j.Node;
030: import org.pentaho.commons.connection.IPentahoMetaData;
031: import org.pentaho.commons.connection.IPentahoResultSet;
032: import org.pentaho.core.solution.ActionResource;
033: import org.pentaho.core.solution.IActionResource;
034: import org.pentaho.core.system.PentahoSystem;
035: import org.pentaho.core.ui.IPentahoUrlFactory;
036: import org.pentaho.core.util.XmlHelper;
037: import org.pentaho.messages.Messages;
038:
039: public class FlashChartComponent extends AbstractChartComponent {
040:
041: private static final long serialVersionUID = 925147871232129020L;
042:
043: protected Node chartNode;
044:
045: protected Node chartTemplate;
046:
047: protected String backgroundColor;
048:
049: protected String chartType = "bar"; //$NON-NLS-1$
050:
051: private String valueItem = null;
052:
053: private String nameItem = null;
054:
055: private int topX = -1;
056:
057: public FlashChartComponent(String definitionPath, int width,
058: int height, IPentahoUrlFactory urlFactory, List messages) {
059: super (urlFactory, messages);
060: this .definitionPath = definitionPath;
061: this .width = width;
062: this .height = height;
063: PentahoSystem.ActionInfo info = PentahoSystem
064: .parseActionString(definitionPath);
065: if (info != null) {
066: setSourcePath(info.getSolutionName() + File.separator
067: + info.getPath());
068: }
069: logger = LogFactory.getLog(this .getClass());
070: }
071:
072: public Log getLogger() {
073: return logger;
074: }
075:
076: public boolean validate() {
077: return true;
078: }
079:
080: public Document getXmlContent() {
081:
082: return null;
083:
084: }
085:
086: public void setTopX(int topX) {
087: this .topX = topX;
088: }
089:
090: public boolean setDataAction(String chartDefinition) {
091: ActionResource resource = new ActionResource(
092: "", IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$ //$NON-NLS-2$
093: chartDefinition);
094: try {
095: Document dataActionDocument = PentahoSystem
096: .getSolutionRepository(getSession())
097: .getResourceAsDocument(resource);
098: if (dataActionDocument == null) {
099: return false;
100: }
101: Node dataNode = dataActionDocument
102: .selectSingleNode("chart/data"); //$NON-NLS-1$
103: chartNode = dataActionDocument.selectSingleNode("chart"); //$NON-NLS-1$
104: title = XmlHelper.getNodeText("title", chartNode); //$NON-NLS-1$
105: chartType = XmlHelper.getNodeText(
106: "chart_type", chartNode, "bar"); //$NON-NLS-1$ //$NON-NLS-2$
107: boolean isGauge = chartType.toLowerCase()
108: .startsWith("dial"); //$NON-NLS-1$
109: chartTemplate = chartNode
110: .selectSingleNode(isGauge ? "template/gauge" : "template/chart"); //$NON-NLS-1$ //$NON-NLS-2$
111: if (chartTemplate == null) {
112: String templatePath = XmlHelper.getNodeText(
113: "template-file", chartNode); //$NON-NLS-1$
114: if (templatePath != null) {
115: // we have a reference to a document to look up
116: ActionResource templateResource = new ActionResource(
117: "", IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$ //$NON-NLS-2$
118: templatePath);
119: try {
120: Document templateDocument = PentahoSystem
121: .getSolutionRepository(getSession())
122: .getResourceAsDocument(templateResource);
123: chartTemplate = templateDocument
124: .getRootElement();
125: } catch (Exception e) {
126: // the chart template document is not valid
127: error(
128: Messages
129: .getErrorString("FlashChartComponent.ERROR_0001_CHART_TEMPLATE_INVALID"), e); //$NON-NLS-1$
130: }
131: }
132: }
133: solution = XmlHelper.getNodeText("data-solution", dataNode); //$NON-NLS-1$
134: actionPath = XmlHelper.getNodeText("data-path", dataNode); //$NON-NLS-1$
135: actionName = XmlHelper.getNodeText("data-action", dataNode); //$NON-NLS-1$
136: actionOutput = XmlHelper.getNodeText(
137: "data-output", dataNode); //$NON-NLS-1$
138: valueItem = XmlHelper.getNodeText("data-value", dataNode); //$NON-NLS-1$
139: nameItem = XmlHelper.getNodeText("data-name", dataNode); //$NON-NLS-1$
140: backgroundColor = XmlHelper
141: .getNodeText(
142: "chart/background-color", dataActionDocument, "#ffffff"); //$NON-NLS-1$ //$NON-NLS-2$
143: byRow = XmlHelper
144: .getNodeText("data-orientation", dataNode, "rows").equals("rows"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
145: if (width == -1) {
146: width = (int) XmlHelper.getNodeText(
147: "chart/width", dataActionDocument, 400); //$NON-NLS-1$
148: }
149: if (height == -1) {
150: height = (int) XmlHelper.getNodeText(
151: "chart/height", dataActionDocument, 300); //$NON-NLS-1$
152: }
153: } catch (Exception e) {
154: error(
155: Messages
156: .getErrorString(
157: "CategoryDatasetChartComponent.ERROR_0001_INVALID_CHART_DEFINITION", chartDefinition), e); //$NON-NLS-1$
158: return false;
159: }
160: return true;
161: }
162:
163: public String getContent(String mimeType) {
164: if (chartType.toLowerCase().startsWith("dial")) { //$NON-NLS-1$
165: return getDialContent(mimeType);
166: } else {
167: return getChartContent(mimeType);
168: }
169:
170: }
171:
172: protected Object[] getValue() {
173: Object result[] = new Object[2];
174:
175: IPentahoResultSet resultSet = null;
176: try {
177: resultSet = getActionData();
178: if (resultSet == null) {
179: return null;
180: }
181: IPentahoMetaData metaData = resultSet.getMetaData();
182: // TODO support multiple column headers / row headers
183: // TODO support an iteration across columns for a given row
184:
185: // find the column that we have been told to you
186: Object columnHeaders[][] = metaData.getColumnHeaders();
187: int nameColumnNo = -1;
188: int valueColumnNo = -1;
189: for (int idx = 0; idx < columnHeaders[0].length; idx++) {
190: if (columnHeaders[0][idx].toString().equalsIgnoreCase(
191: nameItem)) {
192: nameColumnNo = idx;
193: }
194: if (columnHeaders[0][idx].toString().equalsIgnoreCase(
195: valueItem)) {
196: valueColumnNo = idx;
197: }
198: }
199: if (nameColumnNo == -1) {
200: // we did not find the specified name column
201: error(Messages
202: .getErrorString(
203: "FlashDial.ERROR_0001_NAME_COLUMN_MISSING", nameItem)); //$NON-NLS-1$
204: return null;
205: }
206:
207: if (valueColumnNo == -1) {
208: // we did not find the specified name column
209: error(Messages
210: .getErrorString(
211: "FlashDial.ERROR_0002_VALUE_COLUMN_MISSING", valueItem)); //$NON-NLS-1$
212: return null;
213: }
214:
215: Object row[] = resultSet.next();
216: while (row != null) {
217: result[0] = row[nameColumnNo].toString();
218: try {
219: result[1] = new Double(row[valueColumnNo]
220: .toString());
221: } catch (Exception e) {
222: }
223: row = resultSet.next();
224: }
225: } finally {
226: if (resultSet != null) {
227: resultSet.dispose();
228: }
229: }
230: return result;
231: }
232:
233: public String getDialContent(String mimeType) {
234: return getDialContent(mimeType, true);
235: }
236:
237: public String getDialContent(String mimeType, boolean objectWrapper) {
238: Object data[] = null;
239:
240: Object tmpVal = getParameter("value", null); //$NON-NLS-1$
241: if (tmpVal != null) {
242: data = fixupDialData(getParameter("title", title), tmpVal); //$NON-NLS-1$
243: } else {
244: data = getValue();
245: if ((data != null) && (data.length > 0)) {
246: if (data.length == 1) {
247: tmpVal = data[0];
248: data = fixupDialData(
249: getParameter("title", title), data[0]); //$NON-NLS-1$
250: } else {
251: tmpVal = data[1];
252: data = fixupDialData(data[0], data[1]);
253: }
254: }
255:
256: if (data == null) {
257: return Messages
258: .getErrorString(
259: "FlashChartComponent.ERROR_0002_DIAL_DATA_INVALID", String.valueOf(tmpVal)); //$NON-NLS-1$
260: }
261: }
262:
263: title = (String) data[0];
264: double value = ((Double) data[1]).doubleValue();
265: double span = 0;
266: if (chartType.equalsIgnoreCase("DialPct")) { //$NON-NLS-1$
267: double fullSpan = XmlHelper.getNodeText(
268: "dial_limits/@full-span", chartNode, 360.0); //$NON-NLS-1$
269: double minClamp = XmlHelper.getNodeText(
270: "dial_limits/@min-clamp", chartNode, 0); //$NON-NLS-1$
271: double maxClamp = XmlHelper.getNodeText(
272: "dial_limits/@max-clamp", chartNode, 360.0); //$NON-NLS-1$
273:
274: span = value / 100.0 * fullSpan;
275: span = Math.max(minClamp, Math.min(maxClamp, span));
276: } else {
277: span = value;
278: }
279:
280: String solutionDir = "system/tmp/"; //$NON-NLS-1$
281: String fileNamePrefix = "tmp_flash_"; //$NON-NLS-1$
282: String extension = ".xml"; //$NON-NLS-1$
283: String fileName = null;
284: String template = ""; //$NON-NLS-1$
285: String gaugeLicense = PentahoSystem.getSystemSetting(
286: "FlashChart/GaugeLicense", ""); //$NON-NLS-1$ //$NON-NLS-2$
287: if (gaugeLicense.length() > 0) {
288: gaugeLicense = "license=" + gaugeLicense + "&"; //$NON-NLS-1$ //$NON-NLS-2$
289: }
290: if (chartTemplate != null) {
291: template = chartTemplate.asXML().replace('"', '\'');
292: template = template.replaceFirst("\\{title\\}", title); //$NON-NLS-1$
293: template = template
294: .replaceFirst(
295: "\\{span\\}", String.valueOf(span).replace('"', '\'')); //$NON-NLS-1$
296: template = template
297: .replaceFirst(
298: "\\{data\\}", String.valueOf(value).replace('"', '\'')); //$NON-NLS-1$
299:
300: if (urlTemplate != null) {
301: template = template.replaceFirst(
302: "\\{drill-url\\}", urlTemplate); //$NON-NLS-1$
303: }
304:
305: // Do tick marks
306: List nodeList = chartNode.selectNodes("radial_ticks"); //$NON-NLS-1$
307: for (int i = 0; i < nodeList.size(); ++i) {
308: template = setRadialTicks((Node) nodeList.get(i),
309: template);
310: }
311:
312: nodeList = chartNode.selectNodes("radial_numbers"); //$NON-NLS-1$
313: for (int i = 0; i < nodeList.size(); ++i) {
314: template = setRadialNumbers((Node) nodeList.get(i),
315: template);
316: }
317:
318: } else {
319: StringBuffer sb = new StringBuffer();
320: sb.append("<gauge>"); //$NON-NLS-1$
321: sb
322: .append(" <rotate x='").append(width / 2).append("' y='").append(height / 2).append("' span='").append(String.valueOf(span)).append("'>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
323: sb
324: .append(" <line x1='").append(width / 2).append("' y1='0' x2='").append(width / 2).append("' y2='").append(height / 2).append("' />\n"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
325: sb.append(" </rotate>\n"); //$NON-NLS-1$
326: sb.append("</gauge>"); //$NON-NLS-1$
327: template = sb.toString();
328: }
329:
330: if (!objectWrapper) {
331: return template;
332: }
333:
334: // create a temporary file
335: try {
336: File file = File.createTempFile(fileNamePrefix, extension,
337: new File(PentahoSystem.getApplicationContext()
338: .getFileOutputPath(solutionDir)));
339: // file.deleteOnExit();
340: fileName = file.getName();
341: if (file.canWrite()) {
342: Writer out = new FileWriter(file);
343: out.write(template);
344: out.close();
345: }
346: } catch (IOException e) {
347: // TODO Auto-generated catch block
348: e.printStackTrace();
349: }
350:
351: String baseUrl = PentahoSystem.getApplicationContext()
352: .getBaseUrl();
353:
354: StringBuffer sb = new StringBuffer();
355: sb
356: .append(
357: "<OBJECT classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n") //$NON-NLS-1$
358: .append(
359: "codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" ") //$NON-NLS-1$
360: .append("WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" id=\"charts\" ALIGN=\"\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
361: .append("<PARAM NAME=\"movie\" VALUE=\"").append(baseUrl).append("chart/gauge.swf?").append(gaugeLicense).append("xml_source=").append(baseUrl).append("getImage?image=").append(fileName).append("\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
362: .append("<PARAM NAME=\"quality\" VALUE=\"high\"> ") //$NON-NLS-1$
363: .append("<PARAM NAME=\"bgcolor\" VALUE=\"").append(backgroundColor).append("\"> ") //$NON-NLS-1$ //$NON-NLS-2$
364:
365: .append("<EMBED src=\"").append(baseUrl).append("chart/gauge.swf?").append(gaugeLicense).append("xml_source=").append(baseUrl).append("getImage?image=").append(fileName).append("\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
366: .append("quality=\"high\" bgcolor=\"").append(backgroundColor).append("\" WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" NAME=\"charts\" ALIGN=\"\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
367: .append(
368: "TYPE=\"application/x-shockwave-flash\" PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\"></EMBED>") //$NON-NLS-1$
369: .append(" </OBJECT>"); //$NON-NLS-1$
370:
371: return sb.toString();
372: }
373:
374: private Object[] fixupDialData(Object inTitle, Object value) {
375: Object[] data = null;
376: if (value == null) {
377: return data;
378: }
379:
380: if (inTitle == null) {
381: inTitle = ""; //$NON-NLS-1$
382: }
383: inTitle = inTitle.toString();
384:
385: try {
386: if (value instanceof Double) {
387: data = new Object[] { inTitle, value };
388: } else {
389: data = new Object[] { inTitle,
390: new Double(value.toString()) };
391: }
392: } catch (Throwable t) {
393: error(Messages
394: .getErrorString(
395: "FlashChartComponent.ERROR_0002_DIAL_DATA_INVALID", value.toString())); //$NON-NLS-1$
396: }
397: return (data);
398: }
399:
400: //function that generates the XML code to draw radial ticks
401: private String setRadialTicks(Node node, String template) {
402: try {
403: String xml = setRadialTicks(XmlHelper.getNodeText(
404: "@x", node, (width / 2.0)), //$NON-NLS-1$
405: XmlHelper.getNodeText("@y", node, (height / 2.0)), //$NON-NLS-1$
406: XmlHelper.getNodeText(
407: "@radius", node, (height / 2.0)), //$NON-NLS-1$
408: XmlHelper.getNodeText("@length", node, 8.0), //$NON-NLS-1$
409: XmlHelper.getNodeText("@start_angle", node, 0.0), //$NON-NLS-1$
410: XmlHelper.getNodeText("@end_angle", node, 350.0), //$NON-NLS-1$
411: XmlHelper.getNodeText("@tick_count", node, 36), //$NON-NLS-1$
412: XmlHelper.getNodeText("@thickness", node, 2), //$NON-NLS-1$
413: XmlHelper.getNodeText("@color", node, "000000") //$NON-NLS-1$ //$NON-NLS-2$
414: );
415: String param_name = XmlHelper.getNodeText(
416: "@param_name", node, null); //$NON-NLS-1$
417: return (template
418: .replaceAll("\\{" + param_name + "\\}", xml)); //$NON-NLS-1$ //$NON-NLS-2$
419: } catch (Throwable t) {
420: error(Messages
421: .getString(
422: "FlashChartComponent.ERROR_0003_INVALID_XML_ATTRIBUTES_FOR_DIAL", "radial_ticks", node.asXML())); //$NON-NLS-1$ //$NON-NLS-2$
423: }
424: return (template);
425: }
426:
427: private String setRadialTicks(double x_center, double y_center,
428: double radius, double length, double start_angle,
429: double end_angle, long ticks_count, long thickness,
430: String color) {
431: StringBuffer sb = new StringBuffer();
432: for (double i = start_angle; i <= end_angle; i += (end_angle - start_angle)
433: / (ticks_count - 1)) {
434: sb
435: .append("<line x1='").append(x_center + Math.sin(Math.toRadians(i)) * radius).append("' y1='").append(y_center - Math.cos(Math.toRadians(i)) * radius).append("'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
436: sb
437: .append(" x2='").append(x_center + Math.sin(Math.toRadians(i)) * (radius + length)).append("' y2='").append(y_center - Math.cos(Math.toRadians(i)) * (radius + length)).append("'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
438: sb
439: .append(" thickness='").append(thickness).append("' color='").append(color).append("' />\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
440: }
441: return (sb.toString());
442: }
443:
444: //function that generates the XML code to draw radial ticks
445: private String setRadialNumbers(Node node, String template) {
446: try {
447: String xml = setRadialNumbers(XmlHelper.getNodeText(
448: "@x", node, (width / 2.0)), //$NON-NLS-1$
449: XmlHelper.getNodeText("@y", node, (height / 2.0)), //$NON-NLS-1$
450: XmlHelper.getNodeText(
451: "@radius", node, (height / 2.0)), //$NON-NLS-1$
452: XmlHelper.getNodeText("@start_angle", node, 0.0), //$NON-NLS-1$
453: XmlHelper.getNodeText("@end_angle", node, 350.0), //$NON-NLS-1$
454: XmlHelper.getNodeText("@start_number", node, 0), //$NON-NLS-1$
455: XmlHelper.getNodeText("@end_number", node, 340), //$NON-NLS-1$
456: XmlHelper.getNodeText("@tick_count", node, 18), //$NON-NLS-1$
457: XmlHelper.getNodeText("@font_size", node, 12), //$NON-NLS-1$
458: XmlHelper.getNodeText("@color", node, "000000") //$NON-NLS-1$ //$NON-NLS-2$
459: );
460: String param_name = XmlHelper.getNodeText(
461: "@param_name", node, null); //$NON-NLS-1$
462: return (template
463: .replaceAll("\\{" + param_name + "\\}", xml)); //$NON-NLS-1$ //$NON-NLS-2$
464: } catch (Throwable t) {
465: error(Messages
466: .getString(
467: "FlashChartComponent.ERROR_0003_INVALID_XML_ATTRIBUTES_FOR_DIAL", "radial_numbers", node.asXML())); //$NON-NLS-1$ //$NON-NLS-2$
468: }
469: return (template);
470: }
471:
472: //function that generates the XML code to draw radial numbers
473: private String setRadialNumbers(double x_center, double y_center,
474: double radius, double start_angle, double end_angle,
475: long start_number, long end_number, long ticks_count,
476: long font_size, String color) {
477: StringBuffer sb = new StringBuffer();
478: long number = start_number;
479:
480: for (double i = start_angle; i <= end_angle; i += (end_angle - start_angle)
481: / (ticks_count - 1)) {
482: sb
483: .append("<text x='").append(x_center + Math.sin(Math.toRadians(i)) * radius).append("' y='").append(y_center - Math.cos(Math.toRadians(i)) * radius).append("'"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
484: sb
485: .append(" width='200' size='").append(font_size).append("' color='").append(color).append("' align='left' rotation='").append(i).append("'>"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
486: sb.append(number).append("</text>\n"); //$NON-NLS-1$
487: number += (end_number - start_number) / (ticks_count - 1);
488: }
489: return (sb.toString());
490: }
491:
492: public String getChartContent(String mimeType) {
493: return getChartContent(mimeType, true);
494: }
495:
496: public String getChartContent(String mimeType, boolean objectWrapper) {
497:
498: IPentahoResultSet data = getActionData();
499:
500: if (data == null || data.getRowCount() == 0) {
501: // there is no data to display, prevent the default chart from showing
502: // TODO surface any error to the UI
503: return Messages
504: .getString("FlashChartComponent.USER_NO_DATA"); //$NON-NLS-1$
505: }
506:
507: ArrayList nameList = new ArrayList();
508: ArrayList series1 = new ArrayList();
509: ArrayList series2 = new ArrayList();
510: ArrayList series3 = new ArrayList();
511: ArrayList series4 = new ArrayList();
512: StringBuffer dataXml = new StringBuffer();
513: Object row[];
514: if (data != null) {
515: row = data.next();
516: int n = 0;
517: while (row != null) {
518: if (row[0] == null) {
519: nameList.add("null"); //$NON-NLS-1$
520: } else {
521: nameList.add(row[0].toString());
522: }
523: if (row.length > 1) {
524: if (row[1] == null) {
525: series1.add("<null/>"); //$NON-NLS-1$
526: } else {
527: series1.add(row[1].toString());
528: }
529: }
530: if (row.length > 2) {
531: if (row[2] == null) {
532: series2.add("<null/>"); //$NON-NLS-1$
533: } else {
534: series2.add(row[2].toString());
535: }
536: }
537: if (row.length > 3) {
538: if (row[3] == null) {
539: series3.add("<null/>"); //$NON-NLS-1$
540: } else {
541: series3.add(row[3].toString());
542: }
543: }
544: if (row.length > 4) {
545: if (row[4] == null) {
546: series4.add("<null/>"); //$NON-NLS-1$
547: } else {
548: series4.add(row[4].toString());
549: }
550: }
551: row = data.next();
552: n++;
553: if (n == topX) {
554: row = null;
555: }
556: }
557: dataXml.append("<row>"); //$NON-NLS-1$
558: dataXml.append("<null/>"); //$NON-NLS-1$
559: int start = 0;
560: int end = nameList.size();
561: int step = 1;
562: if (topX != -1) {
563: start = end - 1;
564: end = -1;
565: step = -1;
566: }
567: if (data != null) {
568: for (int i = start; i != end; i += step) {
569: dataXml.append("<string>"); //$NON-NLS-1$
570: dataXml.append(XmlHelper.encode((String) nameList
571: .get(i)));
572: dataXml.append("</string>"); //$NON-NLS-1$
573: }
574: }
575: dataXml.append("</row>"); //$NON-NLS-1$
576: if (series1.size() > 0) {
577: dataXml.append("<row>"); //$NON-NLS-1$
578: dataXml.append("<string>"); //$NON-NLS-1$
579: dataXml.append(XmlHelper.encode((String) data
580: .getMetaData().getColumnHeaders()[0][1]));
581: dataXml.append("</string>"); //$NON-NLS-1$
582: for (int i = start; i != end; i += step) {
583: dataXml.append("<number>"); //$NON-NLS-1$
584: dataXml.append((String) series1.get(i));
585: dataXml.append("</number>"); //$NON-NLS-1$
586: }
587: dataXml.append("</row>"); //$NON-NLS-1$
588: }
589: if (series2.size() > 0) {
590: dataXml.append("<row>"); //$NON-NLS-1$
591: dataXml.append("<string>"); //$NON-NLS-1$
592: dataXml.append(XmlHelper.encode((String) data
593: .getMetaData().getColumnHeaders()[0][2]));
594: dataXml.append("</string>"); //$NON-NLS-1$
595: for (int i = start; i != end; i += step) {
596: dataXml.append("<number>"); //$NON-NLS-1$
597: dataXml.append((String) series2.get(i));
598: dataXml.append("</number>"); //$NON-NLS-1$
599: }
600: dataXml.append("</row>"); //$NON-NLS-1$
601: }
602: if (series3.size() > 0) {
603: dataXml.append("<row>"); //$NON-NLS-1$
604: dataXml.append("<string>"); //$NON-NLS-1$
605: dataXml.append(XmlHelper.encode((String) data
606: .getMetaData().getColumnHeaders()[0][3]));
607: dataXml.append("</string>"); //$NON-NLS-1$
608: for (int i = start; i != end; i += step) {
609: dataXml.append("<number>"); //$NON-NLS-1$
610: dataXml.append((String) series3.get(i));
611: dataXml.append("</number>"); //$NON-NLS-1$
612: }
613: dataXml.append("</row>"); //$NON-NLS-1$
614: }
615: if (series4.size() > 0) {
616: dataXml.append("<row>"); //$NON-NLS-1$
617: dataXml.append("<string>"); //$NON-NLS-1$
618: dataXml.append(XmlHelper.encode((String) data
619: .getMetaData().getColumnHeaders()[0][4]));
620: dataXml.append("</string>"); //$NON-NLS-1$
621: for (int i = start; i != end; i += step) {
622: dataXml.append("<number>"); //$NON-NLS-1$
623: dataXml.append((String) series4.get(i));
624: dataXml.append("</number>"); //$NON-NLS-1$
625: }
626: dataXml.append("</row>"); //$NON-NLS-1$
627: }
628: }
629: String baseUrl = PentahoSystem.getApplicationContext()
630: .getBaseUrl();
631:
632: String solutionDir = "system/tmp/"; //$NON-NLS-1$
633: String fileNamePrefix = "tmp_flash_"; //$NON-NLS-1$
634: String extension = ".xml"; //$NON-NLS-1$
635: String fileName = null;
636: String template = ""; //$NON-NLS-1$
637: String chartLicense = PentahoSystem.getSystemSetting(
638: "FlashChart/ChartLicense", ""); //$NON-NLS-1$ //$NON-NLS-2$
639: if (chartLicense.length() > 0) {
640: chartLicense = "license=" + chartLicense + "&"; //$NON-NLS-1$ //$NON-NLS-2$
641: }
642: if (chartTemplate != null) {
643: template = chartTemplate.asXML().replace('"', '\'');
644: if (title != null) {
645: template = template.replaceFirst("\\{title\\}", title); //$NON-NLS-1$
646: } else {
647: template = template.replaceFirst("\\{title\\}", ""); //$NON-NLS-1$ //$NON-NLS-2$
648: }
649: template = template
650: .replaceFirst(
651: "\\{data\\}", dataXml.toString().replace('"', '\'')); //$NON-NLS-1$
652: if (urlTemplate != null) {
653: template = template.replaceFirst(
654: "\\{drill-url\\}", urlTemplate); //$NON-NLS-1$
655: }
656: } else {
657: StringBuffer sb = new StringBuffer();
658: sb.append("<chart>"); //$NON-NLS-1$
659: sb.append("<chart_data>"); //$NON-NLS-1$
660: sb.append(dataXml.toString().replace('"', '\''));
661: sb.append("</chart_data>"); //$NON-NLS-1$
662: sb
663: .append("<chart_grid_h alpha='20' color='000000' thickness='1' type='solid' />"); //$NON-NLS-1$
664: sb
665: .append("<chart_rect positive_color='ffffff' positive_alpha='20' negative_color='ff0000' negative_alpha='10' />"); //$NON-NLS-1$
666: sb.append("<chart_type>"); //$NON-NLS-1$
667: sb.append(chartType);
668: sb.append("</chart_type>"); //$NON-NLS-1$
669: sb
670: .append("<chart_value color='ffffff' alpha='90' font='arial' bold='true' size='12' position='inside' prefix='' suffix='' decimals='0' separator='' as_percentage='true' />"); //$NON-NLS-1$
671:
672: sb
673: .append("<legend_label layout='horizontal' bullet='circle' font='arial' bold='true' size='13' color='ffffff' alpha='85' />"); //$NON-NLS-1$
674: sb
675: .append("<legend_rect fill_color='aaaaaa' fill_alpha='100' line_color='000000' line_alpha='0' line_thickness='0' />"); //$NON-NLS-1$
676:
677: sb.append("</chart>"); //$NON-NLS-1$
678: template = sb.toString();
679: }
680:
681: if (!objectWrapper) {
682: return template;
683: }
684:
685: /*
686: <OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
687: codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
688: WIDTH="400"
689: HEIGHT="250"
690: id="gauge"
691: ALIGN="">
692: <PARAM NAME=movie VALUE="gauge.swf?xml_source=sample.xml&license=XXXXXXXXXXXXXXXXXX.XXXXXXXXXXX">
693: <PARAM NAME=quality VALUE=high>
694: <PARAM NAME=bgcolor VALUE=#888888>
695:
696: <EMBED src="gauge.swf?xml_source=sample.xml&license=XXXXXXXXXXXXXXXXXX.XXXXXXXXXXX"
697: quality=high
698: bgcolor=#888888
699: WIDTH="400"
700: HEIGHT="250"
701: NAME="gauge"
702: ALIGN=""
703: TYPE="application/x-shockwave-flash"
704: PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer">
705: </EMBED>
706: </OBJECT>
707: */
708: if (template.length() < 0) {
709: // this is a small chart file, lets assume all the browsers are ok with this size
710: // TODO verify the maximum size of parameters for the major browsers
711: StringBuffer sb = new StringBuffer();
712: sb
713: .append(
714: "<OBJECT classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n") //$NON-NLS-1$
715: .append(
716: "codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" ") //$NON-NLS-1$
717: .append("WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" id=\"charts\" ALIGN=\"\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
718: .append("<PARAM NAME=\"movie\" VALUE=\"").append(baseUrl).append("chart/charts.swf?").append(chartLicense).append("library_path=").append(baseUrl).append("chart/charts_library\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
719: .append("<PARAM NAME=\"quality\" VALUE=\"high\"> ") //$NON-NLS-1$
720: .append("<PARAM NAME=\"bgcolor\" VALUE=\"").append(backgroundColor).append("\"> ") //$NON-NLS-1$ //$NON-NLS-2$
721: .append(
722: "<PARAM NAME=\"FlashVars\" VALUE=\"source_data=").append(template).append("\">") //$NON-NLS-1$ //$NON-NLS-2$
723: .append("<EMBED src=\"").append(baseUrl).append("chart/charts.swf?").append(chartLicense).append("library_path=").append(baseUrl).append("chart/charts_library\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
724: .append("FlashVars=\"source_data=").append(template).append("\" ") //$NON-NLS-1$ //$NON-NLS-2$
725: .append("quality=\"high\" bgcolor=\"").append(backgroundColor).append("\" WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" NAME=\"charts\" ALIGN=\"\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
726: .append(
727: "TYPE=\"application/x-shockwave-flash\" PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\"></EMBED>") //$NON-NLS-1$
728: .append(" </OBJECT>"); //$NON-NLS-1$
729: return sb.toString();
730: } else {
731: // create a temporary file
732: try {
733: File file = File.createTempFile(fileNamePrefix,
734: extension, new File(PentahoSystem
735: .getApplicationContext()
736: .getFileOutputPath(solutionDir)));
737: // file.deleteOnExit();
738: fileName = file.getName();
739: if (file.canWrite()) {
740: Writer out = new FileWriter(file);
741: out.write(template);
742: out.close();
743: }
744: } catch (IOException e) {
745: // TODO Auto-generated catch block
746: e.printStackTrace();
747: }
748: StringBuffer sb = new StringBuffer();
749: sb
750: .append(
751: "<OBJECT classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n") //$NON-NLS-1$
752: .append(
753: "codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" ") //$NON-NLS-1$
754: .append("WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" id=\"charts\" ALIGN=\"\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
755: .append("<PARAM NAME=\"movie\" VALUE=\"").append(baseUrl).append("chart/charts.swf?").append(chartLicense).append("library_path=").append(baseUrl).append("chart/charts_library&xml_source=").append(baseUrl).append("getImage?image=").append(fileName).append("\">") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
756: .append("<PARAM NAME=\"quality\" VALUE=\"high\"> ") //$NON-NLS-1$
757: .append("<PARAM NAME=\"bgcolor\" VALUE=\"").append(backgroundColor).append("\"> ") //$NON-NLS-1$ //$NON-NLS-2$
758: .append("<EMBED src=\"").append(baseUrl).append("chart/charts.swf?").append(chartLicense).append("library_path=").append(baseUrl).append("chart/charts_library&xml_source=").append(baseUrl).append("getImage?image=").append(fileName).append("\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
759: .append("quality=\"high\" bgcolor=\"").append(backgroundColor).append("\" WIDTH=\"").append(width).append("\" HEIGHT=\"").append(height).append("\" NAME=\"charts\" ALIGN=\"\" ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
760: .append(
761: "TYPE=\"application/x-shockwave-flash\" PLUGINSPAGE=\"http://www.macromedia.com/go/getflashplayer\"></EMBED>") //$NON-NLS-1$
762: .append(" </OBJECT>"); //$NON-NLS-1$
763: return sb.toString();
764: }
765:
766: }
767:
768: public void dispose() {
769:
770: }
771:
772: }
|