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