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