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