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