a628c912998fb5dbd48e55aa3911320a74def2f6
[public/netxms.git] / webui / webapp / Charts / src / org / netxms / ui / eclipse / charts / widgets / GenericBirtChart.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2010 Victor Kirhenshtein
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 package org.netxms.ui.eclipse.charts.widgets;
20
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.InputStream;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.Set;
27 import org.eclipse.birt.chart.api.ChartEngine;
28 import org.eclipse.birt.chart.device.IDeviceRenderer;
29 import org.eclipse.birt.chart.exception.ChartException;
30 import org.eclipse.birt.chart.factory.GeneratedChartState;
31 import org.eclipse.birt.chart.factory.IGenerator;
32 import org.eclipse.birt.chart.model.Chart;
33 import org.eclipse.birt.chart.model.attribute.Bounds;
34 import org.eclipse.birt.chart.model.attribute.ColorDefinition;
35 import org.eclipse.birt.chart.model.attribute.Palette;
36 import org.eclipse.birt.chart.model.attribute.Position;
37 import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
38 import org.eclipse.birt.chart.model.attribute.impl.ColorDefinitionImpl;
39 import org.eclipse.birt.chart.model.attribute.impl.PaletteImpl;
40 import org.eclipse.birt.core.framework.PlatformConfig;
41 import org.eclipse.jface.preference.PreferenceConverter;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.events.ControlEvent;
44 import org.eclipse.swt.events.ControlListener;
45 import org.eclipse.swt.events.PaintEvent;
46 import org.eclipse.swt.events.PaintListener;
47 import org.eclipse.swt.graphics.GC;
48 import org.eclipse.swt.graphics.Image;
49 import org.eclipse.swt.graphics.RGB;
50 import org.eclipse.swt.graphics.Rectangle;
51 import org.eclipse.swt.widgets.Composite;
52 import org.netxms.client.datacollection.GraphSettings;
53 import org.netxms.ui.eclipse.charts.Activator;
54 import org.netxms.ui.eclipse.charts.api.ChartColor;
55 import org.netxms.ui.eclipse.tools.ColorCache;
56
57 /**
58 * Abstract base class for all BIRT-based charts
59 *
60 */
61 public abstract class GenericBirtChart extends GenericChart implements PaintListener, ControlListener
62 {
63 private Chart chart = null;
64 private boolean fullRepaint = true;
65 private IDeviceRenderer deviceRenderer = null;
66 private GeneratedChartState generatedChartState = null;
67 private IGenerator generator = null;
68 private Image imgChart = null;
69 private ColorCache colors;
70 private Set<String> errors = new HashSet<String>(0);
71 private Image errorImage = null;
72 protected boolean autoscale = true;
73 protected int from;
74 protected int to;
75
76 /**
77 * Create chart widget
78 *
79 * @param parent parent widget
80 * @param style widget style
81 */
82 public GenericBirtChart(Composite parent, int style)
83 {
84 super(parent, style | SWT.NO_BACKGROUND);
85
86 colors = new ColorCache(this);
87
88 try
89 {
90 PlatformConfig config = new PlatformConfig();
91 config.setBIRTHome(""); //$NON-NLS-1$
92 final ChartEngine chartEngine = ChartEngine.instance(config);
93 deviceRenderer = chartEngine.getRenderer("dv.PNG");
94 generator = chartEngine.getGenerator();
95 }
96 catch(ChartException e)
97 {
98 /* TODO: implement logging or error reporting */
99 e.printStackTrace();
100 }
101
102 addPaintListener(this);
103 addControlListener(this);
104 }
105
106 /* (non-Javadoc)
107 * @see org.netxms.ui.eclipse.charts.api.DataChart#initializationComplete()
108 */
109 @Override
110 public void initializationComplete()
111 {
112 chart = createChart();
113 fullRepaint = true;
114 redraw();
115 }
116
117 /**
118 * Force chart recreation (for example, after chart type change).
119 */
120 protected void recreateChart()
121 {
122 chart = createChart();
123 fullRepaint = true;
124 redraw();
125 }
126
127 /**
128 * Create underlying chart object. Must be implemented by subclasses.
129 *
130 * @return BIRT chart object
131 */
132 protected abstract Chart createChart();
133
134 /**
135 * Get underlying BIRT chart object.
136 *
137 * @return underlying BIRT chart object
138 */
139 public Chart getChart()
140 {
141 return chart;
142 }
143
144 /* (non-Javadoc)
145 * @see org.eclipse.swt.events.ControlListener#controlMoved(org.eclipse.swt.events.ControlEvent)
146 */
147 @Override
148 public void controlMoved(ControlEvent arg0)
149 {
150 fullRepaint = true;
151 }
152
153 /* (non-Javadoc)
154 * @see org.eclipse.swt.events.ControlListener#controlResized(org.eclipse.swt.events.ControlEvent)
155 */
156 @Override
157 public void controlResized(ControlEvent arg0)
158 {
159 fullRepaint = true;
160 }
161
162 /* (non-Javadoc)
163 * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
164 */
165 @Override
166 public final void paintControl(PaintEvent event)
167 {
168 if (chart == null)
169 return;
170
171 Rectangle clientArea = this.getClientArea();
172 if ((clientArea.width == 0) || (clientArea.height == 0))
173 return;
174
175 if (fullRepaint)
176 {
177 // if resized
178 // imgChart is factory created and should not be disposed
179 imgChart = null;
180
181 try
182 {
183 File tmpFile = File.createTempFile("birt_" + hashCode(), "_" + clientArea.width + "_" + clientArea.height);
184
185 deviceRenderer.setProperty(IDeviceRenderer.FILE_IDENTIFIER, tmpFile);
186 final Bounds bounds = BoundsImpl.create(0, 0, clientArea.width, clientArea.height);
187 bounds.scale(72.0 / deviceRenderer.getDisplayServer().getDpiResolution());
188
189 generatedChartState = generator.build(deviceRenderer.getDisplayServer(), chart, bounds, null, null, null);
190 generator.render(deviceRenderer, generatedChartState);
191
192 InputStream inputStream = null;
193 try
194 {
195 inputStream = new FileInputStream(tmpFile);
196 imgChart = new Image(getDisplay(), inputStream);
197 tmpFile.delete();
198 }
199 finally
200 {
201 if (inputStream != null)
202 {
203 inputStream.close();
204 }
205 }
206 }
207 catch(Exception e)
208 {
209 /* TODO: add logging and/or user notification */
210 e.printStackTrace();
211 }
212
213 fullRepaint = false;
214 }
215
216 event.gc.drawImage(imgChart, clientArea.x, clientArea.y);
217 paintErrorIndicator(event.gc);
218 }
219
220 /* (non-Javadoc)
221 * @see org.netxms.ui.eclipse.charts.api.DataChart#refresh()
222 */
223 @Override
224 public void refresh()
225 {
226 fullRepaint = true;
227 redraw();
228 }
229
230 /* (non-Javadoc)
231 * @see org.netxms.ui.eclipse.charts.api.DataChart#rebuild()
232 */
233 @Override
234 public void rebuild()
235 {
236 recreateChart();
237 }
238
239 /* (non-Javadoc)
240 * @see org.netxms.ui.eclipse.charts.api.DataChart#setTitle(java.lang.String)
241 */
242 @Override
243 public void setChartTitle(String title)
244 {
245 this.title = title;
246 if (chart != null)
247 {
248 chart.getTitle().getLabel().getCaption().setValue(title);
249 refresh();
250 }
251 }
252
253 /* (non-Javadoc)
254 * @see org.netxms.ui.eclipse.charts.api.DataChart#setLegendVisible(boolean)
255 */
256 @Override
257 public void setLegendVisible(boolean visible)
258 {
259 legendVisible = visible;
260 if (chart != null)
261 {
262 chart.getLegend().setVisible(visible);
263 refresh();
264 }
265 }
266
267 /* (non-Javadoc)
268 * @see org.netxms.ui.eclipse.charts.api.DataChart#setTitleVisible(boolean)
269 */
270 @Override
271 public void setTitleVisible(boolean visible)
272 {
273 titleVisible = visible;
274 if (chart != null)
275 chart.getTitle().setVisible(visible);
276 }
277
278 /* (non-Javadoc)
279 * @see org.netxms.ui.eclipse.charts.api.DataChart#set3DModeEnabled(boolean)
280 */
281 @Override
282 public void set3DModeEnabled(boolean enabled)
283 {
284 displayIn3D = enabled;
285 if (chart != null)
286 recreateChart();
287 }
288
289 /**
290 * Get palette usable by BIRT
291 * @return BIRT palette object
292 */
293 protected Palette getBirtPalette()
294 {
295 Palette birtPalette = PaletteImpl.create(0, true);
296 for(ChartColor c : palette)
297 birtPalette.getEntries().add(ColorDefinitionImpl.create(c.red, c.green, c.blue, c.alpha));
298 return birtPalette;
299 }
300
301 /* (non-Javadoc)
302 * @see org.netxms.ui.eclipse.charts.api.DataChart#setLogScaleEnabled(boolean)
303 */
304 @Override
305 public void setLogScaleEnabled(boolean enabled)
306 {
307 if (useLogScale != enabled)
308 {
309 useLogScale = enabled;
310 if (chart != null)
311 recreateChart();
312 }
313 }
314
315 /**
316 * Create BIRT color definition object from preference string
317 *
318 * @param name Preference name
319 * @return color definition object
320 */
321 protected ColorDefinition getColorFromPreferences(final String name)
322 {
323 RGB rgb = PreferenceConverter.getColor(preferenceStore, name);
324 return ColorDefinitionImpl.create(rgb.red, rgb.green, rgb.blue);
325 }
326
327 /**
328 * Get Position object from int constant
329 *
330 * @param value
331 * @return
332 */
333 protected Position positionFromInt(int value)
334 {
335 switch(value)
336 {
337 case GraphSettings.POSITION_LEFT:
338 return Position.LEFT_LITERAL;
339 case GraphSettings.POSITION_RIGHT:
340 return Position.RIGHT_LITERAL;
341 case GraphSettings.POSITION_TOP:
342 return Position.ABOVE_LITERAL;
343 case GraphSettings.POSITION_BOTTOM:
344 return Position.BELOW_LITERAL;
345 }
346 return Position.RIGHT_LITERAL;
347 }
348
349 /* (non-Javadoc)
350 * @see org.netxms.ui.eclipse.charts.widgets.GenericChart#setLegendPosition(int)
351 */
352 @Override
353 public void setLegendPosition(int position)
354 {
355 super.setLegendPosition(position);
356 if (chart != null)
357 recreateChart();
358 }
359
360 /* (non-Javadoc)
361 * @see org.netxms.ui.eclipse.charts.widgets.GenericChart#setTranslucent(boolean)
362 */
363 @Override
364 public void setTranslucent(boolean translucent)
365 {
366 super.setTranslucent(translucent);
367 if (chart != null)
368 recreateChart();
369 }
370
371 /* (non-Javadoc)
372 * @see org.netxms.ui.eclipse.charts.api.DataChart#addError(java.lang.String)
373 */
374 @Override
375 public void addError(String message)
376 {
377 if (errors.add(message))
378 redraw();
379 }
380
381 /* (non-Javadoc)
382 * @see org.netxms.ui.eclipse.charts.api.DataChart#clearErrors()
383 */
384 @Override
385 public void clearErrors()
386 {
387 if (errors.size() > 0)
388 {
389 errors.clear();
390 redraw();
391 }
392 }
393
394 /**
395 * Draw error indicator if needed
396 *
397 * @param gc
398 */
399 private void paintErrorIndicator(GC gc)
400 {
401 if (errors.size() == 0)
402 return;
403
404 if (errorImage == null)
405 errorImage = Activator.getImageDescriptor("icons/chart_error.png").createImage(); //$NON-NLS-1$
406
407 gc.setAlpha(127);
408 gc.setBackground(colors.create(127, 127, 127));
409 gc.fillRectangle(getClientArea());
410 gc.setAlpha(255);
411 gc.drawImage(errorImage, 10, 10);
412
413 gc.setForeground(colors.create(192, 0, 0));
414 Iterator<String> it = errors.iterator();
415 int y = 12;
416 int h = gc.textExtent("X").y; //$NON-NLS-1$
417 while(it.hasNext())
418 {
419 gc.drawText(it.next(), 40, y, true);
420 y += h + 5;
421 }
422 }
423
424 @Override
425 public void setYAxisRange(int from, int to)
426 {
427 if(from == to)
428 return;
429 if(from > to)
430 {
431 int tmp = to;
432 to = from;
433 from = tmp;
434 }
435 autoscale = false;
436 this.from = from;
437 this.to = to;
438 }
439 }