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