/*******************************************************************************
* Copyright (c) 2006, 2009 University of Edinburgh.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the BSD Licence, which
* accompanies this feature and can be downloaded from
* http://groups.inf.ed.ac.uk/pepa/update/licence.txt
*******************************************************************************/
package uk.ac.ed.inf.common.ui.plotting.dialogs;
import org.eclipse.birt.chart.device.IDeviceRenderer;
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.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.util.PluginSettings;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
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.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import uk.ac.ed.inf.common.ui.plotting.IChart;
import uk.ac.ed.inf.common.ui.plotting.internal.CommonChart;
/**
* The canvas to show chart.
* In alternative, use
* package org.eclipse.birt.chart.examples.view.util.ChartExamples
* and ChartPreview.
*
* @author Qi Liang
*/
public class ChartCanvas extends Canvas {
/**
* The device render for rendering chart.
*/
protected IDeviceRenderer render = null;
/**
* The chart instantce.
*/
protected Chart chart = null;
/**
* The chart state.
*/
protected GeneratedChartState state = null;
/**
* The image which caches the chart image to improve drawing performance.
*/
private Image cachedImage = null;
/**
* Constructs one canvas containing chart.
*
* @param parent
* a composite control which will be the parent of the new
* instance (cannot be null)
* @param style
* the style of control to construct
*/
public ChartCanvas(IChart chart, Composite parent, int style) {
super(parent, style);
// initialize the SWT rendering device
try {
PluginSettings ps = PluginSettings.instance();
render = ps.getDevice("dv.SWT");
} catch (ChartException ex) {
ex.printStackTrace();
}
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
Composite co = (Composite) e.getSource();
final Rectangle rect = co.getClientArea();
if (cachedImage == null) {
buildChart(rect);
drawToCachedImage(rect);
}
e.gc.drawImage(cachedImage,
0,
0,
cachedImage.getBounds().width,
cachedImage.getBounds().height,
0,
0,
rect.width,
rect.height);
}
});
addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
Composite co = (Composite) e.getSource();
final Rectangle rect = co.getClientArea();
buildChart(rect);
cachedImage = null;
}
});
setChart(((CommonChart) chart).getBirtChart());
}
/**
* Builds the chart state. This method should be call when data is changed.
*/
private void buildChart(Rectangle rect) {
Point size = getSize();
Bounds bo = BoundsImpl.create(0, 0, size.x, size.y);
int resolution = render.getDisplayServer().getDpiResolution();
bo.scale(72d / resolution);
try {
Generator gr = Generator.instance();
if (cachedImage != null)
cachedImage.dispose();
cachedImage = new Image(Display.getCurrent(), rect.width,
rect.height);
GC gc = new GC(cachedImage);
render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gc);
state = gr.build(render.getDisplayServer(),
chart,
bo,
null,
null,
null);
} catch (ChartException ex) {
ex.printStackTrace();
}
}
/**
* Draws the chart onto the cached image in the area of the given
* <code>Rectangle</code>.
*
* @param size
* the area to draw
*/
public void drawToCachedImage(Rectangle size) {
GC gc = null;
try {
if (cachedImage != null)
cachedImage.dispose();
cachedImage = new Image(Display.getCurrent(), size.width,
size.height);
gc = new GC(cachedImage);
render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gc);
Generator gr = Generator.instance();
gr.render(render, state);
} catch (ChartException ex) {
ex.printStackTrace();
} finally {
if (gc != null)
gc.dispose();
}
}
/**
* Returns the chart which is contained in this canvas.
*
* @return the chart contained in this canvas.
*/
public Chart getChart() {
return chart;
}
/**
* Sets the chart into this canvas. Note: When the chart is set, the cached
* image will be dopped, but this method doesn't reset the flag
* <code>cachedImage</code>.
*
* @param chart
* the chart to set
*/
public void setChart(Chart chart) {
if (cachedImage != null)
cachedImage.dispose();
cachedImage = null;
this.chart = chart;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
public void dispose() {
if (cachedImage != null)
cachedImage.dispose();
super.dispose();
}
}