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: * @author Ingo Klose
014: *
015: */
016:
017: package org.pentaho.plugin.jfreereport.reportcharts;
018:
019: import org.jfree.util.*;
020: import org.jfree.chart.JFreeChart;
021: import org.jfree.chart.axis.AxisLocation;
022: import org.jfree.chart.axis.CategoryAxis;
023: import org.jfree.chart.axis.NumberAxis;
024: import org.jfree.chart.plot.CategoryPlot;
025: import org.jfree.chart.plot.DatasetRenderingOrder;
026: import org.jfree.chart.renderer.category.BarRenderer;
027: import org.jfree.chart.renderer.category.BarRenderer3D;
028: import org.jfree.chart.renderer.category.LineAndShapeRenderer;
029: import org.jfree.chart.renderer.category.LineRenderer3D;
030: import org.jfree.data.category.CategoryDataset;
031: import org.pentaho.messages.Messages;
032: import java.awt.*;
033: import java.text.DecimalFormat;
034: import java.util.ArrayList;
035: import java.util.Arrays;
036:
037: public class BarLineChartExpression extends BarChartExpression {
038:
039: private static final long serialVersionUID = 7082583397390897215L;
040:
041: // the dataSource (in AbstractChartExpression) represents the bar's datasource
042: private String linesDataSource;
043:
044: // valueAxisLabel (in CategoricalChartExpression) is the label for the bar chart value axis
045: private String secondValueAxisLabel = ""; //$NON-NLS-1$
046:
047: // seriesColor (in CategoricalChartExpression) represents the bars' series colors
048: private ArrayList lineSeriesColor = new ArrayList();
049:
050: private String categoryTickLabelFont = "SansSerif--8"; //$NON-NLS-1$
051:
052: private String barsLabelFont = "SansSerif--8"; //$NON-NLS-1$
053:
054: private String linesLabelFont = "SansSerif--8"; //$NON-NLS-1$
055:
056: private String barsTickLabelFont = "SansSerif--8"; //$NON-NLS-1$
057:
058: private String linesTickLabelFont = "SansSerif--8"; //$NON-NLS-1$
059:
060: private String lineTicksLabelFormat = ""; //$NON-NLS-1$
061:
062: private String barTicksLabelFormat = ""; //$NON-NLS-1$
063:
064: private String lineStyle = ""; //$NON-NLS-1$
065:
066: private float lineWidth = 1.0f;
067:
068: private boolean markersVisible = false;
069:
070: //constructor
071: public BarLineChartExpression() {
072: super ();
073: }
074:
075: public String getLinesDataSource() {
076: return linesDataSource;
077: }
078:
079: public void setLinesDataSource(String linesDataSource) {
080: this .linesDataSource = linesDataSource;
081: }
082:
083: public String getLinesLabelFont() {
084: return linesLabelFont;
085: }
086:
087: public void setLinesLabelFont(String linesLabelFont) {
088: this .linesLabelFont = linesLabelFont;
089: }
090:
091: public String getLinesTickLabelFont() {
092: return linesTickLabelFont;
093: }
094:
095: public void setLinesTickLabelFont(String linesTickLabelFont) {
096: this .linesTickLabelFont = linesTickLabelFont;
097: }
098:
099: public String getSecondValueAxisLabel() {
100: return secondValueAxisLabel;
101: }
102:
103: public void setSecondValueAxisLabel(String secondValueAxisLabel) {
104: this .secondValueAxisLabel = secondValueAxisLabel;
105: }
106:
107: public void setLineSeriesColor(final int index, final String field) {
108: if (lineSeriesColor.size() == index) {
109: lineSeriesColor.add(field);
110: } else {
111: lineSeriesColor.set(index, field);
112: }
113: }
114:
115: public String getLineSeriesColor(final int index) {
116: return (String) this .lineSeriesColor.get(index);
117: }
118:
119: public int getLineSeriesColorCount() {
120: return this .lineSeriesColor.size();
121: }
122:
123: public String[] getLineSeriesColor() {
124: Object[] toArray = this .lineSeriesColor
125: .toArray(new String[this .lineSeriesColor.size()]);
126: return (String[]) toArray;
127: }
128:
129: public void setLineSeriesColor(final String[] fields) {
130: this .lineSeriesColor.clear();
131: this .lineSeriesColor.addAll(Arrays.asList(fields));
132: }
133:
134: /**
135: *
136: * @return returns the style set for the lines
137: * @see LINE_STYLE_SOLID_STR
138: * @see LINE_STYLE_DASH_STR
139: * @see LINE_STYLE_DOT_STR
140: * @see LINE_STYLE_DASHDOT_STR
141: * @see LINE_STYLE_DASHDOTDOT_STR
142: */
143: public String getLineStyle() {
144: return lineStyle;
145: }
146:
147: /**
148: *
149: * @param value set the style for all line series
150: * @see LINE_STYLE_SOLID_STR
151: * @see LINE_STYLE_DASH_STR
152: * @see LINE_STYLE_DOT_STR
153: * @see LINE_STYLE_DASHDOT_STR
154: * @see LINE_STYLE_DASHDOTDOT_STR
155: */
156: public void setLineStyle(String value) {
157: lineStyle = value;
158: }
159:
160: /**
161: *
162: * @return the width of all line series
163: * Valid values are float numbers zero or greater
164: */
165: public float getLineWidth() {
166: return lineWidth;
167: }
168:
169: /**
170: *
171: * @param lineWidth set the width of all line series
172: * Valid values are float numbers zero or greater
173: */
174: public void setLineWidth(float value) {
175: lineWidth = value;
176: }
177:
178: /**
179: *
180: * @return boolean whether the markers (data points) for all series are displayed
181: */
182: public boolean isMarkersVisible() {
183: return markersVisible;
184: }
185:
186: /**
187: *
188: * @param markersVisible set whether the markers (data points) for all series should be displayed
189: */
190: public void setMarkersVisible(boolean markersVisible) {
191: this .markersVisible = markersVisible;
192: }
193:
194: public String getBarsTickLabelFont() {
195: return barsTickLabelFont;
196: }
197:
198: public void setBarsTickLabelFont(String barsTickLabelFont) {
199: this .barsTickLabelFont = barsTickLabelFont;
200: }
201:
202: public String getCategoryTickLabelFont() {
203: return categoryTickLabelFont;
204: }
205:
206: public void setCategoryTickLabelFont(String categoryTickLabelFont) {
207: this .categoryTickLabelFont = categoryTickLabelFont;
208: }
209:
210: public String getLineTicksLabelFormat() {
211: return lineTicksLabelFormat;
212: }
213:
214: public void setLineTicksLabelFormat(String lineTicksLabelFormat) {
215: this .lineTicksLabelFormat = lineTicksLabelFormat;
216: }
217:
218: public String getBarTicksLabelFormat() {
219: return barTicksLabelFormat;
220: }
221:
222: public void setBarTicksLabelFormat(String lineTicksLabelDateFormat) {
223: this .barTicksLabelFormat = lineTicksLabelDateFormat;
224: }
225:
226: /**
227: * getValue() is our opportunity to set up the chart with it's datasets, plot, axes, etc.
228: */
229: public Object getValue() {
230:
231: CategoryPlot plot;
232:
233: // Get the bars' data
234: final Object maybeCategorySetCollector = getDataRow().get(
235: getDataSource());
236: if (!(maybeCategorySetCollector instanceof CategorySetCollectorFunction)) {
237: Log
238: .debug(Messages
239: .getString("CATEGORICALCHARTEXPRESSION.USER_NOT_A_DATASET")); //$NON-NLS-1$
240: return null;
241: }
242:
243: final CategorySetCollectorFunction cscf = (CategorySetCollectorFunction) maybeCategorySetCollector;
244: CategoryDataset barsDataset = (CategoryDataset) cscf
245: .getDatasourceValue();
246:
247: // And get the lines' data
248: final Object maybeCategorySetCollector2 = getDataRow().get(
249: getLinesDataSource());
250: if (!(maybeCategorySetCollector2 instanceof CategorySetCollectorFunction)) {
251: Log
252: .debug(Messages
253: .getString("CATEGORICALCHARTEXPRESSION.USER_NOT_A_DATASET")); //$NON-NLS-1$
254: return null;
255: }
256:
257: final CategorySetCollectorFunction cscf2 = (CategorySetCollectorFunction) maybeCategorySetCollector2;
258: CategoryDataset linesDataset = (CategoryDataset) cscf2
259: .getDatasourceValue();
260:
261: //Create Axis Objects
262: CategoryAxis catAxis = new CategoryAxis(getCategoryAxisLabel());
263: NumberAxis barsAxis = new NumberAxis(getValueAxisLabel());
264: NumberAxis linesAxis = new NumberAxis(getSecondValueAxisLabel());
265:
266: // TODO: We should be intelligent enough here to render a bar chart
267: // if no series are lines, or a line chart if no series are bars, or return a reasonable
268: // message or exception telling the user WHY they didn't get a chart.
269:
270: if ((barsDataset == null || barsDataset.getRowCount() == 0)
271: && (linesDataset == null || linesDataset.getRowCount() == 0)) {
272: return null;
273: }
274:
275: //Create the renderer with the barchart, use a different bar renderer depending
276: //if 3D chart or not
277:
278: if (this .isThreeD()) {
279: plot = new CategoryPlot(barsDataset, catAxis, barsAxis,
280: new BarRenderer3D());
281: plot.setRenderer(1, new LineRenderer3D());
282:
283: } else {
284: plot = new CategoryPlot(barsDataset, catAxis, barsAxis,
285: new BarRenderer());
286: plot.setRenderer(1, new LineAndShapeRenderer());
287:
288: }
289:
290: //add lines dataset and axis to plot
291: plot.setDataset(1, linesDataset);
292: plot.setRangeAxis(1, linesAxis);
293:
294: //map lines to second axis
295: plot.mapDatasetToRangeAxis(1, 1);
296:
297: //set rendering order
298: plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
299:
300: //set location of second axis
301: plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT);
302:
303: Object key = cscf.getCacheKey() != null ? cscf.getCacheKey()
304: : getName();
305:
306: final Object o = getChartFromCache(key);
307: JFreeChart chart = null;
308: if (o != null) {
309: chart = (JFreeChart) o;
310: } else {
311: chart = new JFreeChart(plot);
312: putChartInCache(chart, key);
313: }
314: setChartProperties(chart);
315: return getValue(chart);
316: }
317:
318: /**
319: * Set the relevant properties on the chart; those properties that have
320: * getter/setter methods should be set here, or in a parent class.
321: */
322: protected void setChartProperties(JFreeChart chart) {
323: super .setChartProperties(chart);
324:
325: Font tFont;
326:
327: CategoryPlot plot = chart.getCategoryPlot();
328: CategoryAxis catAxis = plot.getDomainAxis();
329: NumberAxis barsAxis = (NumberAxis) plot.getRangeAxis();
330: NumberAxis linesAxis = (NumberAxis) plot.getRangeAxis(1);
331: LineAndShapeRenderer linesRenderer = (LineAndShapeRenderer) plot
332: .getRenderer(1);
333:
334: // This gets set in the factory call for chart creatrion in other
335: // chart expressions; we have to set it ourselves here, since there is
336: // no factory creator method suitable for us.
337: chart.setTitle(getTitle());
338: tFont = Font.decode(getTitleFont());
339: if (chart.getTitle() != null)
340: chart.getTitle().setFont(tFont);
341:
342: //format category axis tick labels
343: tFont = Font.decode(getCategoryTickLabelFont());
344: catAxis.setTickLabelFont(tFont);
345:
346: //setting fonts on the two Y-axis labels
347: tFont = Font.decode(barsLabelFont);
348: barsAxis.setLabelFont(tFont);
349:
350: tFont = Font.decode(linesLabelFont);
351: linesAxis.setLabelFont(tFont);
352:
353: tFont = Font.decode(barsTickLabelFont);
354: barsAxis.setTickLabelFont(tFont);
355:
356: tFont = Font.decode(linesTickLabelFont);
357: linesAxis.setTickLabelFont(tFont);
358:
359: //Setting fonts on the tick labels
360: if (lineTicksLabelFormat != null) {
361: linesAxis.setNumberFormatOverride(new DecimalFormat(
362: lineTicksLabelFormat));
363: }
364:
365: if (barTicksLabelFormat != null) {
366: barsAxis.setNumberFormatOverride(new DecimalFormat(
367: barTicksLabelFormat));
368: }
369:
370: //set stroke with line width
371: linesRenderer.setStroke(ChartConstants.translateLineStyle(
372: lineWidth, lineStyle));
373: //hide shapes on line
374: linesRenderer.setShapesVisible(isMarkersVisible());
375: linesRenderer.setBaseShapesFilled(isMarkersVisible());
376:
377: //set colors for each line
378: for (int i = 0; i < lineSeriesColor.size(); i++) {
379: linesRenderer
380: .setSeriesPaint(i,
381: getColorFromString((String) lineSeriesColor
382: .get(i)));
383: }
384: }
385:
386: /**
387: * This method is not useful for this particular subbclass, since we have multiple datasets...
388: */
389: public JFreeChart getChart(CategoryDataset categoryDataset) {
390: Log
391: .debug(Messages
392: .getString("BarLineChartExpression.DEBUG_FUNCTION_NOT_SUITABLE")); //$NON-NLS-1$
393: return null;
394: }
395:
396: public String getBarsLabelFont() {
397: return barsLabelFont;
398: }
399:
400: public void setBarsLabelFont(String barsLabelFont) {
401: this.barsLabelFont = barsLabelFont;
402: }
403:
404: }
|