tmf: Support navigation for all markers in time graph viewer
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / widgets / TimeGraphScale.java
CommitLineData
8e1f81f1 1/*****************************************************************************
85203d74 2 * Copyright (c) 2007, 2015 Intel Corporation, Ericsson
8e1f81f1
PT
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
c1cd9635 13 * Marc-Andre Laperle - Add time zone preference
8e1f81f1
PT
14 *****************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets;
8e1f81f1 17
026664b7 18import java.text.NumberFormat;
8e1f81f1 19import java.text.SimpleDateFormat;
55d1fc96 20import java.util.ArrayList;
8e1f81f1
PT
21import java.util.Calendar;
22import java.util.Date;
6dcc38b9 23import java.util.List;
c1cd9635 24import java.util.TimeZone;
8e1f81f1 25
8e1f81f1
PT
26import org.eclipse.swt.SWT;
27import org.eclipse.swt.events.MouseEvent;
28import org.eclipse.swt.events.MouseListener;
29import org.eclipse.swt.events.MouseMoveListener;
30import org.eclipse.swt.events.PaintEvent;
31import org.eclipse.swt.graphics.GC;
32import org.eclipse.swt.graphics.Point;
33import org.eclipse.swt.graphics.Rectangle;
34import org.eclipse.swt.widgets.Composite;
3573a01c 35import org.eclipse.swt.widgets.Control;
2bdf0193
AM
36import org.eclipse.tracecompass.internal.tmf.ui.Messages;
37import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
38import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
39import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
40import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimePreferences;
56b43ab2 41import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
2bdf0193
AM
42import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
43import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
8e1f81f1 44
6dcc38b9
MK
45import com.google.common.collect.ImmutableList;
46
8e1f81f1
PT
47/**
48 * Implementation of the scale for the time graph view.
49 *
50 * This goes above the "gantt chart" area.
51 *
52 * @version 1.0
53 * @author Alvaro Sanchez-Leon
54 * @author Patrick Tasse
55 */
56public class TimeGraphScale extends TimeGraphBaseControl implements
57 MouseListener, MouseMoveListener {
58
83dcfe09
MK
59 private static final int BASE_10 = 10;
60 private static final int X_OFFSET = 4;
61 private static final int Y_OFFSET = 4;
62
63 private static final int MIN_SECOND_FACTOR = 20;
64 private static final int SECOND_FACTOR = 30;
65 private static final int MAX_SECOND_FACTOR = 30;
66
67 private static final int MIN_MINUTE_FACTOR = 10;
68 private static final int MINUTE_FACTOR = 15;
69 private static final int MAX_MINUTE_FACTOR = 30;
70
71 private static final int MIN_HOUR_FACTOR = 3;
72 private static final int HOUR_FACTOR = 6;
73 private static final int MAX_HOUR_FACTOR = 12;
74
75 private static final int MAX_DAY_FACTOR = 10;
76
77 private static final int MAX_MONTH_FACTOR = 6;
78 private static final int MONTH_FACTOR = 6;
79 private static final int MIN_MONTH_FACTOR = 3;
80
f1fae91f
PT
81 private static final long MICROSEC_IN_NS = 1000;
82 private static final long MILLISEC_IN_NS = 1000000;
8e1f81f1
PT
83 private static final long SEC_IN_NS = 1000000000;
84 private static final long MIN_IN_NS = 60 * SEC_IN_NS;
85 private static final long HOUR_IN_NS = 60 * MIN_IN_NS;
86 private static final long DAY_IN_NS = 24 * HOUR_IN_NS;
87 private static final long MONTH_IN_NS = 31 * DAY_IN_NS; // upper limit
88 private static final long YEAR_IN_NS = 366 * DAY_IN_NS; // upper limit
89
90 private static final double LOG10_1 = Math.log10(1);
91 private static final double LOG10_2 = Math.log10(2);
92 private static final double LOG10_3 = Math.log10(3);
93 private static final double LOG10_5 = Math.log10(5);
94
95 private static final Calendar GREGORIAN_CALENDAR = Calendar.getInstance();
96
f1fae91f
PT
97 private static final TimeDraw TIMEDRAW_NANOSEC = new TimeDrawNanosec();
98 private static final TimeDraw TIMEDRAW_MICROSEC = new TimeDrawMicrosec();
99 private static final TimeDraw TIMEDRAW_MILLISEC = new TimeDrawMillisec();
100 private static final TimeDraw TIMEDRAW_SEC = new TimeDrawSec();
101 private static final TimeDraw TIMEDRAW_ABS_NANOSEC = new TimeDrawAbsNanoSec();
102 private static final TimeDraw TIMEDRAW_ABS_MICROSEC = new TimeDrawAbsMicroSec();
103 private static final TimeDraw TIMEDRAW_ABS_MILLISEC = new TimeDrawAbsMillisec();
104 private static final TimeDraw TIMEDRAW_ABS_SEC = new TimeDrawAbsSec();
105 private static final TimeDraw TIMEDRAW_ABS_MIN = new TimeDrawAbsMin();
106 private static final TimeDraw TIMEDRAW_ABS_HRS = new TimeDrawAbsHrs();
107 private static final TimeDraw TIMEDRAW_ABS_DAY = new TimeDrawAbsDay();
108 private static final TimeDraw TIMEDRAW_ABS_MONTH = new TimeDrawAbsMonth();
109 private static final TimeDraw TIMEDRAW_ABS_YEAR = new TimeDrawAbsYear();
110 private static final TimeDraw TIMEDRAW_NUMBER = new TimeDrawNumber();
0fab12b0 111 private static final TimeDraw TIMEDRAW_CYCLES = new TimeDrawCycles();
f1fae91f 112
0fcf3b09 113 private static final int DRAG_EXTERNAL = -1;
f1fae91f
PT
114 private static final int NO_BUTTON = 0;
115 private static final int LEFT_BUTTON = 1;
f1fae91f 116
1d012443
PT
117 private static final int MAX_LABEL_LENGTH = 256;
118
f1fae91f
PT
119 private ITimeDataProvider fTimeProvider;
120 private int fDragState = NO_BUTTON;
121 private int fDragX0 = 0;
122 private int fDragX = 0;
123 private long fTime0bak;
124 private long fTime1bak;
125 private boolean fIsInUpdate;
126 private int fHeight;
55d1fc96 127 private List<Integer> fTickList = new ArrayList<>();
56b43ab2
PT
128 private List<IMarkerEvent> fMarkers = null;
129 private boolean fMarkersVisible = true;
f1fae91f
PT
130
131 /**
132 * Standard constructor
133 *
134 * @param parent
135 * The parent composite object
136 * @param colors
137 * The color scheme to use
138 */
139 public TimeGraphScale(Composite parent, TimeGraphColorScheme colors) {
140 super(parent, colors, SWT.NO_BACKGROUND | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED);
c1cd9635 141 TmfSignalManager.register(this);
f1fae91f
PT
142 addMouseListener(this);
143 addMouseMoveListener(this);
c1cd9635
MAL
144 TimeDraw.updateTimeZone();
145 }
146
147 @Override
148 public void dispose() {
149 TmfSignalManager.deregister(this);
150 super.dispose();
f1fae91f 151 }
8e1f81f1
PT
152
153 /**
154 * Assign the time provider for this scale
155 *
156 * @param timeProvider
157 * The provider to use
158 */
159 public void setTimeProvider(ITimeDataProvider timeProvider) {
f1fae91f 160 fTimeProvider = timeProvider;
8e1f81f1
PT
161 }
162
0fab12b0
PT
163 /**
164 * Get the time provider used by this scale
165 *
166 * @return The time provider
0fab12b0
PT
167 */
168 public ITimeDataProvider getTimeProvider() {
169 return fTimeProvider;
170 }
171
8e1f81f1
PT
172 @Override
173 public Point computeSize(int wHint, int hHint, boolean changed) {
f1fae91f 174 return super.computeSize(wHint, fHeight, changed);
8e1f81f1
PT
175 }
176
177 /**
178 * Set the height of the scale
179 *
180 * @param height
181 * The height to use
182 */
183 public void setHeight(int height) {
3573a01c
MAL
184 if (fHeight != height) {
185 fHeight = height;
186 getParent().layout(new Control[] { this });
187 }
8e1f81f1
PT
188 }
189
0fcf3b09
PT
190 /**
191 * Set the drag range to paint decorators
192 *
193 * @param begin
194 * The begin x-coordinate
195 * @param end
196 * The end x-coordinate
0fcf3b09
PT
197 */
198 public void setDragRange(int begin, int end) {
199 if (NO_BUTTON == fDragState || DRAG_EXTERNAL == fDragState) {
200 fDragX0 = begin - fTimeProvider.getNameSpace();
201 fDragX = end - fTimeProvider.getNameSpace();
202 if (begin >= 0 || end >= 0) {
203 fDragState = DRAG_EXTERNAL;
204 } else {
205 fDragState = NO_BUTTON;
206 }
207 }
208 redraw();
209 }
210
55d1fc96
PT
211 /**
212 * Get the list of visible ticks of the time axis.
213 *
214 * @return the list of visible tick x-coordinates
215 * @since 2.0
216 */
217 public List<Integer> getTickList() {
218 return fTickList;
219 }
220
56b43ab2
PT
221 /**
222 * Set the markers list.
223 *
224 * @param markers
225 * The markers list, or null
226 * @since 2.0
227 */
228 public void setMarkers(List<IMarkerEvent> markers) {
229 fMarkers = markers;
230 }
231
232 /**
233 * Set the markers visibility. The default is true.
234 *
235 * @param visible
236 * true to show the markers, false otherwise
237 * @since 2.0
238 */
239 public void setMarkersVisible(boolean visible) {
240 fMarkersVisible = visible;
241 }
242
f1fae91f
PT
243 private long calcTimeDelta(int width, double pixelsPerNanoSec) {
244 long timeDelta;
8e1f81f1
PT
245 double minDelta = (pixelsPerNanoSec == 0) ? YEAR_IN_NS : width / pixelsPerNanoSec;
246 long unit = 1;
0fab12b0 247 if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
83dcfe09 248 if (minDelta > MAX_MONTH_FACTOR * MONTH_IN_NS) {
8e1f81f1 249 unit = YEAR_IN_NS;
83dcfe09
MK
250 } else if (minDelta > MIN_MONTH_FACTOR * MONTH_IN_NS) {
251 unit = MONTH_FACTOR * MONTH_IN_NS;
252 } else if (minDelta > MAX_DAY_FACTOR * DAY_IN_NS) {
8e1f81f1 253 unit = MONTH_IN_NS;
83dcfe09 254 } else if (minDelta > MAX_HOUR_FACTOR * HOUR_IN_NS) {
8e1f81f1 255 unit = DAY_IN_NS;
83dcfe09
MK
256 } else if (minDelta > MIN_HOUR_FACTOR * HOUR_IN_NS) {
257 unit = HOUR_FACTOR * HOUR_IN_NS;
258 } else if (minDelta > MAX_MINUTE_FACTOR * MIN_IN_NS) {
8e1f81f1 259 unit = HOUR_IN_NS;
83dcfe09
MK
260 } else if (minDelta > MIN_MINUTE_FACTOR * MIN_IN_NS) {
261 unit = MINUTE_FACTOR * MIN_IN_NS;
262 } else if (minDelta > MAX_SECOND_FACTOR * SEC_IN_NS) {
8e1f81f1 263 unit = MIN_IN_NS;
83dcfe09
MK
264 } else if (minDelta > MIN_SECOND_FACTOR * SEC_IN_NS) {
265 unit = SECOND_FACTOR * SEC_IN_NS;
8e1f81f1 266 } else if (minDelta <= 1) {
f1fae91f
PT
267 timeDelta = 1;
268 return timeDelta;
8e1f81f1
PT
269 }
270 }
271 double log = Math.log10(minDelta / unit);
272 long pow10 = (long) log;
273 double remainder = log - pow10;
274 if (remainder < LOG10_1) {
83dcfe09 275 timeDelta = (long) Math.pow(BASE_10, pow10) * unit;
8e1f81f1 276 } else if (remainder < LOG10_2) {
83dcfe09 277 timeDelta = 2 * (long) Math.pow(BASE_10, pow10) * unit;
8e1f81f1 278 } else if (remainder < LOG10_3 && unit >= HOUR_IN_NS && unit < YEAR_IN_NS) {
83dcfe09 279 timeDelta = 3 * (long) Math.pow(BASE_10, pow10) * unit;
8e1f81f1 280 } else if (remainder < LOG10_5) {
83dcfe09 281 timeDelta = 5 * (long) Math.pow(BASE_10, pow10) * unit;
8e1f81f1 282 } else {
83dcfe09 283 timeDelta = 10 * (long) Math.pow(BASE_10, pow10) * unit;
8e1f81f1 284 }
f1fae91f
PT
285 if (timeDelta <= 0) {
286 timeDelta = 1;
f85266f3 287 }
f1fae91f 288 return timeDelta;
8e1f81f1
PT
289 }
290
8e1f81f1
PT
291 TimeDraw getTimeDraw(long timeDelta) {
292 TimeDraw timeDraw;
f1fae91f 293 if (fTimeProvider != null) {
0fab12b0
PT
294 switch (fTimeProvider.getTimeFormat()) {
295 case CALENDAR:
026664b7
XR
296 if (timeDelta >= YEAR_IN_NS) {
297 timeDraw = TIMEDRAW_ABS_YEAR;
298 } else if (timeDelta >= MONTH_IN_NS) {
299 timeDraw = TIMEDRAW_ABS_MONTH;
300 } else if (timeDelta >= DAY_IN_NS) {
301 timeDraw = TIMEDRAW_ABS_DAY;
302 } else if (timeDelta >= HOUR_IN_NS) {
303 timeDraw = TIMEDRAW_ABS_HRS;
304 } else if (timeDelta >= MIN_IN_NS) {
305 timeDraw = TIMEDRAW_ABS_MIN;
306 } else if (timeDelta >= SEC_IN_NS) {
307 timeDraw = TIMEDRAW_ABS_SEC;
f1fae91f 308 } else if (timeDelta >= MILLISEC_IN_NS) {
026664b7 309 timeDraw = TIMEDRAW_ABS_MILLISEC;
f1fae91f 310 } else if (timeDelta >= MICROSEC_IN_NS) {
026664b7
XR
311 timeDraw = TIMEDRAW_ABS_MICROSEC;
312 } else {
313 timeDraw = TIMEDRAW_ABS_NANOSEC;
314 }
315 return timeDraw;
0fab12b0
PT
316 case NUMBER:
317 return TIMEDRAW_NUMBER;
318 case CYCLES:
319 return TIMEDRAW_CYCLES;
320 case RELATIVE:
321 default:
8e1f81f1 322 }
026664b7 323
8e1f81f1 324 }
f1fae91f 325 if (timeDelta >= SEC_IN_NS) {
8e1f81f1 326 timeDraw = TIMEDRAW_SEC;
f1fae91f 327 } else if (timeDelta >= MILLISEC_IN_NS) {
8e1f81f1 328 timeDraw = TIMEDRAW_MILLISEC;
f1fae91f 329 } else if (timeDelta >= MICROSEC_IN_NS) {
8e1f81f1
PT
330 timeDraw = TIMEDRAW_MICROSEC;
331 } else {
332 timeDraw = TIMEDRAW_NANOSEC;
333 }
334 return timeDraw;
335 }
336
337 @Override
338 void paint(Rectangle rect, PaintEvent e) {
339
f1fae91f 340 if (fIsInUpdate || null == fTimeProvider) {
8e1f81f1
PT
341 return;
342 }
343
344 GC gc = e.gc;
345 gc.fillRectangle(rect);
346
f1fae91f
PT
347 long time0 = fTimeProvider.getTime0();
348 long time1 = fTimeProvider.getTime1();
f1fae91f
PT
349 int leftSpace = fTimeProvider.getNameSpace();
350 int timeSpace = fTimeProvider.getTimeSpace();
8e1f81f1 351
f1fae91f
PT
352 gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.TOOL_BACKGROUND));
353 gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.TOOL_FOREGROUND));
354 Rectangle rect0 = new Rectangle(0, 0, 0, 0);
355 Utils.init(rect0, rect);
8e1f81f1
PT
356
357 // draw top left area
f1fae91f 358 rect0.width = leftSpace;
83dcfe09
MK
359 rect0.x += X_OFFSET;
360 rect0.width -= X_OFFSET;
f1fae91f 361 Rectangle absHeaderRect = new Rectangle(rect0.x, rect0.y, rect0.width, rect0.height);
83dcfe09
MK
362 rect0.x -= X_OFFSET;
363 rect0.width += X_OFFSET;
8e1f81f1
PT
364
365 // prepare and draw right rect of the timescale
f1fae91f
PT
366 rect0.x += leftSpace;
367 rect0.width = rect.width - leftSpace;
8e1f81f1
PT
368
369 // draw bottom border and erase all other area
370 gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1,
371 rect.y + rect.height - 1);
f1fae91f
PT
372 rect0.height--;
373 gc.fillRectangle(rect0);
8e1f81f1
PT
374
375 if (time1 <= time0 || timeSpace < 2) {
55d1fc96 376 fTickList.clear();
8e1f81f1
PT
377 return;
378 }
379
380 int numDigits = calculateDigits(time0, time1);
381
382 int labelWidth = gc.getCharWidth('0') * numDigits;
383 double pixelsPerNanoSec = (timeSpace <= RIGHT_MARGIN) ? 0 :
6dcc38b9 384 (double) (timeSpace - RIGHT_MARGIN) / (time1 - time0);
f1fae91f 385 long timeDelta = calcTimeDelta(labelWidth, pixelsPerNanoSec);
8e1f81f1 386
f1fae91f 387 TimeDraw timeDraw = getTimeDraw(timeDelta);
8e1f81f1 388
0fcf3b09
PT
389 // draw range decorators
390 if (DRAG_EXTERNAL == fDragState) {
85203d74
PT
391 int x1 = leftSpace + fDragX0;
392 int x2 = leftSpace + fDragX;
0fcf3b09
PT
393 drawRangeDecorators(rect0, gc, x1, x2);
394 } else {
395 int x1;
396 int x2;
baf92cac
AM
397 long selectionBegin = fTimeProvider.getSelectionBegin();
398 long selectionEnd = fTimeProvider.getSelectionEnd();
399 x1 = leftSpace + (int) ((selectionBegin - time0) * pixelsPerNanoSec);
400 x2 = leftSpace + (int) ((selectionEnd - time0) * pixelsPerNanoSec);
0fcf3b09 401 drawRangeDecorators(rect0, gc, x1, x2);
8e1f81f1
PT
402 }
403
f1fae91f 404 if (rect0.isEmpty()) {
8e1f81f1
PT
405 return;
406 }
407
8e1f81f1 408 // draw time scale ticks
f1fae91f 409 rect0.y = rect.y;
83dcfe09 410 rect0.height = rect.height - Y_OFFSET;
f1fae91f 411 rect0.width = labelWidth;
8e1f81f1
PT
412
413 long time;
0fab12b0 414 if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
f1fae91f 415 time = floorToCalendar(time0, timeDelta);
8e1f81f1 416 } else {
f1fae91f 417 time = (time0 / timeDelta) * timeDelta;
8e1f81f1 418 if (time != time0) {
f1fae91f 419 time += timeDelta;
8e1f81f1
PT
420 }
421 }
422
f1fae91f 423 int y = rect0.y + rect0.height;
8e1f81f1 424
0fab12b0 425 if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
8e1f81f1
PT
426 timeDraw.drawAbsHeader(gc, time, absHeaderRect);
427 }
428
55d1fc96 429 List<Integer> tickList = new ArrayList<>();
8e1f81f1 430 while (true) {
0fcf3b09 431 int x = rect.x + leftSpace + (int) (Math.floor((time - time0) * pixelsPerNanoSec));
f1fae91f 432 if (x >= rect.x + leftSpace + rect.width - rect0.width) {
8e1f81f1
PT
433 break;
434 }
435 if (x >= rect.x + leftSpace) {
83dcfe09 436 gc.drawLine(x, y, x, y + Y_OFFSET);
f1fae91f
PT
437 rect0.x = x;
438 if (x + rect0.width <= rect.x + rect.width) {
439 timeDraw.draw(gc, time, rect0);
8e1f81f1 440 }
55d1fc96 441 tickList.add(x);
8e1f81f1 442 }
f1fae91f 443 if (pixelsPerNanoSec == 0 || time > Long.MAX_VALUE - timeDelta || timeDelta == 0) {
8e1f81f1
PT
444 break;
445 }
0fab12b0 446 if (fTimeProvider != null && fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
f1fae91f
PT
447 if (timeDelta >= YEAR_IN_NS) {
448 long millis = time / MILLISEC_IN_NS;
8e1f81f1 449 GREGORIAN_CALENDAR.setTime(new Date(millis));
f1fae91f 450 GREGORIAN_CALENDAR.add(Calendar.YEAR, (int) (timeDelta / YEAR_IN_NS));
8e1f81f1 451 millis = GREGORIAN_CALENDAR.getTimeInMillis();
f1fae91f
PT
452 time = millis * MILLISEC_IN_NS;
453 } else if (timeDelta >= MONTH_IN_NS) {
454 long millis = time / MILLISEC_IN_NS;
8e1f81f1 455 GREGORIAN_CALENDAR.setTime(new Date(millis));
f1fae91f 456 GREGORIAN_CALENDAR.add(Calendar.MONTH, (int) (timeDelta / MONTH_IN_NS));
8e1f81f1 457 millis = GREGORIAN_CALENDAR.getTimeInMillis();
f1fae91f
PT
458 time = millis * MILLISEC_IN_NS;
459 } else if (timeDelta >= DAY_IN_NS) {
460 long millis = time / MILLISEC_IN_NS;
8e1f81f1 461 GREGORIAN_CALENDAR.setTime(new Date(millis));
f1fae91f 462 GREGORIAN_CALENDAR.add(Calendar.DAY_OF_MONTH, (int) (timeDelta / DAY_IN_NS));
8e1f81f1 463 millis = GREGORIAN_CALENDAR.getTimeInMillis();
f1fae91f 464 time = millis * MILLISEC_IN_NS;
8e1f81f1 465 } else {
f1fae91f 466 time += timeDelta;
8e1f81f1
PT
467 }
468 } else {
f1fae91f 469 time += timeDelta;
8e1f81f1
PT
470 }
471 }
55d1fc96 472 fTickList = tickList;
56b43ab2
PT
473
474 // draw marker labels
1d012443
PT
475 if (fMarkersVisible) {
476 drawMarkerLabels(fMarkers, rect, gc, time0, leftSpace, pixelsPerNanoSec);
477 }
1d012443
PT
478 }
479
480 private static void drawMarkerLabels(List<IMarkerEvent> markerEvents, Rectangle rect, GC gc, long time0, int leftSpace, double pixelsPerNanoSec) {
481 if (markerEvents == null) {
482 return;
483 }
484 for (IMarkerEvent markerEvent : markerEvents) {
485 String label = markerEvent.getLabel();
486 if (label != null && markerEvent.getEntry() == null) {
487 label = label.substring(0, Math.min(label.indexOf('\n') != -1 ? label.indexOf('\n') : label.length(), MAX_LABEL_LENGTH));
488 int x = rect.x + leftSpace + (int) (Math.floor((markerEvent.getTime() - time0) * pixelsPerNanoSec));
489 int y = rect.y + rect.height - gc.stringExtent(" ").y + 2; //$NON-NLS-1$
490 gc.setForeground(markerEvent.getColor());
491 Utils.drawText(gc, label, x, y, true);
56b43ab2
PT
492 }
493 }
8e1f81f1
PT
494 }
495
0fcf3b09
PT
496 private static void drawRangeDecorators(Rectangle rect, GC gc, int x1, int x2) {
497 int y1 = rect.y + rect.height - 9;
498 int y2 = rect.y + rect.height - 5;
499 int ym = (y1 + y2) / 2;
500 if (x1 >= rect.x) {
501 // T1
85203d74
PT
502 gc.drawLine(x1 - 2, y1, x1 - 2, y2);
503 gc.drawLine(x1 - 3, y1, x1 - 1, y1);
504 gc.drawLine(x1 + 1, y1, x1 + 1, y2);
0fcf3b09 505 }
85203d74
PT
506 if (x2 >= rect.x && Math.abs(x2 - x1 - 2) > 3) {
507 // T of T2
0fcf3b09
PT
508 gc.drawLine(x2 - 2, y1, x2 - 2, y2);
509 gc.drawLine(x2 - 3, y1, x2 - 1, y1);
510 }
85203d74
PT
511 if (x2 >= rect.x && Math.abs(x2 - x1 + 3) > 3) {
512 // 2 of T2
0fcf3b09
PT
513 gc.drawLine(x2 + 1, y1, x2 + 3, y1);
514 gc.drawLine(x2 + 3, y1, x2 + 3, ym);
515 gc.drawLine(x2 + 1, ym, x2 + 3, ym);
516 gc.drawLine(x2 + 1, ym, x2 + 1, y2);
517 gc.drawLine(x2 + 1, y2, x2 + 3, y2);
518 }
519 }
520
f1fae91f 521 private static long floorToCalendar(long time, long timeDelta) {
41b5c37f
AM
522 long ret = time;
523
f1fae91f
PT
524 if (timeDelta >= YEAR_IN_NS) {
525 GREGORIAN_CALENDAR.setTime(new Date(ret / MILLISEC_IN_NS));
8e1f81f1
PT
526 int year = GREGORIAN_CALENDAR.get(Calendar.YEAR);
527 int yearDelta = (int) (timeDelta / YEAR_IN_NS);
528 year = (year / yearDelta) * yearDelta;
529 GREGORIAN_CALENDAR.set(Calendar.YEAR, year);
530 GREGORIAN_CALENDAR.set(Calendar.MONTH, 0); // January 1st of year
531 GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1);
532 GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);
533 GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);
534 GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);
535 GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);
f1fae91f
PT
536 ret = GREGORIAN_CALENDAR.getTimeInMillis() * MILLISEC_IN_NS;
537 } else if (timeDelta >= MONTH_IN_NS) {
538 GREGORIAN_CALENDAR.setTime(new Date(ret / MILLISEC_IN_NS));
8e1f81f1
PT
539 int month = GREGORIAN_CALENDAR.get(Calendar.MONTH);
540 int monthDelta = (int) (timeDelta / MONTH_IN_NS);
541 month = (month / monthDelta) * monthDelta;
542 GREGORIAN_CALENDAR.set(Calendar.MONTH, month);
543 GREGORIAN_CALENDAR.set(Calendar.DAY_OF_MONTH, 1); // 1st of month
544 GREGORIAN_CALENDAR.set(Calendar.HOUR_OF_DAY, 0);
545 GREGORIAN_CALENDAR.set(Calendar.MINUTE, 0);
546 GREGORIAN_CALENDAR.set(Calendar.SECOND, 0);
547 GREGORIAN_CALENDAR.set(Calendar.MILLISECOND, 0);
f1fae91f 548 ret = GREGORIAN_CALENDAR.getTimeInMillis() * MILLISEC_IN_NS;
8e1f81f1 549 } else {
f1fae91f 550 long offset = GREGORIAN_CALENDAR.getTimeZone().getOffset(ret / MILLISEC_IN_NS) * MILLISEC_IN_NS;
41b5c37f
AM
551 ret += offset;
552 ret = (ret / timeDelta) * timeDelta;
553 ret -= offset;
8e1f81f1 554 }
41b5c37f 555 return ret;
8e1f81f1
PT
556 }
557
558 private int calculateDigits(long time0, long time1) {
559 int numDigits = 5;
560 long timeRange = time1 - time0;
561
0fab12b0 562 if (fTimeProvider.getTimeFormat() == TimeFormat.CALENDAR) {
8e1f81f1
PT
563 // Calculate the number of digits to represent the minutes provided
564 // 11:222
565 // HH:mm:ss
566 numDigits += 8;
567 if (timeRange < 10000) {
568 // HH:11:222:333:444__
569 numDigits += 10;
570 } else if (timeRange < 10000000) {
571 // HH:11:222:333__
572 numDigits += 6;
573 }
574 } else {
f1fae91f 575 long sec = time1 / SEC_IN_NS;
8e1f81f1
PT
576 numDigits = Long.toString(sec).length();
577 int thousandGroups = (numDigits - 1) / 3;
578 numDigits += thousandGroups;
579 numDigits += 12; // .000 000 000
0fab12b0
PT
580 if (fTimeProvider.getTimeFormat() == TimeFormat.CYCLES) {
581 numDigits += Messages.Utils_ClockCyclesUnit.length();
582 }
8e1f81f1
PT
583 }
584
585 return numDigits;
586 }
587
588 @Override
589 public void mouseDown(MouseEvent e) {
590 getParent().setFocus();
f1fae91f
PT
591 if (fDragState == NO_BUTTON && null != fTimeProvider) {
592 int x = e.x - fTimeProvider.getNameSpace();
593 if (LEFT_BUTTON == e.button && x > 0) {
8e1f81f1 594 setCapture(true);
f1fae91f 595 fDragState = LEFT_BUTTON;
8e1f81f1
PT
596 }
597 if (x < 0) {
598 x = 0;
f1fae91f
PT
599 } else if (x > getSize().x - fTimeProvider.getNameSpace()) {
600 x = getSize().x - fTimeProvider.getNameSpace();
8e1f81f1 601 }
f1fae91f
PT
602 fDragX = x;
603 fDragX0 = x;
604 fTime0bak = fTimeProvider.getTime0();
605 fTime1bak = fTimeProvider.getTime1();
8e1f81f1
PT
606 }
607 }
608
609 @Override
610 public void mouseUp(MouseEvent e) {
f1fae91f 611 if (e.button == LEFT_BUTTON && fDragState == LEFT_BUTTON) {
8e1f81f1 612 setCapture(false);
f1fae91f 613 fDragState = NO_BUTTON;
8e1f81f1
PT
614
615 // Notify time provider to check the need for listener notification
f1fae91f
PT
616 if (fDragX != fDragX0 && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
617 fTimeProvider.setStartFinishTimeNotify(fTimeProvider.getTime0(), fTimeProvider.getTime1());
8e1f81f1 618 }
8e1f81f1
PT
619 }
620 }
621
622 @Override
623 public void mouseMove(MouseEvent e) {
f1fae91f 624 if (fDragX0 < 0 || fDragState == NO_BUTTON || fTimeProvider == null) {
8e1f81f1
PT
625 return;
626 }
627 Point size = getSize();
f1fae91f 628 int leftSpace = fTimeProvider.getNameSpace();
8e1f81f1 629 int x = e.x - leftSpace;
f1fae91f
PT
630 if (LEFT_BUTTON == fDragState) {
631 if (x > 0 && size.x > leftSpace && fDragX != x) {
632 fDragX = x;
633 if (fTimeProvider.getTime0() == fTimeProvider.getTime1()) {
8e1f81f1
PT
634 return;
635 }
f1fae91f 636 long interval = (long) ((fTime1bak - fTime0bak) * ((double) fDragX0 / fDragX));
8e1f81f1 637 if (interval == Long.MAX_VALUE) {
88de10c6 638 fTimeProvider.setStartFinishTimeNotify(fTime0bak, Long.MAX_VALUE);
8e1f81f1 639 } else {
f1fae91f 640 long time1 = fTime0bak + (long) ((fTime1bak - fTime0bak) * ((double) fDragX0 / fDragX));
88de10c6 641 fTimeProvider.setStartFinishTimeNotify(fTime0bak, time1);
8e1f81f1
PT
642 }
643 }
8e1f81f1
PT
644 }
645 }
646
647 @Override
648 public void mouseDoubleClick(MouseEvent e) {
f1fae91f
PT
649 if (e.button == 1 && null != fTimeProvider && fTimeProvider.getTime0() != fTimeProvider.getTime1() && (e.stateMask & SWT.BUTTON_MASK) == 0) {
650 fTimeProvider.resetStartFinishTime();
f1fae91f
PT
651 fTime0bak = fTimeProvider.getTime0();
652 fTime1bak = fTimeProvider.getTime1();
8e1f81f1
PT
653 }
654 }
c1cd9635 655
6dcc38b9 656 /**
c1cd9635
MAL
657 * Update the display to use the updated timestamp format
658 *
6dcc38b9
MK
659 * @param signal
660 * the incoming signal
c1cd9635
MAL
661 */
662 @TmfSignalHandler
663 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
664 TimeDraw.updateTimeZone();
665 Utils.updateTimeZone();
666 redraw();
667 }
8e1f81f1
PT
668}
669
670abstract class TimeDraw {
f1fae91f
PT
671 protected static final long MICROSEC_IN_NS = 1000;
672 protected static final long MILLISEC_IN_NS = 1000000;
673 protected static final long MILLISEC_IN_US = 1000;
674 protected static final long SEC_IN_NS = 1000000000;
675 protected static final long SEC_IN_MS = 1000;
6dcc38b9
MK
676 private static final String S = ""; //$NON-NLS-1$
677 private static final String S0 = "0"; //$NON-NLS-1$
f1fae91f
PT
678 private static final String S00 = "00"; //$NON-NLS-1$
679 protected static final long PAD_1000 = 1000;
6dcc38b9
MK
680 protected static final SimpleDateFormat SEC_FORMAT_HEADER =
681 new SimpleDateFormat("yyyy MMM dd");//$NON-NLS-1$
682 protected static final SimpleDateFormat SEC_FORMAT =
683 new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
684 protected static final SimpleDateFormat MIN_FORMAT_HEADER =
685 new SimpleDateFormat("yyyy MMM dd"); //$NON-NLS-1$
686 protected static final SimpleDateFormat MIN_FORMAT =
687 new SimpleDateFormat("HH:mm"); //$NON-NLS-1$
688 protected static final SimpleDateFormat HOURS_FORMAT_HEADER =
689 new SimpleDateFormat("yyyy"); //$NON-NLS-1$
690 protected static final SimpleDateFormat HOURS_FORMAT =
691 new SimpleDateFormat("MMM dd HH:mm"); //$NON-NLS-1$
692 protected static final SimpleDateFormat DAY_FORMAT_HEADER =
693 new SimpleDateFormat("yyyy"); //$NON-NLS-1$
694 protected static final SimpleDateFormat DAY_FORMAT =
695 new SimpleDateFormat("MMM dd"); //$NON-NLS-1$
696 protected static final SimpleDateFormat MONTH_FORMAT =
697 new SimpleDateFormat("yyyy MMM"); //$NON-NLS-1$
698 protected static final SimpleDateFormat YEAR_FORMAT =
699 new SimpleDateFormat("yyyy"); //$NON-NLS-1$
700
701 protected static final List<SimpleDateFormat> formats;
702 static
703 {
704 ImmutableList.Builder<SimpleDateFormat> formatArrayBuilder = ImmutableList.<SimpleDateFormat> builder();
705 formatArrayBuilder.add(SEC_FORMAT);
706 formatArrayBuilder.add(SEC_FORMAT_HEADER);
707 formatArrayBuilder.add(MIN_FORMAT);
708 formatArrayBuilder.add(MIN_FORMAT_HEADER);
709 formatArrayBuilder.add(HOURS_FORMAT);
710 formatArrayBuilder.add(HOURS_FORMAT_HEADER);
711 formatArrayBuilder.add(DAY_FORMAT);
712 formatArrayBuilder.add(DAY_FORMAT_HEADER);
713 formatArrayBuilder.add(MONTH_FORMAT);
714 formatArrayBuilder.add(YEAR_FORMAT);
715 formats = formatArrayBuilder.build();
716 }
c1cd9635
MAL
717
718 /**
719 * Updates the timezone using the preferences.
720 */
721 public static void updateTimeZone() {
7c34a4ea 722 final TimeZone timeZone = TmfTimePreferences.getTimeZone();
6dcc38b9
MK
723 for (SimpleDateFormat sdf : formats) {
724 synchronized (sdf) {
725 sdf.setTimeZone(timeZone);
726 }
c1cd9635
MAL
727 }
728 }
729
8e1f81f1
PT
730 static String sep(long n) {
731 StringBuilder retVal = new StringBuilder();
732 String s = Long.toString(n);
733 for (int i = 0; i < s.length(); i++) {
734 int pos = s.length() - i - 1;
735 retVal.append(s.charAt(i));
736 if (pos % 3 == 0 && pos != 0) {
737 retVal.append(' ');
738 }
739 }
740 return retVal.toString();
741 }
742
743 static String pad(long n) {
744 String s;
745 if (n < 10) {
746 s = S00;
747 } else if (n < 100) {
748 s = S0;
749 } else {
750 s = S;
751 }
752 return s + n;
753 }
754
0fab12b0 755 public abstract int draw(GC gc, long time, Rectangle rect);
8e1f81f1 756
a0a88f65 757 /**
f1fae91f 758 * Override to draw absolute time header. This is for the time information
a0a88f65
AM
759 * not shown in the draw of each tick
760 *
761 * @param gc
762 * Graphics context
f1fae91f
PT
763 * @param nanosec
764 * time in nanosec
a0a88f65
AM
765 * @param absHeaderRect
766 * Header rectangle
767 */
f1fae91f 768 public void drawAbsHeader(GC gc, long nanosec, Rectangle absHeaderRect) {
8e1f81f1 769 }
8e1f81f1
PT
770}
771
772class TimeDrawSec extends TimeDraw {
8e1f81f1 773 @Override
0fab12b0 774 public int draw(GC gc, long nanosec, Rectangle rect) {
f1fae91f 775 long sec = nanosec / SEC_IN_NS;
0fab12b0 776 return Utils.drawText(gc, sep(sec), rect, true);
8e1f81f1
PT
777 }
778}
779
780class TimeDrawMillisec extends TimeDraw {
8e1f81f1 781 @Override
0fab12b0 782 public int draw(GC gc, long nanosec, Rectangle rect) {
f1fae91f
PT
783 long millisec = nanosec / MILLISEC_IN_NS;
784 long ms = millisec % PAD_1000;
785 long sec = millisec / SEC_IN_MS;
0fab12b0 786 return Utils.drawText(gc, sep(sec) + "." + pad(ms), rect, true); //$NON-NLS-1$
8e1f81f1
PT
787 }
788}
789
790class TimeDrawMicrosec extends TimeDraw {
8e1f81f1 791 @Override
0fab12b0 792 public int draw(GC gc, long nanosec, Rectangle rect) {
f1fae91f
PT
793 long microsec = nanosec / MICROSEC_IN_NS;
794 long us = microsec % PAD_1000;
795 long millisec = microsec / MILLISEC_IN_US;
796 long ms = millisec % PAD_1000;
797 long sec = millisec / SEC_IN_MS;
0fab12b0 798 return Utils.drawText(gc, sep(sec) + "." + pad(ms) + " " + pad(us), rect, true); //$NON-NLS-1$ //$NON-NLS-2$
8e1f81f1
PT
799 }
800}
801
802class TimeDrawNanosec extends TimeDraw {
8e1f81f1 803 @Override
0fab12b0 804 public int draw(GC gc, long nanosec, Rectangle rect) {
f1fae91f
PT
805 long ns = nanosec % PAD_1000;
806 long microsec = nanosec / MICROSEC_IN_NS;
807 long us = microsec % PAD_1000;
808 long millisec = microsec / MILLISEC_IN_US;
809 long ms = millisec % PAD_1000;
810 long sec = millisec / SEC_IN_MS;
0fab12b0 811 return Utils.drawText(gc, sep(sec) + "." + pad(ms) + " " + pad(us) + " " + pad(ns), rect, true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
8e1f81f1
PT
812 }
813}
814
815class TimeDrawAbsYear extends TimeDraw {
8e1f81f1 816 @Override
0fab12b0 817 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
818 String stime;
819 synchronized (YEAR_FORMAT) {
820 stime = YEAR_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
821 }
0fab12b0 822 return Utils.drawText(gc, stime, rect, true);
8e1f81f1 823 }
8e1f81f1
PT
824}
825
826class TimeDrawAbsMonth extends TimeDraw {
8e1f81f1 827 @Override
0fab12b0 828 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
829 String stime;
830 synchronized (MONTH_FORMAT) {
831 stime = MONTH_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
832 }
0fab12b0 833 return Utils.drawText(gc, stime, rect, true);
8e1f81f1 834 }
8e1f81f1
PT
835}
836
837class TimeDrawAbsDay extends TimeDraw {
8e1f81f1 838 @Override
0fab12b0 839 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
840 String stime;
841 synchronized (DAY_FORMAT) {
842 stime = DAY_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
843 }
0fab12b0 844 return Utils.drawText(gc, stime, rect, true);
8e1f81f1
PT
845 }
846
847 @Override
f1fae91f 848 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
849 String header;
850 synchronized (DAY_FORMAT_HEADER) {
851 header = DAY_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
852 }
8e1f81f1
PT
853 int headerwidth = gc.stringExtent(header).x + 4;
854 if (headerwidth <= rect.width) {
855 rect.x += (rect.width - headerwidth);
856 Utils.drawText(gc, header, rect, true);
857 }
858 }
8e1f81f1
PT
859}
860
861class TimeDrawAbsHrs extends TimeDraw {
8e1f81f1 862 @Override
0fab12b0 863 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
864 String stime;
865 synchronized (HOURS_FORMAT) {
866 stime = HOURS_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
867 }
0fab12b0 868 return Utils.drawText(gc, stime, rect, true);
8e1f81f1
PT
869 }
870
871 @Override
f1fae91f 872 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
873 String header;
874 synchronized (HOURS_FORMAT_HEADER) {
875 header = HOURS_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
876 }
8e1f81f1
PT
877 int headerwidth = gc.stringExtent(header).x + 4;
878 if (headerwidth <= rect.width) {
879 rect.x += (rect.width - headerwidth);
880 Utils.drawText(gc, header, rect, true);
881 }
882 }
8e1f81f1
PT
883}
884
885class TimeDrawAbsMin extends TimeDraw {
8e1f81f1 886 @Override
0fab12b0 887 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
888 String stime;
889 synchronized (MIN_FORMAT) {
890 stime = MIN_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
891 }
0fab12b0 892 return Utils.drawText(gc, stime, rect, true);
8e1f81f1
PT
893 }
894
895 @Override
f1fae91f 896 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
897 String header;
898 synchronized (MIN_FORMAT_HEADER) {
899 header = MIN_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
900 }
8e1f81f1
PT
901 int headerwidth = gc.stringExtent(header).x + 4;
902 if (headerwidth <= rect.width) {
903 rect.x += (rect.width - headerwidth);
904 Utils.drawText(gc, header, rect, true);
905 }
906 }
8e1f81f1
PT
907}
908
909class TimeDrawAbsSec extends TimeDraw {
8e1f81f1 910 @Override
0fab12b0 911 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
912 String stime;
913 synchronized (SEC_FORMAT) {
914 stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
915 }
0fab12b0 916 return Utils.drawText(gc, stime, rect, true);
8e1f81f1
PT
917 }
918
919 @Override
f1fae91f 920 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
921 String header;
922 synchronized (SEC_FORMAT_HEADER) {
923 header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
924 }
8e1f81f1
PT
925 int headerwidth = gc.stringExtent(header).x + 4;
926 if (headerwidth <= rect.width) {
927 rect.x += (rect.width - headerwidth);
928 Utils.drawText(gc, header, rect, true);
929 }
930 }
8e1f81f1
PT
931}
932
933class TimeDrawAbsMillisec extends TimeDraw {
8e1f81f1 934 @Override
0fab12b0 935 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
936 String stime;
937 synchronized (SEC_FORMAT) {
938 stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
939 }
f1fae91f 940 String ns = Utils.formatNs(nanosec, Resolution.MILLISEC);
0fab12b0 941 return Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$
8e1f81f1
PT
942 }
943
944 @Override
f1fae91f 945 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
946 String header;
947 synchronized (SEC_FORMAT_HEADER) {
948 header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
949 }
8e1f81f1
PT
950 int headerwidth = gc.stringExtent(header).x + 4;
951 if (headerwidth <= rect.width) {
952 rect.x += (rect.width - headerwidth);
953 Utils.drawText(gc, header, rect, true);
954 }
955 }
8e1f81f1
PT
956}
957
958class TimeDrawAbsMicroSec extends TimeDraw {
8e1f81f1 959 @Override
0fab12b0 960 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
961 String stime;
962 synchronized (SEC_FORMAT) {
963 stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
964 }
f1fae91f 965 String micr = Utils.formatNs(nanosec, Resolution.MICROSEC);
0fab12b0 966 return Utils.drawText(gc, stime + "." + micr, rect, true); //$NON-NLS-1$
8e1f81f1
PT
967 }
968
969 @Override
f1fae91f 970 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
971 String header;
972 synchronized (SEC_FORMAT_HEADER) {
973 header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
974 }
8e1f81f1
PT
975 int headerwidth = gc.stringExtent(header).x + 4;
976 if (headerwidth <= rect.width) {
977 rect.x += (rect.width - headerwidth);
978 Utils.drawText(gc, header, rect, true);
979 }
980 }
8e1f81f1
PT
981}
982
983class TimeDrawAbsNanoSec extends TimeDraw {
8e1f81f1 984 @Override
0fab12b0 985 public int draw(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
986 String stime;
987 synchronized (SEC_FORMAT) {
988 stime = SEC_FORMAT.format(new Date(nanosec / MILLISEC_IN_NS));
989 }
f1fae91f 990 String ns = Utils.formatNs(nanosec, Resolution.NANOSEC);
0fab12b0 991 return Utils.drawText(gc, stime + "." + ns, rect, true); //$NON-NLS-1$
8e1f81f1
PT
992 }
993
994 @Override
f1fae91f 995 public void drawAbsHeader(GC gc, long nanosec, Rectangle rect) {
6dcc38b9
MK
996 String header;
997 synchronized (SEC_FORMAT_HEADER) {
998 header = SEC_FORMAT_HEADER.format(new Date(nanosec / MILLISEC_IN_NS));
999 }
8e1f81f1
PT
1000 int headerwidth = gc.stringExtent(header).x + 4;
1001 if (headerwidth <= rect.width) {
1002 rect.x += (rect.width - headerwidth);
1003 Utils.drawText(gc, header, rect, true);
1004 }
1005 }
8e1f81f1 1006}
026664b7 1007
026664b7 1008class TimeDrawNumber extends TimeDraw {
026664b7 1009 @Override
0fab12b0 1010 public int draw(GC gc, long time, Rectangle rect) {
026664b7 1011 String stime = NumberFormat.getInstance().format(time);
0fab12b0
PT
1012 return Utils.drawText(gc, stime, rect, true);
1013 }
1014}
1015
1016class TimeDrawCycles extends TimeDraw {
1017 @Override
1018 public int draw(GC gc, long time, Rectangle rect) {
1019 String stime = Utils.formatTime(time, TimeFormat.CYCLES, Resolution.SECONDS);
1020 return Utils.drawText(gc, stime, rect, true);
026664b7 1021 }
026664b7 1022}
This page took 0.125882 seconds and 5 git commands to generate.