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