/******************************************************************************* * Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> * This file is part of Gluster Management Console. * * Gluster Management Console is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Gluster Management Console 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. *******************************************************************************/ package org.gluster.storage.management.console.utils; import java.util.Arrays; import java.util.Collections; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.birt.chart.api.ChartEngine; import org.eclipse.birt.chart.device.IDeviceRenderer; import org.eclipse.birt.chart.device.IUpdateNotifier; import org.eclipse.birt.chart.exception.ChartException; import org.eclipse.birt.chart.factory.GeneratedChartState; import org.eclipse.birt.chart.factory.Generator; import org.eclipse.birt.chart.model.Chart; import org.eclipse.birt.chart.model.ChartWithoutAxes; import org.eclipse.birt.chart.model.attribute.Anchor; import org.eclipse.birt.chart.model.attribute.AxisType; import org.eclipse.birt.chart.model.attribute.Bounds; import org.eclipse.birt.chart.model.attribute.ChartDimension; import org.eclipse.birt.chart.model.attribute.LineAttributes; import org.eclipse.birt.chart.model.attribute.LineStyle; import org.eclipse.birt.chart.model.attribute.Position; import org.eclipse.birt.chart.model.attribute.Text; import org.eclipse.birt.chart.model.attribute.TickStyle; import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl; import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl; import org.eclipse.birt.chart.model.attribute.impl.JavaDateFormatSpecifierImpl; import org.eclipse.birt.chart.model.attribute.impl.LineAttributesImpl; import org.eclipse.birt.chart.model.attribute.impl.NumberFormatSpecifierImpl; import org.eclipse.birt.chart.model.component.Axis; import org.eclipse.birt.chart.model.component.Series; import org.eclipse.birt.chart.model.component.impl.SeriesImpl; import org.eclipse.birt.chart.model.data.DateTimeDataElement; import org.eclipse.birt.chart.model.data.DateTimeDataSet; import org.eclipse.birt.chart.model.data.NumberDataSet; import org.eclipse.birt.chart.model.data.SeriesDefinition; import org.eclipse.birt.chart.model.data.TextDataSet; import org.eclipse.birt.chart.model.data.impl.DateTimeDataElementImpl; import org.eclipse.birt.chart.model.data.impl.DateTimeDataSetImpl; import org.eclipse.birt.chart.model.data.impl.NumberDataElementImpl; import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl; import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl; import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl; import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl; import org.eclipse.birt.chart.model.impl.ChartWithoutAxesImpl; import org.eclipse.birt.chart.model.layout.Legend; import org.eclipse.birt.chart.model.layout.Plot; import org.eclipse.birt.chart.model.type.AreaSeries; import org.eclipse.birt.chart.model.type.PieSeries; import org.eclipse.birt.chart.model.type.impl.AreaSeriesImpl; import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl; import org.eclipse.birt.core.framework.PlatformConfig; import org.eclipse.core.runtime.Platform; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import com.ibm.icu.util.Calendar; /** * */ public final class ChartViewerComposite extends Composite implements PaintListener, IUpdateNotifier { public enum CHART_TYPE { PIE, LINE }; private IDeviceRenderer deviceReader = null; private Chart chart = null; private GeneratedChartState generatedChartState = null; private boolean needsGeneration = true; private static Logger logger = Logger.getLogger(ChartViewerComposite.class.getName()); /** * @param parent * Parent composite of this pie chart viewer composite * @param style * SWT style to be used * @param categories * Categories of the pie chart * @param values * Values of each category in the pie chart Constructs a pie * chart viewer composite for given categories and values */ public ChartViewerComposite(Composite parent, int style, String[] categories, Double[] values) { super(parent, style); init(); chart = createPieChart(categories, values); addPaintListener(this); } /** * @param parent * Parent composite of this pie chart viewer composite * @param style * SWT style to be used * @param categories * Categories of the pie chart * @param values * Values of each category in the pie chart Constructs a pie * chart viewer composite for given categories and values * @param maxValue */ public ChartViewerComposite(Composite parent, int style, Calendar[] categories, Double[] values, String unit, String timestampFormat, double maxValue) { super(parent, style); init(); createSingleAreaChart(categories, values, unit, timestampFormat, maxValue); addPaintListener(this); } public void init() { try { PlatformConfig config = new PlatformConfig(); config.setBIRTHome(Platform.getInstallLocation().getURL().getPath()); // Get the connection with SWT device to render the graphics. deviceReader = ChartEngine.instance(config).getRenderer("dv.SWT");//$NON-NLS-1$ } catch (ChartException ex) { logger.log(Level.SEVERE, "Could not create Chart Renderer for SWT", ex); } addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { needsGeneration = true; } public void controlResized(ControlEvent e) { needsGeneration = true; } }); } private void createSingleAreaChart(Calendar[] timestamps, Double[] values, String unit, String timestampFormat, double maxValue) { createAreaChart(timestamps, new Double[][] {values}, unit, timestampFormat, maxValue); } /** * Creates a line chart model as a reference implementation * @param maxValue * * @return An instance of the simulated runtime chart model (containing * filled datasets) */ private final void createAreaChart(Calendar[] timestamps, Double[][] values, final String unit, final String timestampFormat, double maxValue) { chart = ChartWithAxesImpl.create(); // Plot chart.getBlock().setBackground(ColorDefinitionImpl.WHITE()); Plot p = chart.getPlot(); p.getClientArea().setBackground(ColorDefinitionImpl.WHITE()); p.setBackground(ColorDefinitionImpl.WHITE()); // Title chart.getTitle().getLabel().getCaption().setValue("Line Chart");//$NON-NLS-1$ chart.getTitle().setVisible(false); chart.getTitle().getLabel().setVisible(true); chart.getTitle().getInsets().set(0, 10, 0, 0); chart.getTitle().setAnchor(Anchor.SOUTH_LITERAL); // Legend Legend lg = chart.getLegend(); lg.setVisible(false); LineAttributes lia = lg.getOutline( ); lia.setStyle( LineStyle.SOLID_LITERAL ); lg.getText( ).getFont( ).setSize( 10 ); //lg.getInsets( ).set( 10, 5, 0, 0 ); lg.getInsets( ).set( 0, 0, 0, 0 ); lg.getOutline( ).setVisible( false ); lg.setAnchor( Anchor.NORTH_LITERAL ); updateDataSet(timestamps, values, unit, timestampFormat, maxValue); } private void updateDataSet(Calendar[] timestamps, Double[][] values, final String unit, final String timestampFormat, double maxValue) { Axis xAxisPrimary = setupXAxis(timestamps, timestampFormat); if(maxValue <= 0) { maxValue = getMaxValue(values); } Axis yAxisPrimary = setupYAxis(unit, xAxisPrimary, maxValue); configureXSeries(timestamps, xAxisPrimary); configureYSeries(values, yAxisPrimary); } private double getMaxValue(Double[][] values) { double maxValue = -1; for(Double[] seriesValues : values) { double seriesMaxVal = Collections.max(Arrays.asList(seriesValues)); if(seriesMaxVal > maxValue) { maxValue = Math.round(seriesMaxVal) + 5 - (Math.round(seriesMaxVal) % 5); } } return maxValue; } private void configureYSeries(Double[][] values, Axis yAxisPrimary) { SeriesDefinition sdY = SeriesDefinitionImpl.create(); sdY.getSeriesPalette().shift(-3); yAxisPrimary.getSeriesDefinitions().add(sdY); for (int i = 0; i < values.length; i++) { // Y-Sereis AreaSeries ls = (AreaSeries) AreaSeriesImpl.create(); // LineSeries ls = (LineSeries) LineSeriesImpl.create(); NumberDataSet orthoValues = NumberDataSetImpl.create(values[i]); ls.setDataSet(orthoValues); ls.getLineAttributes().setColor(ColorDefinitionImpl.create(50, 50, 255)); // for (int j = 0; j < ls.getMarkers().size(); j++) { // ( (Marker) ls.getMarkers( ).get( j ) ).setType( MarkerType.CIRCLE_LITERAL); // ((Marker) ls.getMarkers().get(j)).setVisible(true); // } ls.setTranslucent(true); // don't show values on each point on the line chart ls.getLabel().setVisible(false); sdY.getSeries().add(ls); } } private void configureXSeries(Calendar[] timestamps, Axis xAxisPrimary) { // Data Set DateTimeDataSet categoryValues = DateTimeDataSetImpl.create(timestamps); // X-Series Series seCategory = SeriesImpl.create(); seCategory.setDataSet(categoryValues); SeriesDefinition sdX = SeriesDefinitionImpl.create(); xAxisPrimary.getSeriesDefinitions().add(sdX); sdX.getSeries().add(seCategory); } private Axis setupYAxis(final String unit, Axis xAxisPrimary, double maxValue) { Axis yAxisPrimary = ((ChartWithAxesImpl)chart).getPrimaryOrthogonalAxis(xAxisPrimary); if(maxValue > 0) { yAxisPrimary.getScale().setMax(NumberDataElementImpl.create(maxValue)); yAxisPrimary.getScale().setStep(maxValue / 5); } yAxisPrimary.getScale().setMin(NumberDataElementImpl.create(0)); yAxisPrimary.setGapWidth(0); yAxisPrimary.getScale().setMajorGridsStepNumber(1); yAxisPrimary.getMajorGrid().setTickStyle(TickStyle.LEFT_LITERAL); yAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1)); yAxisPrimary.getLabel().setVisible(true); yAxisPrimary.getLabel().getCaption().getFont().setSize(8); yAxisPrimary.setFormatSpecifier(new NumberFormatSpecifierImpl() { @Override public String getSuffix() { return " " + unit; } }); return yAxisPrimary; } private Axis setupXAxis(Calendar[] timestamps, final String timestampFormat) { Axis xAxisPrimary = ((ChartWithAxesImpl)chart).getPrimaryBaseAxes()[0]; xAxisPrimary.setType(AxisType.TEXT_LITERAL); DateTimeDataElement dtde = DateTimeDataElementImpl.create(timestamps[timestamps.length-1]); DateTimeDataElement dtde1 = DateTimeDataElementImpl.create(timestamps[0]); xAxisPrimary.getScale().setMax(dtde); xAxisPrimary.getScale().setStep((dtde.getValue() - dtde1.getValue())/ 10); xAxisPrimary.getScale().setMajorGridsStepNumber(timestamps.length > 10 ? timestamps.length / 10 : 1); //xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.ABOVE_LITERAL); xAxisPrimary.getMajorGrid().getTickAttributes().setVisible(false); xAxisPrimary.getMajorGrid().setLineAttributes(LineAttributesImpl.create(ColorDefinitionImpl.GREY(), LineStyle.SOLID_LITERAL, 1)); xAxisPrimary.getTitle().setVisible(false); xAxisPrimary.getTitle().getInsets().set(1, 1, 1, 1); xAxisPrimary.getLabel().getInsets().set(1, 1, 1, 1); //xAxisPrimary.getLabel().getCaption().setFont(createChartFont()); xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setSize(8); //commenting to check whether this is causing the problem on windows //xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setRotation( 75 ); xAxisPrimary.setFormatSpecifier( JavaDateFormatSpecifierImpl.create( timestampFormat ) ); return xAxisPrimary; } /** * @param categories * Categories of the pie chart * @param values * Values of each category in the pie chart * @return The chart object created for given categories and values */ public static final Chart createPieChart(String[] categories, Double[] values) { ChartWithoutAxes pieChart = ChartWithoutAxesImpl.create(); // script hook to NOT show the label if value is zero pieChart.setScript("function beforeDrawDataPointLabel( dph, label, icsc ){ if (dph.getOrthogonalValue() == 0){ label.setVisible(false); } } "); // Plot pieChart.setSeriesThickness(10); pieChart.setDimension(ChartDimension.TWO_DIMENSIONAL_WITH_DEPTH_LITERAL); pieChart.getBlock().setBackground(ColorDefinitionImpl.WHITE()); Plot p = pieChart.getPlot(); p.getClientArea().setBackground(null); p.getClientArea().getOutline().setVisible(false); p.getOutline().setVisible(false); // Legend Legend lg = pieChart.getLegend(); lg.setMaxPercent(0.7); lg.getText().getFont().setSize(9); lg.setBackground(null); lg.getOutline().setVisible(false); lg.setVisible(true); // Title pieChart.getTitle().getLabel().getCaption().setValue("Pie Chart");//$NON-NLS-1$ pieChart.getTitle().getOutline().setVisible(false); pieChart.getTitle().setVisible(false); TextDataSet categoryValues = TextDataSetImpl.create(categories); NumberDataSet seriesOneValues = NumberDataSetImpl.create(values); // Base Series Series seCategory = SeriesImpl.create(); seCategory.setDataSet(categoryValues); SeriesDefinition sd = SeriesDefinitionImpl.create(); pieChart.getSeriesDefinitions().add(sd); sd.setSeriesPalette(new GlusterChartPalette()); sd.getSeriesPalette().shift(0); sd.getSeries().add(seCategory); // Orthogonal Series PieSeries sePie = (PieSeries) PieSeriesImpl.create(); sePie.setRatio(0.60); sePie.setDataSet(seriesOneValues); sePie.setSeriesIdentifier("Chart");//$NON-NLS-1$ sePie.getTitle().setVisible(false); // no title sePie.getLabel().setVisible(true); // show label (values) sePie.setExplosion(0); // no gap between the pie slices sePie.setLabelPosition(Position.INSIDE_LITERAL); Text labelCaption = sePie.getLabel().getCaption(); labelCaption.setColor(ColorDefinitionImpl.CYAN()); labelCaption.getFont().setSize(8); labelCaption.getFont().setBold(true); SeriesDefinition seriesDefinition = SeriesDefinitionImpl.create(); seriesDefinition.getQuery().setDefinition("query.definition");//$NON-NLS-1$ sd.getSeriesDefinitions().add(seriesDefinition); seriesDefinition.getSeries().add(sePie); return pieChart; } /* * (non-Javadoc) * * @see * org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events * .PaintEvent) */ public final void paintControl(PaintEvent e) { Rectangle d = ((Composite) e.getSource()).getBounds(); Image imgChart = new Image(this.getDisplay(), d); GC gcImage = new GC(imgChart); deviceReader.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gcImage); deviceReader.setProperty(IDeviceRenderer.UPDATE_NOTIFIER, this); Bounds bo = BoundsImpl.create(0, 0, d.width, d.height); bo.scale(71d / deviceReader.getDisplayServer().getDpiResolution()); Generator gr = Generator.instance(); if (needsGeneration) { needsGeneration = false; try { generatedChartState = gr.build(deviceReader.getDisplayServer(), chart, bo, null, null, null); } catch (ChartException ce) { ce.printStackTrace(); } } try { gr.render(deviceReader, generatedChartState); GC gc = e.gc; gc.drawImage(imgChart, d.x, d.y); } catch (ChartException gex) { logger.log(Level.SEVERE, "Exception while rendering pie chart [" + gex.getMessage() + "]", gex); } } // public void chartRefresh(Calendar[] timestamps, Double[][] values, String unit, String timestampFormat) // { // if ( !isDisposed( ) ) // { // final Generator gr = Generator.instance( ); // updateDataSet( timestamps, values, unit, timestampFormat); // // // Refresh // try // { // gr.refresh( generatedChartState ); // } // catch ( ChartException ex ) // { // // TODO: log the exception // ex.printStackTrace( ); // } // redraw( ); // } // } /* * (non-Javadoc) * * @see org.eclipse.birt.chart.device.IUpdateNotifier#getDesignTimeModel() */ public Chart getDesignTimeModel() { return chart; } /* * (non-Javadoc) * * @see org.eclipse.birt.chart.device.IUpdateNotifier#getRunTimeModel() */ public Chart getRunTimeModel() { return generatedChartState.getChartModel(); } /* * (non-Javadoc) * * @see org.eclipse.birt.chart.device.IUpdateNotifier#peerInstance() */ public Object peerInstance() { return this; } /* * (non-Javadoc) * * @see org.eclipse.birt.chart.device.IUpdateNotifier#regenerateChart() */ public void regenerateChart() { redraw(); } /* * (non-Javadoc) * * @see org.eclipse.birt.chart.device.IUpdateNotifier#repaintChart() */ public void repaintChart() { redraw(); } }