6e4136236ee78bae8226a51d1f6783eda525b726
[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 tmpFile.deleteOnExit();
185
186 deviceRenderer.setProperty(IDeviceRenderer.FILE_IDENTIFIER, tmpFile);
187 final Bounds bounds = BoundsImpl.create(0, 0, clientArea.width, clientArea.height);
188 bounds.scale(72.0 / deviceRenderer.getDisplayServer().getDpiResolution());
189
190 generatedChartState = generator.build(deviceRenderer.getDisplayServer(), chart, bounds, null, null, null);
191 generator.render(deviceRenderer, generatedChartState);
192
193 InputStream inputStream = null;
194 try
195 {
196 inputStream = new FileInputStream(tmpFile);
197 imgChart = new Image(getDisplay(), inputStream);
198 tmpFile.delete();
199 }
200 finally
201 {
202 if (inputStream != null)
203 {
204 inputStream.close();
205 }
206 }
207 }
208 catch(Exception e)
209 {
210 /* TODO: add logging and/or user notification */
211 e.printStackTrace();
212 }
213
214 fullRepaint = false;
215 }
216
217 event.gc.drawImage(imgChart, clientArea.x, clientArea.y);
218 paintErrorIndicator(event.gc);
219 }
220
221 /* (non-Javadoc)
222 * @see org.netxms.ui.eclipse.charts.api.DataChart#refresh()
223 */
224 @Override
225 public void refresh()
226 {
227 fullRepaint = true;
228 redraw();
229 }
230
231 /* (non-Javadoc)
232 * @see org.netxms.ui.eclipse.charts.api.DataChart#rebuild()
233 */
234 @Override
235 public void rebuild()
236 {
237 recreateChart();
238 }
239
240 /* (non-Javadoc)
241 * @see org.netxms.ui.eclipse.charts.api.DataChart#setTitle(java.lang.String)
242 */
243 @Override
244 public void setChartTitle(String title)
245 {
246 this.title = title;
247 if (chart != null)
248 {
249 chart.getTitle().getLabel().getCaption().setValue(title);
250 refresh();
251 }
252 }
253
254 /* (non-Javadoc)
255 * @see org.netxms.ui.eclipse.charts.api.DataChart#setLegendVisible(boolean)
256 */
257 @Override
258 public void setLegendVisible(boolean visible)
259 {
260 legendVisible = visible;
261 if (chart != null)
262 {
263 chart.getLegend().setVisible(visible);
264 refresh();
265 }
266 }
267
268 /* (non-Javadoc)
269 * @see org.netxms.ui.eclipse.charts.api.DataChart#setTitleVisible(boolean)
270 */
271 @Override
272 public void setTitleVisible(boolean visible)
273 {
274 titleVisible = visible;
275 if (chart != null)
276 chart.getTitle().setVisible(visible);
277 }
278
279 /* (non-Javadoc)
280 * @see org.netxms.ui.eclipse.charts.api.DataChart#set3DModeEnabled(boolean)
281 */
282 @Override
283 public void set3DModeEnabled(boolean enabled)
284 {
285 displayIn3D = enabled;
286 if (chart != null)
287 recreateChart();
288 }
289
290 /**
291 * Get palette usable by BIRT
292 * @return BIRT palette object
293 */
294 protected Palette getBirtPalette()
295 {
296 Palette birtPalette = PaletteImpl.create(0, true);
297 for(ChartColor c : palette)
298 birtPalette.getEntries().add(ColorDefinitionImpl.create(c.red, c.green, c.blue, c.alpha));
299 return birtPalette;
300 }
301
302 /* (non-Javadoc)
303 * @see org.netxms.ui.eclipse.charts.api.DataChart#setLogScaleEnabled(boolean)
304 */
305 @Override
306 public void setLogScaleEnabled(boolean enabled)
307 {
308 if (useLogScale != enabled)
309 {
310 useLogScale = enabled;
311 if (chart != null)
312 recreateChart();
313 }
314 }
315
316 /**
317 * Create BIRT color definition object from preference string
318 *
319 * @param name Preference name
320 * @return color definition object
321 */
322 protected ColorDefinition getColorFromPreferences(final String name)
323 {
324 RGB rgb = PreferenceConverter.getColor(preferenceStore, name);
325 return ColorDefinitionImpl.create(rgb.red, rgb.green, rgb.blue);
326 }
327
328 /**
329 * Get Position object from int constant
330 *
331 * @param value
332 * @return
333 */
334 protected Position positionFromInt(int value)
335 {
336 switch(value)
337 {
338 case GraphSettings.POSITION_LEFT:
339 return Position.LEFT_LITERAL;
340 case GraphSettings.POSITION_RIGHT:
341 return Position.RIGHT_LITERAL;
342 case GraphSettings.POSITION_TOP:
343 return Position.ABOVE_LITERAL;
344 case GraphSettings.POSITION_BOTTOM:
345 return Position.BELOW_LITERAL;
346 }
347 return Position.RIGHT_LITERAL;
348 }
349
350 /* (non-Javadoc)
351 * @see org.netxms.ui.eclipse.charts.widgets.GenericChart#setLegendPosition(int)
352 */
353 @Override
354 public void setLegendPosition(int position)
355 {
356 super.setLegendPosition(position);
357 if (chart != null)
358 recreateChart();
359 }
360
361 /* (non-Javadoc)
362 * @see org.netxms.ui.eclipse.charts.widgets.GenericChart#setTranslucent(boolean)
363 */
364 @Override
365 public void setTranslucent(boolean translucent)
366 {
367 super.setTranslucent(translucent);
368 if (chart != null)
369 recreateChart();
370 }
371
372 /* (non-Javadoc)
373 * @see org.netxms.ui.eclipse.charts.api.DataChart#addError(java.lang.String)
374 */
375 @Override
376 public void addError(String message)
377 {
378 if (errors.add(message))
379 redraw();
380 }
381
382 /* (non-Javadoc)
383 * @see org.netxms.ui.eclipse.charts.api.DataChart#clearErrors()
384 */
385 @Override
386 public void clearErrors()
387 {
388 if (errors.size() > 0)
389 {
390 errors.clear();
391 redraw();
392 }
393 }
394
395 /**
396 * Draw error indicator if needed
397 *
398 * @param gc
399 */
400 private void paintErrorIndicator(GC gc)
401 {
402 if (errors.size() == 0)
403 return;
404
405 if (errorImage == null)
406 errorImage = Activator.getImageDescriptor("icons/chart_error.png").createImage(); //$NON-NLS-1$
407
408 gc.setAlpha(127);
409 gc.setBackground(colors.create(127, 127, 127));
410 gc.fillRectangle(getClientArea());
411 gc.setAlpha(255);
412 gc.drawImage(errorImage, 10, 10);
413
414 gc.setForeground(colors.create(192, 0, 0));
415 Iterator<String> it = errors.iterator();
416 int y = 12;
417 int h = gc.textExtent("X").y; //$NON-NLS-1$
418 while(it.hasNext())
419 {
420 gc.drawText(it.next(), 40, y, true);
421 y += h + 5;
422 }
423 }
424
425 @Override
426 public void setYAxisRange(int from, int to)
427 {
428 if(from == to)
429 return;
430 if(from > to)
431 {
432 int tmp = to;
433 to = from;
434 from = tmp;
435 }
436 autoscale = false;
437 this.from = from;
438 this.to = to;
439 }
440 }