tmf: Ellipse function names that don't fit in CallStackView
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Thu, 30 Jun 2016 21:39:00 +0000 (17:39 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Thu, 14 Jul 2016 16:40:00 +0000 (12:40 -0400)
Add "..." to function names that get cut due to short rectangles
in the call stack view, and avoid printing anything if at least
1 character + the "..." won't fit.

Also, instead of starting from the full string length and going
down to find a fitting string, start from 1 and work our way
up. This will better handle the worst case, which is lots of
very small states in a view that all want to print very long
strings.

Bug: 497111

Change-Id: I94ccca31fb890923063f75359ff714721a8b6f68
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Reviewed-on: https://git.eclipse.org/r/76401
Reviewed-by: Hudson CI
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/Utils.java

index b6478f028afb0a3c7823b7e89b9b55bf5875dba3..2542fadbf3942a14415ecf926e328241e15425da 100644 (file)
@@ -48,7 +48,12 @@ public class CallStackPresentationProvider extends TimeGraphPresentationProvider
 
     private CallStackView fView;
 
-    private Integer fAverageCharWidth;
+    /**
+     * Minimum width of a displayed state below which we will not print any text
+     * into it. It corresponds to the average width of 1 char, plus the width of
+     * the ellipsis characters.
+     */
+    private Integer fMinimumBarWidth;
 
     private final LoadingCache<CallStackEvent, Optional<String>> fTimeEventNames = CacheBuilder.newBuilder()
             .maximumSize(1000)
@@ -141,16 +146,27 @@ public class CallStackPresentationProvider extends TimeGraphPresentationProvider
 
     @Override
     public void postDrawEvent(ITimeEvent event, Rectangle bounds, GC gc) {
-        if (fAverageCharWidth == null) {
-            fAverageCharWidth = gc.getFontMetrics().getAverageCharWidth();
+        if (!(event instanceof CallStackEvent)) {
+            return;
         }
-        if (bounds.width <= fAverageCharWidth) {
+
+        if (fMinimumBarWidth == null) {
+            fMinimumBarWidth = gc.getFontMetrics().getAverageCharWidth() + gc.stringExtent(Utils.ELLIPSIS).x;
+        }
+        if (bounds.width <= fMinimumBarWidth) {
+            /*
+             * Don't print anything if we cannot at least show one character and
+             * ellipses.
+             */
             return;
         }
-        if (!(event instanceof CallStackEvent)) {
+
+        String name = fTimeEventNames.getUnchecked((CallStackEvent) event).orElse(""); //$NON-NLS-1$
+        if (name.isEmpty()) {
+            /* No text to print */
             return;
         }
-        String name = fTimeEventNames.getUnchecked((CallStackEvent) event).orElse(null);
+
         gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
         Utils.drawText(gc, name, bounds.x, bounds.y, bounds.width, bounds.height, true, true);
     }
index dbd565a0f6b943709ec369e446634083313fd213..0b0bf7c36d04e47a5021dd9d2ca58114ed185ee0 100644 (file)
@@ -83,6 +83,14 @@ public class Utils {
         NANOSEC
     }
 
+    /**
+     * Ellipsis character, used to shorten strings that don't fit in their
+     * target area.
+     *
+     * @since 2.1
+     */
+    public static final String ELLIPSIS = "…"; //$NON-NLS-1$
+
     private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$
     private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
     private static final long HOURS_PER_DAY = 24;
@@ -305,7 +313,9 @@ public class Utils {
      * @param isTransparent
      *            If <code>true</code> the background will be transparent, otherwise it will be opaque
      * @return The number of characters written
+     * @deprecated Use {@link #drawText(GC, String, int, int, int, int, boolean, boolean)} instead.
      */
+    @Deprecated
     public static int drawText(GC gc, String text, int x, int y, int width, boolean isCentered, boolean isTransparent) {
         if (width < 1) {
             return 0;
@@ -356,36 +366,64 @@ public class Utils {
      * @since 2.0
      */
     public static int drawText(GC gc, String text, int x, int y, int width, int height, boolean isCentered, boolean isTransparent) {
-        if (width < 1) {
+        if (width < 1 || text.isEmpty()) {
             return 0;
         }
 
-        int len = text.length();
-        int textWidth = 0;
+        String stringToDisplay;
+        int len;
+
         boolean isCenteredWidth = isCentered;
         int realX = x;
         int realY = y;
 
-        Point textExtent = null;
-        while (len > 0) {
-            textExtent = gc.textExtent(text.substring(0, len));
-            textWidth = textExtent.x;
-            if (textWidth <= width) {
-                break;
-            }
+        /* First check if the whole string fits */
+        Point textExtent = gc.textExtent(text);
+        if (textExtent.x <= width) {
+            len = text.length();
+            stringToDisplay = text;
+        } else {
+            /*
+             * The full string doesn't fit, try to find the longest one with
+             * "..." at the end that does fit.
+             *
+             * Iterate on the string length sizes, starting from 1 going up,
+             * until we find a string that does not fit. Once we do, we keep the
+             * one just before that did fit.
+             */
             isCenteredWidth = false;
-            len--;
-            textExtent = gc.textExtent(text.substring(0, len));
-        }
-        if (len > 0) {
-            if (isCenteredWidth) {
-                realX += (width - textWidth) / 2;
-            }
-            if (isCentered && textExtent != null) {
-                realY += (height - textExtent.y) / 2 - 1;
+            int prevLen = 0;
+            len = 1;
+            while (len <= text.length()) {
+                textExtent = gc.textExtent(text.substring(0, len) + ELLIPSIS);
+                if (textExtent.x > width) {
+                    /*
+                     * Here is the first length that does not fit, the one from
+                     * the previous iteration is the one we will use.
+                     */
+                    len = prevLen;
+                    break;
+                }
+                /* This string would fit, try the next one */
+                prevLen = len;
+                len++;
             }
-            gc.drawText(text.substring(0, len), realX, realY, isTransparent);
+            stringToDisplay = text.substring(0, len) + ELLIPSIS;
+        }
+
+        if (len <= 0) {
+            /* Nothing fits, we end up drawing nothing */
+            return 0;
+        }
+
+        if (isCenteredWidth) {
+            realX += (width - textExtent.x) / 2;
+        }
+        if (isCentered) {
+            realY += (height - textExtent.y) / 2 - 1;
         }
+        gc.drawText(stringToDisplay, realX, realY, isTransparent);
+
         return len;
     }
 
This page took 0.027714 seconds and 5 git commands to generate.