]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.trend/src/org/simantics/trend/impl/ItemNode.java
Still fixes history collection value band endTime setting and rendering
[simantics/platform.git] / bundles / org.simantics.trend / src / org / simantics / trend / impl / ItemNode.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.trend.impl;
13
14 import java.awt.AlphaComposite;
15 import java.awt.BasicStroke;
16 import java.awt.Color;
17 import java.awt.Composite;
18 import java.awt.Graphics2D;
19 import java.awt.RenderingHints;
20 import java.awt.geom.AffineTransform;
21 import java.awt.geom.Path2D;
22 import java.awt.geom.Point2D;
23 import java.awt.geom.Rectangle2D;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.TreeSet;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import org.simantics.databoard.Bindings;
31 import org.simantics.databoard.accessor.StreamAccessor;
32 import org.simantics.databoard.accessor.error.AccessorException;
33 import org.simantics.databoard.binding.Binding;
34 import org.simantics.databoard.binding.BooleanBinding;
35 import org.simantics.databoard.binding.ByteBinding;
36 import org.simantics.databoard.binding.error.BindingException;
37 import org.simantics.databoard.binding.error.RuntimeBindingException;
38 import org.simantics.databoard.type.BooleanType;
39 import org.simantics.databoard.type.Datatype;
40 import org.simantics.databoard.type.NumberType;
41 import org.simantics.databoard.type.RecordType;
42 import org.simantics.databoard.util.Bean;
43 import org.simantics.history.HistoryException;
44 import org.simantics.history.HistoryItem;
45 import org.simantics.history.HistoryManager;
46 import org.simantics.history.ItemManager;
47 import org.simantics.history.util.Stream;
48 import org.simantics.history.util.ValueBand;
49 import org.simantics.history.util.subscription.SamplingFormat;
50 import org.simantics.scenegraph.g2d.G2DNode;
51 import org.simantics.trend.configuration.LineQuality;
52 import org.simantics.trend.configuration.Scale;
53 import org.simantics.trend.configuration.TrendItem;
54 import org.simantics.trend.configuration.TrendItem.DrawMode;
55 import org.simantics.trend.configuration.TrendItem.Renderer;
56 import org.simantics.trend.util.KvikDeviationBuilder;
57 import org.slf4j.LoggerFactory;
58
59 /**
60  * Data node for a TrendItem
61  * 
62  * @author toni.kalajainen
63  */
64 public class ItemNode extends G2DNode implements TrendLayout {
65
66         private static final long serialVersionUID = -4741446944761752871L;
67         private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ItemNode.class);
68         
69         public static final AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .61f);
70
71         public TrendItem item;
72         VertRuler ruler;
73         TrendNode trendNode;
74
75         /** History Items */
76         Bean historyItems[];
77         
78         /** A list of items that is ordered in by interval value, starting from the lowest interval */
79         Bean[] renderableItems = new Bean[0];
80         
81         /** Format for the minmax stream, or null */  
82         Bean minmaxItem;
83         
84         /** Known item min->max value range, and from->end time range */
85         double from=Double.NaN, end=Double.NaN, min=0, max=1;
86
87         BasicStroke stroke;
88         Color color;
89         
90         Stream openStream;
91         StreamAccessor openStreamAccessor;
92         Bean openStreamItem;
93         
94         Logger log = Logger.getLogger( this.getClass().getName() );     
95         
96         boolean disabled = false;
97         Point2D.Double pt = new Point2D.Double();
98         Point2D.Double pt2 = new Point2D.Double();
99         
100         // Cached shapes
101         KvikDeviationBuilder dev = new KvikDeviationBuilder();
102         Path2D.Double line = new Path2D.Double();
103         
104         /**
105          * Set trend item and initialize history
106          * @param ti
107          * @param items all items in history
108          */
109         public void setTrendItem(TrendItem ti, ItemManager items) {
110                 if (openStream!=null) {
111                         openStream.close();
112                         openStream = null;
113                         openStreamAccessor = null;
114                         openStreamItem = null;
115                 }
116                 this.item = ti;
117                 this.minmaxItem = null;
118                 this.renderableItems = new HistoryItem[0];
119                 disabled = true;
120                 if (ti==null) return;
121                 
122                 try {
123                         List<Bean> trendItems = items.search("groupId", ti.groupId, "groupItemId", ti.groupItemId, "variableId", ti.variableId);
124                         this.historyItems = trendItems.toArray( new Bean[trendItems.size()] );
125                         Arrays.sort( this.historyItems, SamplingFormat.INTERVAL_COMPARATOR );
126                         
127                         // Read renderable formats, and minmax format
128                         TreeSet<Bean> streamFormats = new TreeSet<Bean>( SamplingFormat.INTERVAL_COMPARATOR );
129                         for (Bean item : trendItems) {
130                                 SamplingFormat format = new SamplingFormat();
131                                 format.readAvailableFields(item);
132                                 RecordType rt = (RecordType) format.format;
133                                 Boolean enabled = (Boolean) item.getField("enabled");
134                                 if (!enabled) continue;
135                                         
136                                 boolean isMinMaxFormat = format.interval==Double.MAX_VALUE &&
137                                                 format.deadband==Double.MAX_VALUE &&
138                                                 rt.getComponentIndex2("min")>=0 &&
139                                                 rt.getComponentIndex2("max")>=0;
140         
141                                 if (isMinMaxFormat) {
142                                         this.minmaxItem = item;
143                                 } else {
144                                         streamFormats.add(item);
145                                 }                                       
146                         }
147                         if (streamFormats.isEmpty()) return;
148                         
149                         renderableItems = streamFormats.toArray( new Bean[streamFormats.size()] );
150                         disabled = false;
151                 } catch (BindingException e) {
152                         throw new RuntimeException( e );
153                 }
154         }
155
156         /**
157          * Draw to graphics context as time,value pairs are.
158          * 
159          * Phases, 0-Init data, 1-Draw deviation, 2-Draw line, 3-Cleanup 
160          * 
161          * @param g
162          * @param phase 
163          */
164         public void draw(Graphics2D g, int phase, boolean bold) {
165                 boolean devAndLine = 
166                                 item.drawMode==DrawMode.DeviationAndAverage || 
167                                 item.drawMode==DrawMode.DeviationAndLine || 
168                                 item.drawMode==DrawMode.DeviationAndSample;
169                 
170                 // Draw deviation
171                 Object newQuality = getTrendNode().printing||getTrendNode().quality.lineQuality==LineQuality.Antialias?RenderingHints.VALUE_ANTIALIAS_ON:RenderingHints.VALUE_ANTIALIAS_OFF;
172                 if (phase == 1) {                       
173                         g.setColor(color);
174                         if (!dev.isEmpty()) {
175                                 Object old = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
176                                 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, newQuality);
177
178                                 if (item.renderer == Renderer.Binary) {
179                                         dev.drawRectangles(g);
180                                 } 
181                                 
182                                 if (item.renderer == Renderer.Analog) {
183                                         if (devAndLine) {
184                                                 // Draw opaque
185                                                 Composite c = g.getComposite();
186                                                 g.setComposite( composite );
187                                                 dev.drawRectangles(g);
188                                                 g.setComposite( c );
189                                         } else if (item.drawMode == DrawMode.Deviation) {
190                                                 // Draw solid
191                                                 dev.drawRectangles(g);
192                                         }
193                                 }
194                     g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, old);
195                         }                       
196                 }
197                         
198                 // Draw line
199                 if (phase == 2) {
200                         g.setColor(color);
201                         Object old = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
202                         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, newQuality);
203                         g.draw(line);                   
204             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, old);
205                 }
206                 
207         }
208         
209         private boolean validSample(ValueBand band) throws HistoryException {
210                 if(band.getTimeDouble() > 1e50) return false;
211                 if(band.getTimeDouble() > band.getEndTimeDouble()) return false;
212 //              if(band.getTimeDouble() < 0) return false;
213 //              if(band.getEndTimeDouble() < 0) return false;
214                 //if(band.getEndTimeDouble()-band.getTimeDouble() < 1e-9) return false;
215                 return true;
216         }
217         
218         // Draw state needed for clipping
219         double currentX;
220         double currentY;
221         double minX;
222         double maxX;
223         
224         void moveTo(double x, double y) {
225                 line.moveTo(x, y);
226                 currentX = x;
227                 currentY = y;
228         }
229
230         void lineToOrdered(double x, double y) {
231                 
232                 if(x < minX) return;
233                 if(currentX > maxX) return;
234                 
235                 // We have something to draw
236                 
237                 // Clip left
238                 if(currentX < minX) {
239                         double ny = currentY + (y-currentY) * (minX-currentX) / (x-currentX);
240                         line.moveTo(minX, ny);
241                         currentX = minX;
242                         currentY = ny;
243                 }
244
245                 // Right clip
246                 if(x > maxX) {
247                         double ny = currentY + (y-currentY) * (maxX-currentX) / (x-currentX);
248                         line.lineTo(maxX, ny);
249                         line.moveTo(x, y);              
250                 } else {
251                         if (x != currentX || y != currentY) {
252                                 line.lineTo(x, y);
253                         }
254                 }
255                 
256         }
257         
258         void lineTo(double x, double y) {
259
260                 // First assert ordering - if samples are in wrong order draw nothing
261                 if(currentX <= x) {
262                         lineToOrdered(x, y);
263                 } else {
264                         line.moveTo(x, y);
265                 }
266                 
267                 currentX = x;
268                 currentY = y;
269                 
270         }
271         
272
273         /**
274          * This method prepares line and deviation shapes.
275          * @param from
276          * @param end
277          * @param secondsPerPixel
278          * @param at 
279          * @throws HistoryException 
280          * @throws AccessorException 
281          */
282         public void prepareLine(double from, double end, double pixelsPerSecond, AffineTransform at) throws HistoryException, AccessorException
283         {
284 //              boolean devAndLine = 
285 //                              item.drawMode==DrawMode.DeviationAndAverage || 
286 //                              item.drawMode==DrawMode.DeviationAndLine || 
287 //                              item.drawMode==DrawMode.DeviationAndSample;
288 //              boolean deviationEnabled = devAndLine || 
289 //                              item.drawMode == DrawMode.Deviation;
290
291                 boolean devAndLine = false;
292                 boolean deviationEnabled = false;
293                 
294                 // Collect data
295                 dev.reset();
296                 line.reset();
297                 Stream s = openStream(pixelsPerSecond);
298                 if (s==null) return;
299                 ValueBand vb = new ValueBand(s.sampleBinding, s.sampleBinding.createDefaultUnchecked());
300                 boolean hasDeviation = vb.hasMin() && vb.hasMax();
301                 boolean drawDeviation = hasDeviation & deviationEnabled;
302                 
303                 Datatype valueType = vb.getValueBinding().type();
304                 s.reset();
305                 if ( valueType instanceof BooleanType == false && valueType instanceof NumberType == false ) return;
306                                 
307                 int start = s.binarySearch(Bindings.DOUBLE, from);
308                 int count = s.count();
309                 if (start<0) start = -2-start;
310                 if (start<0) start = 0;
311                                 
312                 // moveTo, on next draw, if true
313                 boolean lineNotAttached = true; // =next draw should be move to
314                 boolean devNotAttached = true;
315                 
316                 currentX = Double.NaN;
317                 currentY = Double.NaN;
318
319                 pt.setLocation(from, 0);
320                 at.transform(pt, pt);
321                 minX = pt.x;
322                 
323                 pt.setLocation(end, 0);
324                 at.transform(pt, pt);
325                 maxX = pt.x;
326                                 
327                 s.reset();
328                 
329                 boolean wentOver = false;
330                 
331                 for (int i=start; i<count; i++) {
332                         // Read sample
333                         s.accessor.get(i, s.sampleBinding, vb.getSample());
334                         
335                         if(!validSample(vb)) {
336                                 LOGGER.warn("-invalid value band: " + i + "/" + count + ":" + vb);
337                                 continue;
338                         }
339                         // Non-continuation point
340                         if (vb.hasQuality()) {
341                                 Byte b = (Byte) vb.getQuality(Bindings.BYTE);
342                                 boolean noncontinuation = b.equals( ValueBand.QUALITY_NOVALUE ); 
343                                 if ( noncontinuation ) {
344                                         lineNotAttached = true;
345                                         devNotAttached = true;
346                                         continue;
347                                 }
348                         }
349                                         
350                         // Line
351                         double t1 = vb.getTimeDouble();
352                         double t2 = vb.hasEndTime() ? vb.getEndTimeDouble() : t1;
353                                         
354                         // Analog signal
355                         if (item.renderer == Renderer.Analog) {
356                                                 
357                                 // Add points to line
358                                 if (item.drawMode == DrawMode.Deviation && hasDeviation) {
359                                         // ...
360                                 } else {
361                                         
362                                         double yy = Double.NaN;
363 //                                      boolean showBand = true;
364                                         boolean flat = false;
365
366                                         if( trendNode != null && trendNode.drawSamples ) {
367                                                 yy = vb.getValueDouble();
368                                                 flat = true;
369                                         } else {
370                                                 yy = vb.getValueDouble();
371                                                 // Only render the last band
372 //                                              if(i < count-1) showBand = false;                                       
373                                         }
374                                         
375 //                                      if (item.drawMode == DrawMode.DeviationAndAverage) {
376 //                                              yy = vb.hasMedian() ? vb.getMedianDouble() : ( vb.hasAvg() ? vb.getAvgDouble() : vb.getValueDouble() );
377 //                                      } else if (item.drawMode == DrawMode.Average || item.drawMode == DrawMode.DeviationAndAverage) {
378 //                                              yy = vb.hasAvg() ? vb.getAvgDouble() : vb.getValueDouble();
379 //                                      } else if (item.drawMode == DrawMode.Line || item.drawMode == DrawMode.DeviationAndLine) {
380 //                                              yy = vb.getValueDouble();
381 //                                              // Only render the last band
382 //                                              if(i < count-1) showBand = false;                                       
383 //                                      } else /* if (item.drawMode == DrawMode.Sample || item.drawMode == DrawMode.DeviationAndSample) */ {
384 //                                              yy = vb.getValueDouble();
385 //                                              flat = true;
386 //                                      } 
387                         
388                                         if ( Double.isNaN(yy) ) {
389                                                 lineNotAttached = true;
390                                         } else {
391 //                                              pt.setLocation(t1, yy);
392 //                                              at.transform(pt, pt);
393 //                                              if ( t1==t2 ) {
394 //                                                      if (lineNotAttached) {
395 //                                                              moveTo(pt.getX(), pt.getY());
396 //                                                      } else {
397 //                                                              if(flat) {
398 //                                                                      
399 //                                                              } else {
400 //                                                                      lineTo(pt.getX(), pt.getY());
401 //                                                              }
402 //                                                      }
403 //                                              } else {
404                                                         // Static variables may have months data that consists of single value
405                                                         // When zoomed in, the single line may be drawn from -1e10, ... 1e10
406                                                         // This is too much for Graphics2D, it refuses to draw.
407 //                                                      if (t1<from) {
408 //                                                              t1 = from;
409 //                                                      }
410 //                                                      if (t2>end) {
411 //                                                              t2 = end;
412 //                                                      }
413                                                                         
414                                                         pt.setLocation(t1, yy);
415                                                         at.transform(pt, pt);
416                                                         pt2.setLocation(t2, yy);
417                                                         at.transform(pt2, pt2);
418
419                                                         double x1 = pt.x, y1 = pt.y, x2 = pt2.x, y2 = pt2.y;
420
421                                                         if (lineNotAttached) {
422                                                                 moveTo(x1, y1);
423                                                         } else {
424                                                                 if(flat) {
425                                                                         lineTo(x1, currentY);
426                                                                         lineTo(x1, y1);
427                                                                 } else {
428                                                                         lineTo(x1, y1);
429                                                                 }
430                                                         }
431
432                                                         // gitlab #35: t2 > t1 ensure that the value band is
433                                                         // rendered as a horizontal line until the the time when
434                                                         // the band's value went out of dead-band.
435                                                         if (flat || t2 > t1)
436                                                                 lineTo(x2, y2);
437                                                         
438 //                                                      if(showBand) {
439 //                                                              lineTo(x2, y2);
440 //                                                      }
441                                                         
442 //                                              }
443                                                 lineNotAttached = false;                                        
444                                         }
445                                 }
446                                                 
447                                 if (drawDeviation) {
448                                         double min = vb.getMinDouble();
449                                         double max = vb.getMaxDouble();
450
451                                         pt.setLocation(t1, min);
452                                         at.transform(pt, pt);
453                                         pt2.setLocation(t2, max);
454                                         at.transform(pt2, pt2);
455                                         double x1 = pt.x;
456                                         double x2 = pt2.x;
457                                         double y1 = pt.y;
458                                         double y2 = pt2.y;
459                                                         
460                                         double width = x2-x1;
461                                         boolean tooWide = devAndLine && (width>2.0);
462                                         if (Double.isNaN(min) || Double.isNaN(max) || tooWide || width<=0.0 || y1==y2) {
463                                                 devNotAttached = true;
464                                         } else {
465                                                 if (devNotAttached) {
466                                                         dev.addRectangle(x1, x2, y1, y2);
467                                                 } else {
468                                                         dev.extendRectangle(x1);
469                                                         dev.addRectangle(x1, x2, y1, y2);
470                                                 }
471                                                 devNotAttached = false;
472                                         }
473                                 }
474                         }
475                                         
476                         // Binary signal
477                         else if (item.renderer == Renderer.Binary) {
478                                 byte value = 0;
479                                 if (vb.getValueBinding() instanceof BooleanBinding) {
480                                         value = ((Boolean) vb.getValue(Bindings.BOOLEAN)) ? (byte)0 : (byte)1;
481                                 } else if (vb.getValueBinding() instanceof ByteBinding) {
482                                         value = ((Byte) vb.getValue(Bindings.BYTE));
483                                 } else if (vb.hasMax()) {
484                                         value = (Byte) vb.getMax(Bindings.BYTE);
485                                 } else {
486                                         value = (Byte) vb.getValue(Bindings.BYTE);
487                                 }
488                                 pt.setLocation(t1, value==1 ? BINARY[1] : BINARY[0]);
489                                 at.transform(pt, pt);
490                                 pt2.setLocation(t2, BINARY[2]);
491                                 at.transform(pt2, pt2);
492                                 double x1 = pt.x;
493                                 double x2 = pt2.x;
494                                 double y1 = pt.y;
495                                 double y2 = pt2.y;
496                                 dev.extendRectangle(x1);
497                                 dev.addRectangle(x1, x2, y1, y2);
498                                 devNotAttached = false;                                 
499                         }
500                                         
501                         // Already over => break
502                         if(wentOver) break;
503                         
504                         // Out of range
505                         if (t2>=end) {
506                                 wentOver = true;
507                         }
508                 }       
509                 
510         }
511         
512         public boolean readMinMaxFromEnd() {
513                 if (disabled) return false;
514                 HistoryManager history = getTrendNode().historian;
515
516                 boolean hasVariable = !item.variableId.isEmpty() && !item.groupItemId.isEmpty() && !item.groupId.isEmpty();
517                 boolean canReadMinMax = minmaxItem != null;
518                 boolean manualScale = item.scale instanceof Scale.Manual;
519                 
520                 if ( !hasVariable ) {
521                         min = 0;
522                         max = 1;
523                         from = Double.NaN;
524                         end = Double.NaN;
525                         return false;
526                 }
527                 
528                 try {
529                         if (canReadMinMax && !manualScale) {            
530                                 String id = (String) minmaxItem.getFieldUnchecked("id");
531                                 StreamAccessor sa = history.openStream(id, "r");
532                                 if ( sa==null ) {
533                                         min = 0;
534                                         max = 1;
535                                         from = Double.NaN;
536                                         end = Double.NaN;
537                                         return false;
538                                 } else 
539                                 try {
540                                         if (sa.size()==0) return false;
541                                         min = Double.MAX_VALUE;
542                                         max = -Double.MAX_VALUE;
543                                         from = Double.MAX_VALUE;
544                                         end = -Double.MAX_VALUE;
545                                         for (int i=0; i<sa.size(); i++) {
546                                                 Binding binding = Bindings.getBinding( sa.type().componentType() );
547                                                 Object sample = sa.get(i, binding);
548                                                 ValueBand vb = new ValueBand(binding, sample);
549                                                 if (!vb.isNullValue() && !vb.isNanSample()) {
550                                                         min = Math.min(min, vb.getMinDouble());
551                                                         max = Math.max(max, vb.getMaxDouble());
552                                                 } 
553                                                 if (!vb.isNullValue()) {
554                                                         from = Math.min(from, vb.getTimeDouble());
555                                                         end = Math.max(end, vb.getEndTimeDouble());
556                                                 }
557                                         }
558                                         if ( min==Double.MAX_VALUE || max==-Double.MAX_VALUE) {
559                                                 min = 0; max = 1.0;
560                                         }
561                                         if ( from==Double.MAX_VALUE || end==-Double.MAX_VALUE) {
562                                                 from = 0; end = 100.0;
563                                         }
564                                         return true;
565                                 } finally {
566                                         try { sa.close(); } catch (AccessorException e) {}
567                                 } 
568                         } else {
569                                 
570                                 if (manualScale) {
571                                         Scale.Manual ms = (Scale.Manual) item.scale;
572                                         min = ms.min;
573                                         max = ms.max;
574                                 } 
575                                 
576                                 // Read from, end from any stream
577                                 if (openStreamAccessor==null) {
578                                         openStream(1);
579                                 } 
580                                 if (openStreamAccessor!=null){
581                                         // Open some stream
582                                         StreamAccessor sa = openStreamAccessor;
583                                         sa.reset();
584                                         int count = sa.size();
585                                         if (count>0) {
586                                                 Binding binding = Bindings.getBinding( sa.type().componentType() );
587                                                 Object sample = sa.get(0, binding);
588                                                 ValueBand vb = new ValueBand(binding, sample);
589                                                 from = vb.getTimeDouble();
590                                                 sa.get(count-1, binding, sample);
591                                                 end = vb.hasEndTime() ? vb.getEndTimeDouble() : vb.getTimeDouble();
592                                         }
593                                         return true;
594                                 } else {
595                                         return false;
596                                 }
597                         }
598                 } catch (AccessorException e) {
599                         log.log(Level.FINE, e.toString(), e);
600                         return false;
601                 } catch (HistoryException e) {
602                         log.log(Level.FINE, e.toString(), e);
603                         return false;
604                 }
605         }
606         
607         @Override
608         public void cleanup() {
609                 trendNode = null;
610                 if (openStreamAccessor != null) {
611                         try {
612                                 openStreamAccessor.close();
613                         } catch (AccessorException e) {
614                         }
615                         openStreamAccessor = null;
616                         openStreamItem = null;
617                 }
618                 super.cleanup();
619         }
620         
621         Bean getFormat(double pixelsPerSecond) {
622                 Bean result = null;
623                 if (renderableItems == null)
624                         return null;
625                 
626                 for (Bean format : renderableItems)
627                 {
628                         double interval = 0.0;
629                         try {
630                                 interval = format.hasField("interval") ? (Double) format.getFieldUnchecked("interval") : 0.0;
631                         } catch (RuntimeBindingException e) {
632                         } catch (BindingException e) {
633                         }
634                         if (Double.isNaN( interval ) || interval<=pixelsPerSecond) {
635                                 result = format;
636                         } else {
637                                 break;
638                         }
639                 }               
640                 if (result==null) {
641                         if ( renderableItems.length == 0 ) {
642                                 result = null;
643                         } else {
644                                 result = renderableItems[0];
645                         }
646                 }
647                 
648                 return result;
649         }
650         
651         public Stream openStream(double pixelsPerSecond) {
652                 Bean f = getFormat(pixelsPerSecond);
653                 if (f==openStreamItem) return openStream;
654                 
655                 if (openStream != null) {
656                         openStream.close();
657                         openStreamAccessor = null;
658                         openStreamItem = null;
659                         openStream = null;
660                 }
661                 
662                 if (disabled) return null;
663                 
664                 if (f!=null) {
665                         HistoryManager historian = getTrendNode().historian;
666                         try {
667                                 String id = (String) f.getFieldUnchecked("id");
668                                 openStreamAccessor = historian.openStream(id, "r");
669                                 if ( openStreamAccessor!=null ) {
670                                         openStream = new Stream(openStreamAccessor);
671                                         openStreamItem = f;                     
672                                 } else {
673                                         openStream = null;
674                                 }
675                         } catch (HistoryException e) {
676                                 log.log(Level.FINE, e.toString(), e);
677                         }
678                 }
679                 
680                 return openStream;
681         }
682         
683         @Override
684         public void render(Graphics2D g2d) {
685         }
686
687         @Override
688         public Rectangle2D getBoundsInLocal() {
689                 return null;
690         }
691         
692         TrendNode getTrendNode() {
693                 return (TrendNode) getParent();
694         }
695         
696 }