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
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 *****************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
17 import java
.text
.NumberFormat
;
18 import java
.text
.SimpleDateFormat
;
19 import java
.util
.Calendar
;
20 import java
.util
.Date
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
24 import org
.eclipse
.swt
.SWT
;
25 import org
.eclipse
.swt
.events
.MouseEvent
;
26 import org
.eclipse
.swt
.events
.MouseListener
;
27 import org
.eclipse
.swt
.events
.MouseMoveListener
;
28 import org
.eclipse
.swt
.events
.PaintEvent
;
29 import org
.eclipse
.swt
.graphics
.GC
;
30 import org
.eclipse
.swt
.graphics
.Point
;
31 import org
.eclipse
.swt
.graphics
.Rectangle
;
32 import org
.eclipse
.swt
.widgets
.Composite
;
35 * Implementation of the scale for the time graph view.
37 * This goes above the "gantt chart" area.
40 * @author Alvaro Sanchez-Leon
41 * @author Patrick Tasse
43 public class TimeGraphScale
extends TimeGraphBaseControl
implements
44 MouseListener
, MouseMoveListener
{
46 private static final long MICROSEC_IN_NS
= 1000;
47 private static final long MILLISEC_IN_NS
= 1000000;
48 private static final long SEC_IN_NS
= 1000000000;
49 private static final long MIN_IN_NS
= 60 * SEC_IN_NS
;
50 private static final long HOUR_IN_NS
= 60 * MIN_IN_NS
;
51 private static final long DAY_IN_NS
= 24 * HOUR_IN_NS
;
52 private static final long MONTH_IN_NS
= 31 * DAY_IN_NS
; // upper limit
53 private static final long YEAR_IN_NS
= 366 * DAY_IN_NS
; // upper limit
55 private static final double LOG10_1
= Math
.log10(1);
56 private static final double LOG10_2
= Math
.log10(2);
57 private static final double LOG10_3
= Math
.log10(3);
58 private static final double LOG10_5
= Math
.log10(5);
60 private static final Calendar GREGORIAN_CALENDAR
= Calendar
.getInstance();
62 private static final TimeDraw TIMEDRAW_NANOSEC
= new TimeDrawNanosec();
63 private static final TimeDraw TIMEDRAW_MICROSEC
= new TimeDrawMicrosec();
64 private static final TimeDraw TIMEDRAW_MILLISEC
= new TimeDrawMillisec();
65 private static final TimeDraw TIMEDRAW_SEC
= new TimeDrawSec();
66 private static final TimeDraw TIMEDRAW_ABS_NANOSEC
= new TimeDrawAbsNanoSec();
67 private static final TimeDraw TIMEDRAW_ABS_MICROSEC
= new TimeDrawAbsMicroSec();
68 private static final TimeDraw TIMEDRAW_ABS_MILLISEC
= new TimeDrawAbsMillisec();
69 private static final TimeDraw TIMEDRAW_ABS_SEC
= new TimeDrawAbsSec();
70 private static final TimeDraw TIMEDRAW_ABS_MIN
= new TimeDrawAbsMin();
71 private static final TimeDraw TIMEDRAW_ABS_HRS
= new TimeDrawAbsHrs();
72 private static final TimeDraw TIMEDRAW_ABS_DAY
= new TimeDrawAbsDay();
73 private static final TimeDraw TIMEDRAW_ABS_MONTH
= new TimeDrawAbsMonth();
74 private static final TimeDraw TIMEDRAW_ABS_YEAR
= new TimeDrawAbsYear();
75 private static final TimeDraw TIMEDRAW_NUMBER
= new TimeDrawNumber();
77 private static final int NO_BUTTON
= 0;
78 private static final int LEFT_BUTTON
= 1;
79 private static final int RIGHT_BUTTON
= 3;
81 private ITimeDataProvider fTimeProvider
;
82 private int fDragState
= NO_BUTTON
;
83 private int fDragX0
= 0;
84 private int fDragX
= 0;
85 private long fTime0bak
;
86 private long fTime1bak
;
87 private boolean fIsInUpdate
;
91 * Standard constructor
94 * The parent composite object
96 * The color scheme to use
98 public TimeGraphScale(Composite parent
, TimeGraphColorScheme colors
) {
99 super(parent
, colors
, SWT
.NO_BACKGROUND
| SWT
.NO_FOCUS
| SWT
.DOUBLE_BUFFERED
);
100 addMouseListener(this);
101 addMouseMoveListener(this);
105 * Assign the time provider for this scale
107 * @param timeProvider
108 * The provider to use
110 public void setTimeProvider(ITimeDataProvider timeProvider
) {
111 fTimeProvider
= timeProvider
;
115 public Point
computeSize(int wHint
, int hHint
, boolean changed
) {
116 return super.computeSize(wHint
, fHeight
, changed
);
120 * Set the height of the scale
125 public void setHeight(int height
) {
126 this.fHeight
= height
;
129 private long calcTimeDelta(int width
, double pixelsPerNanoSec
) {
131 double minDelta
= (pixelsPerNanoSec
== 0) ? YEAR_IN_NS
: width
/ pixelsPerNanoSec
;
133 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
134 if (minDelta
> 6 * MONTH_IN_NS
) {
136 } else if (minDelta
> 3 * MONTH_IN_NS
) {
137 unit
= 6 * MONTH_IN_NS
;
138 } else if (minDelta
> 10 * DAY_IN_NS
) {
140 } else if (minDelta
> 12 * HOUR_IN_NS
) {
142 } else if (minDelta
> 3 * HOUR_IN_NS
) {
143 unit
= 6 * HOUR_IN_NS
;
144 } else if (minDelta
> 30 * MIN_IN_NS
) {
146 } else if (minDelta
> 10 * MIN_IN_NS
) {
147 unit
= 15 * MIN_IN_NS
;
148 } else if (minDelta
> 30 * SEC_IN_NS
) {
150 } else if (minDelta
> 20 * SEC_IN_NS
) {
151 unit
= 30 * SEC_IN_NS
;
152 } else if (minDelta
<= 1) {
157 double log
= Math
.log10(minDelta
/ unit
);
158 long pow10
= (long) log
;
159 double remainder
= log
- pow10
;
160 if (remainder
< LOG10_1
) {
161 timeDelta
= (long) Math
.pow(10, pow10
) * unit
;
162 } else if (remainder
< LOG10_2
) {
163 timeDelta
= 2 * (long) Math
.pow(10, pow10
) * unit
;
164 } else if (remainder
< LOG10_3
&& unit
>= HOUR_IN_NS
&& unit
< YEAR_IN_NS
) {
165 timeDelta
= 3 * (long) Math
.pow(10, pow10
) * unit
;
166 } else if (remainder
< LOG10_5
) {
167 timeDelta
= 5 * (long) Math
.pow(10, pow10
) * unit
;
169 timeDelta
= 10 * (long) Math
.pow(10, pow10
) * unit
;
171 if (timeDelta
<= 0) {
177 TimeDraw
getTimeDraw(long timeDelta
) {
179 if (fTimeProvider
!= null) {
181 if (fTimeProvider
.getTimeFormat() == TimeFormat
.CALENDAR
) {
182 if (timeDelta
>= YEAR_IN_NS
) {
183 timeDraw
= TIMEDRAW_ABS_YEAR
;
184 } else if (timeDelta
>= MONTH_IN_NS
) {
185 timeDraw
= TIMEDRAW_ABS_MONTH
;
186 } else if (timeDelta
>= DAY_IN_NS
) {
187 timeDraw
= TIMEDRAW_ABS_DAY
;
188 } else if (timeDelta
>= HOUR_IN_NS
) {
189 timeDraw
= TIMEDRAW_ABS_HRS
;
190 } else if (timeDelta
>= MIN_IN_NS
) {
191 timeDraw
= TIMEDRAW_ABS_MIN
;
192 } else if (timeDelta
>= SEC_IN_NS
) {
193 timeDraw
= TIMEDRAW_ABS_SEC
;
194 } else if (timeDelta
>= MILLISEC_IN_NS
) {
195 timeDraw
= TIMEDRAW_ABS_MILLISEC
;
196 } else if (timeDelta
>= MICROSEC_IN_NS
) {
197 timeDraw
= TIMEDRAW_ABS_MICROSEC
;
199 timeDraw
= TIMEDRAW_ABS_NANOSEC
;
202 } else if (fTimeProvider
.getTimeFormat() == TimeFormat
.NUMBER
) {
203 timeDraw
= TIMEDRAW_NUMBER
;
208 if (timeDelta
>= SEC_IN_NS
) {
209 timeDraw
= TIMEDRAW_SEC
;
210 } else if (timeDelta
>= MILLISEC_IN_NS
) {
211 timeDraw
= TIMEDRAW_MILLISEC
;
212 } else if (timeDelta
>= MICROSEC_IN_NS
) {
213 timeDraw
= TIMEDRAW_MICROSEC
;
215 timeDraw
= TIMEDRAW_NANOSEC
;
221 void paint(Rectangle rect
, PaintEvent e
) {
223 if (fIsInUpdate
|| null == fTimeProvider
) {
228 gc
.fillRectangle(rect
);
230 long time0
= fTimeProvider
.getTime0();
231 long time1
= fTimeProvider
.getTime1();
232 long selectedTime
= fTimeProvider
.getSelectedTime();
233 int leftSpace
= fTimeProvider
.getNameSpace();
234 int timeSpace
= fTimeProvider
.getTimeSpace();
236 gc
.setBackground(getColorScheme().getColor(TimeGraphColorScheme
.TOOL_BACKGROUND
));
237 gc
.setForeground(getColorScheme().getColor(TimeGraphColorScheme
.TOOL_FOREGROUND
));
238 Rectangle rect0
= new Rectangle(0, 0, 0, 0);
239 Utils
.init(rect0
, rect
);
241 // draw top left area
242 rect0
.width
= leftSpace
;
245 Rectangle absHeaderRect
= new Rectangle(rect0
.x
, rect0
.y
, rect0
.width
, rect0
.height
);
249 // prepare and draw right rect of the timescale
250 rect0
.x
+= leftSpace
;
251 rect0
.width
= rect
.width
- leftSpace
;
253 // draw bottom border and erase all other area
254 gc
.drawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
- 1,
255 rect
.y
+ rect
.height
- 1);
257 gc
.fillRectangle(rect0
);
259 if (RIGHT_BUTTON
== fDragState
&& null != fTimeProvider
) {
260 // draw selected zoom region background
261 gc
.setBackground(getColorScheme().getBkColor(true, false, true));
262 if (fDragX0
< fDragX
) {
263 gc
.fillRectangle(new Rectangle(leftSpace
+ fDragX0
, rect0
.y
, fDragX
- fDragX0
, rect0
.height
));
264 } else if (fDragX0
> fDragX
) {
265 gc
.fillRectangle(new Rectangle(leftSpace
+ fDragX
, rect0
.y
, fDragX0
- fDragX
, rect0
.height
));
269 if (time1
<= time0
|| timeSpace
< 2) {
273 int numDigits
= calculateDigits(time0
, time1
);
275 int labelWidth
= gc
.getCharWidth('0') * numDigits
;
276 double pixelsPerNanoSec
= (timeSpace
<= RIGHT_MARGIN
) ?
0 :
277 (double) (timeSpace
- RIGHT_MARGIN
) / (time1
- time0
);
278 long timeDelta
= calcTimeDelta(labelWidth
, pixelsPerNanoSec
);
280 TimeDraw timeDraw
= getTimeDraw(timeDelta
);
282 // draw selected zoom region lines
283 if (RIGHT_BUTTON
== fDragState
&& null != fTimeProvider
) {
284 gc
.drawLine(leftSpace
+ fDragX0
, rect
.y
, leftSpace
+ fDragX0
, rect
.y
+ rect
.height
);
285 gc
.drawLine(leftSpace
+ fDragX
, rect
.y
, leftSpace
+ fDragX
, rect
.y
+ rect
.height
);
288 if (rect0
.isEmpty()) {
292 // draw selected time
293 int x
= rect0
.x
+ (int) ((selectedTime
- time0
) * pixelsPerNanoSec
);
294 if (x
>= rect0
.x
&& x
< rect0
.x
+ rect0
.width
) {
295 gc
.setForeground(getColorScheme().getColor(TimeGraphColorScheme
.SELECTED_TIME
));
296 gc
.drawLine(x
, rect0
.y
+ rect0
.height
- 6, x
, rect0
.y
298 gc
.setForeground(getColorScheme().getColor(TimeGraphColorScheme
.TOOL_FOREGROUND
));
301 // draw time scale ticks
303 rect0
.height
= rect
.height
- 4;
304 rect0
.width
= labelWidth
;
307 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
308 time
= floorToCalendar(time0
, timeDelta
);
310 time
= (time0
/ timeDelta
) * timeDelta
;
316 int y
= rect0
.y
+ rect0
.height
;
318 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
319 timeDraw
.drawAbsHeader(gc
, time
, absHeaderRect
);
323 x
= rect
.x
+ leftSpace
+ (int) (Math
.floor((time
- time0
) * pixelsPerNanoSec
));
324 if (x
>= rect
.x
+ leftSpace
+ rect
.width
- rect0
.width
) {
327 if (x
>= rect
.x
+ leftSpace
) {
328 gc
.drawLine(x
, y
, x
, y
+ 4);
330 if (x
+ rect0
.width
<= rect
.x
+ rect
.width
) {
331 timeDraw
.draw(gc
, time
, rect0
);
334 if (pixelsPerNanoSec
== 0 || time
> Long
.MAX_VALUE
- timeDelta
|| timeDelta
== 0) {
337 if (fTimeProvider
!= null && fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
338 if (timeDelta
>= YEAR_IN_NS
) {
339 long millis
= time
/ MILLISEC_IN_NS
;
340 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
341 GREGORIAN_CALENDAR
.add(Calendar
.YEAR
, (int) (timeDelta
/ YEAR_IN_NS
));
342 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
343 time
= millis
* MILLISEC_IN_NS
;
344 } else if (timeDelta
>= MONTH_IN_NS
) {
345 long millis
= time
/ MILLISEC_IN_NS
;
346 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
347 GREGORIAN_CALENDAR
.add(Calendar
.MONTH
, (int) (timeDelta
/ MONTH_IN_NS
));
348 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
349 time
= millis
* MILLISEC_IN_NS
;
350 } else if (timeDelta
>= DAY_IN_NS
) {
351 long millis
= time
/ MILLISEC_IN_NS
;
352 GREGORIAN_CALENDAR
.setTime(new Date(millis
));
353 GREGORIAN_CALENDAR
.add(Calendar
.DAY_OF_MONTH
, (int) (timeDelta
/ DAY_IN_NS
));
354 millis
= GREGORIAN_CALENDAR
.getTimeInMillis();
355 time
= millis
* MILLISEC_IN_NS
;
365 private static long floorToCalendar(long time
, long timeDelta
) {
368 if (timeDelta
>= YEAR_IN_NS
) {
369 GREGORIAN_CALENDAR
.setTime(new Date(ret
/ MILLISEC_IN_NS
));
370 int year
= GREGORIAN_CALENDAR
.get(Calendar
.YEAR
);
371 int yearDelta
= (int) (timeDelta
/ YEAR_IN_NS
);
372 year
= (year
/ yearDelta
) * yearDelta
;
373 GREGORIAN_CALENDAR
.set(Calendar
.YEAR
, year
);
374 GREGORIAN_CALENDAR
.set(Calendar
.MONTH
, 0); // January 1st of year
375 GREGORIAN_CALENDAR
.set(Calendar
.DAY_OF_MONTH
, 1);
376 GREGORIAN_CALENDAR
.set(Calendar
.HOUR_OF_DAY
, 0);
377 GREGORIAN_CALENDAR
.set(Calendar
.MINUTE
, 0);
378 GREGORIAN_CALENDAR
.set(Calendar
.SECOND
, 0);
379 GREGORIAN_CALENDAR
.set(Calendar
.MILLISECOND
, 0);
380 ret
= GREGORIAN_CALENDAR
.getTimeInMillis() * MILLISEC_IN_NS
;
381 } else if (timeDelta
>= MONTH_IN_NS
) {
382 GREGORIAN_CALENDAR
.setTime(new Date(ret
/ MILLISEC_IN_NS
));
383 int month
= GREGORIAN_CALENDAR
.get(Calendar
.MONTH
);
384 int monthDelta
= (int) (timeDelta
/ MONTH_IN_NS
);
385 month
= (month
/ monthDelta
) * monthDelta
;
386 GREGORIAN_CALENDAR
.set(Calendar
.MONTH
, month
);
387 GREGORIAN_CALENDAR
.set(Calendar
.DAY_OF_MONTH
, 1); // 1st of month
388 GREGORIAN_CALENDAR
.set(Calendar
.HOUR_OF_DAY
, 0);
389 GREGORIAN_CALENDAR
.set(Calendar
.MINUTE
, 0);
390 GREGORIAN_CALENDAR
.set(Calendar
.SECOND
, 0);
391 GREGORIAN_CALENDAR
.set(Calendar
.MILLISECOND
, 0);
392 ret
= GREGORIAN_CALENDAR
.getTimeInMillis() * MILLISEC_IN_NS
;
394 long offset
= GREGORIAN_CALENDAR
.getTimeZone().getOffset(ret
/ MILLISEC_IN_NS
) * MILLISEC_IN_NS
;
396 ret
= (ret
/ timeDelta
) * timeDelta
;
402 private int calculateDigits(long time0
, long time1
) {
404 long timeRange
= time1
- time0
;
406 if (fTimeProvider
.getTimeFormat().equals(TimeFormat
.CALENDAR
)) {
407 // Calculate the number of digits to represent the minutes provided
411 if (timeRange
< 10000) {
412 // HH:11:222:333:444__
414 } else if (timeRange
< 10000000) {
419 long sec
= time1
/ SEC_IN_NS
;
420 numDigits
= Long
.toString(sec
).length();
421 int thousandGroups
= (numDigits
- 1) / 3;
422 numDigits
+= thousandGroups
;
423 numDigits
+= 12; // .000 000 000
430 public void mouseDown(MouseEvent e
) {
431 getParent().setFocus();
432 if (fDragState
== NO_BUTTON
&& null != fTimeProvider
) {
433 int x
= e
.x
- fTimeProvider
.getNameSpace();
434 if (LEFT_BUTTON
== e
.button
&& x
> 0) {
436 fDragState
= LEFT_BUTTON
;
437 } else if (RIGHT_BUTTON
== e
.button
) {
438 fDragState
= RIGHT_BUTTON
;
442 } else if (x
> getSize().x
- fTimeProvider
.getNameSpace()) {
443 x
= getSize().x
- fTimeProvider
.getNameSpace();
447 fTime0bak
= fTimeProvider
.getTime0();
448 fTime1bak
= fTimeProvider
.getTime1();
453 public void mouseUp(MouseEvent e
) {
454 if (e
.button
== LEFT_BUTTON
&& fDragState
== LEFT_BUTTON
) {
456 fDragState
= NO_BUTTON
;
458 // Notify time provider to check the need for listener notification
459 if (fDragX
!= fDragX0
&& fTimeProvider
.getTime0() != fTimeProvider
.getTime1()) {
460 fTimeProvider
.setStartFinishTimeNotify(fTimeProvider
.getTime0(), fTimeProvider
.getTime1());
462 } else if (e
.button
== RIGHT_BUTTON
&& fDragState
== RIGHT_BUTTON
&& null != fTimeProvider
) {
463 fDragState
= NO_BUTTON
;
464 if (fDragX0
== fDragX
|| fTimeProvider
.getTime0() == fTimeProvider
.getTime1()) {
468 int timeSpace
= fTimeProvider
.getTimeSpace();
469 int leftSpace
= fTimeProvider
.getNameSpace();
470 int x
= Math
.max(0, e
.x
- leftSpace
);
473 if (fDragX0
> fDragX
) { // drag right to left
477 long time0
= fTime0bak
+ (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX0
/ timeSpace
));
478 long time1
= fTime0bak
+ (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX
/ timeSpace
));
480 fTimeProvider
.setStartFinishTimeNotify(time0
, time1
);
481 fTime0bak
= fTimeProvider
.getTime0();
482 fTime1bak
= fTimeProvider
.getTime1();
488 public void mouseMove(MouseEvent e
) {
489 if (fDragX0
< 0 || fDragState
== NO_BUTTON
|| fTimeProvider
== null) {
492 Point size
= getSize();
493 int leftSpace
= fTimeProvider
.getNameSpace();
494 int timeSpace
= fTimeProvider
.getTimeSpace();
495 int x
= e
.x
- leftSpace
;
496 if (LEFT_BUTTON
== fDragState
) {
497 if (x
> 0 && size
.x
> leftSpace
&& fDragX
!= x
) {
499 if (fTimeProvider
.getTime0() == fTimeProvider
.getTime1()) {
502 long interval
= (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX0
/ fDragX
));
503 if (interval
== Long
.MAX_VALUE
) {
504 fTimeProvider
.setStartFinishTime(fTime0bak
, Long
.MAX_VALUE
);
506 long time1
= fTime0bak
+ (long) ((fTime1bak
- fTime0bak
) * ((double) fDragX0
/ fDragX
));
507 fTimeProvider
.setStartFinishTime(fTime0bak
, time1
);
510 } else if (RIGHT_BUTTON
== fDragState
) {
513 } else if (x
> timeSpace
) {
523 public void mouseDoubleClick(MouseEvent e
) {
524 if (e
.button
== 1 && null != fTimeProvider
&& fTimeProvider
.getTime0() != fTimeProvider
.getTime1() && (e
.stateMask
& SWT
.BUTTON_MASK
) == 0) {
525 fTimeProvider
.resetStartFinishTime();
526 fTimeProvider
.notifyStartFinishTime();
527 fTime0bak
= fTimeProvider
.getTime0();
528 fTime1bak
= fTimeProvider
.getTime1();
533 abstract class TimeDraw
{
534 protected static final long MICROSEC_IN_NS
= 1000;
535 protected static final long MILLISEC_IN_NS
= 1000000;
536 protected static final long MILLISEC_IN_US
= 1000;
537 protected static final long SEC_IN_NS
= 1000000000;
538 protected static final long SEC_IN_MS
= 1000;
539 private static final String S
= "" ; //$NON-NLS-1$
540 private static final String S0
= "0" ; //$NON-NLS-1$
541 private static final String S00
= "00"; //$NON-NLS-1$
542 protected static final long PAD_1000
= 1000;
543 protected static final SimpleDateFormat SEC_FORMAT_HEADER
= new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
544 protected static final SimpleDateFormat SEC_FORMAT
= new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
545 protected static final SimpleDateFormat MIN_FORMAT_HEADER
= new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
546 protected static final SimpleDateFormat MIN_FORMAT
= new SimpleDateFormat("HH:mm"); //$NON-NLS-1$
547 protected static final SimpleDateFormat HOURS_FORMAT_HEADER
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
548 protected static final SimpleDateFormat HOURS_FORMAT
= new SimpleDateFormat("MMM dd HH:mm"); //$NON-NLS-1$
549 protected static final SimpleDateFormat DAY_FORMAT_HEADER
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
550 protected static final SimpleDateFormat DAY_FORMAT
= new SimpleDateFormat("MMM dd"); //$NON-NLS-1$
551 protected static final SimpleDateFormat MONTH_FORMAT
= new SimpleDateFormat("yyyy MMM"); //$NON-NLS-1$
552 protected static final SimpleDateFormat YEAR_FORMAT
= new SimpleDateFormat("yyyy"); //$NON-NLS-1$
554 static String
sep(long n
) {
555 StringBuilder retVal
= new StringBuilder();
556 String s
= Long
.toString(n
);
557 for (int i
= 0; i
< s
.length(); i
++) {
558 int pos
= s
.length() - i
- 1;
559 retVal
.append(s
.charAt(i
));
560 if (pos
% 3 == 0 && pos
!= 0) {
564 return retVal
.toString();
567 static String
pad(long n
) {
571 } else if (n
< 100) {
579 public abstract void draw(GC gc
, long time
, Rectangle rect
);
582 * Override to draw absolute time header. This is for the time information
583 * not shown in the draw of each tick
589 * @param absHeaderRect
592 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle absHeaderRect
) {
596 class TimeDrawSec
extends TimeDraw
{
598 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
599 long sec
= nanosec
/ SEC_IN_NS
;
600 Utils
.drawText(gc
, sep(sec
), rect
, true);
604 class TimeDrawMillisec
extends TimeDraw
{
606 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
607 long millisec
= nanosec
/ MILLISEC_IN_NS
;
608 long ms
= millisec
% PAD_1000
;
609 long sec
= millisec
/ SEC_IN_MS
;
610 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
), rect
, true); //$NON-NLS-1$
614 class TimeDrawMicrosec
extends TimeDraw
{
616 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
617 long microsec
= nanosec
/ MICROSEC_IN_NS
;
618 long us
= microsec
% PAD_1000
;
619 long millisec
= microsec
/ MILLISEC_IN_US
;
620 long ms
= millisec
% PAD_1000
;
621 long sec
= millisec
/ SEC_IN_MS
;
622 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
) + " " + pad(us
), rect
, true); //$NON-NLS-1$ //$NON-NLS-2$
626 class TimeDrawNanosec
extends TimeDraw
{
628 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
629 long ns
= nanosec
% PAD_1000
;
630 long microsec
= nanosec
/ MICROSEC_IN_NS
;
631 long us
= microsec
% PAD_1000
;
632 long millisec
= microsec
/ MILLISEC_IN_US
;
633 long ms
= millisec
% PAD_1000
;
634 long sec
= millisec
/ SEC_IN_MS
;
635 Utils
.drawText(gc
, sep(sec
) + "." + pad(ms
) + " " + pad(us
) + " " + pad(ns
), rect
, true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
639 class TimeDrawAbsYear
extends TimeDraw
{
641 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
642 String stime
= YEAR_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
643 Utils
.drawText(gc
, stime
, rect
, true);
647 class TimeDrawAbsMonth
extends TimeDraw
{
649 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
650 String stime
= MONTH_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
651 Utils
.drawText(gc
, stime
, rect
, true);
655 class TimeDrawAbsDay
extends TimeDraw
{
657 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
658 String stime
= DAY_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
659 Utils
.drawText(gc
, stime
, rect
, true);
663 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
664 String header
= DAY_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
665 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
666 if (headerwidth
<= rect
.width
) {
667 rect
.x
+= (rect
.width
- headerwidth
);
668 Utils
.drawText(gc
, header
, rect
, true);
673 class TimeDrawAbsHrs
extends TimeDraw
{
675 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
676 String stime
= HOURS_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
677 Utils
.drawText(gc
, stime
, rect
, true);
681 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
682 String header
= HOURS_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
683 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
684 if (headerwidth
<= rect
.width
) {
685 rect
.x
+= (rect
.width
- headerwidth
);
686 Utils
.drawText(gc
, header
, rect
, true);
691 class TimeDrawAbsMin
extends TimeDraw
{
693 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
694 String stime
= MIN_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
695 Utils
.drawText(gc
, stime
, rect
, true);
699 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
700 String header
= MIN_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
701 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
702 if (headerwidth
<= rect
.width
) {
703 rect
.x
+= (rect
.width
- headerwidth
);
704 Utils
.drawText(gc
, header
, rect
, true);
709 class TimeDrawAbsSec
extends TimeDraw
{
711 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
712 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
713 Utils
.drawText(gc
, stime
, rect
, true);
717 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
718 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
719 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
720 if (headerwidth
<= rect
.width
) {
721 rect
.x
+= (rect
.width
- headerwidth
);
722 Utils
.drawText(gc
, header
, rect
, true);
727 class TimeDrawAbsMillisec
extends TimeDraw
{
729 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
730 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
731 String ns
= Utils
.formatNs(nanosec
, Resolution
.MILLISEC
);
733 Utils
.drawText(gc
, stime
+ "." + ns
, rect
, true); //$NON-NLS-1$
737 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
738 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
739 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
740 if (headerwidth
<= rect
.width
) {
741 rect
.x
+= (rect
.width
- headerwidth
);
742 Utils
.drawText(gc
, header
, rect
, true);
747 class TimeDrawAbsMicroSec
extends TimeDraw
{
749 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
750 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
751 String micr
= Utils
.formatNs(nanosec
, Resolution
.MICROSEC
);
752 Utils
.drawText(gc
, stime
+ "." + micr
, rect
, true); //$NON-NLS-1$
756 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
757 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
758 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
759 if (headerwidth
<= rect
.width
) {
760 rect
.x
+= (rect
.width
- headerwidth
);
761 Utils
.drawText(gc
, header
, rect
, true);
766 class TimeDrawAbsNanoSec
extends TimeDraw
{
768 public void draw(GC gc
, long nanosec
, Rectangle rect
) {
769 String stime
= SEC_FORMAT
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
770 String ns
= Utils
.formatNs(nanosec
, Resolution
.NANOSEC
);
771 Utils
.drawText(gc
, stime
+ "." + ns
, rect
, true); //$NON-NLS-1$
775 public void drawAbsHeader(GC gc
, long nanosec
, Rectangle rect
) {
776 String header
= SEC_FORMAT_HEADER
.format(new Date(nanosec
/ MILLISEC_IN_NS
));
777 int headerwidth
= gc
.stringExtent(header
).x
+ 4;
778 if (headerwidth
<= rect
.width
) {
779 rect
.x
+= (rect
.width
- headerwidth
);
780 Utils
.drawText(gc
, header
, rect
, true);
785 class TimeDrawNumber
extends TimeDraw
{
787 public void draw(GC gc
, long time
, Rectangle rect
) {
788 String stime
= NumberFormat
.getInstance().format(time
);
789 Utils
.drawText(gc
, stime
, rect
, true);