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