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;
# 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
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;
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
*/
* @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());
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);
}
/**
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;
}
}
+ 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) {
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;
}
}
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));
+ }
}