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
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
14 *****************************************************************************/
16 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
18 import java
.text
.NumberFormat
;
19 import java
.text
.SimpleDateFormat
;
20 import java
.util
.Date
;
21 import java
.util
.Iterator
;
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
;
33 * General utilities and definitions used by the time graph widget
36 * @author Alvaro Sanchez-Leon
37 * @author Patrick Tasse
41 /** Time format for dates and timestamp */
42 public enum TimeFormat
{
43 /** Relative to the start of the trace */
47 * Absolute timestamp (ie, relative to the Unix epoch)
53 * Timestamp displayed as a simple number
59 static public final int IMG_THREAD_RUNNING
= 0;
60 static public final int IMG_THREAD_SUSPENDED
= 1;
61 static public final int IMG_THREAD_STOPPED
= 2;
62 static public final int IMG_METHOD_RUNNING
= 3;
63 static public final int IMG_METHOD
= 4;
64 static public final int IMG_NUM
= 5;
66 static public final Object
[] _empty
= new Object
[0];
68 public static enum Resolution
{
69 SECONDS
, MILLISEC
, MICROSEC
, NANOSEC
72 static private final SimpleDateFormat stimeformat
= new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
73 static private final SimpleDateFormat sdateformat
= new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
75 static Rectangle
clone(Rectangle source
) {
76 return new Rectangle(source
.x
, source
.y
, source
.width
, source
.height
);
80 * Initialize a Rectangle object to default values (all equal to 0)
83 * The Rectangle to initialize
85 static public void init(Rectangle rect
) {
93 * Initialize a Rectangle object with all the given values
96 * The Rectangle object to initialize
102 * The width of the rectangle
104 * The height of the rectangle
106 static public void init(Rectangle rect
, int x
, int y
, int width
, int height
) {
110 rect
.height
= height
;
114 * Initialize a Rectangle object to another existing Rectangle's values.
117 * The Rectangle to initialize
119 * The reference Rectangle to copy
121 static public void init(Rectangle rect
, Rectangle source
) {
124 rect
.width
= source
.width
;
125 rect
.height
= source
.height
;
129 * Reduce the size of a given rectangle by the given amounts.
132 * The rectangle to modify
134 * The reduction in width
136 * The reduction in height
138 static public void deflate(Rectangle rect
, int x
, int y
) {
142 rect
.height
-= y
+ y
;
146 * Increase the size of a given rectangle by the given amounts.
149 * The rectangle to modify
151 * The augmentation in width
153 * The augmentation in height
155 static public void inflate(Rectangle rect
, int x
, int y
) {
159 rect
.height
+= y
+ y
;
162 static void dispose(Color col
) {
169 * Get the resulting color from a mix of two existing ones for a given
173 * The display device (which might affect the color conversion)
179 * The gamma level for color 1
181 * The gamma level for color 2
182 * @return The resulting color
184 static public Color
mixColors(Device display
, Color c1
, Color c2
, int w1
,
186 return new Color(display
, (w1
* c1
.getRed() + w2
* c2
.getRed())
187 / (w1
+ w2
), (w1
* c1
.getGreen() + w2
* c2
.getGreen())
188 / (w1
+ w2
), (w1
* c1
.getBlue() + w2
* c2
.getBlue())
193 * Get the system color with the given ID.
197 * @return The resulting color
199 static public Color
getSysColor(int id
) {
200 Color col
= Display
.getCurrent().getSystemColor(id
);
201 return new Color(col
.getDevice(), col
.getRGB());
205 * Get the resulting color from a mix of two existing ones for the current
213 * The gamma level for color 1
215 * The gamma level for color 2
216 * @return The resulting color
218 static public Color
mixColors(Color col1
, Color col2
, int w1
, int w2
) {
219 return mixColors(Display
.getCurrent(), col1
, col2
, w1
, w2
);
223 * Draw text in a rectangle.
230 * The rectangle object which is being drawn
232 * Should we transpose the color
233 * @return The X coordinate where we have written
235 static public int drawText(GC gc
, String text
, Rectangle rect
, boolean transp
) {
236 Point size
= gc
.stringExtent(text
);
237 gc
.drawText(text
, rect
.x
, rect
.y
, transp
);
242 * Draw text at a given location.
249 * The X coordinate of the starting point
251 * the Y coordinate of the starting point
253 * Should we transpose the color
254 * @return The X coordinate where we have written
256 static public int drawText(GC gc
, String text
, int x
, int y
, boolean transp
) {
257 Point size
= gc
.stringExtent(text
);
258 gc
.drawText(text
, x
, y
, transp
);
263 * Draw text in a rectangle, trimming the text to prevent exceeding the specified width.
268 * The string to be drawn
270 * The x coordinate of the top left corner of the rectangular area where the text is to be drawn
272 * The y coordinate of the top left corner of the rectangular area where the text is to be drawn
274 * The width of the area to be drawn
276 * If <code>true</code> the text will be centered in the available width if space permits
277 * @param isTransparent
278 * If <code>true</code> the background will be transparent, otherwise it will be opaque
279 * @return The number of characters written
283 static public int drawText(GC gc
, String text
, int x
, int y
, int width
, boolean isCentered
, boolean isTransparent
) {
284 int len
= text
.length();
287 textWidth
= gc
.stringExtent(text
.substring(0, len
)).x
;
288 if (textWidth
<= width
) {
296 x
+= (width
- textWidth
) / 2;
298 gc
.drawText(text
.substring(0, len
), x
, y
, isTransparent
);
304 * Formats time in format: MM:SS:NNN
307 * @param format 0: MMMM:ss:nnnnnnnnn, 1: HH:MM:ss MMM.mmmm.nnn
308 * @param resolution the resolution
309 * @return the formatted time
311 static public String
formatTime(long time
, TimeFormat format
, Resolution resolution
) {
312 // if format is absolute (Calendar)
313 if (format
== TimeFormat
.CALENDAR
) {
314 return formatTimeAbs(time
, resolution
);
315 } else if (format
== TimeFormat
.NUMBER
) {
316 return NumberFormat
.getInstance().format(time
);
319 StringBuffer str
= new StringBuffer();
320 boolean neg
= time
< 0;
326 long sec
= (long) (time
* 1E-9);
327 // TODO: Expand to make it possible to select the minute, second, nanosecond format
328 //printing minutes is suppressed just sec and ns
329 // if (sec / 60 < 10)
331 // str.append(sec / 60);
337 String ns
= formatNs(time
, resolution
);
338 if (!ns
.equals("")) { //$NON-NLS-1$
343 return str
.toString();
347 * From input time in nanoseconds, convert to Date format YYYY-MM-dd
350 * The source time, in ns
351 * @return the formatted date
353 public static String
formatDate(long absTime
) {
354 String sdate
= sdateformat
.format(new Date((long) (absTime
* 1E-6)));
359 * Formats time in ns to Calendar format: HH:MM:SS MMM.mmm.nnn
362 * The source time, in ns
364 * The resolution to use
365 * @return the formatted time
367 static public String
formatTimeAbs(long time
, Resolution res
) {
368 StringBuffer str
= new StringBuffer();
370 // format time from nanoseconds to calendar time HH:MM:SS
371 String stime
= stimeformat
.format(new Date((long) (time
* 1E-6)));
374 // append the Milliseconds, MicroSeconds and NanoSeconds as specified in
376 str
.append(formatNs(time
, res
));
377 return str
.toString();
381 * Obtains the remainder fraction on unit Seconds of the entered value in
382 * nanoseconds. e.g. input: 1241207054171080214 ns The number of fraction
383 * seconds can be obtained by removing the last 9 digits: 1241207054 the
384 * fractional portion of seconds, expressed in ns is: 171080214
387 * The source time in ns
389 * The Resolution to use
390 * @return the formatted nanosec
392 public static String
formatNs(long time
, Resolution res
) {
393 StringBuffer str
= new StringBuffer();
394 boolean neg
= time
< 0;
399 // The following approach could be used although performance
400 // decreases in half.
401 // String strVal = String.format("%09d", time);
402 // String tmp = strVal.substring(strVal.length() - 9);
407 str
.append("00000000"); //$NON-NLS-1$
408 } else if (ns
< 100) {
409 str
.append("0000000"); //$NON-NLS-1$
410 } else if (ns
< 1000) {
411 str
.append("000000"); //$NON-NLS-1$
412 } else if (ns
< 10000) {
413 str
.append("00000"); //$NON-NLS-1$
414 } else if (ns
< 100000) {
415 str
.append("0000"); //$NON-NLS-1$
416 } else if (ns
< 1000000) {
417 str
.append("000"); //$NON-NLS-1$
418 } else if (ns
< 10000000) {
419 str
.append("00"); //$NON-NLS-1$
420 } else if (ns
< 100000000) {
421 str
.append("0"); //$NON-NLS-1$
425 if (res
== Resolution
.MILLISEC
) {
426 return str
.substring(0, 3);
427 } else if (res
== Resolution
.MICROSEC
) {
428 return str
.substring(0, 6);
429 } else if (res
== Resolution
.NANOSEC
) {
430 return str
.substring(0, 9);
432 return ""; //$NON-NLS-1$
436 * FIXME Currently does nothing.
443 * The minimal accepted value
445 * The maximal accepted value
446 * @return The value that was read
448 static public int loadIntOption(String opt
, int def
, int min
, int max
) {
450 // TraceUIPlugin.getDefault().getPreferenceStore().getInt(opt);
461 * FIXME currently does nothing
468 static public void saveIntOption(String opt
, int val
) {
469 // TraceUIPlugin.getDefault().getPreferenceStore().setValue(opt, val);
472 static ITimeEvent
getFirstEvent(ITimeGraphEntry entry
) {
473 if (null == entry
|| ! entry
.hasTimeEvents()) {
476 Iterator
<ITimeEvent
> iterator
= entry
.getTimeEventsIterator();
477 if (iterator
!= null && iterator
.hasNext()) {
478 return iterator
.next();
484 * N means: <list> <li>-1: Previous Event</li> <li>0: Current Event</li> <li>
485 * 1: Next Event</li> <li>2: Previous Event when located in a non Event Area
493 static ITimeEvent
findEvent(ITimeGraphEntry entry
, long time
, int n
) {
494 if (null == entry
|| ! entry
.hasTimeEvents()) {
497 Iterator
<ITimeEvent
> iterator
= entry
.getTimeEventsIterator();
498 if (iterator
== null) {
501 ITimeEvent nextEvent
= null;
502 ITimeEvent currEvent
= null;
503 ITimeEvent prevEvent
= null;
505 while (iterator
.hasNext()) {
506 nextEvent
= iterator
.next();
507 long nextStartTime
= nextEvent
.getTime();
509 if (nextStartTime
> time
) {
513 if (currEvent
== null || currEvent
.getTime() != nextStartTime
) {
514 prevEvent
= currEvent
;
515 currEvent
= nextEvent
;
519 if (n
== -1) { //previous
520 if (currEvent
!= null && currEvent
.getTime() + currEvent
.getDuration() >= time
) {
524 } else if (n
== 0) { //current
525 if (currEvent
!= null && currEvent
.getTime() + currEvent
.getDuration() >= time
) {
529 } else if (n
== 1) { //next
530 if (nextEvent
!= null && nextEvent
.getTime() > time
) {
534 } else if (n
== 2) { //current or previous when in empty space
542 * Pretty-print a method signature.
545 * The original signature
546 * @return The pretty signature
548 static public String
fixMethodSignature(String sig
) {
549 int pos
= sig
.indexOf('(');
551 String ret
= sig
.substring(0, pos
);
552 sig
= sig
.substring(pos
);
553 sig
= sig
+ " " + ret
; //$NON-NLS-1$
559 * Restore an original method signature from a pretty-printed one.
562 * The pretty-printed signature
563 * @return The original method signature
565 static public String
restoreMethodSignature(String sig
) {
566 String ret
= ""; //$NON-NLS-1$
567 int pos
= sig
.indexOf('(');
569 ret
= sig
.substring(0, pos
);
570 sig
= sig
.substring(pos
+ 1);
572 pos
= sig
.indexOf(')');
574 sig
= sig
.substring(0, pos
);
576 String args
[] = sig
.split(","); //$NON-NLS-1$
577 StringBuffer result
= new StringBuffer("("); //$NON-NLS-1$
578 for (int i
= 0; i
< args
.length
; i
++) {
579 String arg
= args
[i
].trim();
580 if (arg
.length() == 0 && args
.length
== 1) {
583 result
.append(getTypeSignature(arg
));
585 result
.append(")").append(getTypeSignature(ret
)); //$NON-NLS-1$
586 return result
.toString();
590 * Get the mangled type information from an array of types.
593 * The types to convert. See method implementation for what it
595 * @return The mangled string of types
597 static public String
getTypeSignature(String type
) {
599 for (int j
= 0; j
< type
.length(); j
++) {
600 if (type
.charAt(j
) == '[') {
604 int pos
= type
.indexOf('[');
606 type
= type
.substring(0, pos
);
608 StringBuffer sig
= new StringBuffer(""); //$NON-NLS-1$
609 for (int j
= 0; j
< dim
; j
++)
611 sig
.append("["); //$NON-NLS-1$
613 if (type
.equals("boolean")) { //$NON-NLS-1$
615 } else if (type
.equals("byte")) { //$NON-NLS-1$
617 } else if (type
.equals("char")) { //$NON-NLS-1$
619 } else if (type
.equals("short")) { //$NON-NLS-1$
621 } else if (type
.equals("int")) { //$NON-NLS-1$
623 } else if (type
.equals("long")) { //$NON-NLS-1$
625 } else if (type
.equals("float")) { //$NON-NLS-1$
627 } else if (type
.equals("double")) { //$NON-NLS-1$
629 } else if (type
.equals("void")) { //$NON-NLS-1$
633 sig
.append('L').append(type
.replace('.', '/')).append(';');
635 return sig
.toString();
639 * Compare two doubles together.
645 * @return 1 if they are different, and 0 if they are *exactly* the same.
646 * Because of the way doubles are stored, it's possible for the
647 * same number obtained in two different ways to actually look
650 static public int compare(double d1
, double d2
) {
661 * Compare two character strings alphabetically. This is simply a wrapper
662 * around String.compareToIgnoreCase but that will handle cases where
663 * strings can be null
669 * @return A number below, equal, or greater than zero if the first string
670 * is smaller, equal, or bigger (alphabetically) than the second
673 static public int compare(String s1
, String s2
) {
674 if (s1
!= null && s2
!= null) {
675 return s1
.compareToIgnoreCase(s2
);