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