1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.trend.impl;
\r
14 import java.awt.Color;
\r
15 import java.awt.Graphics2D;
\r
16 import java.text.Format;
\r
17 import java.text.NumberFormat;
\r
19 import org.simantics.g2d.utils.GridSpacing;
\r
20 import org.simantics.g2d.utils.GridUtil;
\r
21 import org.simantics.trend.configuration.TimeWindow;
\r
22 import org.simantics.trend.configuration.TrendSpec;
\r
23 import org.simantics.utils.format.TimeFormat;
\r
25 public class HorizRuler extends TrendGraphicalNode {
\r
27 private static final long serialVersionUID = 7155812928124259094L;
\r
29 GridSpacing spacing = GridSpacing.SOME_SPACING;
\r
30 public double from = 0;
\r
31 public double end = 100;
\r
32 public boolean autoscroll = true; // Determines if auto-scroll is on/off
\r
33 boolean manualscale = false; // Locked in trend spec
\r
34 TimeFormat timeFormat = new TimeFormat(0, 0);
\r
35 private Format f = timeFormat;
\r
36 double iFrom = Double.MAX_VALUE;
\r
37 double iEnd = -Double.MAX_VALUE;
\r
38 public double basetime = 0;
\r
39 public TimeWindowListener listener;
\r
40 public static final Color AUTOSCROLL_ON = new Color(0, 225, 34);
\r
41 public static final Color AUTOSCROLL_OFF = new Color(255, 115, 115);
\r
44 public boolean setWidth(double width) {
\r
45 if (getWidth()==width) return false;
\r
46 this.setSize(width, 20);
\r
50 public boolean setFromEnd(double from, double end) {
\r
51 if (this.from!=from || this.end!=end) {
\r
54 getTrend().shapedirty = true;
\r
60 public boolean setFromScale(double from, double scaleX) {
\r
61 double end = getWidth() * scaleX + from;
\r
62 return setFromEnd(from, end);
\r
66 public void fireListener() {
\r
67 if (listener != null) {
\r
68 double wid = getWidth();
\r
69 if ( wid == 0.0 ) wid = 0.1;
\r
70 double sx = (end-from) / wid;
\r
71 listener.onNewWindow(from, end, sx);
\r
76 * Set grid spacing and text formatter;
\r
78 public void layout() {
\r
79 TrendNode trend = getTrend();
\r
80 if (trend.timeFormat == org.simantics.trend.configuration.TimeFormat.Time) {
\r
81 // Figure out how many decimals are needed
\r
82 timeFormat.setMaxValue(end);
\r
83 timeFormat.setDecimals(1);
\r
85 double labelWidth = 0;
\r
86 double maxLabelWidth = 0;
\r
87 for (int i=0; i<2; i++) {
\r
88 labelWidth = GridUtil.calcLabelWidth(from - basetime, end - basetime, timeFormat, spacing);
\r
89 maxLabelWidth = Math.max(labelWidth, maxLabelWidth);
\r
90 spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10);
\r
91 timeFormat.setDecimals((int) -spacing.segmentExp);
\r
94 if (maxLabelWidth>labelWidth) {
\r
95 spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), maxLabelWidth+10);
\r
96 timeFormat.setDecimals((int) -spacing.segmentExp);
\r
102 f = NumberFormat.getInstance();
\r
103 double labelWidth = GridUtil.calcLabelWidth(from - basetime, end, f, spacing);
\r
104 this.spacing = GridSpacing.makeGridSpacing(end-from, getWidth(), labelWidth+10);
\r
109 protected void doRender(Graphics2D g2d) {
\r
110 TrendNode trend = getTrend();
\r
112 // Draw little "Frozen"
\r
113 if ( !trend.printing )
\r
115 // g2d.setColor( Color.LIGHT_GRAY );
\r
116 g2d.setColor( autoscroll ? AUTOSCROLL_ON : AUTOSCROLL_OFF );
\r
117 g2d.setFont( GridUtil.RULER_FONT );
\r
118 String txt = !autoscroll ? (manualscale ? "*" : "Auto-scroll off") : (manualscale ? "" : "Auto-scroll on");
\r
120 // g2d.drawString(txt, 0.f, (float)getHeight() + 12.f );
\r
122 g2d.drawString(txt, (float) getWidth()+20, 20.f );
\r
125 g2d.setPaint(Color.GRAY);
\r
126 g2d.setStroke( GridUtil.RULER_LINE_STROKE );
\r
127 GridUtil.paintHorizontalRuler(
\r
136 * This method sets iFrom and iEnd values.
\r
137 * Read reads values from ItemNodes.
\r
138 * So it is good idea to call {@link ItemNode#readMinMaxFromEnd()} first.
\r
140 public void setKnownFromEnd() {
\r
141 TrendNode trendNode = (TrendNode) getParent();
\r
143 iFrom = Double.MAX_VALUE;
\r
144 iEnd = -Double.MAX_VALUE;
\r
145 for (ItemNode item : trendNode.allItems) {
\r
146 if ( !Double.isNaN(item.from) ) iFrom = Math.min(iFrom, item.from);
\r
147 if ( !Double.isNaN(item.end ) ) iEnd = Math.max(iEnd , item.end );
\r
149 // Scale to 0..10 if there is no data
\r
150 if (iFrom == Double.MAX_VALUE && iEnd == -Double.MAX_VALUE) {
\r
157 * If zoomed, do nothing.
\r
158 * If not zoomed, set from and end according to TrendSpec's time window settings.
\r
160 public boolean autoscale() {
\r
161 if (!autoscroll) return false;
\r
164 TrendNode trendNode = (TrendNode) getParent();
\r
165 TrendSpec spec = trendNode.spec;
\r
167 double nFrom = from;
\r
170 TimeWindow timeWindow = spec.viewProfile.timeWindow;
\r
171 double len = timeWindow.timeWindowLength != null ? timeWindow.timeWindowLength : iEnd-iFrom;
\r
173 if (timeWindow.timeWindowStart != null) {
\r
175 if (timeWindow.timeWindowIncrement != null && timeWindow.timeWindowLength==null) {
\r
176 nFrom = timeWindow.timeWindowStart + basetime;
\r
178 nEnd = nFrom + 1.0;
\r
180 len = Math.max(0, iEnd-nFrom);
\r
181 double f = (100-timeWindow.timeWindowIncrement) / 100;
\r
183 double x = Math.log( len ) / Math.log( b );
\r
184 x = Math.ceil( x );
\r
185 x = Math.pow(b, x);
\r
189 nFrom = timeWindow.timeWindowStart + basetime;
\r
190 nEnd = nFrom + len;
\r
194 if (timeWindow.timeWindowIncrement == null) {
\r
195 nFrom = iEnd - len;
\r
198 nEnd += len * 0.02;
\r
202 if (timeWindow.timeWindowLength != null) {
\r
203 double f = timeWindow.timeWindowIncrement / 100;
\r
204 double fraction = len * f;
\r
206 nEnd = Math.floor( (iEnd +fraction)/ fraction ) * fraction;
\r
207 nFrom = nEnd - len;
\r
209 double diff = iFrom-nFrom;
\r
214 if (Double.isInfinite(nEnd)) {
\r
219 nEnd += len * 0.02;
\r
222 double f = (100-timeWindow.timeWindowIncrement) / 100;
\r
224 double x = Math.log( len ) / Math.log( b );
\r
225 x = Math.ceil( x );
\r
226 x = Math.pow(b, x);
\r
233 if (nFrom>nEnd) nFrom = nEnd;
\r
236 return setFromEnd(nFrom, nEnd);
\r
239 public void translate(double dx) {
\r
242 autoscroll = false;
\r
247 * Convert x position in rulers coordinate space to time value.
\r
248 * This function does not apply basetime. To apply basetime deduct it from
\r
254 public double toTime( double x ) {
\r
255 double sx = (end-from) / getWidth();
\r
256 return from + x*sx;
\r
259 public double toX( double time ) {
\r
260 double sx = (end-from) / getWidth();
\r
261 return (time-from) / sx;
\r
264 public void zoomIn(double x, double width) {
\r
265 autoscroll = false;
\r
267 double sx = (end-from) / getWidth();
\r
268 double newFrom = from + x*sx;
\r
269 double newEnd = from + (x+width)*sx;
\r
276 public void zoomOut() {
\r
283 public double unitsPerPixel() {
\r
284 return (end-from) / getWidth();
\r
288 * @return the current ending sample time calculated from all visible chart
\r
291 public double getItemEndTime() {
\r
295 public interface TimeWindowListener {
\r
296 void onNewWindow(double from, double end, double sx);
\r