tmf: Support tool tip for arrows in time graph
authorPatrick Tasse <patrick.tasse@gmail.com>
Thu, 4 Sep 2014 17:51:13 +0000 (13:51 -0400)
committerPatrick Tasse <patrick.tasse@gmail.com>
Mon, 8 Sep 2014 20:25:02 +0000 (16:25 -0400)
The tool tip will show the time link event information of the closest
arrow to the mouse position, provided that it is within 5 pixels.
Holding the Shift key will disable the arrow tool tip so that the tool
tip can show the information of the underlying state.

Change-Id: I5f4daaea130817a16dd5d222b262cb0ec9aee76b
Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/32875
Tested-by: Hudson CI
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphTooltipHandler.java
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/Utils.java

index 56d02a551f5821f50aa5737ae6e472b19bd2b1a4..06e3683c70010e3a7248e46f1846036e1bba0078 100644 (file)
@@ -82,6 +82,11 @@ public class Messages extends NLS {
     public static String TmfTimeFilterDialog_UNCHECK_SUBTREE;
 
     public static String TmfTimeTipHandler_DURATION;
+    public static String TmfTimeTipHandler_LINK_SOURCE;
+    public static String TmfTimeTipHandler_LINK_SOURCE_TIME;
+    public static String TmfTimeTipHandler_LINK_TARGET;
+    public static String TmfTimeTipHandler_LINK_TARGET_TIME;
+    public static String TmfTimeTipHandler_LINK_TIME;
     public static String TmfTimeTipHandler_TRACE_DATE;
     public static String TmfTimeTipHandler_TRACE_EVENT_TIME;
     public static String TmfTimeTipHandler_TRACE_START_TIME;
index 3d021c1336e690a89cba5bdb157d8219f4be95fb..4b3c6bc997dac00add25f721f1564237b91aedba 100644 (file)
@@ -77,6 +77,11 @@ TmfTimeFilterDialog_UNCHECK_SUBTREE=Uncheck subtree
 
 # org.eclipse.linuxtools.tmf.ui.viewers.timegraph.widgets
 TmfTimeTipHandler_DURATION=Duration
+TmfTimeTipHandler_LINK_SOURCE=Source
+TmfTimeTipHandler_LINK_SOURCE_TIME=Source Time
+TmfTimeTipHandler_LINK_TARGET=Target
+TmfTimeTipHandler_LINK_TARGET_TIME=Target Time
+TmfTimeTipHandler_LINK_TIME=Time
 TmfTimeTipHandler_TRACE_DATE=Date
 TmfTimeTipHandler_TRACE_EVENT_TIME=Event Time
 TmfTimeTipHandler_TRACE_START_TIME=Start Time
index 9a2ecb04be5a9b8f27f5b2f06779e2e5f0968aac..7edbb2456a6ac8c92f035d4f512b8effa83c9e4e 100644 (file)
@@ -113,6 +113,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private static final double ZOOM_OUT_FACTOR = 1.25;
 
     private static final int SNAP_WIDTH = 2;
+    private static final int ARROW_HOVER_MAX_DIST = 5;
 
     private static final int NO_STATUS = -1;
 
@@ -1145,6 +1146,41 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return idx >= 0 ? fItemData.fExpandedItems[idx].fEntry : null;
     }
 
+    /**
+     * Return the arrow event closest to the given point that is no further than
+     * a maximum distance.
+     *
+     * @param pt
+     *            a point in the widget
+     * @return The closest arrow event, or null if there is none close enough.
+     * @since 3.1
+     */
+    protected ILinkEvent getArrow(Point pt) {
+        if (fHideArrows) {
+            return null;
+        }
+        ILinkEvent linkEvent = null;
+        double minDistance = Double.MAX_VALUE;
+        for (ILinkEvent event : fItemData.fLinks) {
+            Rectangle rect = getArrowRectangle(new Rectangle(0, 0, 0, 0), event);
+            if (rect != null) {
+                int x1 = rect.x;
+                int y1 = rect.y;
+                int x2 = x1 + rect.width;
+                int y2 = y1 + rect.height;
+                double d = Utils.distance(pt.x, pt.y, x1, y1, x2, y2);
+                if (minDistance > d) {
+                    minDistance = d;
+                    linkEvent = event;
+                }
+            }
+        }
+        if (minDistance <= ARROW_HOVER_MAX_DIST) {
+            return linkEvent;
+        }
+        return null;
+    }
+
     /**
      * @since 2.0
      */
@@ -1560,15 +1596,19 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @since 2.1
      */
     protected void drawLink(ILinkEvent event, Rectangle bounds, ITimeDataProvider timeProvider, int nameSpace, GC gc) {
+        drawArrow(getColorScheme(), event, getArrowRectangle(bounds, event), gc);
+    }
+
+    private Rectangle getArrowRectangle(Rectangle bounds, ILinkEvent event) {
         int srcIndex = fItemData.findItemIndex(event.getEntry());
         int destIndex = fItemData.findItemIndex(event.getDestinationEntry());
 
         if ((srcIndex == -1) || (destIndex == -1)) {
-            return;
+            return null;
         }
 
-        Rectangle src = getStatesRect(bounds, srcIndex, nameSpace);
-        Rectangle dst = getStatesRect(bounds, destIndex, nameSpace);
+        Rectangle src = getStatesRect(bounds, srcIndex, fTimeProvider.getNameSpace());
+        Rectangle dst = getStatesRect(bounds, destIndex, fTimeProvider.getNameSpace());
 
         int x0 = getXForTime(event.getTime());
         int x1 = getXForTime(event.getTime() + event.getDuration());
@@ -1581,7 +1621,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
         int y0 = src.y + src.height / 2;
         int y1 = dst.y + dst.height / 2;
-        drawArrow(getColorScheme(), event, new Rectangle(x0, y0, x1 - x0, y1 - y0), gc);
+        return new Rectangle(x0, y0, x1 - x0, y1 - y0);
     }
 
     /**
index 3e52994b5aacbaa11ac5dde6326ea8c7384969c0..9bc79c36d2b72f17477956be15e695732e7a7ce2 100644 (file)
@@ -19,6 +19,7 @@ import java.util.Map;
 
 import org.eclipse.linuxtools.internal.tmf.ui.Messages;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.NullTimeEvent;
@@ -240,6 +241,42 @@ public class TimeGraphTooltipHandler {
                 }
             }
 
+            private void fillValues(ILinkEvent linkEvent) {
+                addItem(Messages.TmfTimeTipHandler_LINK_SOURCE, linkEvent.getEntry().getName());
+                addItem(Messages.TmfTimeTipHandler_LINK_TARGET, linkEvent.getDestinationEntry().getName());
+
+                // This block receives a list of <String, String> values to be added to the tip table
+                Map<String, String> eventAddOns = fTimeGraphProvider.getEventHoverToolTipInfo(linkEvent);
+                if (eventAddOns != null) {
+                    for (Iterator<String> iter = eventAddOns.keySet().iterator(); iter.hasNext();) {
+                        String message = iter.next();
+                        addItem(message, eventAddOns.get(message));
+                    }
+                }
+                if (fTimeGraphProvider.displayTimesInTooltip()) {
+                    long sourceTime = linkEvent.getTime();
+                    long duration = linkEvent.getDuration();
+                    long targetTime = sourceTime + duration;
+
+                    Resolution res = Resolution.NANOSEC;
+                    TimeFormat tf = fTimeDataProvider.getTimeFormat();
+                    if (tf == TimeFormat.CALENDAR) {
+                        addItem(Messages.TmfTimeTipHandler_TRACE_DATE, Utils.formatDate(sourceTime));
+                    }
+                    if (duration > 0) {
+                        addItem(Messages.TmfTimeTipHandler_LINK_SOURCE_TIME, Utils.formatTime(sourceTime, tf, res));
+                        addItem(Messages.TmfTimeTipHandler_LINK_TARGET_TIME, Utils.formatTime(targetTime, tf, res));
+                        // Duration in relative format in any case
+                        if (tf == TimeFormat.CALENDAR) {
+                            tf = TimeFormat.RELATIVE;
+                        }
+                        addItem(Messages.TmfTimeTipHandler_DURATION, Utils.formatTime(duration, tf, res));
+                    } else {
+                        addItem(Messages.TmfTimeTipHandler_LINK_TIME, Utils.formatTime(sourceTime, tf, res));
+                    }
+                }
+            }
+
             @Override
             public void mouseHover(MouseEvent event) {
                 if ((event.stateMask & SWT.BUTTON_MASK) != 0) {
@@ -248,11 +285,19 @@ public class TimeGraphTooltipHandler {
                 Point pt = new Point(event.x, event.y);
                 TimeGraphControl timeGraphControl = (TimeGraphControl) event.widget;
                 createTooltipShell(timeGraphControl.getShell());
-                ITimeGraphEntry entry = timeGraphControl.getEntry(pt);
                 for (Control child : fTipComposite.getChildren()) {
                     child.dispose();
                 }
-                fillValues(pt, timeGraphControl, entry);
+                if ((event.stateMask & SWT.MODIFIER_MASK) != SWT.SHIFT) {
+                    ILinkEvent linkEvent = timeGraphControl.getArrow(pt);
+                    if (linkEvent != null) {
+                        fillValues(linkEvent);
+                    }
+                }
+                if (fTipComposite.getChildren().length == 0) {
+                    ITimeGraphEntry entry = timeGraphControl.getEntry(pt);
+                    fillValues(pt, timeGraphControl, entry);
+                }
                 if (fTipComposite.getChildren().length == 0) {
                     return;
                 }
index a75c5d9fe3ccb0dd3c5c857d3be5208e51a85d7d..364c90cccb82f2a3da696931d6d5543d056a3061 100644 (file)
@@ -675,4 +675,73 @@ public class Utils {
         }
         return 0;
     }
+
+    /**
+     * Calculates the square of the distance between two points.
+     *
+     * @param x1
+     *            x-coordinate of point 1
+     * @param y1
+     *            y-coordinate of point 1
+     * @param x2
+     *            x-coordinate of point 2
+     * @param y2
+     *            y-coordinate of point 2
+     *
+     * @return the square of the distance in pixels^2
+     * @since 3.1
+     */
+    public static double distance2(int x1, int y1, int x2, int y2) {
+        int dx = x2 - x1;
+        int dy = y2 - y1;
+        int d2 = dx * dx + dy * dy;
+        return d2;
+    }
+
+    /**
+     * Calculates the distance between a point and a line segment. If the point
+     * is in the perpendicular region between the segment points, return the
+     * distance from the point to its projection on the segment. Otherwise
+     * return the distance from the point to its closest segment point.
+     *
+     * @param px
+     *            x-coordinate of the point
+     * @param py
+     *            y-coordinate of the point
+     * @param x1
+     *            x-coordinate of segment point 1
+     * @param y1
+     *            y-coordinate of segment point 1
+     * @param x2
+     *            x-coordinate of segment point 2
+     * @param y2
+     *            y-coordinate of segment point 2
+     *
+     * @return the distance in pixels
+     * @since 3.1
+     */
+    public static double distance(int px, int py, int x1, int y1, int x2, int y2) {
+        double length2 = distance2(x1, y1, x2, y2);
+        if (length2 == 0) {
+            return Math.sqrt(distance2(px, py, x1, y1));
+        }
+        // 'r' is the ratio of the position, between segment point 1 and segment
+        // point 2, of the projection of the point on the segment
+        double r = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / length2;
+        if (r <= 0.0) {
+            // the projection is before segment point 1, return distance from
+            // the point to segment point 1
+            return Math.sqrt(distance2(px, py, x1, y1));
+        }
+        if (r >= 1.0) {
+            // the projection is after segment point 2, return distance from
+            // the point to segment point 2
+            return Math.sqrt(distance2(px, py, x2, y2));
+        }
+        // the projection is between the segment points, return distance from
+        // the point to its projection on the segment
+        int x = (int) (x1 + r * (x2 - x1));
+        int y = (int) (y1 + r * (y2 - y1));
+        return Math.sqrt(distance2(px, py, x, y));
+    }
 }
This page took 0.031733 seconds and 5 git commands to generate.