/*******************************************************************************
* Copyright (c) 2006, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Qi Liang (IBM Corporation)
*
* Modified as explained in
* http://www.eclipse.org/forums/index.php/mv/msg/171310/557779/#msg_557779
*******************************************************************************/
package net.sf.eclipsefp.haskell.profiler.internal.editors;
import net.sf.eclipsefp.haskell.profiler.ProfilerPlugin;
import net.sf.eclipsefp.haskell.profiler.internal.util.UITexts;
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.core.runtime.IStatus;
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;
/**
* The canvas to show chart.
*
* @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(Composite parent, int style) {
super(parent, style);
// initialize the SWT rendering device
try {
PluginSettings ps = PluginSettings.instance();
render = ps.getDevice("dv.SWT");
if (render!=null){
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
Composite co = (Composite) e.getSource();
final Rectangle rect = co.getClientArea();
render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, e.gc);
if (cachedImage == null) {
buildChart();
drawToCachedImage(rect);
}
e.gc.drawImage(cachedImage,
0,
0,
cachedImage.getBounds().width,
cachedImage.getBounds().height,
0,
0,
rect.width,
rect.height);
}
});
addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, new GC(ChartCanvas.this));
buildChart();
cachedImage = null;
}
});
}
} catch (ChartException ex) {
//ex.printStackTrace();
ProfilerPlugin.log(IStatus.ERROR, ex.getLocalizedMessage(), ex);
}
}
public void rebuildChart() {
render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, new GC(ChartCanvas.this));
buildChart();
cachedImage = null;
}
/**
* Builds the chart state. This method should be call when data is changed.
*/
private void buildChart() {
state=null;
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();
state = gr.build(render.getDisplayServer(),
chart,
bo,
null,null);
} catch (ChartException ex) {
ProfilerPlugin.log(IStatus.ERROR, UITexts.graph_generate_error, ex);
}
}
/**
* 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();
if (state!=null){
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()
*/
@Override
public void dispose() {
if (cachedImage != null)
cachedImage.dispose();
super.dispose();
}
}