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