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.chart;
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.Acop;
38  import de.desy.acop.chart.AcopDisplayMode;
39  import de.desy.acop.chart.AcopGraphStyleEnum;
40  import de.desy.acop.displayers.AcopChart;
41  import de.desy.acop.displayers.AcopChartReorg;
42  import de.desy.acop.displayers.tools.AcopGraphParameters;
43  
44  /**
45   * <code>AcopChartConsumer</code> is the common consumer used by the 
46   * <code>AcopChart</code> and <code>AcopChartReorg</code>.
47   * Each consumer can present one graph in the chart and can be added
48   * or removed from the chart in runtime. This consumer works with 
49   * <code>AcopGraphParameters</code> which specifiy all the properties 
50   * required to customize a particular graph.
51   *  
52   * 
53   * @author ikriznar
54   * @see AcopChart
55   * @see AcopChartReorg
56   *
57   */
58  public class AcopChartConsumer implements DoubleSeqConsumer {
59  
60  	@SuppressWarnings("unchecked")
61  	public static final Class[] SUPPORTED_CONSUMER_TYPES = {
62  		DoubleSeqConsumer.class
63  		};
64  	public static final String[] SUPPORTED_CHARACTERISTICS = {
65  		CommonDisplayer.C_GRAPH_MAX, CommonDisplayer.C_GRAPH_MIN
66  		};
67  	
68  	protected String name;
69  	protected AcopChartReorg acopChartReorg;
70  
71  	protected double[] xData;
72  	protected double[] yData;
73  	protected int displayHandle = -1;
74  	protected int textHandle = -1;
75  	protected long lastTimestamp;
76  	protected Color color= Color.RED;
77  	protected int width = 1;
78  	protected int dispalyMode = 0;
79  	protected String[] xLabels;
80  	protected Object disable;
81  	protected int arraySize;
82  	protected int maxNumber;
83  	private boolean chubbyLines;
84  	private AcopDisplayMode displayMode;
85      
86      private boolean isTrendChart = false;
87      
88      private double preferredYMax;
89      private double preferredYMin;
90      
91      protected AcopGraphParameters displayerParameters;
92      	
93  	/**
94  	 * Constructs new AcopChartConsumer.
95  	 * 
96  	 * @param acopChartReorg parent chart
97  	 * @param name the name of the consumer
98  	 */
99  	public AcopChartConsumer(AcopChartReorg acopChartReorg, String name) {
100 		super();
101 		this.name=name;
102 		this.acopChartReorg=acopChartReorg;
103 		preferredYMax = acopChartReorg.getAcop().getYMax();
104 		preferredYMin = acopChartReorg.getAcop().getYMin();
105 		
106 		//color= new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255));
107 	}
108 
109 	/* (non-Javadoc)
110 	 * @see com.cosylab.gui.displayers.DataConsumer#getDataConsumer(java.lang.Class)
111 	 */
112 	@SuppressWarnings("unchecked")
113     public DataConsumer getDataConsumer(Class type) {
114 		if (type.isAssignableFrom(getClass())) {
115 			return this;
116 		}
117 		return null;
118 	}
119 
120 	/* (non-Javadoc)
121 	 * @see com.cosylab.gui.displayers.DataConsumer#getDefaultDataConsumer()
122 	 */
123 	public DataConsumer getDefaultDataConsumer() {
124 		return this;
125 	}
126 
127 	/* (non-Javadoc)
128 	 * @see com.cosylab.gui.displayers.DataConsumer#updateDataState(com.cosylab.gui.displayers.DataState)
129 	 */
130 	public void updateDataState(DataState state) {
131 		// TODO Auto-generated method stub
132 
133 	}
134 
135 	/* (non-Javadoc)
136 	 * @see com.cosylab.gui.displayers.DataConsumer#setCharacteristics(java.util.Map)
137 	 */
138 	public void setCharacteristics(Map characteristics) {
139 		
140 		if (acopChartReorg == null) {
141 			return;
142 		}
143 
144 		Object o1 = null;
145 		Object o2 = null;
146 
147 		o1 = characteristics.get(CommonDisplayer.C_GRAPH_MAX);
148 
149 		if (o1 == null) {
150 			o1 = characteristics.get(CommonDisplayer.C_MAXIMUM);
151 		}
152 
153 		o2 = characteristics.get(CommonDisplayer.C_GRAPH_MIN);
154 
155 		if (o2 == null) {
156 			o2 = characteristics.get(CommonDisplayer.C_MINIMUM);
157 		}
158 
159 		if (o1 != null || o2 != null) {
160 			double max = o1 != null ? ((Number)o1).doubleValue()
161 				: acopChartReorg.getYRangeMax();
162 			double min = o2 != null ? ((Number)o2).doubleValue()
163 				: acopChartReorg.getYRangeMin();
164 			
165 			this.preferredYMax = max;
166 			this.preferredYMin = min;
167 			acopChartReorg.updateYScale(this);
168 		}
169 
170 		o1 = characteristics.get(CommonDisplayer.C_DISPLAY_NAME);
171 		
172 		String newName = (String) o1;
173 		if (newName != null && !newName.equals(acopChartReorg.getTitle())) {
174 			// TODO what was this used for?
175 //		    acopChart2.getAcop().setName(newName);
176 		    acopChartReorg.setTitle(newName);
177 		}
178 		
179 		o1 = characteristics.get(Displayer.C_UNITS);
180 		if (o1 != null) {
181 			acopChartReorg.getAcop().setYAxisLabel((String)o1);
182 		}
183 
184 		//avoid setting colors through characterstics to avoid different threads
185 		//setting the same property at the same time - consumer might end up with wrong color
186 		o1 = characteristics.get(Displayer.C_COLOR);
187 
188 		if (o1 != null) {
189 			color = (Color) o1;
190 			acopChartReorg.getAcop().setForeground(color);
191 		}
192 			
193 		o1 = characteristics.get("xLabels");
194 		if (o1 != null && !isTrendChart) {
195 			setXLabels((String[])o1);
196 		}
197 		
198 		o1 = characteristics.get(CommonDisplayer.C_SEQUENCE_LENGTH);
199 		if (getArraySize() == 0 || getArraySize() == -1 && o1 != null) {
200 			setArraySize((Integer)o1);
201 		}
202 		
203 		if (!Beans.isDesignTime()) {
204 			acopChartReorg.updateXScale(this);
205 		}
206 		acopChartReorg.repaint();
207 
208 	}
209 
210 	/* (non-Javadoc)
211 	 * @see com.cosylab.gui.displayers.DataConsumer#getName()
212 	 */
213 	public String getName() {
214 		return name;
215 	}
216 
217 	/* (non-Javadoc)
218 	 * @see com.cosylab.gui.displayers.DataConsumer#getSupportedCharacteristics()
219 	 */
220 	public String[] getSupportedCharacteristics() {
221 		return DisplayerUtilities.combineCharacteristics(DisplayerUtilities.COMMON_NUMERIC_DISPLAYER_CHARACTERISTICS,
222 			    SUPPORTED_CHARACTERISTICS);
223 	}
224 
225 	/* (non-Javadoc)
226 	 * @see com.cosylab.gui.displayers.DataConsumer#getSupportedConsumerTypes()
227 	 */
228 	@SuppressWarnings("unchecked")
229 	public Class<DataConsumer>[] getSupportedConsumerTypes() {
230 		return SUPPORTED_CONSUMER_TYPES;
231 	}
232 	
233 	protected void updateChart() {
234 		if (acopChartReorg==null) {
235 			return;
236 		}
237 		
238 		synchronized (acopChartReorg) {
239 
240 	        //System.out.println("disp id : " + displayHandle);
241 	//	    acop.clearScreen(-1,0); <- this will wipe out all display references
242 	        //Acop aChart = acop.getAcopChart();
243 	//      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)
244 	//	    acop.draw(y,x,null,null,141,100);
245 	        if (displayHandle < 0)
246 	        { // display the initial data set ...
247 	          applyParameters();
248 		      displayHandle = acopChartReorg.getAcop().draw(yData,xData,disable,xLabels,getArraySize(),maxNumber);
249 	//        System.out.println("assigned display handle : " + displayHandle + "  color : " + color.toString());
250 	        }
251 	        else
252 	        {
253 	          if (!isTrendChart)
254 	          { // not a trend chart : just refresh the display ...
255 	            acopChartReorg.getAcop().refreshScreen(yData, displayHandle, getArraySize(), 0, xData);
256 	//          System.out.println("refresh display handle : " + displayHandle + "  color : " + color.toString());
257 	          }
258 	          else
259 	          { // append 1 value to the end ...  (ACOP should be in LIN_TIME or LOG_TIME graph mode)
260 	            double[] yValue = new double[1];
261 	            yValue[0] = yData[0];
262 	            double[] xValue = new double[1];
263 	            xValue[0] = lastTimestamp/1000.;
264 	            
265 //	            System.out.println("Append: ["+xValue[0]+", "+yValue[0]+"]");
266 	            acopChartReorg.getAcop().appendScreen(yData, displayHandle, xValue);            
267 	            
268 //	            double[][] data= dumpData();
269 //	            System.out.print("X: ");
270 //	            System.out.println(Arrays.toString(data[0]));
271 //	            System.out.print("Y: ");
272 //	            System.out.println(Arrays.toString(data[1]));
273 	          }
274 	        }
275 	//	    a.GetDataSize(d,null,-1);
276 	//	    acopLabel.setText(a.getStatus() + " " + a.GetDataSize(-1) + " elements " + a.getTimeStamp().toString());
277 		    //acop.setForeground(Color.BLUE);
278 	//	    a.draw(z,x,null,null,141,100);
279 		    //acop.draw(z);
280 	        getAcopChart().autoScale();
281 		}
282 		
283 	}
284 	
285 	/**
286 	 * Refreshes all drawn points.
287 	 * @see Acop#refreshScreen(Object, int, int, int, Object)
288 	 *
289 	 */
290 	public void refreshPlot() {
291 		synchronized (acopChartReorg) {
292 			applyParameters();
293 			acopChartReorg.getAcop().refreshScreen(yData, displayHandle, getArraySize(), 0, xData);
294 		}
295 	}
296 	
297 	/**
298 	 * Redraws all graphs.
299 	 *
300 	 */
301 	public void reinitializePlot() {
302 		acopChartReorg.getAcop().clearScreen(displayHandle);
303 		displayHandle = -1;
304 		updateChart();
305 	}
306 
307 	/**
308 	 * Returns all data from chart. First index is 0 for X data array and 1 for Y data array.
309 	 * @return all dat a from chart in X and Y array
310 	 */
311 	public double[][] dumpData() {
312 		
313 		double[][] array= new double[2][getArraySize()];
314 		
315 		acopChartReorg.getAcop().getDrawnData(array[0], array[1], getArraySize(), 0, displayHandle);
316 		
317 		return array;
318 	}
319 	
320 	/**
321 	 * Removes the graph that this consumer shows from the chart.
322 	 *
323 	 */
324 	public void destroy() {
325 		acopChartReorg.getAcop().clearScreen(displayHandle);
326 		acopChartReorg=null;
327 	}
328 	
329 	/* (non-Javadoc)
330 	 * @see com.cosylab.gui.displayers.DoubleSeqConsumer#updateValue(long, double[])
331 	 */
332 	public void updateValue(long timestamp, double[] value) throws CommonException {
333 		lastTimestamp=timestamp;
334 		yData=value;
335 		updateChart();
336 	}
337 
338 	/**
339 	 * Returns the x data
340 	 * @return x values of the data
341 	 */
342 	public double[] getXData() {
343 		return xData;
344 	}
345 
346 	/**
347 	 * Returns the y data.
348 	 * @return y values of the data
349 	 */
350 	public double[] getYData() {
351 		return yData;
352 	}
353 
354 	/**
355 	 * Returns the parent chart component.
356 	 * 
357 	 * @return the acop chart
358 	 */
359 	public AcopChartReorg getAcopChart() {
360 		return acopChartReorg;
361 	}
362 
363 	/**
364 	 * Returns the last timestamp when value was updated.
365 	 * 
366 	 * @return last timestamp
367 	 */
368 	public long getLastTimestamp() {
369 		return lastTimestamp;
370 	}
371 
372 	/**
373 	 * Returns the color of this graph.
374 	 * 
375 	 * @return the color of the graph
376 	 */
377 	public Color getColor() {
378 		return color;
379 	}
380 
381 	/**
382 	 * Sets the color for this graph. Can only be set before first draw.
383 	 * 
384 	 * @param color the color of the graph 
385 	 */
386 	public void setColor(Color color) {
387 		this.color = color;
388 	}
389 
390 	/**
391 	 * Returns the horizotanl axis labels. Can only be set before the first
392 	 * draw.
393 	 * 
394 	 * @return the horizontal axis labels
395 	 */
396 	public String[] getXLabels() {
397 		return xLabels;
398 	}
399 
400 	/**
401 	 * Sets the labels for the horizontal axis. Can only be set before the first
402 	 * draw.
403 	 * 
404 	 * @param labels new horizontal axis labels
405 	 */
406 	public void setXLabels(String[] labels) {
407 		xLabels = labels;
408 	}
409 
410 	/**
411 	 * Returns the array size of the consumer.
412 	 * 
413 	 * @return the arraySize
414 	 */
415 	public int getArraySize() {
416 		return arraySize;
417 	}
418 
419 	/**
420 	 * Sets the array size for this consumer.
421 	 * 
422 	 * @param arraySize
423 	 */
424 	private void setArraySize(int arraySize) {
425 		this.arraySize = arraySize;
426 	}
427 
428 	/**
429 	 * Returns the preferred maximum of the vertical axis.
430 	 * 
431      * @return the preferred maximum of y axis
432      */
433     public double getPreferredYMax() {
434     	return preferredYMax;
435     }
436 
437 	/**
438 	 * Sets the preferred maximum of the vertical axis.
439      * @param preferredYMax new maximum for the vertical axis.
440      */
441     public void setPreferredYMax(double preferredYMax) {
442     	this.preferredYMax = preferredYMax;
443     	getAcopChart().updateYScale(this);
444     }
445 
446 	/**
447 	 * Returns the preferred minimum of the vertical axis.
448 	 * 
449      * @return the preferred minimum of y axis
450      */
451     public double getPreferredYMin() {
452     	return preferredYMin;
453     }
454     
455     /**
456      * Returns the preferred minimum of the horizontal axis.
457      * 
458      * @return preferred minimum of the x axis
459      */
460     public double getPreferredXMin() {
461     	return 0;
462     }
463     
464     /**
465      * Returns the preferred maximum of the horizontal axis.
466      * 
467      * @return horizontal maximum
468      */
469     public double getPreferredXMax() {
470     	return getArraySize();
471     }
472 
473 	/**
474 	 * Sets the preferred minimum of the vertical axis.
475 	 * 
476      * @param preferredYMin new preferred minimum
477      */
478     public void setPreferredYMin(double preferredYMin) {
479     	this.preferredYMin = preferredYMin;
480     	getAcopChart().updateYScale(this);
481     }
482     
483     protected void applyParameters() {
484     	if (displayerParameters != null) {
485 	    	acopChartReorg.getAcop().setForeground(displayerParameters.getColor());
486 	    	acopChartReorg.getAcop().setDrawStyle(displayerParameters.getDrawStyle());
487 	    	acopChartReorg.getAcop().setFFT(displayerParameters.getFFT());
488 	    	if (displayMode == null) {
489 	    		acopChartReorg.getAcop().setDisplayMode(displayerParameters.getMode());
490 	    	} else {
491 	    		acopChartReorg.getAcop().setDisplayMode(displayMode.ordinal());
492 	    	}
493 	    	if (chubbyLines) {
494 	    		acopChartReorg.getAcop().setDrawWidth(2*displayerParameters.getWidth());
495 	    	} else {
496 	    		acopChartReorg.getAcop().setDrawWidth(displayerParameters.getWidth());
497 	    	}
498 	    	if (displayerParameters.isTrend()) {
499 	    		acopChartReorg.getAcop().setGraphStyle(AcopGraphStyleEnum.TimeLin.ordinal());
500 	    		double[] data = new double[displayerParameters.getTrendLength()];
501 	    		if (yData != null) {
502 		    		for (int i = 0; i < yData.length && i < data.length; i++) {
503 		    			data[i] = yData[i];
504 		    		}
505 	    		}
506 	    		yData = data;
507 	    		maxNumber = data.length;
508 	    	}
509     	} else {
510     		if (color != null) {
511     			acopChartReorg.getAcop().setForeground(color);
512     		}
513     		if (chubbyLines) {
514     			acopChartReorg.getAcop().setDrawWidth(2*width);
515     		} else {
516     			acopChartReorg.getAcop().setDrawWidth(width);
517     		}
518     		if (displayMode == null) {
519     			acopChartReorg.getAcop().setDisplayMode(dispalyMode);
520     		} else {
521     			acopChartReorg.getAcop().setDisplayMode(displayMode.ordinal());
522     		}
523     	}
524     }
525 
526     /**
527      * Returns the AcopGraphParameters associated with this consumer.
528      * 
529      * @return the acop graph parameters
530      */
531 	public AcopGraphParameters getDisplayerParameters() {
532 		return displayerParameters;
533 	}
534 
535 	/**
536 	 * Associates AcopGraphParameters with this consumer.
537 	 * 
538 	 * @param displayerParameters
539 	 */
540 	public void setDisplayerParameters(AcopGraphParameters displayerParameters) {
541 		this.displayerParameters = displayerParameters;
542 		this.color = displayerParameters.getColor() != null ? displayerParameters.getColor() : this.color;
543 		this.width = displayerParameters.getWidth();
544 		this.dispalyMode = displayerParameters.getMode() > -1 ? displayerParameters.getMode() : acopChartReorg.getAcop().getDisplayMode();
545 		setTrendChart(displayerParameters.isTrend());
546 		if (isTrendChart()) {
547 			setArraySize(displayerParameters.getTrendLength());
548 		} else {
549 			setArraySize(displayerParameters.getConnectionParameters().getPropertySize());
550 		}
551 	}
552 	
553 	/**
554 	 * Returns true if data is plotted on the chart.
555 	 * 
556 	 * @return true data is plotted.
557 	 */
558 	public boolean isDataDrawn() {
559 		return displayHandle > -1;
560 	}
561 
562 	/**
563 	 * Returns true if this graph is a trend.
564 	 * 
565 	 * @return true if this is a trend
566 	 */
567 	public boolean isTrendChart() {
568 		return isTrendChart;
569 	}
570 
571 	/**
572 	 * Sets the trend chart mode for this graph. Can only be set before the first 
573 	 * draw.
574 	 * 
575 	 * @param isTrendChart
576 	 */
577 	public void setTrendChart(boolean isTrendChart) {
578 		this.isTrendChart = isTrendChart;
579 	}
580 
581 	/**
582 	 * Returns true if this graph is drawn with a thicker line.
583 	 * 
584 	 * @return the chubbyLines
585 	 */
586 	public boolean isChubbyLines() {
587 		return chubbyLines;
588 	}
589 
590 	/**
591 	 * If true this graph is drawn with a thicker line.
592 	 * 
593 	 * @param chubbyLines the chubbyLines to set
594 	 */
595 	public void setChubbyLines(boolean chubbyLines) {
596 		if (this.chubbyLines == chubbyLines) return;
597 		this.chubbyLines = chubbyLines;
598 		reinitializePlot();
599 		// TODO this does not work! refreshPlot();
600 	}
601 
602 	/**
603 	 * Returns the display mode of this graph.
604 	 * 
605 	 * @return the displayMode
606 	 */
607 	public AcopDisplayMode getDisplayMode() {
608 		return displayMode;
609 	}
610 
611 	/**
612 	 * Sets the display mode for this graph.
613 	 * 
614 	 * @param displayMode new display mode
615 	 */
616 	public void setDisplayMode(AcopDisplayMode displayMode) {
617 		if (this.displayMode == displayMode) return;
618 		this.displayMode = displayMode;
619 		reinitializePlot();
620 	}
621 
622 }