From 1053eaa61ef9b4f27bf5f1719b1f80de8a4ed32f Mon Sep 17 00:00:00 2001 From: Patrick Tasse Date: Thu, 4 Sep 2014 13:51:13 -0400 Subject: [PATCH] tmf: Support tool tip for arrows in time graph 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 Reviewed-on: https://git.eclipse.org/r/32875 Tested-by: Hudson CI --- .../linuxtools/internal/tmf/ui/Messages.java | 5 ++ .../internal/tmf/ui/messages.properties | 5 ++ .../timegraph/widgets/TimeGraphControl.java | 48 +++++++++++-- .../widgets/TimeGraphTooltipHandler.java | 49 ++++++++++++- .../ui/widgets/timegraph/widgets/Utils.java | 69 +++++++++++++++++++ 5 files changed, 170 insertions(+), 6 deletions(-) diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java index 56d02a551f..06e3683c70 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/Messages.java @@ -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; diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties index 3d021c1336..4b3c6bc997 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/messages.properties @@ -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 diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java index 9a2ecb04be..7edbb2456a 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphControl.java @@ -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); } /** diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphTooltipHandler.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphTooltipHandler.java index 3e52994b5a..9bc79c36d2 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphTooltipHandler.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/TimeGraphTooltipHandler.java @@ -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 values to be added to the tip table + Map eventAddOns = fTimeGraphProvider.getEventHoverToolTipInfo(linkEvent); + if (eventAddOns != null) { + for (Iterator 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; } diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/Utils.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/Utils.java index a75c5d9fe3..364c90cccb 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/Utils.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/widgets/timegraph/widgets/Utils.java @@ -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)); + } } -- 2.34.1