lttng/tmf: add a "unit-less" representation of time in timechart
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / widgets / Utils.java
1 /*****************************************************************************
2 * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2012 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 - Udpated for TMF
12 * Patrick Tasse - Refactoring
13 *
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.Date;
21 import java.util.Iterator;
22
23 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
24 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
25 import org.eclipse.swt.graphics.Color;
26 import org.eclipse.swt.graphics.Device;
27 import org.eclipse.swt.graphics.GC;
28 import org.eclipse.swt.graphics.Point;
29 import org.eclipse.swt.graphics.Rectangle;
30 import org.eclipse.swt.widgets.Display;
31
32 /**
33 * General utilities and definitions used by the time graph widget
34 *
35 * @version 1.0
36 * @author Alvaro Sanchez-Leon
37 * @author Patrick Tasse
38 */
39 public class Utils {
40
41 /** Time format for dates and timestamp */
42 public enum TimeFormat {
43 /** Relative to the start of the trace */
44 RELATIVE,
45 /** Absolute timestamp (ie, relative to the Unix epoch) */
46 CALENDAR,
47 /** timestamp displayed as a simple number */
48 NUMBER,
49 }
50
51 static public final int IMG_THREAD_RUNNING = 0;
52 static public final int IMG_THREAD_SUSPENDED = 1;
53 static public final int IMG_THREAD_STOPPED = 2;
54 static public final int IMG_METHOD_RUNNING = 3;
55 static public final int IMG_METHOD = 4;
56 static public final int IMG_NUM = 5;
57
58 static public final Object[] _empty = new Object[0];
59
60 public static enum Resolution {
61 SECONDS, MILLISEC, MICROSEC, NANOSEC
62 }
63
64 static private final SimpleDateFormat stimeformat = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
65 static private final SimpleDateFormat sdateformat = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
66
67 static Rectangle clone(Rectangle source) {
68 return new Rectangle(source.x, source.y, source.width, source.height);
69 }
70
71 /**
72 * Initialize a Rectangle object to default values (all equal to 0)
73 *
74 * @param rect
75 * The Rectangle to initialize
76 */
77 static public void init(Rectangle rect) {
78 rect.x = 0;
79 rect.y = 0;
80 rect.width = 0;
81 rect.height = 0;
82 }
83
84 /**
85 * Initialize a Rectangle object with all the given values
86 *
87 * @param rect
88 * The Rectangle object to initialize
89 * @param x
90 * The X coordinate
91 * @param y
92 * The Y coordinate
93 * @param width
94 * The width of the rectangle
95 * @param height
96 * The height of the rectangle
97 */
98 static public void init(Rectangle rect, int x, int y, int width, int height) {
99 rect.x = x;
100 rect.y = y;
101 rect.width = width;
102 rect.height = height;
103 }
104
105 /**
106 * Initialize a Rectangle object to another existing Rectangle's values.
107 *
108 * @param rect
109 * The Rectangle to initialize
110 * @param source
111 * The reference Rectangle to copy
112 */
113 static public void init(Rectangle rect, Rectangle source) {
114 rect.x = source.x;
115 rect.y = source.y;
116 rect.width = source.width;
117 rect.height = source.height;
118 }
119
120 /**
121 * Reduce the size of a given rectangle by the given amounts.
122 *
123 * @param rect
124 * The rectangle to modify
125 * @param x
126 * The reduction in width
127 * @param y
128 * The reduction in height
129 */
130 static public void deflate(Rectangle rect, int x, int y) {
131 rect.x += x;
132 rect.y += y;
133 rect.width -= x + x;
134 rect.height -= y + y;
135 }
136
137 /**
138 * Increase the size of a given rectangle by the given amounts.
139 *
140 * @param rect
141 * The rectangle to modify
142 * @param x
143 * The augmentation in width
144 * @param y
145 * The augmentation in height
146 */
147 static public void inflate(Rectangle rect, int x, int y) {
148 rect.x -= x;
149 rect.y -= y;
150 rect.width += x + x;
151 rect.height += y + y;
152 }
153
154 static void dispose(Color col) {
155 if (null != col) {
156 col.dispose();
157 }
158 }
159
160 /**
161 * Get the resulting color from a mix of two existing ones for a given
162 * display.
163 *
164 * @param display
165 * The display device (which might affect the color conversion)
166 * @param c1
167 * The first color
168 * @param c2
169 * The second color
170 * @param w1
171 * The gamma level for color 1
172 * @param w2
173 * The gamma level for color 2
174 * @return The resulting color
175 */
176 static public Color mixColors(Device display, Color c1, Color c2, int w1,
177 int w2) {
178 return new Color(display, (w1 * c1.getRed() + w2 * c2.getRed())
179 / (w1 + w2), (w1 * c1.getGreen() + w2 * c2.getGreen())
180 / (w1 + w2), (w1 * c1.getBlue() + w2 * c2.getBlue())
181 / (w1 + w2));
182 }
183
184 /**
185 * Get the system color with the given ID.
186 *
187 * @param id
188 * The color ID
189 * @return The resulting color
190 */
191 static public Color getSysColor(int id) {
192 Color col = Display.getCurrent().getSystemColor(id);
193 return new Color(col.getDevice(), col.getRGB());
194 }
195
196 /**
197 * Get the resulting color from a mix of two existing ones for the current
198 * display.
199 *
200 * @param col1
201 * The first color
202 * @param col2
203 * The second color
204 * @param w1
205 * The gamma level for color 1
206 * @param w2
207 * The gamma level for color 2
208 * @return The resulting color
209 */
210 static public Color mixColors(Color col1, Color col2, int w1, int w2) {
211 return mixColors(Display.getCurrent(), col1, col2, w1, w2);
212 }
213
214 /**
215 * Draw text in a rectangle.
216 *
217 * @param gc
218 * The SWT GC object
219 * @param text
220 * The text to draw
221 * @param rect
222 * The rectangle object which is being drawn
223 * @param transp
224 * Should we transpose the color
225 * @return The X coordinate where we have written
226 */
227 static public int drawText(GC gc, String text, Rectangle rect, boolean transp) {
228 Point size = gc.stringExtent(text);
229 gc.drawText(text, rect.x, rect.y, transp);
230 return size.x;
231 }
232
233 /**
234 * Draw text at a given location.
235 *
236 * @param gc
237 * The SWT GC object
238 * @param text
239 * The text to draw
240 * @param x
241 * The X coordinate of the starting point
242 * @param y
243 * the Y coordinate of the starting point
244 * @param transp
245 * Should we transpose the color
246 * @return The X coordinate where we have written
247 */
248 static public int drawText(GC gc, String text, int x, int y, boolean transp) {
249 Point size = gc.stringExtent(text);
250 gc.drawText(text, x, y, transp);
251 return size.x;
252 }
253
254 /**
255 * Draw text in a rectangle, trimming the text to prevent exceeding the specified width.
256 *
257 * @param gc
258 * The SWT GC object
259 * @param text
260 * The string to be drawn
261 * @param x
262 * The x coordinate of the top left corner of the rectangular area where the text is to be drawn
263 * @param y
264 * The y coordinate of the top left corner of the rectangular area where the text is to be drawn
265 * @param width
266 * The width of the area to be drawn
267 * @param isCentered
268 * If <code>true</code> the text will be centered in the available width if space permits
269 * @param isTransparent
270 * If <code>true</code> the background will be transparent, otherwise it will be opaque
271 * @return The number of characters written
272 *
273 * @since 2.0
274 */
275 static public int drawText(GC gc, String text, int x, int y, int width, boolean isCentered, boolean isTransparent) {
276 int len = text.length();
277 int textWidth = 0;
278 while (len > 0) {
279 textWidth = gc.stringExtent(text.substring(0, len)).x;
280 if (textWidth <= width) {
281 break;
282 }
283 isCentered = false;
284 len--;
285 }
286 if (len > 0) {
287 if (isCentered) {
288 x += (width - textWidth) / 2;
289 }
290 gc.drawText(text.substring(0, len), x, y, isTransparent);
291 }
292 return len;
293 }
294
295 /**
296 * Formats time in format: MM:SS:NNN
297 *
298 * @param time time
299 * @param format 0: MMMM:ss:nnnnnnnnn, 1: HH:MM:ss MMM.mmmm.nnn
300 * @param resolution the resolution
301 * @return the formatted time
302 */
303 static public String formatTime(long time, TimeFormat format, Resolution resolution) {
304 // if format is absolute (Calendar)
305 if (format == TimeFormat.CALENDAR) {
306 return formatTimeAbs(time, resolution);
307 } else if (format == TimeFormat.NUMBER) {
308 return NumberFormat.getInstance().format(time);
309 }
310
311 StringBuffer str = new StringBuffer();
312 boolean neg = time < 0;
313 if (neg) {
314 time = -time;
315 str.append('-');
316 }
317
318 long sec = (long) (time * 1E-9);
319 // TODO: Expand to make it possible to select the minute, second, nanosecond format
320 //printing minutes is suppressed just sec and ns
321 // if (sec / 60 < 10)
322 // str.append('0');
323 // str.append(sec / 60);
324 // str.append(':');
325 // sec %= 60;
326 // if (sec < 10)
327 // str.append('0');
328 str.append(sec);
329 String ns = formatNs(time, resolution);
330 if (!ns.equals("")) { //$NON-NLS-1$
331 str.append('.');
332 str.append(ns);
333 }
334
335 return str.toString();
336 }
337
338 /**
339 * From input time in nanoseconds, convert to Date format YYYY-MM-dd
340 *
341 * @param absTime
342 * The source time, in ns
343 * @return the formatted date
344 */
345 public static String formatDate(long absTime) {
346 String sdate = sdateformat.format(new Date((long) (absTime * 1E-6)));
347 return sdate;
348 }
349
350 /**
351 * Formats time in ns to Calendar format: HH:MM:SS MMM.mmm.nnn
352 *
353 * @param time
354 * The source time, in ns
355 * @param res
356 * The resolution to use
357 * @return the formatted time
358 */
359 static public String formatTimeAbs(long time, Resolution res) {
360 StringBuffer str = new StringBuffer();
361
362 // format time from nanoseconds to calendar time HH:MM:SS
363 String stime = stimeformat.format(new Date((long) (time * 1E-6)));
364 str.append(stime);
365 str.append('.');
366 // append the Milliseconds, MicroSeconds and NanoSeconds as specified in
367 // the Resolution
368 str.append(formatNs(time, res));
369 return str.toString();
370 }
371
372 /**
373 * Obtains the remainder fraction on unit Seconds of the entered value in
374 * nanoseconds. e.g. input: 1241207054171080214 ns The number of fraction
375 * seconds can be obtained by removing the last 9 digits: 1241207054 the
376 * fractional portion of seconds, expressed in ns is: 171080214
377 *
378 * @param time
379 * The source time in ns
380 * @param res
381 * The Resolution to use
382 * @return the formatted nanosec
383 */
384 public static String formatNs(long time, Resolution res) {
385 StringBuffer str = new StringBuffer();
386 boolean neg = time < 0;
387 if (neg) {
388 time = -time;
389 }
390
391 // The following approach could be used although performance
392 // decreases in half.
393 // String strVal = String.format("%09d", time);
394 // String tmp = strVal.substring(strVal.length() - 9);
395
396 long ns = time;
397 ns %= 1000000000;
398 if (ns < 10) {
399 str.append("00000000"); //$NON-NLS-1$
400 } else if (ns < 100) {
401 str.append("0000000"); //$NON-NLS-1$
402 } else if (ns < 1000) {
403 str.append("000000"); //$NON-NLS-1$
404 } else if (ns < 10000) {
405 str.append("00000"); //$NON-NLS-1$
406 } else if (ns < 100000) {
407 str.append("0000"); //$NON-NLS-1$
408 } else if (ns < 1000000) {
409 str.append("000"); //$NON-NLS-1$
410 } else if (ns < 10000000) {
411 str.append("00"); //$NON-NLS-1$
412 } else if (ns < 100000000) {
413 str.append("0"); //$NON-NLS-1$
414 }
415 str.append(ns);
416
417 if (res == Resolution.MILLISEC) {
418 return str.substring(0, 3);
419 } else if (res == Resolution.MICROSEC) {
420 return str.substring(0, 6);
421 } else if (res == Resolution.NANOSEC) {
422 return str.substring(0, 9);
423 }
424 return ""; //$NON-NLS-1$
425 }
426
427 /**
428 * FIXME Currently does nothing.
429 *
430 * @param opt
431 * The option name
432 * @param def
433 * The option value
434 * @param min
435 * The minimal accepted value
436 * @param max
437 * The maximal accepted value
438 * @return The value that was read
439 */
440 static public int loadIntOption(String opt, int def, int min, int max) {
441 // int val =
442 // TraceUIPlugin.getDefault().getPreferenceStore().getInt(opt);
443 // if (0 == val)
444 // val = def;
445 // if (val < min)
446 // val = min;
447 // if (val > max)
448 // val = max;
449 return def;
450 }
451
452 /**
453 * FIXME currently does nothing
454 *
455 * @param opt
456 * The option name
457 * @param val
458 * The option value
459 */
460 static public void saveIntOption(String opt, int val) {
461 // TraceUIPlugin.getDefault().getPreferenceStore().setValue(opt, val);
462 }
463
464 static ITimeEvent getFirstEvent(ITimeGraphEntry entry) {
465 if (null == entry || ! entry.hasTimeEvents()) {
466 return null;
467 }
468 Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator();
469 if (iterator != null && iterator.hasNext()) {
470 return iterator.next();
471 }
472 return null;
473 }
474
475 /**
476 * N means: <list> <li>-1: Previous Event</li> <li>0: Current Event</li> <li>
477 * 1: Next Event</li> <li>2: Previous Event when located in a non Event Area
478 * </list>
479 *
480 * @param entry
481 * @param time
482 * @param n
483 * @return
484 */
485 static ITimeEvent findEvent(ITimeGraphEntry entry, long time, int n) {
486 if (null == entry || ! entry.hasTimeEvents()) {
487 return null;
488 }
489 Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator();
490 if (iterator == null) {
491 return null;
492 }
493 ITimeEvent nextEvent = null;
494 ITimeEvent currEvent = null;
495 ITimeEvent prevEvent = null;
496
497 while (iterator.hasNext()) {
498 nextEvent = iterator.next();
499 long nextStartTime = nextEvent.getTime();
500
501 if (nextStartTime > time) {
502 break;
503 }
504
505 if (currEvent == null || currEvent.getTime() != nextStartTime) {
506 prevEvent = currEvent;
507 currEvent = nextEvent;
508 }
509 }
510
511 if (n == -1) { //previous
512 if (currEvent != null && currEvent.getTime() + currEvent.getDuration() >= time) {
513 return prevEvent;
514 }
515 return currEvent;
516 } else if (n == 0) { //current
517 if (currEvent != null && currEvent.getTime() + currEvent.getDuration() >= time) {
518 return currEvent;
519 }
520 return null;
521 } else if (n == 1) { //next
522 if (nextEvent != null && nextEvent.getTime() > time) {
523 return nextEvent;
524 }
525 return null;
526 } else if (n == 2) { //current or previous when in empty space
527 return currEvent;
528 }
529
530 return null;
531 }
532
533 /**
534 * Pretty-print a method signature.
535 *
536 * @param sig
537 * The original signature
538 * @return The pretty signature
539 */
540 static public String fixMethodSignature(String sig) {
541 int pos = sig.indexOf('(');
542 if (pos >= 0) {
543 String ret = sig.substring(0, pos);
544 sig = sig.substring(pos);
545 sig = sig + " " + ret; //$NON-NLS-1$
546 }
547 return sig;
548 }
549
550 /**
551 * Restore an original method signature from a pretty-printed one.
552 *
553 * @param sig
554 * The pretty-printed signature
555 * @return The original method signature
556 */
557 static public String restoreMethodSignature(String sig) {
558 String ret = ""; //$NON-NLS-1$
559 int pos = sig.indexOf('(');
560 if (pos >= 0) {
561 ret = sig.substring(0, pos);
562 sig = sig.substring(pos + 1);
563 }
564 pos = sig.indexOf(')');
565 if (pos >= 0) {
566 sig = sig.substring(0, pos);
567 }
568 String args[] = sig.split(","); //$NON-NLS-1$
569 StringBuffer result = new StringBuffer("("); //$NON-NLS-1$
570 for (int i = 0; i < args.length; i++) {
571 String arg = args[i].trim();
572 if (arg.length() == 0 && args.length == 1) {
573 break;
574 }
575 result.append(getTypeSignature(arg));
576 }
577 result.append(")").append(getTypeSignature(ret)); //$NON-NLS-1$
578 return result.toString();
579 }
580
581 /**
582 * Get the mangled type information from an array of types.
583 *
584 * @param type
585 * The types to convert. See method implementation for what it
586 * expects.
587 * @return The mangled string of types
588 */
589 static public String getTypeSignature(String type) {
590 int dim = 0;
591 for (int j = 0; j < type.length(); j++) {
592 if (type.charAt(j) == '[') {
593 dim++;
594 }
595 }
596 int pos = type.indexOf('[');
597 if (pos >= 0) {
598 type = type.substring(0, pos);
599 }
600 StringBuffer sig = new StringBuffer(""); //$NON-NLS-1$
601 for (int j = 0; j < dim; j++)
602 {
603 sig.append("["); //$NON-NLS-1$
604 }
605 if (type.equals("boolean")) { //$NON-NLS-1$
606 sig.append('Z');
607 } else if (type.equals("byte")) { //$NON-NLS-1$
608 sig.append('B');
609 } else if (type.equals("char")) { //$NON-NLS-1$
610 sig.append('C');
611 } else if (type.equals("short")) { //$NON-NLS-1$
612 sig.append('S');
613 } else if (type.equals("int")) { //$NON-NLS-1$
614 sig.append('I');
615 } else if (type.equals("long")) { //$NON-NLS-1$
616 sig.append('J');
617 } else if (type.equals("float")) { //$NON-NLS-1$
618 sig.append('F');
619 } else if (type.equals("double")) { //$NON-NLS-1$
620 sig.append('D');
621 } else if (type.equals("void")) { //$NON-NLS-1$
622 sig.append('V');
623 }
624 else {
625 sig.append('L').append(type.replace('.', '/')).append(';');
626 }
627 return sig.toString();
628 }
629
630 /**
631 * Compare two doubles together.
632 *
633 * @param d1
634 * First double
635 * @param d2
636 * Second double
637 * @return 1 if they are different, and 0 if they are *exactly* the same.
638 * Because of the way doubles are stored, it's possible for the
639 * same number obtained in two different ways to actually look
640 * different.
641 */
642 static public int compare(double d1, double d2) {
643 if (d1 > d2) {
644 return 1;
645 }
646 if (d1 < d2) {
647 return 1;
648 }
649 return 0;
650 }
651
652 /**
653 * Compare two character strings alphabetically. This is simply a wrapper
654 * around String.compareToIgnoreCase but that will handle cases where
655 * strings can be null
656 *
657 * @param s1
658 * The first string
659 * @param s2
660 * The second string
661 * @return A number below, equal, or greater than zero if the first string
662 * is smaller, equal, or bigger (alphabetically) than the second
663 * one.
664 */
665 static public int compare(String s1, String s2) {
666 if (s1 != null && s2 != null) {
667 return s1.compareToIgnoreCase(s2);
668 }
669 if (s1 != null) {
670 return 1;
671 }
672 if (s2 != null) {
673 return -1;
674 }
675 return 0;
676 }
677 }
This page took 0.045921 seconds and 6 git commands to generate.