1 /*****************************************************************************
2 * Copyright (c) 2007, 2014 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
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 *****************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
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
;
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
;
41 * Implementation of the scale for the time graph view.
43 * This goes above the "gantt chart" area.
46 * @author Alvaro Sanchez-Leon
47 * @author Patrick Tasse
49 public class TimeGraphScale
extends TimeGraphBaseControl
implements
50 MouseListener
, MouseMoveListener
{
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
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);
66 private static final Calendar GREGORIAN_CALENDAR
= Calendar
.getInstance();
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();
83 private static final int DRAG_EXTERNAL
= -1;
84 private static final int NO_BUTTON
= 0;
85 private static final int LEFT_BUTTON
= 1;
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
;
97 * Standard constructor
100 * The parent composite object
102 * The color scheme to use
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();
113 public void dispose() {
114 TmfSignalManager
.deregister(this);
119 * Assign the time provider for this scale
121 * @param timeProvider
122 * The provider to use
124 public void setTimeProvider(ITimeDataProvider timeProvider
) {
125 fTimeProvider
= timeProvider
;
129 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
130 return super.computeSize(wHint
, fHeight
, changed
);
134 * Set the height of the scale
139 public void setHeight(int height
) {
140 this.fHeight
= height
;
144 * Set the drag range to paint decorators
147 * The begin x-coordinate
149 * The end x-coordinate
152 public void setDragRange(int begin
, int end
) {
153 if (NO_BUTTON
== fDragState
|| DRAG_EXTERNAL
== fDragState
) {
154 fDragX0
= begin
- fTimeProvider
.getNameSpace();
155 fDragX
= end
- fTimeProvider
.getNameSpace();
156 if (begin
>= 0 || end
>= 0) {
157 fDragState
= DRAG_EXTERNAL
;
159 fDragState
= NO_BUTTON
;
165 private long calcTimeDelta(int width
, double pixelsPerNanoSec
) {
167 double minDelta
= (pixelsPerNanoSec
== 0) ? YEAR_IN_NS
: width
/ pixelsPerNanoSec
;
169 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
170 if (minDelta
> 6 * MONTH_IN_NS
) {
172 } else if (minDelta
> 3 * MONTH_IN_NS
) {
173 unit
= 6 * MONTH_IN_NS
;
174 } else if (minDelta
> 10 * DAY_IN_NS
) {
176 } else if (minDelta
> 12 * HOUR_IN_NS
) {
178 } else if (minDelta
> 3 * HOUR_IN_NS
) {
179 unit
= 6 * HOUR_IN_NS
;
180 } else if (minDelta
> 30 * MIN_IN_NS
) {
182 } else if (minDelta
> 10 * MIN_IN_NS
) {
183 unit
= 15 * MIN_IN_NS
;
184 } else if (minDelta
> 30 * SEC_IN_NS
) {
186 } else if (minDelta
> 20 * SEC_IN_NS
) {
187 unit
= 30 * SEC_IN_NS
;
188 } else if (minDelta
<= 1) {
193 double log
= Math
.log10(minDelta
/ unit
);
194 long pow10
= (long) log
;
195 double remainder
= log
- pow10
;
196 if (remainder
< LOG10_1
) {
197 timeDelta
= (long) Math
.pow(10, pow10
) * unit
;
198 } else if (remainder
< LOG10_2
) {
199 timeDelta
= 2 * (long) Math
.pow(10, pow10
) * unit
;
200 } else if (remainder
< LOG10_3
&& unit
>= HOUR_IN_NS
&& unit
< YEAR_IN_NS
) {
201 timeDelta
= 3 * (long) Math
.pow(10, pow10
) * unit
;
202 } else if (remainder
< LOG10_5
) {
203 timeDelta
= 5 * (long) Math
.pow(10, pow10
) * unit
;
205 timeDelta
= 10 * (long) Math
.pow(10, pow10
) * unit
;
207 if (timeDelta
<= 0) {
213 TimeDraw
getTimeDraw(long timeDelta
) {
215 if (fTimeProvider
!= null) {
217 if (fTimeProvider
.getTimeFormat() == TimeFormat
.CALENDAR
) {
218 if (timeDelta
>= YEAR_IN_NS
) {
219 timeDraw
= TIMEDRAW_ABS_YEAR
;
220 } else if (timeDelta
>= MONTH_IN_NS
) {
221 timeDraw
= TIMEDRAW_ABS_MONTH
;
222 } else if (timeDelta
>= DAY_IN_NS
) {
223 timeDraw
= TIMEDRAW_ABS_DAY
;
224 } else if (timeDelta
>= HOUR_IN_NS
) {
225 timeDraw
= TIMEDRAW_ABS_HRS
;
226 } else if (timeDelta
>= MIN_IN_NS
) {
227 timeDraw
= TIMEDRAW_ABS_MIN
;
228 } else if (timeDelta
>= SEC_IN_NS
) {
229 timeDraw
= TIMEDRAW_ABS_SEC
;
230 } else if (timeDelta
>= MILLISEC_IN_NS
) {
231 timeDraw
= TIMEDRAW_ABS_MILLISEC
;
232 } else if (timeDelta
>= MICROSEC_IN_NS
) {
233 timeDraw
= TIMEDRAW_ABS_MICROSEC
;
235 timeDraw
= TIMEDRAW_ABS_NANOSEC
;
238 } else if (fTimeProvider
.getTimeFormat() == TimeFormat
.NUMBER
) {
239 timeDraw
= TIMEDRAW_NUMBER
;
244 if (timeDelta
>= SEC_IN_NS
) {
245 timeDraw
= TIMEDRAW_SEC
;
246 } else if (timeDelta
>= MILLISEC_IN_NS
) {
247 timeDraw
= TIMEDRAW_MILLISEC
;
248 } else if (timeDelta
>= MICROSEC_IN_NS
) {
249 timeDraw
= TIMEDRAW_MICROSEC
;
251 timeDraw
= TIMEDRAW_NANOSEC
;
257 void paint(Rectangle rect
, PaintEvent e
) {
259 if (fIsInUpdate
|| null == fTimeProvider
) {
264 gc
.fillRectangle(rect
);
266 long time0
= fTimeProvider
.getTime0();
267 long time1
= fTimeProvider
.getTime1();
268 int leftSpace
= fTimeProvider
.getNameSpace();
269 int timeSpace
= fTimeProvider
.getTimeSpace();
271 gc
.setBackground(getColorScheme().getColor(TimeGraphColorScheme
.TOOL_BACKGROUND
));
272 gc
.setForeground(getColorScheme().getColor(TimeGraphColorScheme
.TOOL_FOREGROUND
));
273 Rectangle rect0
= new Rectangle(0, 0, 0, 0);
274 Utils
.init(rect0
, rect
);
276 // draw top left area
277 rect0
.width
= leftSpace
;
280 Rectangle absHeaderRect
= new Rectangle(rect0
.x
, rect0
.y
, rect0
.width
, rect0
.height
);
284 // prepare and draw right rect of the timescale
285 rect0
.x
+= leftSpace
;
286 rect0
.width
= rect
.width
- leftSpace
;
288 // draw bottom border and erase all other area
289 gc
.drawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
- 1,
290 rect
.y
+ rect
.height
- 1);
292 gc
.fillRectangle(rect0
);
294 if (time1
<= time0
|| timeSpace
< 2) {
298 int numDigits
= calculateDigits(time0
, time1
);
300 int labelWidth
= gc
.getCharWidth('0') * numDigits
;
301 double pixelsPerNanoSec
= (timeSpace
<= RIGHT_MARGIN
) ?
0 :
302 (double) (timeSpace
- RIGHT_MARGIN
) / (time1
- time0
);
303 long timeDelta
= calcTimeDelta(labelWidth
, pixelsPerNanoSec
);
305 TimeDraw timeDraw
= getTimeDraw(timeDelta
);
307 // draw range decorators
308 if (DRAG_EXTERNAL
== fDragState
) {
309 int x1
= leftSpace
+ Math
.min(fDragX0
, fDragX
);
310 int x2
= leftSpace
+ Math
.max(fDragX0
, fDragX
);
311 drawRangeDecorators(rect0
, gc
, x1
, x2
);
315 long selectionBegin
= fTimeProvider
.getSelectionBegin();
316 long selectionEnd
= fTimeProvider
.getSelectionEnd();
317 x1
= leftSpace
+ (int) ((selectionBegin
- time0
) * pixelsPerNanoSec
);
318 x2
= leftSpace
+ (int) ((selectionEnd
- time0
) * pixelsPerNanoSec
);
319 drawRangeDecorators(rect0
, gc
, x1
, x2
);
322 if (rect0
.isEmpty()) {
326 // draw time scale ticks
328 rect0
.height
= rect
.height
- 4;
329 rect0
.width
= labelWidth
;
332 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
333 time
= floorToCalendar(time0
, timeDelta
);
335 time
= (time0
/ timeDelta
) * timeDelta
;
341 int y
= rect0
.y
+ rect0
.height
;
343 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
344 timeDraw
.drawAbsHeader(gc
, time
, absHeaderRect
);
348 int x
= rect
.x
+ leftSpace
+ (int) (Math
.floor((time
- time0
) * pixelsPerNanoSec
));
349 if (x
>= rect
.x
+ leftSpace
+ rect
.width
- rect0
.width
) {
352 if (x
>= rect
.x
+ leftSpace
) {
353 gc
.drawLine(x
, y
, x
, y
+ 4);
355 if (x
+ rect0
.width
<= rect
.x
+ rect
.width
) {
356 timeDraw
.draw(gc
, time
, rect0
);
359 if (pixelsPerNanoSec
== 0 || time
> Long
.MAX_VALUE
- timeDelta
|| timeDelta
== 0) {
362 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
363 if (timeDelta
>= YEAR_IN_NS
) {
364 long millis
= time
/ MILLISEC_IN_NS
;
365 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
366 GREGORIAN_CALENDAR
.add(Calendar
.YEAR
, (int) (timeDelta
/ YEAR_IN_NS
));
367 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
368 time
= millis
* MILLISEC_IN_NS
;
369 } else if (timeDelta
>= MONTH_IN_NS
) {
370 long millis
= time
/ MILLISEC_IN_NS
;
371 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
372 GREGORIAN_CALENDAR
.add(Calendar
.MONTH
, (int) (timeDelta
/ MONTH_IN_NS
));
373 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
374 time
= millis
* MILLISEC_IN_NS
;
375 } else if (timeDelta
>= DAY_IN_NS
) {
376 long millis
= time
/ MILLISEC_IN_NS
;
377 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
378 GREGORIAN_CALENDAR
.add(Calendar
.DAY_OF_MONTH
, (int) (timeDelta
/ DAY_IN_NS
));
379 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
380 time
= millis
* MILLISEC_IN_NS
;
390 private static void drawRangeDecorators(Rectangle rect
, GC gc
, int x1
, int x2
) {
391 int y1
= rect
.y
+ rect
.height
- 9;
392 int y2
= rect
.y
+ rect
.height
- 5;
393 int ym
= (y1
+ y2
) / 2;
396 gc
.drawLine(x1
- 3, y1
, x1
- 3, y2
);
397 gc
.drawLine(x1
- 4, y1
, x1
- 2, y1
);
398 gc
.drawLine(x1
, y1
, x1
, y2
);
400 if (x2
>= rect
.x
&& x2
- x1
> 3) {
402 gc
.drawLine(x2
- 2, y1
, x2
- 2, y2
);
403 gc
.drawLine(x2
- 3, y1
, x2
- 1, y1
);
405 if (x2
>= rect
.x
&& x2
- x1
> 0) {
406 gc
.drawLine(x2
+ 1, y1
, x2
+ 3, y1
);
407 gc
.drawLine(x2
+ 3, y1
, x2
+ 3, ym
);
408 gc
.drawLine(x2
+ 1, ym
, x2
+ 3, ym
);
409 gc
.drawLine(x2
+ 1, ym
, x2
+ 1, y2
);
410 gc
.drawLine(x2
+ 1, y2
, x2
+ 3, y2
);
414 private static long floorToCalendar(long time
, long timeDelta
) {
417 if (timeDelta
>= YEAR_IN_NS
) {
418 GREGORIAN_CALENDAR
.setTime(new Date(ret
/ MILLISEC_IN_NS
));
419 int year
= GREGORIAN_CALENDAR
.get(Calendar
.YEAR
);
420 int yearDelta
= (int) (timeDelta
/ YEAR_IN_NS
);
421 year
= (year
/ yearDelta
) * yearDelta
;
422 GREGORIAN_CALENDAR
.set(Calendar
.YEAR
, year
);
423 GREGORIAN_CALENDAR
.set(Calendar
.MONTH
, 0); // January 1st of year
424 GREGORIAN_CALENDAR
.set(Calendar
.DAY_OF_MONTH
, 1);
425 GREGORIAN_CALENDAR
.set(Calendar
.HOUR_OF_DAY
, 0);
426 GREGORIAN_CALENDAR
.set(Calendar
.MINUTE
, 0);
427 GREGORIAN_CALENDAR
.set(Calendar
.SECOND
, 0);
428 GREGORIAN_CALENDAR
.set(Calendar
.MILLISECOND
, 0);
429 ret
= GREGORIAN_CALENDAR
.getTimeInMillis() * MILLISEC_IN_NS
;
430 } else if (timeDelta
>= MONTH_IN_NS
) {
431 GREGORIAN_CALENDAR
.setTime(new Date(ret
/ MILLISEC_IN_NS
));
432 int month
= GREGORIAN_CALENDAR
.get(Calendar
.MONTH
);
433 int monthDelta
= (int) (timeDelta
/ MONTH_IN_NS
);
434 month
= (month
/ monthDelta
) * monthDelta
;
435 GREGORIAN_CALENDAR
.set(Calendar
.MONTH
, month
);
436 GREGORIAN_CALENDAR
.set(Calendar
.DAY_OF_MONTH
, 1); // 1st of month
437 GREGORIAN_CALENDAR
.set(Calendar
.HOUR_OF_DAY
, 0);
438 GREGORIAN_CALENDAR
.set(Calendar
.MINUTE
, 0);
439 GREGORIAN_CALENDAR
.set(Calendar
.SECOND
, 0);
440 GREGORIAN_CALENDAR
.set(Calendar
.MILLISECOND
, 0);
441 ret
= GREGORIAN_CALENDAR
.getTimeInMillis() * MILLISEC_IN_NS
;
443 long offset
= GREGORIAN_CALENDAR
.getTimeZone().getOffset(ret
/ MILLISEC_IN_NS
) * MILLISEC_IN_NS
;
445 ret
= (ret
/ timeDelta
) * timeDelta
;
451 private int calculateDigits(long time0
, long time1
) {
453 long timeRange
= time1
- time0
;
455 if (fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
456 // Calculate the number of digits to represent the minutes provided
460 if (timeRange
< 10000) {
461 // HH:11:222:333:444__
463 } else if (timeRange
< 10000000) {
468 long sec
= time1
/ SEC_IN_NS
;
469 numDigits
= Long
.toString(sec
).length();
470 int thousandGroups
= (numDigits
- 1) / 3;
471 numDigits
+= thousandGroups
;
472 numDigits
+= 12; // .000 000 000
479 public void mouseDown(MouseEvent e
) {
480 getParent().setFocus();
481 if (fDragState
== NO_BUTTON
&& null != fTimeProvider
) {
482 int x
= e
.x
- fTimeProvider
.getNameSpace();
483 if (LEFT_BUTTON
== e
.button
&& x
> 0) {
485 fDragState
= LEFT_BUTTON
;
489 } else if (x
> getSize().x
- fTimeProvider
.getNameSpace()) {
490 x
= getSize().x
- fTimeProvider
.getNameSpace();
494 fTime0bak
= fTimeProvider
.getTime0();
495 fTime1bak
= fTimeProvider
.getTime1();
500 public void mouseUp(MouseEvent e
) {
501 if (e
.button
== LEFT_BUTTON
&& fDragState
== LEFT_BUTTON
) {
503 fDragState
= NO_BUTTON
;
505 // Notify time provider to check the need for listener notification
506 if (fDragX
!= fDragX0
&& fTimeProvider
.getTime0() != fTimeProvider
.getTime1()) {
507 fTimeProvider
.setStartFinishTimeNotify(fTimeProvider
.getTime0(), fTimeProvider
.getTime1());
513 public void mouseMove(MouseEvent e
) {
514 if (fDragX0
< 0 || fDragState
== NO_BUTTON
|| fTimeProvider
== null) {
517 Point size
= getSize();
518 int leftSpace
= fTimeProvider
.getNameSpace();
519 int x
= e
.x
- leftSpace
;
520 if (LEFT_BUTTON
== fDragState
) {
521 if (x
> 0 && size
.x
> leftSpace
&& fDragX
!= x
) {
523 if (fTimeProvider
.getTime0() == fTimeProvider
.getTime1()) {
526 long interval
= (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX0
/ fDragX
));
527 if (interval
== Long
.MAX_VALUE
) {
528 fTimeProvider
.setStartFinishTime(fTime0bak
, Long
.MAX_VALUE
);
530 long time1
= fTime0bak
+ (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX0
/ fDragX
));
531 fTimeProvider
.setStartFinishTime(fTime0bak
, time1
);
538 public void mouseDoubleClick(MouseEvent e
) {
539 if (e
.button
== 1 && null != fTimeProvider
&& fTimeProvider
.getTime0() != fTimeProvider
.getTime1() && (e
.stateMask
& SWT
.BUTTON_MASK
) == 0) {
540 fTimeProvider
.resetStartFinishTime();
541 fTimeProvider
.notifyStartFinishTime();
542 fTime0bak
= fTimeProvider
.getTime0();
543 fTime1bak
= fTimeProvider
.getTime1();
548 * Update the display to use the updated timestamp format
550 * @param signal the incoming signal
554 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal
) {
555 TimeDraw
.updateTimeZone();
556 Utils
.updateTimeZone();
561 abstract class TimeDraw
{
562 protected static final long MICROSEC_IN_NS
= 1000;
563 protected static final long MILLISEC_IN_NS
= 1000000;
564 protected static final long MILLISEC_IN_US
= 1000;
565 protected static final long SEC_IN_NS
= 1000000000;
566 protected static final long SEC_IN_MS
= 1000;
567 private static final String S
= "" ; //$NON-NLS-1$
568 private static final String S0
= "0" ; //$NON-NLS-1$
569 private static final String S00
= "00"; //$NON-NLS-1$
570 protected static final long PAD_1000
= 1000;
571 protected static final SimpleDateFormat SEC_FORMAT_HEADER
= new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
572 protected static final SimpleDateFormat SEC_FORMAT
= new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
573 protected static final SimpleDateFormat MIN_FORMAT_HEADER
= new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
574 protected static final SimpleDateFormat MIN_FORMAT
= new SimpleDateFormat("HH:mm"); //$NON-NLS-1$
575 protected static final SimpleDateFormat HOURS_FORMAT_HEADER
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
576 protected static final SimpleDateFormat HOURS_FORMAT
= new SimpleDateFormat("MMM dd HH:mm"); //$NON-NLS-1$
577 protected static final SimpleDateFormat DAY_FORMAT_HEADER
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
578 protected static final SimpleDateFormat DAY_FORMAT
= new SimpleDateFormat("MMM dd"); //$NON-NLS-1$
579 protected static final SimpleDateFormat MONTH_FORMAT
= new SimpleDateFormat("yyyy MMM"); //$NON-NLS-1$
580 protected static final SimpleDateFormat YEAR_FORMAT
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
582 protected static final SimpleDateFormat formatArray
[] = {
583 SEC_FORMAT
, SEC_FORMAT_HEADER
, MIN_FORMAT
, MIN_FORMAT_HEADER
,
584 HOURS_FORMAT
, HOURS_FORMAT_HEADER
, DAY_FORMAT
, DAY_FORMAT_HEADER
, MONTH_FORMAT
, YEAR_FORMAT
588 * Updates the timezone using the preferences.
590 public static void updateTimeZone() {
591 final TimeZone timeZone
= TmfTimePreferences
.getInstance().getTimeZone();
592 for (SimpleDateFormat sdf
: formatArray
) {
593 sdf
.setTimeZone(timeZone
);
597 static String
sep(long n
) {
598 StringBuilder retVal
= new StringBuilder();
599 String s
= Long
.toString(n
);
600 for (int i
= 0; i
< s
.length(); i
++) {
601 int pos
= s
.length() - i
- 1;
602 retVal
.append(s
.charAt(i
));
603 if (pos
% 3 == 0 && pos
!= 0) {
607 return retVal
.toString();
610 static String
pad(long n
) {
614 } else if (n
< 100) {
622 public abstract void draw(GC gc
, long time
, Rectangle rect
);
625 * Override to draw absolute time header. This is for the time information
626 * not shown in the draw of each tick
632 * @param absHeaderRect
635 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle absHeaderRect
) {
639 class TimeDrawSec
extends TimeDraw
{
641 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
642 long sec
= nanosec
/ SEC_IN_NS
;
643 Utils
.drawText(gc
, sep(sec
), rect
, true);
647 class TimeDrawMillisec
extends TimeDraw
{
649 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
650 long millisec
= nanosec
/ MILLISEC_IN_NS
;
651 long ms
= millisec
% PAD_1000
;
652 long sec
= millisec
/ SEC_IN_MS
;
653 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
), rect
, true); //$NON-NLS-1$
657 class TimeDrawMicrosec
extends TimeDraw
{
659 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
660 long microsec
= nanosec
/ MICROSEC_IN_NS
;
661 long us
= microsec
% PAD_1000
;
662 long millisec
= microsec
/ MILLISEC_IN_US
;
663 long ms
= millisec
% PAD_1000
;
664 long sec
= millisec
/ SEC_IN_MS
;
665 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
) + " " + pad(us
), rect
, true); //$NON-NLS-1$ //$NON-NLS-2$
669 class TimeDrawNanosec
extends TimeDraw
{
671 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
672 long ns
= nanosec
% PAD_1000
;
673 long microsec
= nanosec
/ MICROSEC_IN_NS
;
674 long us
= microsec
% PAD_1000
;
675 long millisec
= microsec
/ MILLISEC_IN_US
;
676 long ms
= millisec
% PAD_1000
;
677 long sec
= millisec
/ SEC_IN_MS
;
678 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
) + " " + pad(us
) + " " + pad(ns
), rect
, true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
682 class TimeDrawAbsYear
extends TimeDraw
{
684 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
685 String stime
= YEAR_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
686 Utils
.drawText(gc
, stime
, rect
, true);
690 class TimeDrawAbsMonth
extends TimeDraw
{
692 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
693 String stime
= MONTH_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
694 Utils
.drawText(gc
, stime
, rect
, true);
698 class TimeDrawAbsDay
extends TimeDraw
{
700 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
701 String stime
= DAY_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
702 Utils
.drawText(gc
, stime
, rect
, true);
706 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
707 String header
= DAY_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
708 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
709 if (headerwidth
<= rect
.width
) {
710 rect
.x
+= (rect
.width
- headerwidth
);
711 Utils
.drawText(gc
, header
, rect
, true);
716 class TimeDrawAbsHrs
extends TimeDraw
{
718 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
719 String stime
= HOURS_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
720 Utils
.drawText(gc
, stime
, rect
, true);
724 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
725 String header
= HOURS_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
726 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
727 if (headerwidth
<= rect
.width
) {
728 rect
.x
+= (rect
.width
- headerwidth
);
729 Utils
.drawText(gc
, header
, rect
, true);
734 class TimeDrawAbsMin
extends TimeDraw
{
736 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
737 String stime
= MIN_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
738 Utils
.drawText(gc
, stime
, rect
, true);
742 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
743 String header
= MIN_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
744 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
745 if (headerwidth
<= rect
.width
) {
746 rect
.x
+= (rect
.width
- headerwidth
);
747 Utils
.drawText(gc
, header
, rect
, true);
752 class TimeDrawAbsSec
extends TimeDraw
{
754 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
755 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
756 Utils
.drawText(gc
, stime
, rect
, true);
760 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
761 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
762 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
763 if (headerwidth
<= rect
.width
) {
764 rect
.x
+= (rect
.width
- headerwidth
);
765 Utils
.drawText(gc
, header
, rect
, true);
770 class TimeDrawAbsMillisec
extends TimeDraw
{
772 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
773 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
774 String ns
= Utils
.formatNs(nanosec
, Resolution
.MILLISEC
);
776 Utils
.drawText(gc
, stime
+ "." + ns
, rect
, true); //$NON-NLS-1$
780 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
781 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
782 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
783 if (headerwidth
<= rect
.width
) {
784 rect
.x
+= (rect
.width
- headerwidth
);
785 Utils
.drawText(gc
, header
, rect
, true);
790 class TimeDrawAbsMicroSec
extends TimeDraw
{
792 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
793 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
794 String micr
= Utils
.formatNs(nanosec
, Resolution
.MICROSEC
);
795 Utils
.drawText(gc
, stime
+ "." + micr
, rect
, true); //$NON-NLS-1$
799 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
800 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
801 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
802 if (headerwidth
<= rect
.width
) {
803 rect
.x
+= (rect
.width
- headerwidth
);
804 Utils
.drawText(gc
, header
, rect
, true);
809 class TimeDrawAbsNanoSec
extends TimeDraw
{
811 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
812 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
813 String ns
= Utils
.formatNs(nanosec
, Resolution
.NANOSEC
);
814 Utils
.drawText(gc
, stime
+ "." + ns
, rect
, true); //$NON-NLS-1$
818 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
819 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
820 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
821 if (headerwidth
<= rect
.width
) {
822 rect
.x
+= (rect
.width
- headerwidth
);
823 Utils
.drawText(gc
, header
, rect
, true);
828 class TimeDrawNumber
extends TimeDraw
{
830 public void draw(GC gc
, long time
, Rectangle rect
) {
831 String stime
= NumberFormat
.getInstance().format(time
);
832 Utils
.drawText(gc
, stime
, rect
, true);