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