View Javadoc

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 }