1 /*
2 * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
3 * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
4 *
5 * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
6 * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
7 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
8 * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
9 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
11 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
12 * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
13 * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
14 * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
15 * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
16 * OR MODIFICATIONS.
17 * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
18 * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
19 * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
20 * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
21 */
22
23 package de.desy.acop.displayers.tools;
24
25 import java.awt.Color;
26 import java.beans.Beans;
27 import java.util.Map;
28
29 import com.cosylab.gui.displayers.CommonDisplayer;
30 import com.cosylab.gui.displayers.DataConsumer;
31 import com.cosylab.gui.displayers.DataState;
32 import com.cosylab.gui.displayers.Displayer;
33 import com.cosylab.gui.displayers.DisplayerUtilities;
34 import com.cosylab.gui.displayers.DoubleSeqConsumer;
35 import com.cosylab.util.CommonException;
36
37 import de.desy.acop.chart.AcopGraphStyleEnum;
38 import de.desy.acop.displayers.AcopChart;
39
40 /**
41 * <code>AcopChartConsumer</code> is an implementation of <code>DoubleSeqConsumer</code>
42 * which can be used in connection with <code>AcopChart</code>. AcopChartConsumer
43 * receives updates from the <code>DataSource</code> and updates the chart accordingly.
44 * One consumer can only handle connection to one specific channel.
45 *
46 * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a>
47 * @version $Id: Templates.xml,v 1.10 2004/01/13 16:17:13 jbobnar Exp $
48 * @see AcopChart
49 */
50 public class AcopChartConsumer implements DoubleSeqConsumer {
51
52 @SuppressWarnings("unchecked")
53 public static final Class[] SUPPORTED_CONSUMER_TYPES = {
54 DoubleSeqConsumer.class
55 };
56 public static final String[] SUPPORTED_CHARACTERISTICS = {
57 CommonDisplayer.C_GRAPH_MAX, CommonDisplayer.C_GRAPH_MIN
58 };
59
60 protected String name;
61 protected AcopChart acop;
62
63 protected double[] xData;
64 protected double[] yData;
65 protected int displayHandle = -1;
66 protected int textHandle = -1;
67 protected long lastTimestamp;
68 protected Color color= Color.RED;
69 protected String[] xLabels;
70 protected Object disable;
71 protected int arraySize;
72 protected int maxNumber;
73
74 private boolean isTrendChart = false;
75
76 private double preferredYMax;
77 private double preferredYMin;
78
79 private AcopGraphParameters displayerParameters;
80
81 /**
82 * Constructs new AcopChartConsumer object with the given name.
83 * The consumer belongs to the specified chart.
84 *
85 * @param acop parent chart
86 * @param name the name of the consumer
87 */
88 public AcopChartConsumer(AcopChart acop, String name) {
89 super();
90 this.name=name;
91 this.acop=acop;
92 preferredYMax = acop.getYMax();
93 preferredYMin = acop.getYMin();
94
95 //color= new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255));
96 }
97
98 /* (non-Javadoc)
99 * @see com.cosylab.gui.displayers.DataConsumer#getDataConsumer(java.lang.Class)
100 */
101 @SuppressWarnings("unchecked")
102 public DataConsumer getDataConsumer(Class type) {
103 if (type.isAssignableFrom(getClass())) {
104 return this;
105 }
106 return null;
107 }
108
109 /* (non-Javadoc)
110 * @see com.cosylab.gui.displayers.DataConsumer#getDefaultDataConsumer()
111 */
112 public DataConsumer getDefaultDataConsumer() {
113 return this;
114 }
115
116 /* (non-Javadoc)
117 * @see com.cosylab.gui.displayers.DataConsumer#updateDataState(com.cosylab.gui.displayers.DataState)
118 */
119 public void updateDataState(DataState state) {
120 // TODO Auto-generated method stub
121
122 }
123
124 /* (non-Javadoc)
125 * @see com.cosylab.gui.displayers.DataConsumer#setCharacteristics(java.util.Map)
126 */
127 public void setCharacteristics(Map characteristics) {
128
129 if (acop == null) {
130 return;
131 }
132
133 Object o1 = null;
134 Object o2 = null;
135
136 o1 = characteristics.get(CommonDisplayer.C_GRAPH_MAX);
137
138 if (o1 == null) {
139 o1 = characteristics.get(CommonDisplayer.C_MAXIMUM);
140 }
141
142 o2 = characteristics.get(CommonDisplayer.C_GRAPH_MIN);
143
144 if (o2 == null) {
145 o2 = characteristics.get(CommonDisplayer.C_MINIMUM);
146 }
147
148 if (o1 != null || o2 != null) {
149 double max = o1 != null ? ((Number)o1).doubleValue()
150 : acop.getYMax();
151 double min = o2 != null ? ((Number)o2).doubleValue()
152 : acop.getYMin();
153
154 setPreferredYMax(max);
155 setPreferredYMin(min);
156 acop.updateYScale(this);
157 }
158
159 o1 = characteristics.get(CommonDisplayer.C_DISPLAY_NAME);
160
161 String newName = (String) o1;
162 if (newName != null && !newName.equals(acop.getName())) {
163 acop.setName(newName);
164 acop.setCaption(newName);
165 }
166
167 o1 = characteristics.get(Displayer.C_UNITS);
168 if (o1 != null) {
169 acop.setYAxisLabel((String)o1);
170 }
171
172 //avoid setting colors through characterstics to avoid different threads
173 //setting the same property at the same time - consumer might end up with wrong color
174 o1 = characteristics.get(Displayer.C_COLOR);
175
176 if (o1 != null) {
177 color = (Color) o1;
178 acop.setForeground(color);
179 }
180
181 o1 = characteristics.get("xLabels");
182 if (o1 != null && !isTrendChart) {
183 setXLabels((String[])o1);
184 }
185
186 o1 = characteristics.get(CommonDisplayer.C_SEQUENCE_LENGTH);
187 if (arraySize == 0 || arraySize == -1 && o1 != null) {
188 setArraySize((Integer)o1);
189 }
190
191 if (!Beans.isDesignTime()) {
192 acop.updateXScale(this);
193 }
194 acop.repaint();
195
196 }
197
198 /* (non-Javadoc)
199 * @see com.cosylab.gui.displayers.DataConsumer#getName()
200 */
201 public String getName() {
202 return name;
203 }
204
205 /* (non-Javadoc)
206 * @see com.cosylab.gui.displayers.DataConsumer#getSupportedCharacteristics()
207 */
208 public String[] getSupportedCharacteristics() {
209 return DisplayerUtilities.combineCharacteristics(DisplayerUtilities.COMMON_NUMERIC_DISPLAYER_CHARACTERISTICS,
210 SUPPORTED_CHARACTERISTICS);
211 }
212
213 /* (non-Javadoc)
214 * @see com.cosylab.gui.displayers.DataConsumer#getSupportedConsumerTypes()
215 */
216 @SuppressWarnings("unchecked")
217 public Class<DataConsumer>[] getSupportedConsumerTypes() {
218 return SUPPORTED_CONSUMER_TYPES;
219 }
220
221 private void updateChart() {
222 if (acop==null) {
223 return;
224 }
225
226 synchronized (acop) {
227
228 //System.out.println("disp id : " + displayHandle);
229 // acop.clearScreen(-1,0); <- this will wipe out all display references
230 //Acop aChart = acop.getAcopChart();
231 // aChart.clearScreen(displayHandle,0); <- this removes the given reference (but Acop will reuse the handle, so we don't want to use this inside the AcopDataConsumer)
232 // acop.draw(y,x,null,null,141,100);
233 if (displayHandle < 0)
234 { // display the initial data set ...
235 applyParameters();
236 displayHandle = acop.draw(yData,xData,disable,xLabels,arraySize,maxNumber);
237 // System.out.println("assigned display handle : " + displayHandle + " color : " + color.toString());
238 }
239 else
240 {
241 if (!isTrendChart)
242 { // not a trend chart : just refresh the display ...
243 acop.refreshScreen(yData, displayHandle, arraySize, 0, xData);
244 // System.out.println("refresh display handle : " + displayHandle + " color : " + color.toString());
245 }
246 else
247 { // append 1 value to the end ... (ACOP should be in LIN_TIME or LOG_TIME graph mode)
248 double[] yValue = new double[1];
249 yValue[0] = yData[0];
250 double[] xValue = new double[1];
251 xValue[0] = lastTimestamp/1000.;
252
253 // System.out.println("Append: ["+xValue[0]+", "+yValue[0]+"]");
254 acop.appendScreen(yData, displayHandle, xValue);
255
256 // double[][] data= dumpData();
257 // System.out.print("X: ");
258 // System.out.println(Arrays.toString(data[0]));
259 // System.out.print("Y: ");
260 // System.out.println(Arrays.toString(data[1]));
261 }
262 }
263 // a.GetDataSize(d,null,-1);
264 // acopLabel.setText(a.getStatus() + " " + a.GetDataSize(-1) + " elements " + a.getTimeStamp().toString());
265 //acop.setForeground(Color.BLUE);
266 // a.draw(z,x,null,null,141,100);
267 //acop.draw(z);
268 }
269
270 }
271
272 /**
273 * Returns all data from chart. First index is 0 for X data array and 1 for Y data array.
274 * @return all dat a from chart in X and Y array
275 */
276 public double[][] dumpData() {
277
278 double[][] array= new double[2][arraySize];
279
280 acop.getDrawnData(array[0], array[1], arraySize, 0, displayHandle);
281
282 return array;
283 }
284
285 /**
286 * Destroys this consumer. Removes from the chart any data that belongs
287 * to this consumer.
288 *
289 */
290 public void destroy() {
291 acop.clearScreen(displayHandle);
292 acop=null;
293 }
294
295 /* (non-Javadoc)
296 * @see com.cosylab.gui.displayers.DoubleSeqConsumer#updateValue(long, double[])
297 */
298 public void updateValue(long timestamp, double[] value) throws CommonException {
299 lastTimestamp=timestamp;
300 yData=value;
301 updateChart();
302 }
303
304 /**
305 * Returns the horizontal values.
306 *
307 * @return x values
308 */
309 public double[] getXData() {
310 return xData;
311 }
312
313 /**
314 * Sets the horizontal values.
315 *
316 * @param xdata new horizontal values
317 */
318 public void setXData(double[] xdata) {
319 this.xData = xdata;
320 }
321
322 /**
323 * Returns the vertical values.
324 *
325 * @return y values
326 */
327 public double[] getYData() {
328 return yData;
329 }
330
331 /**
332 * Sets new vertical values.
333 *
334 * @param data new y values
335 */
336 public void setYData(double[] data) {
337 yData = data;
338 }
339
340 /**
341 * Returns the parent chart of this consumer.
342 *
343 * @return the acop
344 */
345 public AcopChart getAcop() {
346 return acop;
347 }
348
349 /**
350 * Returns the last timestamp when value was updated.
351 *
352 * @return last timestamp
353 */
354 public long getLastTimestamp() {
355 return lastTimestamp;
356 }
357
358 /**
359 * Returns the color that shows data of this consumer in the chart.
360 *
361 * @return the color
362 */
363 public Color getColor() {
364 return color;
365 }
366
367 /**
368 * Sets the color that shows data of this consumer in the chart. Color can
369 * only be set before the data was first drawn.
370 *
371 * @param color new color
372 */
373 public void setColor(Color color) {
374 this.color = color;
375 }
376
377 /**
378 * Returns the labels of horizontal values.
379 *
380 * @return x labels
381 */
382 public String[] getXLabels() {
383 return xLabels;
384 }
385
386 /**
387 * Sets the labels of horizontal values. Labels can only be set before data
388 * was first drawn.
389 *
390 * @param labels new labels
391 */
392 public void setXLabels(String[] labels) {
393 xLabels = labels;
394 }
395
396 /**
397 * Returns the size of the array that this consumer shows.
398 *
399 * @return the array size
400 */
401 public int getArraySize() {
402 return arraySize;
403 }
404
405 /**
406 * Sets the size of the array that this consumer handles with. This property can only
407 * be set before data was first drawn.
408 *
409 * @param arraySize new array size
410 */
411 public void setArraySize(int arraySize) {
412 this.arraySize = arraySize;
413 }
414
415 // /**
416 // * @return Returns the disable.
417 // */
418 // public Object getDisable() {
419 // return disable;
420 // }
421 //
422 // /**
423 // * @param disable The disable to set.
424 // */
425 // public void setDisable(Object disable) {
426 // this.disable = disable;
427 // }
428 //
429 // /**
430 // * @return Returns the maxNumber.
431 // */
432 // public int getMaxNumber() {
433 // return maxNumber;
434 // }
435 //
436 // /**
437 // * @param maxNumber The maxNumber to set.
438 // */
439 // public void setMaxNumber(int maxNumber) {
440 // this.maxNumber = maxNumber;
441 // }
442
443 /**
444 * Returns the preferred maximum vertical value for this graph.
445 *
446 * @return the preferred max value
447 */
448 public double getPreferredYMax() {
449 return preferredYMax;
450 }
451
452 /**
453 * Sets the preferred maximum vertical value for this graph.
454 *
455 * @param preferredYMax new preferred maximum value
456 */
457 public void setPreferredYMax(double preferredYMax) {
458 this.preferredYMax = preferredYMax;
459 }
460
461 /**
462 * Returns the preferred minimum vertical value for this graph.
463 * @return the preferred min value
464 */
465 public double getPreferredYMin() {
466 return preferredYMin;
467 }
468
469 /**
470 * Sets the preferred minimum vertical value for this graph.
471 * @param preferredYMin new preferred minimum value
472 */
473 public void setPreferredYMin(double preferredYMin) {
474 this.preferredYMin = preferredYMin;
475 }
476
477 private void applyParameters() {
478 if (displayerParameters != null) {
479 acop.setForeground(displayerParameters.getColor());
480 acop.setDrawStyle(displayerParameters.getDrawStyle());
481 acop.setFFT(displayerParameters.getFFT());
482 acop.setDisplayMode(displayerParameters.getMode());
483 acop.setDrawWidth(displayerParameters.getWidth());
484 if (displayerParameters.isTrend()) {
485 acop.setGraphStyle(AcopGraphStyleEnum.TimeLin.ordinal());
486 double[] data = new double[displayerParameters.getTrendLength()];
487 if (yData != null) {
488 for (int i = 0; i < yData.length && i < data.length; i++) {
489 data[i] = yData[i];
490 }
491 }
492 yData = data;
493 maxNumber = data.length;
494 }
495 } else if (color != null) {
496 acop.setForeground(color);
497 }
498 }
499
500 /**
501 * Returns the AcopGraphParameters associated with this consumer.
502 *
503 * @return associated parameters
504 */
505 public AcopGraphParameters getDisplayerParameters() {
506 return displayerParameters;
507 }
508
509 /**
510 * Sets the AcopGraphParameters which describes the visual appearance of
511 * the data in the chart. DisplayerParameters can only be set before
512 * data was first drawn.
513 *
514 * @param displayerParameters the displayer parameters
515 */
516 public void setDisplayerParameters(AcopGraphParameters displayerParameters) {
517 this.displayerParameters = displayerParameters;
518 this.color = displayerParameters.getColor() != null ? displayerParameters.getColor() : this.color;
519 setTrendChart(displayerParameters.isTrend());
520 if (isTrendChart()) {
521 setArraySize(displayerParameters.getTrendLength());
522 } else {
523 setArraySize(displayerParameters.getConnectionParameters().getPropertySize());
524 }
525 }
526
527 /**
528 * Returns true if this consumer shows a trend graph.
529 *
530 * @return true if this is a trend graph data
531 */
532 public boolean isTrendChart() {
533 return isTrendChart;
534 }
535
536 /**
537 * Sets the trend mode for this consumer. This property can only be set before
538 * the first data was drawn.
539 *
540 * @param isTrendChart trend mode flag
541 */
542 public void setTrendChart(boolean isTrendChart) {
543 this.isTrendChart = isTrendChart;
544 }
545
546 }