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
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 *****************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
17 import java
.text
.NumberFormat
;
18 import java
.text
.SimpleDateFormat
;
19 import java
.util
.Date
;
20 import java
.util
.Iterator
;
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
;
32 * General utilities and definitions used by the time graph widget
35 * @author Alvaro Sanchez-Leon
36 * @author Patrick Tasse
43 /** Time format for dates and timestamp */
44 public enum TimeFormat
{
45 /** Relative to the start of the trace */
49 * Absolute timestamp (ie, relative to the Unix epoch)
55 * Timestamp displayed as a simple number
62 * Timestamp resolution
64 public static enum Resolution
{
78 private static final SimpleDateFormat TIME_FORMAT
= new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
79 private static final SimpleDateFormat DATE_FORMAT
= new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
80 private static final long SEC_IN_NS
= 1000000000;
81 private static final long MILLISEC_IN_NS
= 1000000;
83 static Rectangle
clone(Rectangle source
) {
84 return new Rectangle(source
.x
, source
.y
, source
.width
, source
.height
);
88 * Initialize a Rectangle object to default values (all equal to 0)
91 * The Rectangle to initialize
93 public static void init(Rectangle rect
) {
101 * Initialize a Rectangle object with all the given values
104 * The Rectangle object to initialize
110 * The width of the rectangle
112 * The height of the rectangle
114 public static void init(Rectangle rect
, int x
, int y
, int width
, int height
) {
118 rect
.height
= height
;
122 * Initialize a Rectangle object to another existing Rectangle's values.
125 * The Rectangle to initialize
127 * The reference Rectangle to copy
129 public static void init(Rectangle rect
, Rectangle source
) {
132 rect
.width
= source
.width
;
133 rect
.height
= source
.height
;
137 * Reduce the size of a given rectangle by the given amounts.
140 * The rectangle to modify
142 * The reduction in width
144 * The reduction in height
146 public static void deflate(Rectangle rect
, int x
, int y
) {
150 rect
.height
-= y
+ y
;
154 * Increase the size of a given rectangle by the given amounts.
157 * The rectangle to modify
159 * The augmentation in width
161 * The augmentation in height
163 public static void inflate(Rectangle rect
, int x
, int y
) {
167 rect
.height
+= y
+ y
;
170 static void dispose(Color col
) {
177 * Get the resulting color from a mix of two existing ones for a given
181 * The display device (which might affect the color conversion)
187 * The gamma level for color 1
189 * The gamma level for color 2
190 * @return The resulting color
192 public static Color
mixColors(Device display
, Color c1
, Color c2
, int w1
,
194 return new Color(display
, (w1
* c1
.getRed() + w2
* c2
.getRed())
195 / (w1
+ w2
), (w1
* c1
.getGreen() + w2
* c2
.getGreen())
196 / (w1
+ w2
), (w1
* c1
.getBlue() + w2
* c2
.getBlue())
201 * Get the system color with the given ID.
205 * @return The resulting color
207 public static Color
getSysColor(int id
) {
208 Color col
= Display
.getCurrent().getSystemColor(id
);
209 return new Color(col
.getDevice(), col
.getRGB());
213 * Get the resulting color from a mix of two existing ones for the current
221 * The gamma level for color 1
223 * The gamma level for color 2
224 * @return The resulting color
226 public static Color
mixColors(Color col1
, Color col2
, int w1
, int w2
) {
227 return mixColors(Display
.getCurrent(), col1
, col2
, w1
, w2
);
231 * Draw text in a rectangle.
238 * The rectangle object which is being drawn
240 * Should we transpose the color
241 * @return The X coordinate where we have written
243 public static int drawText(GC gc
, String text
, Rectangle rect
, boolean transp
) {
244 Point size
= gc
.stringExtent(text
);
245 gc
.drawText(text
, rect
.x
, rect
.y
, transp
);
250 * Draw text at a given location.
257 * The X coordinate of the starting point
259 * the Y coordinate of the starting point
261 * Should we transpose the color
262 * @return The X coordinate where we have written
264 public static int drawText(GC gc
, String text
, int x
, int y
, boolean transp
) {
265 Point size
= gc
.stringExtent(text
);
266 gc
.drawText(text
, x
, y
, transp
);
271 * Draw text in a rectangle, trimming the text to prevent exceeding the specified width.
276 * The string to be drawn
278 * The x coordinate of the top left corner of the rectangular area where the text is to be drawn
280 * The y coordinate of the top left corner of the rectangular area where the text is to be drawn
282 * The width of the area to be drawn
284 * If <code>true</code> the text will be centered in the available width if space permits
285 * @param isTransparent
286 * If <code>true</code> the background will be transparent, otherwise it will be opaque
287 * @return The number of characters written
291 public static int drawText(GC gc
, String text
, int x
, int y
, int width
, boolean isCentered
, boolean isTransparent
) {
292 int len
= text
.length();
294 boolean isReallyCentered
= isCentered
;
298 textWidth
= gc
.stringExtent(text
.substring(0, len
)).x
;
299 if (textWidth
<= width
) {
302 isReallyCentered
= false;
306 if (isReallyCentered
) {
307 realX
+= (width
- textWidth
) / 2;
309 gc
.drawText(text
.substring(0, len
), realX
, y
, isTransparent
);
315 * Formats time in format: MM:SS:NNN
318 * @param format 0: MMMM:ss:nnnnnnnnn, 1: HH:MM:ss MMM.mmmm.nnn
319 * @param resolution the resolution
320 * @return the formatted time
322 public static String
formatTime(long time
, TimeFormat format
, Resolution resolution
) {
323 // if format is absolute (Calendar)
324 if (format
== TimeFormat
.CALENDAR
) {
325 return formatTimeAbs(time
, resolution
);
326 } else if (format
== TimeFormat
.NUMBER
) {
327 return NumberFormat
.getInstance().format(time
);
330 StringBuffer str
= new StringBuffer();
338 long sec
= t
/ SEC_IN_NS
;
340 String ns
= formatNs(t
, resolution
);
341 if (!ns
.equals("")) { //$NON-NLS-1$
346 return str
.toString();
350 * From input time in nanoseconds, convert to Date format YYYY-MM-dd
353 * The source time, in ns
354 * @return the formatted date
356 public static String
formatDate(long absTime
) {
357 String sdate
= DATE_FORMAT
.format(new Date(absTime
/ MILLISEC_IN_NS
));
362 * Formats time in ns to Calendar format: HH:MM:SS MMM.mmm.nnn
365 * The source time, in ns
367 * The resolution to use
368 * @return the formatted time
370 public static String
formatTimeAbs(long time
, Resolution res
) {
371 StringBuffer str
= new StringBuffer();
373 // format time from nanoseconds to calendar time HH:MM:SS
374 String stime
= TIME_FORMAT
.format(new Date(time
/ MILLISEC_IN_NS
));
377 // append the Milliseconds, MicroSeconds and NanoSeconds as specified in
379 str
.append(formatNs(time
, res
));
380 return str
.toString();
384 * Obtains the remainder fraction on unit Seconds of the entered value in
385 * nanoseconds. e.g. input: 1241207054171080214 ns The number of fraction
386 * seconds can be obtained by removing the last 9 digits: 1241207054 the
387 * fractional portion of seconds, expressed in ns is: 171080214
390 * The source time in ns
392 * The Resolution to use
393 * @return the formatted nanosec
395 public static String
formatNs(long srcTime
, Resolution res
) {
396 StringBuffer str
= new StringBuffer();
404 String nanos
= Long
.toString(ns
);
405 str
.append("000000000".substring(nanos
.length())); //$NON-NLS-1$
408 if (res
== Resolution
.MILLISEC
) {
409 return str
.substring(0, 3);
410 } else if (res
== Resolution
.MICROSEC
) {
411 return str
.substring(0, 6);
412 } else if (res
== Resolution
.NANOSEC
) {
413 return str
.substring(0, 9);
415 return ""; //$NON-NLS-1$
419 * FIXME Currently does nothing.
426 * The minimal accepted value
428 * The maximal accepted value
429 * @return The value that was read
431 public static int loadIntOption(String opt
, int def
, int min
, int max
) {
436 * FIXME currently does nothing
443 public static void saveIntOption(String opt
, int val
) {
446 static ITimeEvent
getFirstEvent(ITimeGraphEntry entry
) {
447 if (null == entry
|| ! entry
.hasTimeEvents()) {
450 Iterator
<ITimeEvent
> iterator
= entry
.getTimeEventsIterator();
451 if (iterator
!= null && iterator
.hasNext()) {
452 return iterator
.next();
458 * N means: <list> <li>-1: Previous Event</li> <li>0: Current Event</li> <li>
459 * 1: Next Event</li> <li>2: Previous Event when located in a non Event Area
467 static ITimeEvent
findEvent(ITimeGraphEntry entry
, long time
, int n
) {
468 if (null == entry
|| ! entry
.hasTimeEvents()) {
471 Iterator
<ITimeEvent
> iterator
= entry
.getTimeEventsIterator();
472 if (iterator
== null) {
475 ITimeEvent nextEvent
= null;
476 ITimeEvent currEvent
= null;
477 ITimeEvent prevEvent
= null;
479 while (iterator
.hasNext()) {
480 nextEvent
= iterator
.next();
481 long nextStartTime
= nextEvent
.getTime();
483 if (nextStartTime
> time
) {
487 if (currEvent
== null || currEvent
.getTime() != nextStartTime
||
488 (nextStartTime
!= time
&& currEvent
.getDuration() != nextEvent
.getDuration())) {
489 prevEvent
= currEvent
;
490 currEvent
= nextEvent
;
494 if (n
== -1) { //previous
495 if (currEvent
!= null && currEvent
.getTime() + currEvent
.getDuration() >= time
) {
499 } else if (n
== 0) { //current
500 if (currEvent
!= null && currEvent
.getTime() + currEvent
.getDuration() >= time
) {
504 } else if (n
== 1) { //next
505 if (nextEvent
!= null && nextEvent
.getTime() > time
) {
509 } else if (n
== 2) { //current or previous when in empty space
517 * Pretty-print a method signature.
520 * The original signature
521 * @return The pretty signature
523 public static String
fixMethodSignature(String origSig
) {
524 String sig
= origSig
;
525 int pos
= sig
.indexOf('(');
527 String ret
= sig
.substring(0, pos
);
528 sig
= sig
.substring(pos
);
529 sig
= sig
+ " " + ret
; //$NON-NLS-1$
535 * Restore an original method signature from a pretty-printed one.
538 * The pretty-printed signature
539 * @return The original method signature
541 public static String
restoreMethodSignature(String ppSig
) {
542 String ret
= ""; //$NON-NLS-1$
545 int pos
= sig
.indexOf('(');
547 ret
= sig
.substring(0, pos
);
548 sig
= sig
.substring(pos
+ 1);
550 pos
= sig
.indexOf(')');
552 sig
= sig
.substring(0, pos
);
554 String args
[] = sig
.split(","); //$NON-NLS-1$
555 StringBuffer result
= new StringBuffer("("); //$NON-NLS-1$
556 for (int i
= 0; i
< args
.length
; i
++) {
557 String arg
= args
[i
].trim();
558 if (arg
.length() == 0 && args
.length
== 1) {
561 result
.append(getTypeSignature(arg
));
563 result
.append(")").append(getTypeSignature(ret
)); //$NON-NLS-1$
564 return result
.toString();
568 * Get the mangled type information from an array of types.
571 * The types to convert. See method implementation for what it
573 * @return The mangled string of types
575 public static String
getTypeSignature(String typeStr
) {
577 String type
= typeStr
;
578 for (int j
= 0; j
< type
.length(); j
++) {
579 if (type
.charAt(j
) == '[') {
583 int pos
= type
.indexOf('[');
585 type
= type
.substring(0, pos
);
587 StringBuffer sig
= new StringBuffer(""); //$NON-NLS-1$
588 for (int j
= 0; j
< dim
; j
++)
590 sig
.append("["); //$NON-NLS-1$
592 if (type
.equals("boolean")) { //$NON-NLS-1$
594 } else if (type
.equals("byte")) { //$NON-NLS-1$
596 } else if (type
.equals("char")) { //$NON-NLS-1$
598 } else if (type
.equals("short")) { //$NON-NLS-1$
600 } else if (type
.equals("int")) { //$NON-NLS-1$
602 } else if (type
.equals("long")) { //$NON-NLS-1$
604 } else if (type
.equals("float")) { //$NON-NLS-1$
606 } else if (type
.equals("double")) { //$NON-NLS-1$
608 } else if (type
.equals("void")) { //$NON-NLS-1$
612 sig
.append('L').append(type
.replace('.', '/')).append(';');
614 return sig
.toString();
618 * Compare two doubles together.
624 * @return 1 if they are different, and 0 if they are *exactly* the same.
625 * Because of the way doubles are stored, it's possible for the
626 * same number obtained in two different ways to actually look
629 public static int compare(double d1
, double d2
) {
640 * Compare two character strings alphabetically. This is simply a wrapper
641 * around String.compareToIgnoreCase but that will handle cases where
642 * strings can be null
648 * @return A number below, equal, or greater than zero if the first string
649 * is smaller, equal, or bigger (alphabetically) than the second
652 public static int compare(String s1
, String s2
) {
653 if (s1
!= null && s2
!= null) {
654 return s1
.compareToIgnoreCase(s2
);