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