Commit | Line | Data |
---|---|---|
b0d3496e | 1 | /*****************************************************************************\r |
a5823d5f | 2 | * Copyright (c) 2007, 2008, 2010 Intel Corporation and others.\r |
b0d3496e ASL |
3 | * All rights reserved. This program and the accompanying materials\r |
4 | * are made available under the terms of the Eclipse Public License v1.0\r | |
5 | * which accompanies this distribution, and is available at\r | |
6 | * http://www.eclipse.org/legal/epl-v10.html\r | |
7 | *\r | |
8 | * Contributors:\r | |
9 | * Intel Corporation - Initial API and implementation\r | |
10 | * Ruslan A. Scherbakov, Intel - Initial API and implementation\r | |
11 | * Alvaro Sanchex-Leon - Udpated for TMF\r | |
12 | *\r | |
13 | * $Id: TimeScaleCtrl.java,v 1.5 2008/06/16 21:04:49 jkubasta Exp $ \r | |
14 | *****************************************************************************/\r | |
15 | \r | |
16 | package org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets;\r | |
17 | \r | |
18 | import java.text.SimpleDateFormat;\r | |
a5823d5f | 19 | import java.util.Calendar;\r |
b0d3496e | 20 | import java.util.Date;\r |
a5823d5f ASL |
21 | import java.util.GregorianCalendar;\r |
22 | import java.util.TimeZone;\r | |
b0d3496e ASL |
23 | \r |
24 | import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.Messages;\r | |
25 | import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.widgets.Utils.Resolution;\r | |
26 | import org.eclipse.swt.SWT;\r | |
27 | import org.eclipse.swt.events.MouseEvent;\r | |
28 | import org.eclipse.swt.events.MouseListener;\r | |
29 | import org.eclipse.swt.events.MouseMoveListener;\r | |
30 | import org.eclipse.swt.events.PaintEvent;\r | |
31 | import org.eclipse.swt.graphics.GC;\r | |
32 | import org.eclipse.swt.graphics.Point;\r | |
33 | import org.eclipse.swt.graphics.Rectangle;\r | |
34 | import org.eclipse.swt.widgets.Composite;\r | |
35 | \r | |
36 | public class TimeScaleCtrl extends TraceCtrl implements MouseListener,\r | |
37 | MouseMoveListener {\r | |
38 | \r | |
39 | public TimeScaleCtrl(Composite parent, TraceColorScheme colors) {\r | |
40 | super(parent, colors, SWT.NO_BACKGROUND | SWT.NO_FOCUS\r | |
41 | | SWT.DOUBLE_BUFFERED);\r | |
42 | addMouseListener(this);\r | |
43 | addMouseMoveListener(this);\r | |
44 | }\r | |
45 | \r | |
a5823d5f ASL |
46 | private static final long SEC_IN_NS = 1000000000;\r |
47 | private static final long MIN_IN_NS = 60 * SEC_IN_NS;\r | |
48 | private static final long HOUR_IN_NS = 60 * MIN_IN_NS;\r | |
49 | private static final long DAY_IN_NS = 24 * HOUR_IN_NS;\r | |
50 | private static final long MONTH_IN_NS = 31 * DAY_IN_NS; // upper limit\r | |
51 | private static final long YEAR_IN_NS = 366 * DAY_IN_NS; // upper limit\r | |
52 | \r | |
53 | private static final double LOG10_1 = Math.log10(1);\r | |
54 | private static final double LOG10_2 = Math.log10(2);\r | |
55 | private static final double LOG10_3 = Math.log10(3);\r | |
56 | private static final double LOG10_5 = Math.log10(5);\r | |
57 | \r | |
58 | private static final Calendar GREGORIAN_CALENDAR = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));\r | |
59 | \r | |
b0d3496e ASL |
60 | private ITimeDataProvider _timeProvider;\r |
61 | private int _dragState = 0;\r | |
62 | private int _dragX0 = 0;\r | |
63 | private int _dragX = 0;\r | |
64 | private long _time0bak;\r | |
65 | private long _time1bak;\r | |
66 | private boolean _isInUpdate;\r | |
67 | private Rectangle _rect0 = new Rectangle(0, 0, 0, 0);\r | |
a5823d5f | 68 | private int _height;\r |
b0d3496e ASL |
69 | \r |
70 | public void setTimeProvider(ITimeDataProvider timeProvider) {\r | |
71 | _timeProvider = timeProvider;\r | |
72 | }\r | |
73 | \r | |
74 | private long _timeDelta;\r | |
75 | \r | |
a5823d5f ASL |
76 | @Override\r |
77 | public Point computeSize(int wHint, int hHint, boolean changed) {\r | |
78 | return super.computeSize(wHint, _height, changed);\r | |
79 | }\r | |
80 | \r | |
81 | public void setHeight(int height) {\r | |
82 | this._height = height;\r | |
83 | }\r | |
84 | \r | |
85 | private void calcTimeDelta(int width, double pixelsPerNanoSec) {\r | |
86 | double minDelta = (double) ((pixelsPerNanoSec ==0) ? YEAR_IN_NS : width / pixelsPerNanoSec);\r | |
87 | long unit = 1;\r | |
88 | if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r | |
89 | if (minDelta > 6 * MONTH_IN_NS) {\r | |
90 | unit = YEAR_IN_NS;\r | |
91 | } else if (minDelta > 3 * MONTH_IN_NS) {\r | |
92 | unit = 6 * MONTH_IN_NS;\r | |
93 | } else if (minDelta > 10 * DAY_IN_NS) {\r | |
94 | unit = MONTH_IN_NS;\r | |
95 | } else if (minDelta > 12 * HOUR_IN_NS) {\r | |
96 | unit = DAY_IN_NS;\r | |
97 | } else if (minDelta > 3 * HOUR_IN_NS) {\r | |
98 | unit = 6 * HOUR_IN_NS;\r | |
99 | } else if (minDelta > 30 * MIN_IN_NS) {\r | |
100 | unit = HOUR_IN_NS;\r | |
101 | } else if (minDelta > 10 * MIN_IN_NS) {\r | |
102 | unit = 15 * MIN_IN_NS;\r | |
103 | } else if (minDelta > 30 * SEC_IN_NS) {\r | |
104 | unit = MIN_IN_NS;\r | |
105 | } else if (minDelta > 20 * SEC_IN_NS) {\r | |
106 | unit = 30 * SEC_IN_NS;\r | |
107 | }\r | |
108 | }\r | |
109 | double log = Math.log10((double) minDelta / unit);\r | |
110 | long pow10 = (long) log;\r | |
111 | double remainder = log - pow10;\r | |
112 | if (remainder < LOG10_1) {\r | |
113 | _timeDelta = (long) Math.pow(10, pow10) * unit;\r | |
114 | } else if (remainder < LOG10_2) {\r | |
115 | _timeDelta = 2 * (long) Math.pow(10, pow10) * unit;\r | |
116 | } else if (remainder < LOG10_3 && unit >= HOUR_IN_NS && unit < YEAR_IN_NS) {\r | |
117 | _timeDelta = 3 * (long) Math.pow(10, pow10) * unit;\r | |
118 | } else if (remainder < LOG10_5) {\r | |
119 | _timeDelta = 5 * (long) Math.pow(10, pow10) * unit;\r | |
120 | } else {\r | |
121 | _timeDelta = 10 * (long) Math.pow(10, pow10) * unit;\r | |
122 | }\r | |
123 | }\r | |
124 | \r | |
125 | private static TimeDraw TIMEDRAW_NANOSEC = new TimeDrawNanosec();\r | |
126 | private static TimeDraw TIMEDRAW_MICROSEC = new TimeDrawMicrosec();\r | |
127 | private static TimeDraw TIMEDRAW_MILLISEC = new TimeDrawMillisec();\r | |
128 | private static TimeDraw TIMEDRAW_SEC = new TimeDrawSec();\r | |
129 | private static TimeDraw TIMEDRAW_ABS_NANOSEC = new TimeDrawAbsNanoSec();\r | |
130 | private static TimeDraw TIMEDRAW_ABS_MICROSEC = new TimeDrawAbsMicroSec();\r | |
131 | private static TimeDraw TIMEDRAW_ABS_MILLISEC = new TimeDrawAbsMillisec();\r | |
132 | private static TimeDraw TIMEDRAW_ABS_SEC = new TimeDrawAbsSec();\r | |
133 | private static TimeDraw TIMEDRAW_ABS_MIN = new TimeDrawAbsMin();\r | |
134 | private static TimeDraw TIMEDRAW_ABS_HRS = new TimeDrawAbsHrs();\r | |
135 | private static TimeDraw TIMEDRAW_ABS_DAY = new TimeDrawAbsDay();\r | |
136 | private static TimeDraw TIMEDRAW_ABS_MONTH = new TimeDrawAbsMonth();\r | |
137 | private static TimeDraw TIMEDRAW_ABS_YEAR = new TimeDrawAbsYear();\r | |
b0d3496e ASL |
138 | \r |
139 | TimeDraw getTimeDraw(long timeDelta) {\r | |
140 | TimeDraw timeDraw;\r | |
a5823d5f ASL |
141 | if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r |
142 | if (timeDelta >= YEAR_IN_NS)\r | |
143 | timeDraw = TIMEDRAW_ABS_YEAR;\r | |
144 | else if (timeDelta >= MONTH_IN_NS)\r | |
145 | timeDraw = TIMEDRAW_ABS_MONTH;\r | |
146 | else if (timeDelta >= DAY_IN_NS)\r | |
147 | timeDraw = TIMEDRAW_ABS_DAY;\r | |
148 | else if (timeDelta >= HOUR_IN_NS)\r | |
149 | timeDraw = TIMEDRAW_ABS_HRS;\r | |
150 | else if (timeDelta >= MIN_IN_NS)\r | |
151 | timeDraw = TIMEDRAW_ABS_MIN;\r | |
152 | else if (timeDelta >= SEC_IN_NS)\r | |
153 | timeDraw = TIMEDRAW_ABS_SEC;\r | |
154 | else if (timeDelta >= 1000000)\r | |
155 | timeDraw = TIMEDRAW_ABS_MILLISEC;\r | |
156 | else if (timeDelta >= 1000)\r | |
157 | timeDraw = TIMEDRAW_ABS_MICROSEC;\r | |
158 | else\r | |
159 | timeDraw = TIMEDRAW_ABS_NANOSEC;\r | |
160 | return timeDraw;\r | |
b0d3496e ASL |
161 | }\r |
162 | if (timeDelta >= 1000000000)\r | |
a5823d5f | 163 | timeDraw = TIMEDRAW_SEC;\r |
b0d3496e | 164 | else if (timeDelta >= 1000000)\r |
a5823d5f | 165 | timeDraw = TIMEDRAW_MILLISEC;\r |
b0d3496e | 166 | else if (timeDelta >= 1000)\r |
a5823d5f | 167 | timeDraw = TIMEDRAW_MICROSEC;\r |
b0d3496e | 168 | else\r |
a5823d5f | 169 | timeDraw = TIMEDRAW_NANOSEC;\r |
b0d3496e ASL |
170 | return timeDraw;\r |
171 | }\r | |
172 | \r | |
4e3aa37d | 173 | @Override\r |
b0d3496e ASL |
174 | void paint(Rectangle rect, PaintEvent e) {\r |
175 | \r | |
176 | if (_isInUpdate || null == _timeProvider)\r | |
177 | return;\r | |
178 | \r | |
179 | GC gc = e.gc;\r | |
a5823d5f ASL |
180 | gc.fillRectangle(rect);\r |
181 | \r | |
b0d3496e ASL |
182 | if (null == _timeProvider) {\r |
183 | return;\r | |
184 | }\r | |
185 | \r | |
186 | long time0 = _timeProvider.getTime0();\r | |
187 | long time1 = _timeProvider.getTime1();\r | |
188 | long selectedTime = _timeProvider.getSelectedTime();\r | |
189 | int leftSpace = _timeProvider.getNameSpace();\r | |
190 | int timeSpace = _timeProvider.getTimeSpace();\r | |
a5823d5f ASL |
191 | \r |
192 | gc.setBackground(_colors.getColor(TraceColorScheme.TOOL_BACKGROUND));\r | |
193 | gc.setForeground(_colors.getColor(TraceColorScheme.TOOL_FOREGROUND));\r | |
b0d3496e ASL |
194 | Utils.init(_rect0, rect);\r |
195 | \r | |
196 | // draw top left area\r | |
197 | _rect0.width = leftSpace;\r | |
198 | _rect0.x += 4;\r | |
199 | _rect0.width -= 4;\r | |
200 | if (_rect0.width > 0) {\r | |
a5823d5f | 201 | Utils.drawText(gc, Messages._Timescale + ":", _rect0, true);\r |
b0d3496e | 202 | }\r |
a5823d5f ASL |
203 | int messageWidth = gc.stringExtent(Messages._Timescale + ":").x + 4;\r |
204 | Rectangle absHeaderRect = new Rectangle(_rect0.x + messageWidth, _rect0.y, _rect0.width - messageWidth, _rect0.height);\r | |
b0d3496e ASL |
205 | _rect0.x -= 4;\r |
206 | _rect0.width += 4;\r | |
a5823d5f | 207 | \r |
b0d3496e ASL |
208 | // prepare and draw right rect of the timescale\r |
209 | _rect0.x += leftSpace;\r | |
210 | _rect0.width = rect.width - leftSpace;\r | |
a5823d5f | 211 | \r |
b0d3496e ASL |
212 | // draw bottom border and erase all other area\r |
213 | gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1,\r | |
a5823d5f | 214 | rect.y + rect.height - 1);\r |
b0d3496e ASL |
215 | _rect0.height--;\r |
216 | gc.fillRectangle(_rect0);\r | |
a5823d5f ASL |
217 | \r |
218 | if (time1 <= time0 || timeSpace < 2) {\r | |
219 | return;\r | |
220 | }\r | |
221 | \r | |
222 | int numDigits = calculateDigits(time0, time1);\r | |
223 | \r | |
224 | int labelWidth = gc.getCharWidth('0') * numDigits;\r | |
225 | double pixelsPerNanoSec = (timeSpace <= 2) ? 0 :\r | |
226 | (double) (timeSpace - 2) / (time1 - time0); // 2 pixels less to make sure end time is visible\r | |
227 | calcTimeDelta(labelWidth, pixelsPerNanoSec);\r | |
228 | \r | |
229 | TimeDraw timeDraw = getTimeDraw(_timeDelta);\r | |
230 | \r | |
231 | // draw zoom rectangle\r | |
232 | if (3 == _dragState && null != _timeProvider) {\r | |
233 | if (_dragX0 < _dragX) {\r | |
234 | gc.drawRectangle(leftSpace + _dragX0, rect.y, _dragX - _dragX0 - 1, rect.height - 8);\r | |
235 | } else if (_dragX0 > _dragX) {\r | |
236 | gc.drawRectangle(leftSpace + _dragX, rect.y, _dragX0 - _dragX - 1, rect.height - 8);\r | |
237 | }\r | |
238 | }\r | |
b0d3496e ASL |
239 | \r |
240 | if (_rect0.isEmpty())\r | |
241 | return;\r | |
242 | \r | |
243 | // draw selected time\r | |
a5823d5f | 244 | int x = _rect0.x + (int) ((double)(selectedTime - time0) * pixelsPerNanoSec);\r |
b0d3496e ASL |
245 | if (x >= _rect0.x && x < _rect0.x + _rect0.width) {\r |
246 | gc.setForeground(_colors.getColor(TraceColorScheme.SELECTED_TIME));\r | |
247 | gc.drawLine(x, _rect0.y + _rect0.height - 6, x, _rect0.y\r | |
248 | + _rect0.height);\r | |
249 | gc\r | |
250 | .setForeground(_colors\r | |
251 | .getColor(TraceColorScheme.TOOL_FOREGROUND));\r | |
252 | }\r | |
253 | \r | |
254 | // draw time scale ticks\r | |
255 | _rect0.y = rect.y;\r | |
256 | _rect0.height = rect.height - 4;\r | |
257 | _rect0.width = labelWidth;\r | |
a5823d5f ASL |
258 | \r |
259 | long time;\r | |
260 | if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r | |
261 | time = floorToCalendar(time0, _timeDelta);\r | |
262 | } else {\r | |
263 | time = (long) (Math.ceil((double) time0 / _timeDelta) * _timeDelta);\r | |
264 | }\r | |
265 | \r | |
b0d3496e ASL |
266 | // long t = (long) (time * 1000000000);\r |
267 | int y = _rect0.y + _rect0.height;\r | |
a5823d5f ASL |
268 | \r |
269 | if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r | |
270 | timeDraw.drawAbsHeader(gc, time, absHeaderRect);\r | |
271 | }\r | |
272 | \r | |
b0d3496e | 273 | while (true) {\r |
a5823d5f | 274 | x = rect.x + leftSpace + (int) (Math.floor((time - time0) * pixelsPerNanoSec));\r |
b0d3496e ASL |
275 | if (x >= rect.x + leftSpace + rect.width - _rect0.width) {\r |
276 | break;\r | |
277 | }\r | |
278 | if (x >= rect.x + leftSpace) {\r | |
279 | gc.drawLine(x, y, x, y + 4);\r | |
280 | _rect0.x = x;\r | |
281 | if (x + _rect0.width <= rect.x + rect.width)\r | |
a5823d5f ASL |
282 | timeDraw.draw(gc, time, _rect0);\r |
283 | }\r | |
284 | if (pixelsPerNanoSec == 0 || time > Long.MAX_VALUE - _timeDelta) {\r | |
285 | break;\r | |
b0d3496e | 286 | }\r |
a5823d5f ASL |
287 | time += _timeDelta;\r |
288 | if (_timeProvider != null && _timeProvider.isCalendarFormat()) {\r | |
289 | if (_timeDelta >= YEAR_IN_NS) {\r | |
290 | GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r | |
291 | GREGORIAN_CALENDAR.set(Calendar.MONTH, 0); // January 1st of year\r | |
292 | GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1);\r | |
293 | time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r | |
294 | } else if (_timeDelta >= MONTH_IN_NS) {\r | |
295 | GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r | |
296 | GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1); // 1st of month\r | |
297 | time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r | |
298 | }\r | |
299 | }\r | |
b0d3496e ASL |
300 | }\r |
301 | }\r | |
302 | \r | |
a5823d5f ASL |
303 | private long floorToCalendar(long time, long timeDelta) {\r |
304 | if (_timeDelta >= YEAR_IN_NS) {\r | |
305 | GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r | |
306 | int year = GREGORIAN_CALENDAR.get(Calendar.YEAR);\r | |
307 | int yearDelta = (int) (timeDelta / YEAR_IN_NS);\r | |
308 | year = (year / yearDelta) * yearDelta;\r | |
309 | GREGORIAN_CALENDAR.set(Calendar.YEAR, year);\r | |
310 | GREGORIAN_CALENDAR.set(Calendar.MONTH, 0); // January 1st of year\r | |
311 | GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1);\r | |
312 | GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);\r | |
313 | GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);\r | |
314 | GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);\r | |
315 | GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);\r | |
316 | time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r | |
317 | } else if (_timeDelta >= MONTH_IN_NS) {\r | |
318 | GREGORIAN_CALENDAR.setTime(new Date(time / 1000000));\r | |
319 | int month = GREGORIAN_CALENDAR.get(Calendar.MONTH);\r | |
320 | int monthDelta = (int) (timeDelta / MONTH_IN_NS);\r | |
321 | month = (month / monthDelta) * monthDelta;\r | |
322 | GREGORIAN_CALENDAR.set(Calendar.MONTH, month);\r | |
323 | GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1); // 1st of month\r | |
324 | GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);\r | |
325 | GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);\r | |
326 | GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);\r | |
327 | GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);\r | |
328 | time = GREGORIAN_CALENDAR.getTimeInMillis() * 1000000;\r | |
329 | } else {\r | |
330 | time = (time / timeDelta) * timeDelta;\r | |
331 | }\r | |
332 | return time;\r | |
333 | }\r | |
334 | \r | |
b0d3496e ASL |
335 | private int calculateDigits(long time0, long time1) {\r |
336 | int numDigits = 5;\r | |
337 | long timeRange = time1 - time0;\r | |
338 | \r | |
339 | if (_timeProvider.isCalendarFormat()) {\r | |
340 | // Calculate the number of digits to represent the minutes provided\r | |
341 | // 11:222\r | |
342 | // HH:mm:ss\r | |
a5823d5f | 343 | numDigits += 8;\r |
b0d3496e ASL |
344 | if (timeRange < 10000) {\r |
345 | // HH:11:222:333:444__\r | |
346 | numDigits += 10;\r | |
347 | } else if (timeRange < 10000000) {\r | |
348 | // HH:11:222:333__\r | |
349 | numDigits += 6;\r | |
350 | }\r | |
351 | } else {\r | |
352 | // Calculate the number of digits to represent the minutes provided\r | |
353 | long min = (long) ((time1 * 1E-9) / 60); // to sec then to minutes\r | |
354 | String strMinutes = String.valueOf(min);\r | |
355 | // 11:222\r | |
356 | if (strMinutes != null) {\r | |
357 | numDigits += strMinutes.length();\r | |
358 | } else {\r | |
359 | numDigits += 2;\r | |
360 | }\r | |
361 | if (timeRange < 10000) {\r | |
362 | // 11:222:333:444__\r | |
363 | numDigits += 8;\r | |
364 | } else if (timeRange < 10000000) {\r | |
365 | // 11:222:333__\r | |
366 | numDigits += 4;\r | |
367 | }\r | |
368 | }\r | |
369 | \r | |
370 | // Trace.debug("timeRange: " + timeRange + " numDigits: " + numDigits);\r | |
371 | return numDigits;\r | |
372 | }\r | |
373 | \r | |
374 | public void mouseDown(MouseEvent e) {\r | |
a5823d5f ASL |
375 | if (_dragState == 0 && null != _timeProvider) {\r |
376 | if (1 == e.button) {\r | |
377 | setCapture(true);\r | |
378 | _dragState = 1;\r | |
379 | } else if (3 == e.button) {\r | |
380 | _dragState = 3;\r | |
381 | }\r | |
382 | int x = e.x - _timeProvider.getNameSpace();\r | |
383 | if (x < 0) {\r | |
384 | x = 0;\r | |
385 | } else if (x > getSize().x - _timeProvider.getNameSpace()) {\r | |
386 | x = getSize().x - _timeProvider.getNameSpace();\r | |
387 | }\r | |
388 | _dragX = _dragX0 = x;\r | |
389 | _time0bak = _timeProvider.getTime0();\r | |
390 | _time1bak = _timeProvider.getTime1();\r | |
391 | }\r | |
b0d3496e ASL |
392 | }\r |
393 | \r | |
394 | public void mouseUp(MouseEvent e) {\r | |
a5823d5f | 395 | if (e.button == 1 && _dragState == 1) {\r |
b0d3496e ASL |
396 | setCapture(false);\r |
397 | _dragState = 0;\r | |
a5823d5f ASL |
398 | } else if (e.button == 3 && _dragState == 3 && null != _timeProvider) {\r |
399 | _dragState = 0;\r | |
400 | if (_dragX0 == _dragX) {\r | |
b0d3496e ASL |
401 | return;\r |
402 | }\r | |
a5823d5f | 403 | int timeSpace = _timeProvider.getTimeSpace();\r |
b0d3496e ASL |
404 | int leftSpace = _timeProvider.getNameSpace();\r |
405 | int x = e.x - leftSpace;\r | |
a5823d5f | 406 | if (timeSpace > 0) {\r |
b0d3496e | 407 | _dragX = x;\r |
a5823d5f ASL |
408 | if (_dragX0 > _dragX) { // drag right to left\r |
409 | _dragX = _dragX0;\r | |
410 | _dragX0 = x;\r | |
411 | }\r | |
412 | long time0 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX0 / timeSpace));\r | |
413 | long time1 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX / timeSpace));\r | |
79a3a76e FC |
414 | \r |
415 | _timeProvider.setStartFinishTime(time0, time1);\r | |
a5823d5f ASL |
416 | _time0bak = _timeProvider.getTime0();\r |
417 | _time1bak = _timeProvider.getTime1();\r | |
b0d3496e ASL |
418 | }\r |
419 | }\r | |
71c964eb ASL |
420 | \r |
421 | // Notify time provider to check the need for listener notification\r | |
a5823d5f | 422 | _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r |
b0d3496e ASL |
423 | }\r |
424 | \r | |
425 | public void mouseMove(MouseEvent e) {\r | |
a5823d5f | 426 | if (_dragX0 < 0 || _dragState == 0) {\r |
b0d3496e ASL |
427 | return;\r |
428 | }\r | |
429 | Point size = getSize();\r | |
a5823d5f ASL |
430 | int leftSpace = _timeProvider.getNameSpace();\r |
431 | int timeSpace = _timeProvider.getTimeSpace();\r | |
432 | int x = e.x - leftSpace;\r | |
b0d3496e ASL |
433 | if (1 == _dragState && null != _timeProvider) {\r |
434 | if (x > 0 && size.x > leftSpace && _dragX != x) {\r | |
435 | _dragX = x;\r | |
a5823d5f | 436 | long time1 = _time0bak + (long) ((_time1bak - _time0bak) * ((double) _dragX0 / _dragX));\r |
b0d3496e ASL |
437 | _timeProvider.setStartFinishTime(_time0bak, time1);\r |
438 | }\r | |
a5823d5f ASL |
439 | } else if (3 == _dragState && null != _timeProvider) {\r |
440 | if (x < 0) {\r | |
441 | _dragX = 0;\r | |
442 | } else if (x > timeSpace) {\r | |
443 | _dragX = timeSpace;\r | |
444 | } else {\r | |
445 | _dragX = x;\r | |
446 | }\r | |
447 | redraw();\r | |
b0d3496e ASL |
448 | }\r |
449 | }\r | |
450 | \r | |
451 | public void mouseDoubleClick(MouseEvent e) {\r | |
452 | if (null != _timeProvider) {\r | |
453 | _timeProvider.resetStartFinishTime();\r | |
a5823d5f ASL |
454 | _time0bak = _timeProvider.getTime0();\r |
455 | _time1bak = _timeProvider.getTime1();\r | |
b0d3496e ASL |
456 | }\r |
457 | }\r | |
458 | }\r | |
459 | \r | |
460 | abstract class TimeDraw {\r | |
461 | static String S = ":";\r | |
462 | static String S0 = ":0";\r | |
463 | static String S00 = ":00";\r | |
a5823d5f ASL |
464 | protected static final SimpleDateFormat stimeformat = new SimpleDateFormat("HH:mm:ss");\r |
465 | protected static final SimpleDateFormat stimeformatheader = new SimpleDateFormat("yyyy MMM dd");\r | |
466 | protected static final SimpleDateFormat sminformat = new SimpleDateFormat("HH:mm");\r | |
467 | protected static final SimpleDateFormat sminformatheader = new SimpleDateFormat("yyyy MMM dd");\r | |
468 | protected static final SimpleDateFormat shrsformat = new SimpleDateFormat("MMM dd HH:mm");\r | |
469 | protected static final SimpleDateFormat shrsformatheader = new SimpleDateFormat("yyyy");\r | |
470 | protected static final SimpleDateFormat sdayformat = new SimpleDateFormat("MMM dd");\r | |
471 | protected static final SimpleDateFormat sdayformatheader = new SimpleDateFormat("yyyy");\r | |
472 | protected static final SimpleDateFormat smonthformat = new SimpleDateFormat("yyyy MMM");\r | |
473 | protected static final SimpleDateFormat syearformat = new SimpleDateFormat("yyyy");\r | |
474 | static {\r | |
475 | stimeformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
476 | stimeformatheader.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
477 | sminformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
478 | sminformatheader.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
479 | shrsformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
480 | shrsformatheader.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
481 | sdayformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
482 | sdayformatheader.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
483 | smonthformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
484 | syearformat.setTimeZone(TimeZone.getTimeZone("GMT"));\r | |
485 | }\r | |
b0d3496e ASL |
486 | \r |
487 | static String pad(long n) {\r | |
488 | String s = S;\r | |
489 | if (n < 10)\r | |
490 | s = S00;\r | |
491 | else if (n < 100)\r | |
492 | s = S0;\r | |
493 | return s + n;\r | |
494 | }\r | |
495 | \r | |
a5823d5f | 496 | public abstract void draw(GC gc, long time, Rectangle rect);\r |
b0d3496e | 497 | \r |
a5823d5f ASL |
498 | public void drawAbsHeader(GC gc, long time, Rectangle absHeaderRect) {\r |
499 | // Override to draw absolute time header\r | |
500 | // This is for the time information not shown in the draw of each tick\r | |
501 | }\r | |
502 | \r | |
b0d3496e ASL |
503 | public abstract String hint();\r |
504 | }\r | |
505 | \r | |
506 | class TimeDrawSec extends TimeDraw {\r | |
507 | static String _hint = "sec";\r | |
508 | \r | |
4e3aa37d | 509 | @Override\r |
b0d3496e ASL |
510 | public void draw(GC gc, long time, Rectangle rect) {\r |
511 | time /= 1000000000;\r | |
512 | Utils.drawText(gc, time + "", rect, true);\r | |
513 | }\r | |
514 | \r | |
4e3aa37d | 515 | @Override\r |
b0d3496e ASL |
516 | public String hint() {\r |
517 | return _hint;\r | |
518 | }\r | |
519 | }\r | |
520 | \r | |
521 | class TimeDrawMillisec extends TimeDraw {\r | |
522 | static String _hint = "s:ms";\r | |
523 | \r | |
4e3aa37d | 524 | @Override\r |
b0d3496e ASL |
525 | public void draw(GC gc, long time, Rectangle rect) {\r |
526 | time /= 1000000;\r | |
527 | long ms = time % 1000;\r | |
528 | time /= 1000;\r | |
529 | Utils.drawText(gc, time + pad(ms), rect, true);\r | |
530 | }\r | |
531 | \r | |
4e3aa37d | 532 | @Override\r |
b0d3496e ASL |
533 | public String hint() {\r |
534 | return _hint;\r | |
535 | }\r | |
536 | }\r | |
537 | \r | |
538 | class TimeDrawMicrosec extends TimeDraw {\r | |
539 | static String _hint = "s:ms:mcs";\r | |
540 | \r | |
4e3aa37d | 541 | @Override\r |
b0d3496e ASL |
542 | public void draw(GC gc, long time, Rectangle rect) {\r |
543 | time /= 1000;\r | |
544 | long mcs = time % 1000;\r | |
545 | time /= 1000;\r | |
546 | long ms = time % 1000;\r | |
547 | time /= 1000;\r | |
548 | Utils.drawText(gc, time + pad(ms) + pad(mcs), rect, true);\r | |
549 | }\r | |
550 | \r | |
4e3aa37d | 551 | @Override\r |
b0d3496e ASL |
552 | public String hint() {\r |
553 | return _hint;\r | |
554 | }\r | |
555 | }\r | |
556 | \r | |
557 | class TimeDrawNanosec extends TimeDraw {\r | |
558 | static String _hint = "s:ms:mcs:ns";\r | |
559 | \r | |
4e3aa37d | 560 | @Override\r |
b0d3496e ASL |
561 | public void draw(GC gc, long time, Rectangle rect) {\r |
562 | long ns = time % 1000;\r | |
563 | time /= 1000;\r | |
564 | long mcs = time % 1000;\r | |
565 | time /= 1000;\r | |
566 | long ms = time % 1000;\r | |
567 | time /= 1000;\r | |
568 | Utils.drawText(gc, time + pad(ms) + pad(mcs) + pad(ns), rect, true);\r | |
569 | }\r | |
570 | \r | |
4e3aa37d | 571 | @Override\r |
b0d3496e ASL |
572 | public String hint() {\r |
573 | return _hint;\r | |
574 | }\r | |
575 | }\r | |
576 | \r | |
a5823d5f ASL |
577 | class TimeDrawAbsYear extends TimeDraw {\r |
578 | static String _hint = "YYYY";\r | |
b0d3496e | 579 | \r |
a5823d5f ASL |
580 | @Override\r |
581 | public void draw(GC gc, long time, Rectangle rect) {\r | |
582 | String stime = syearformat.format(new Date((long) (time / 1000000)));\r | |
583 | Utils.drawText(gc, stime, rect, true);\r | |
584 | }\r | |
b0d3496e | 585 | \r |
a5823d5f ASL |
586 | @Override\r |
587 | public String hint() {\r | |
588 | return _hint;\r | |
589 | }\r | |
590 | }\r | |
591 | \r | |
592 | class TimeDrawAbsMonth extends TimeDraw {\r | |
593 | static String _hint = "YYYY Mmm";\r | |
594 | \r | |
595 | @Override\r | |
596 | public void draw(GC gc, long time, Rectangle rect) {\r | |
597 | String stime = smonthformat.format(new Date((long) (time / 1000000)));\r | |
598 | Utils.drawText(gc, stime, rect, true);\r | |
599 | }\r | |
600 | \r | |
601 | @Override\r | |
602 | public String hint() {\r | |
603 | return _hint;\r | |
604 | }\r | |
605 | }\r | |
606 | \r | |
607 | class TimeDrawAbsDay extends TimeDraw {\r | |
608 | static String _hint = "Mmm dd";\r | |
609 | \r | |
610 | @Override\r | |
611 | public void draw(GC gc, long time, Rectangle rect) {\r | |
612 | String stime = sdayformat.format(new Date((long) (time / 1000000)));\r | |
613 | Utils.drawText(gc, stime, rect, true);\r | |
614 | }\r | |
615 | \r | |
616 | @Override\r | |
617 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
618 | String header = sdayformatheader.format(new Date((long) (time / 1000000)));\r | |
619 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
620 | if (headerwidth <= rect.width) {\r | |
621 | rect.x += (rect.width - headerwidth);\r | |
622 | Utils.drawText(gc, header, rect, true);\r | |
623 | }\r | |
624 | }\r | |
625 | \r | |
626 | @Override\r | |
627 | public String hint() {\r | |
628 | return _hint;\r | |
629 | }\r | |
630 | }\r | |
631 | \r | |
632 | class TimeDrawAbsHrs extends TimeDraw {\r | |
633 | static String _hint = "Mmm dd HH:mm";\r | |
634 | \r | |
635 | @Override\r | |
636 | public void draw(GC gc, long time, Rectangle rect) {\r | |
637 | String stime = shrsformat.format(new Date((long) (time / 1000000)));\r | |
638 | Utils.drawText(gc, stime, rect, true);\r | |
639 | }\r | |
640 | \r | |
641 | @Override\r | |
642 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
643 | String header = shrsformatheader.format(new Date((long) (time / 1000000)));\r | |
644 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
645 | if (headerwidth <= rect.width) {\r | |
646 | rect.x += (rect.width - headerwidth);\r | |
647 | Utils.drawText(gc, header, rect, true);\r | |
648 | }\r | |
649 | }\r | |
650 | \r | |
651 | @Override\r | |
652 | public String hint() {\r | |
653 | return _hint;\r | |
654 | }\r | |
655 | }\r | |
656 | \r | |
657 | class TimeDrawAbsMin extends TimeDraw {\r | |
658 | static String _hint = "HH:mm";\r | |
659 | \r | |
660 | @Override\r | |
661 | public void draw(GC gc, long time, Rectangle rect) {\r | |
662 | String stime = sminformat.format(new Date((long) (time / 1000000)));\r | |
663 | Utils.drawText(gc, stime, rect, true);\r | |
664 | }\r | |
665 | \r | |
666 | @Override\r | |
667 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
668 | String header = sminformatheader.format(new Date((long) (time / 1000000)));\r | |
669 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
670 | if (headerwidth <= rect.width) {\r | |
671 | rect.x += (rect.width - headerwidth);\r | |
672 | Utils.drawText(gc, header, rect, true);\r | |
673 | }\r | |
674 | }\r | |
675 | \r | |
676 | \r | |
677 | @Override\r | |
678 | public String hint() {\r | |
679 | return _hint;\r | |
680 | }\r | |
681 | }\r | |
682 | \r | |
683 | class TimeDrawAbsSec extends TimeDraw {\r | |
684 | static String _hint = "HH:mm:ss";\r | |
685 | \r | |
686 | @Override\r | |
687 | public void draw(GC gc, long time, Rectangle rect) {\r | |
688 | String stime = stimeformat.format(new Date((long) (time / 1000000)));\r | |
689 | Utils.drawText(gc, stime, rect, true);\r | |
690 | }\r | |
691 | \r | |
692 | @Override\r | |
693 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
694 | String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r | |
695 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
696 | if (headerwidth <= rect.width) {\r | |
697 | rect.x += (rect.width - headerwidth);\r | |
698 | Utils.drawText(gc, header, rect, true);\r | |
699 | }\r | |
700 | }\r | |
701 | \r | |
702 | @Override\r | |
703 | public String hint() {\r | |
704 | return _hint;\r | |
705 | }\r | |
b0d3496e ASL |
706 | }\r |
707 | \r | |
708 | class TimeDrawAbsMillisec extends TimeDraw {\r | |
709 | static String _hint = "HH:ss:ms";\r | |
710 | \r | |
4e3aa37d | 711 | @Override\r |
b0d3496e | 712 | public void draw(GC gc, long time, Rectangle rect) {\r |
a5823d5f | 713 | String stime = stimeformat.format(new Date((long) (time / 1000000)));\r |
b0d3496e ASL |
714 | String ns = Utils.formatNs(time, Resolution.MILLISEC);\r |
715 | \r | |
716 | Utils.drawText(gc, stime + " " + ns, rect, true);\r | |
717 | }\r | |
718 | \r | |
a5823d5f ASL |
719 | @Override\r |
720 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
721 | String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r | |
722 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
723 | if (headerwidth <= rect.width) {\r | |
724 | rect.x += (rect.width - headerwidth);\r | |
725 | Utils.drawText(gc, header, rect, true);\r | |
726 | }\r | |
727 | }\r | |
728 | \r | |
4e3aa37d | 729 | @Override\r |
b0d3496e ASL |
730 | public String hint() {\r |
731 | return _hint;\r | |
732 | }\r | |
733 | }\r | |
734 | \r | |
735 | class TimeDrawAbsMicroSec extends TimeDraw {\r | |
736 | static String _hint = "HH:ss:ms:mcs";\r | |
737 | \r | |
4e3aa37d | 738 | @Override\r |
b0d3496e | 739 | public void draw(GC gc, long time, Rectangle rect) {\r |
a5823d5f | 740 | String stime = stimeformat.format(new Date((long) (time / 1000000)));\r |
b0d3496e ASL |
741 | String micr = Utils.formatNs(time, Resolution.MICROSEC);\r |
742 | Utils.drawText(gc, stime + " " + micr, rect, true);\r | |
743 | }\r | |
744 | \r | |
a5823d5f ASL |
745 | @Override\r |
746 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
747 | String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r | |
748 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
749 | if (headerwidth <= rect.width) {\r | |
750 | rect.x += (rect.width - headerwidth);\r | |
751 | Utils.drawText(gc, header, rect, true);\r | |
752 | }\r | |
753 | }\r | |
754 | \r | |
4e3aa37d | 755 | @Override\r |
b0d3496e ASL |
756 | public String hint() {\r |
757 | return _hint;\r | |
758 | }\r | |
759 | }\r | |
760 | \r | |
761 | class TimeDrawAbsNanoSec extends TimeDraw {\r | |
762 | static String _hint = "HH:ss:ms:mcs:ns";\r | |
763 | \r | |
4e3aa37d | 764 | @Override\r |
b0d3496e | 765 | public void draw(GC gc, long time, Rectangle rect) {\r |
a5823d5f | 766 | String stime = stimeformat.format(new Date((long) (time / 1000000)));\r |
b0d3496e ASL |
767 | String ns = Utils.formatNs(time, Resolution.NANOSEC);\r |
768 | Utils.drawText(gc, stime + " " + ns, rect, true);\r | |
769 | }\r | |
770 | \r | |
a5823d5f ASL |
771 | @Override\r |
772 | public void drawAbsHeader(GC gc, long time, Rectangle rect) {\r | |
773 | String header = stimeformatheader.format(new Date((long) (time / 1000000)));\r | |
774 | int headerwidth = gc.stringExtent(header).x + 4;\r | |
775 | if (headerwidth <= rect.width) {\r | |
776 | rect.x += (rect.width - headerwidth);\r | |
777 | Utils.drawText(gc, header, rect, true);\r | |
778 | }\r | |
779 | }\r | |
780 | \r | |
4e3aa37d | 781 | @Override\r |
b0d3496e ASL |
782 | public String hint() {\r |
783 | return _hint;\r | |
784 | }\r | |
785 | }\r |