/**
SpagoBI - The Business Intelligence Free Platform
Copyright (C) 2005-2008 Engineering Ingegneria Informatica S.p.A.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
**/
package it.eng.spagobi.engines.chart.bo.charttypes.dialcharts;
import it.eng.spago.base.SourceBean;
import it.eng.spago.base.SourceBeanAttribute;
import it.eng.spagobi.engines.chart.bo.charttypes.utils.KpiInterval;
import it.eng.spagobi.engines.chart.bo.charttypes.utils.MyDialPlot;
import it.eng.spagobi.engines.chart.utils.DataSetAccessFunctions;
import it.eng.spagobi.engines.chart.utils.DatasetMap;
import java.awt.Color;
import java.awt.Font;
import java.awt.geom.Ellipse2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.plot.dial.DialBackground;
import org.jfree.chart.plot.dial.DialCap;
import org.jfree.chart.plot.dial.DialPointer;
import org.jfree.chart.plot.dial.DialTextAnnotation;
import org.jfree.chart.plot.dial.StandardDialFrame;
import org.jfree.chart.plot.dial.StandardDialRange;
import org.jfree.chart.plot.dial.StandardDialScale;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.data.general.ValueDataset;
/**
* A class to generate Speedometer charts with multi-needle
* @author Antonella Giachino
*
*/
public class SpeedometerMultiValue extends DialCharts{
private static transient Logger logger=Logger.getLogger(SpeedometerMultiValue.class);
double increment=0.0;
int minorTickCount=0;
boolean dialtextuse = false ;
String dialtext = "";
String serieLegend=null; // keeps the name of the last serie that views the legend (only the last serie!)
HashMap colorMap=null; // keeps user selected colors
Vector intervals;
Vector seriesNames=null; //list series names
Vector valuesNames = null; //list values names
LegendItemCollection legendItems = null;
/** Tag to color values*/
public static final String VALUES_COLORS = "VALUES_COLORS";
/** CONF PARAMETERS: */
public static final String MINOR_TICK = "minor_tick";
public static final String ORIENTATION = "orientation";
public static final String INCREMENT = "increment";
public static final String DIALTEXTUSE = "dialtextuse"; // true or false
public static final String DIALTEXT = "dialtext";
/**
* Instantiates a new sBI speedometer.
*/
public SpeedometerMultiValue() {
super();
intervals=new Vector();
}
/**
* set parameters for the creation of the chart getting them from template or from LOV.
*
* @param content the content of the template.
*
* @return A chart that displays a value as a dial.
*/
public void configureChart(SourceBean content) {
super.configureChart(content);
logger.debug("IN");
if(!isLovConfDefined){
logger.debug("Configuration set in template");
if(confParameters.get(INCREMENT)!=null){
String increment=(String)confParameters.get(INCREMENT);
setIncrement(Double.valueOf(increment).doubleValue());
}
else {
logger.error("increment not defined");
return;
}
if(confParameters.get(MINOR_TICK)!=null){
String minorTickCount=(String)confParameters.get(MINOR_TICK);
setMinorTickCount(Integer.valueOf(minorTickCount).intValue());
}
else {
setMinorTickCount(10);
}
if(confParameters.get(DIALTEXTUSE)!=null){
String dialtextusetemp=(String)confParameters.get(DIALTEXTUSE);
if(dialtextusetemp.equalsIgnoreCase("true")){
dialtextuse = true;
}
else dialtextuse = false;
}
if(dialtextuse && confParameters.get(DIALTEXT)!=null){
dialtext=(String)confParameters.get(DIALTEXT);
}
//reading intervals information
SourceBean intervalsSB = (SourceBean)content.getAttribute("INTERVALS");
List intervalsAttrsList=null;
if(intervalsSB!=null){
intervalsAttrsList = intervalsSB.getContainedSourceBeanAttributes();
}
if(intervalsAttrsList==null || intervalsAttrsList.isEmpty()){ // if intervals are not defined realize a single interval
logger.warn("intervals not defined; default settings");
KpiInterval interval=new KpiInterval();
interval.setMin(getLower());
interval.setMax(getUpper());
interval.setColor(Color.WHITE);
addInterval(interval);
}
else{
Iterator intervalsAttrsIter = intervalsAttrsList.iterator();
while(intervalsAttrsIter.hasNext()) {
SourceBeanAttribute paramSBA = (SourceBeanAttribute)intervalsAttrsIter.next();
SourceBean param = (SourceBean)paramSBA.getValue();
String min= (String)param.getAttribute(MIN_INTERVAL);
String max= (String)param.getAttribute(MAX_INTERVAL);
String col= (String)param.getAttribute(COLOR_INTERVAL);
KpiInterval interval=new KpiInterval();
interval.setMin(Double.valueOf(min).doubleValue());
interval.setMax(Double.valueOf(max).doubleValue());
Color color=new Color(Integer.decode(col).intValue());
if(color!=null){
interval.setColor(color);}
else{
// sets default color
interval.setColor(Color.WHITE);
}
addInterval(interval);
}
}
//reading values colors if present
SourceBean colors = (SourceBean)content.getAttribute(VALUES_COLORS);
if(colors!=null){
colorMap=new HashMap();
List atts=colors.getContainedAttributes();
String colorValue="";
for (Iterator iterator = atts.iterator(); iterator.hasNext();) {
SourceBeanAttribute object = (SourceBeanAttribute) iterator.next();
String valueName=new String(object.getKey());
colorValue=new String((String)object.getValue());
Color col=new Color(Integer.decode(colorValue).intValue());
if(col!=null){
colorMap.put(valueName,col);
}
}
}
}
else{
logger.debug("configuration defined in LOV "+confDataset);
String increment=(String)sbRow.getAttribute("increment");
String minorTickCount=(String)sbRow.getAttribute("minor_tick");
setIncrement(Double.valueOf(increment).doubleValue());
setMinorTickCount(Integer.valueOf(minorTickCount).intValue());
String intervalsNumber=(String)sbRow.getAttribute(INTERVALS_NUMBER);
if(intervalsNumber==null || intervalsNumber.equals("") || intervalsNumber.equals("0")){ // if intervals are not specified
KpiInterval interval=new KpiInterval();
interval.setMin(getLower());
interval.setMax(getUpper());
interval.setColor(Color.WHITE);
addInterval(interval);
}
else{
for(int i=1;i<=Integer.valueOf(intervalsNumber).intValue();i++){
KpiInterval interval=new KpiInterval();
String min=(String)sbRow.getAttribute("min"+(new Integer(i)).toString());
String max=(String)sbRow.getAttribute("max"+(new Integer(i)).toString());
String col=(String)sbRow.getAttribute("color"+(new Integer(i)).toString());
interval.setMin(Double.valueOf(min).doubleValue());
interval.setMax(Double.valueOf(max).doubleValue());
Color color=new Color(Integer.decode(col).intValue());
interval.setColor(color);
addInterval(interval);
}
}
//reading values colors if present
String valuesNumber=(String)sbRow.getAttribute("series_number");
colorMap=new HashMap();
if(valuesNumber!=null && !valuesNumber.equals("") && !valuesNumber.equals("0")){
for(int i=1;i<=Integer.valueOf(valuesNumber).intValue();i++){
String valueName=(String)sbRow.getAttribute("value_name"+(new Integer(i)).toString());
String colorValue=(String)sbRow.getAttribute("value_color"+(new Integer(i)).toString());
Color col=new Color(Integer.decode(colorValue).intValue());
if(col!=null){
colorMap.put(valueName,col);
}
}
}
}
logger.debug("out");
}
/**
* Inherited by IChart: calculates chart value.
*
* @return the dataset
*
* @throws Exception the exception
*/
public DatasetMap calculateValue() throws Exception {
logger.debug("IN");
String res=DataSetAccessFunctions.getDataSetResultFromId(profile, getData(),parametersObject);
DatasetMap datasets = new DatasetMap();
SourceBean sbRows=SourceBean.fromXMLString(res);
List listAtts=sbRows.getAttributeAsList("ROW");
seriesNames=new Vector();
valuesNames=new Vector();
boolean first=true;
// run all dataset rows
for (Iterator iterator = listAtts.iterator(); iterator.hasNext();) {
SourceBean sbSeries = (SourceBean) iterator.next();
List atts=sbSeries.getContainedAttributes();
HashMap series = new LinkedHashMap();
HashMap serValue = new LinkedHashMap();
String name="";
String value="";
int contSer = 0;
//run all the attributes in a row, to define series
for (Iterator iterator2 = atts.iterator(); iterator2.hasNext();) {
SourceBeanAttribute object = (SourceBeanAttribute) iterator2.next();
name=new String(object.getKey());
value=new String((String)object.getValue());
if (name.startsWith("serie")){
// map containing the series
series.put(name, value);
contSer++;
}
else {
serValue.put(name, value);
if(!valuesNames.contains(name))
valuesNames.add(name);
}
}
// add series to dataset
for (Iterator iterator3 = series.keySet().iterator(); iterator3.hasNext();) {
String nameS = (String) iterator3.next();
String valueS=(String)series.get(nameS);
if(valueS!=null && !valueS.equals("null") && !valueS.equals("")){
Object[] arSer = serValue.keySet().toArray();
for (int i=0; i<arSer.length;i++){
datasets.getDatasets().put(valueS + "__" + arSer[i],new DefaultValueDataset(Double.valueOf((String)serValue.get(arSer[i]))));
}
if(!seriesNames.contains(valueS)){
seriesNames.add(valueS);
}
}
}
}
serieLegend = (String)seriesNames.get(seriesNames.size()-1);
logger.debug("OUT");
return datasets;
}
/**
* Creates a chart of type speedometer.
*
* @param chartTitle the chart title.
* @param dataset the dataset.
*
* @return A chart speedometer.
*/
public JFreeChart createChart(DatasetMap datasets) {
logger.debug("IN");
JFreeChart chart = null;
try{
MyDialPlot plot = new MyDialPlot();
HashMap hmDataset = datasets.getDatasets();
Set keyDataset = hmDataset.keySet();
int i = 0;
Iterator itDataset = keyDataset.iterator();
while(itDataset.hasNext()) {
String key = (String) itDataset.next();
Dataset dataset = (Dataset)hmDataset.get(key);
plot.setDataset(i, (ValueDataset)dataset);
if (key.indexOf("__") > 0)
setName(key.substring(0, key.indexOf("__")));
else
setName(key);
i++;
}
plot.setDialFrame(new StandardDialFrame());
plot.setBackground(new DialBackground());
if(dialtextuse){
DialTextAnnotation annotation1 = new DialTextAnnotation(dialtext);
annotation1.setFont(styleTitle.getFont());
annotation1.setRadius(0.7);
plot.addLayer(annotation1);
}
StandardDialScale scale = new StandardDialScale(lower,
upper, -120, -300, 10.0, 4);
if(! ( increment > 0) ){
logger.warn("increment cannot be less than 0, put default to 0.1 ");
increment=0.1;
}
scale.setMajorTickIncrement(increment);
scale.setMinorTickCount(minorTickCount);
scale.setTickRadius(0.88);
scale.setTickLabelOffset(0.15);
//set tick label style
scale.setTickLabelsVisible(true);
Font tickLabelsFont = new Font(labelsTickStyle.getFontName(), Font.PLAIN, labelsTickStyle.getSize());
scale.setTickLabelFont(tickLabelsFont);
scale.setTickLabelPaint(labelsTickStyle.getColor());
plot.addScale(0, scale);
DialCap cap = new DialCap();
plot.setCap(cap);
// sets intervals
for (Iterator iterator = intervals.iterator(); iterator.hasNext();) {
KpiInterval interval = (KpiInterval) iterator.next();
StandardDialRange range = new StandardDialRange(interval.getMin(), interval.getMax(),
interval.getColor());
range.setInnerRadius(0.50);
range.setOuterRadius(0.85);
range.setPaint(interval.getColor());
plot.addLayer(range);
}
plot.setBackground(new DialBackground());
logger.debug("Set values color");
Vector arValuesName = getValuesNames();
legendItems = new LegendItemCollection();
for (int j = 0; j < arValuesName.size(); j++) {
DialPointer.Pin p = new DialPointer.Pin(j);
if(colorMap!=null){
String valueName=(String)arValuesName.get(j);
Color color=(Color)colorMap.get(valueName);
if(color!=null) p.setPaint(color);
if (serieLegend.equalsIgnoreCase(name)){
if (j < arValuesName.size()){
LegendItem item = new LegendItem(valueName, "", "", "", new Ellipse2D.Double(-3, -5, 8, 8),color );
if (item != null) {
legendItems.add(item);
}
}
if (legend)
super.height = super.height + (super.height*12/100);
}
}
plot.addLayer(p);
}
plot.setLegendItems(legendItems);
chart = new JFreeChart(name, JFreeChart.DEFAULT_TITLE_FONT,plot, false);
TextTitle title = setStyleTitle(name, styleTitle);
chart.setTitle(title);
if(subName!= null && !subName.equals("")){
TextTitle subTitle =setStyleTitle(subName, styleSubTitle);
chart.addSubtitle(subTitle);
}
chart.setBackgroundPaint(color);
if(legend==true) drawLegend(chart);
}catch (Exception ex){
logger.debug("Error while creating speedometer multivalue: " + ex);
}
logger.debug("OUT");
return chart;
}
/**
* @return the valuesNames
*/
public Vector getValuesNames() {
return valuesNames;
}
/**
* @param valuesNames the valuesNames to set
*/
public void setValuesNames(Vector valuesNames) {
this.valuesNames = valuesNames;
}
/**
* Gets the intervals.
*
* @return the intervals
*/
public Vector getIntervals() {
return intervals;
}
/**
* Adds the interval.
*
* @param interval the interval
*/
public void addInterval(KpiInterval interval) {
this.intervals.add(interval);
}
/**
* Gets the increment.
*
* @return the increment
*/
public double getIncrement() {
return increment;
}
/**
* Sets the increment.
*
* @param increment the new increment
*/
public void setIncrement(double increment) {
this.increment = increment;
}
/**
* Gets the minor tick count.
*
* @return the minor tick count
*/
public int getMinorTickCount() {
return minorTickCount;
}
/**
* Sets the minor tick count.
*
* @param minorTickCount the new minor tick count
*/
public void setMinorTickCount(int minorTickCount) {
this.minorTickCount = minorTickCount;
}
/**
* Defines the legend for multivalue Speedometer
* @return LegendItemCollection
*/
private LegendItemCollection createLegend(){
LegendItemCollection legendItems = new LegendItemCollection();
return legendItems;
}
}