/*****************************************************************************
- * Copyright (c) 2007, 2013 Intel Corporation and others
+ * Copyright (c) 2007, 2014 Intel Corporation and others
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* Geneviève Bastien, École Polytechnique de Montréal - Move code to
* provide base classes for time graph view
* Add display of links between items
+ * Xavier Raynaud, Kalray - Code optimization
+ * Generoso Pagano, Inria - Support for drag selection listeners
*****************************************************************************/
package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ViewerFilter;
-import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.timestamp.TmfNanoTimestamp;
-import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphColorListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;
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.widgets.Utils.Resolution;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
* @author Alvaro Sanchez-Leon
* @author Patrick Tasse
*/
-public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider, MenuDetectListener, ITmfTimeGraphDrawingHelper {
-
+public class TimeGraphControl extends TimeGraphBaseControl
+ implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener,
+ ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider,
+ MenuDetectListener, ITmfTimeGraphDrawingHelper, ITimeGraphColorListener {
/** Max scrollbar size */
public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
+ /** Constant indicating that all levels of the time graph should be expanded
+ * @since 3.1 */
+ public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
+
private static final int DRAG_NONE = 0;
private static final int DRAG_TRACE_ITEM = 1;
private static final int DRAG_SPLIT_LINE = 2;
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;
private ITimeGraphPresentationProvider fTimeGraphProvider = null;
private ItemData fItemData = null;
private List<SelectionListener> fSelectionListeners;
- private final List<ISelectionChangedListener> fSelectionChangedListeners = new ArrayList<ISelectionChangedListener>();
- private final List<ITimeGraphTreeListener> fTreeListeners = new ArrayList<ITimeGraphTreeListener>();
- private final List<MenuDetectListener> fTimeGraphEntryMenuListeners = new ArrayList<MenuDetectListener>();
- private final List<MenuDetectListener> fTimeEventMenuListeners = new ArrayList<MenuDetectListener>();
+ private List<ITimeGraphTimeListener> fDragSelectionListeners;
+ private final List<ISelectionChangedListener> fSelectionChangedListeners = new ArrayList<>();
+ private final List<ITimeGraphTreeListener> fTreeListeners = new ArrayList<>();
+ private final List<MenuDetectListener> fTimeGraphEntryMenuListeners = new ArrayList<>();
+ private final List<MenuDetectListener> fTimeEventMenuListeners = new ArrayList<>();
private final Cursor fDragCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_HAND);
private final Cursor fResizeCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_IBEAM);
private final Cursor fWaitCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);
private final Cursor fZoomCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_SIZEWE);
- private final List<ViewerFilter> fFilters = new ArrayList<ViewerFilter>();
+ private final List<ViewerFilter> fFilters = new ArrayList<>();
private MenuDetectEvent fPendingMenuDetectEvent = null;
private boolean fHideArrows = false;
+ private int fAutoExpandLevel = ALL_LEVELS;
private int fBorderWidth = 0;
private int fHeaderHeight = 0;
if (timeGraphProvider instanceof ITimeGraphPresentationProvider2) {
((ITimeGraphPresentationProvider2) timeGraphProvider).setDrawingHelper(this);
+ ((ITimeGraphPresentationProvider2) timeGraphProvider).addColorListener(this);
}
- if (fEventColorMap != null) {
- for (Color color : fEventColorMap) {
- fResourceManager.destroyColor(color.getRGB());
- }
- }
StateItem[] stateItems = fTimeGraphProvider.getStateTable();
- if (stateItems != null) {
- fEventColorMap = new Color[stateItems.length];
- for (int i = 0; i < stateItems.length; i++) {
- fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());
- }
- } else {
- fEventColorMap = new Color[] { };
- }
+ colorSettingsChanged(stateItems);
+ }
+
+ /**
+ * Gets the timegraph provider used by this timegraph viewer.
+ *
+ * @return the timegraph provider, or <code>null</code> if not set.
+ * @since 3.0
+ */
+ public ITimeGraphPresentationProvider getTimeGraphProvider() {
+ return fTimeGraphProvider;
+ }
+
+ /**
+ * Gets the color map used by this timegraph viewer.
+ *
+ * @return a color map, or <code>null</code> if not set.
+ * @since 3.0
+ */
+ public Color[] getEventColorMap() {
+ return fEventColorMap;
}
/**
*
* @param statusLineManager
* The status line manager, or null to disable status line messages
- * @since 3.0
+ * @since 2.1
*/
public void setStatusLineManager(IStatusLineManager statusLineManager) {
if (fStatusLineManager != null && statusLineManager == null) {
*
* @param timeGraphScale
* The time graph scale
- * @since 3.0
+ * @since 2.1
*/
public void setTimeGraphScale(TimeGraphScale timeGraphScale) {
fTimeGraphScale = timeGraphScale;
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
if (null == fSelectionListeners) {
- fSelectionListeners = new ArrayList<SelectionListener>();
+ fSelectionListeners = new ArrayList<>();
}
fSelectionListeners.add(listener);
}
}
}
+ /**
+ * Add a drag selection listener
+ *
+ * @param listener
+ * The listener to add
+ * @since 3.1
+ */
+ public void addDragSelectionListener(ITimeGraphTimeListener listener) {
+ if (listener == null) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (null == fDragSelectionListeners) {
+ fDragSelectionListeners = new ArrayList<>();
+ }
+ fDragSelectionListeners.add(listener);
+ }
+
+ /**
+ * Remove a drag selection listener
+ *
+ * @param listener
+ * The listener to remove
+ * @since 3.1
+ */
+ public void removeDragSelectionListener(ITimeGraphTimeListener listener) {
+ if (null != fDragSelectionListeners) {
+ fDragSelectionListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Drag Selection changed callback
+ *
+ * @param start
+ * Time interval start
+ * @param end
+ * Time interval end
+ * @since 3.1
+ */
+ public void fireDragSelectionChanged(long start, long end) {
+ // check for backward intervals
+ long beginTime, endTime;
+ if (start > end) {
+ beginTime = end;
+ endTime = start;
+ } else {
+ beginTime = start;
+ endTime = end;
+ }
+ // call the listeners
+ if (null != fDragSelectionListeners) {
+ Iterator<ITimeGraphTimeListener> it = fDragSelectionListeners.iterator();
+ while (it.hasNext()) {
+ ITimeGraphTimeListener listener = it.next();
+ listener.timeSelected(new TimeGraphTimeEvent(this, beginTime, endTime));
+ }
+ }
+ }
+
/**
* Get the traces in the model
*
* @return The array of traces
*/
public ITimeGraphEntry[] getTraces() {
- return fItemData.getTraces();
+ return fItemData.getEntries();
}
/**
* @return The array of filters
*/
public boolean[] getTraceFilter() {
- return fItemData.getTraceFilter();
+ return fItemData.getEntryFilter();
}
/**
* Refresh the links (arrows) of this widget
*
* @param events The link events to refresh
- * @since 3.0
+ * @since 2.1
*/
public void refreshArrows(List<ILinkEvent> events) {
fItemData.refreshArrows(events);
redraw();
}
+ /**
+ * Sets the auto-expand level to be used when the entries are refreshed
+ * using {@link #refreshData()} or {@link #refreshData(ITimeGraphEntry[])}.
+ * The value 0 means that there is no auto-expand; 1 means that top-level
+ * entries are expanded, but not their children; 2 means that top-level
+ * entries are expanded, and their children, but not grand-children; and so
+ * on.
+ * <p>
+ * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
+ * </p>
+ * @param level
+ * non-negative level, or <code>ALL_LEVELS</code> to expand all
+ * levels of the tree
+ * @since 3.1
+ */
+ public void setAutoExpandLevel(int level) {
+ fAutoExpandLevel = level;
+ }
+
+ /**
+ * Returns the auto-expand level.
+ *
+ * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
+ * the tree are expanded automatically
+ * @see #setAutoExpandLevel
+ * @since 3.1
+ */
+ public int getAutoExpandLevel() {
+ return fAutoExpandLevel;
+ }
+
/**
* Set the expanded state of a given entry
*
}
}
- @SuppressWarnings("deprecation")
@Override
public ISelection getSelection() {
TimeGraphSelection sel = new TimeGraphSelection();
ITimeGraphEntry trace = getSelectedTrace();
if (null != trace && null != fTimeProvider) {
- long selectedTime;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- selectedTime = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- } else {
- selectedTime = fTimeProvider.getSelectedTime();
- }
+ long selectedTime = fTimeProvider.getSelectionBegin();
ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);
if (event != null) {
sel.add(event);
if (trace == null) {
return;
}
- long selectedTime;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- selectedTime = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- } else {
- @SuppressWarnings("deprecation")
- long time = fTimeProvider.getSelectedTime();
- selectedTime = time;
- }
+ long selectedTime = fTimeProvider.getSelectionBegin();
long endTime = fTimeProvider.getEndTime();
ITimeEvent nextEvent;
if (-1 == n && selectedTime > endTime) {
if (prevRange == 0) {
return;
}
- long selTime;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- ITimeDataProvider2 provider = ((ITimeDataProvider2) fTimeProvider);
- selTime = (provider.getSelectionEnd() + provider.getSelectionBegin()) / 2;
- } else {
- @SuppressWarnings("deprecation")
- long selectedTime = fTimeProvider.getSelectedTime();
- selTime = selectedTime;
- }
+ ITimeDataProvider provider = fTimeProvider;
+ long selTime = (provider.getSelectionEnd() + provider.getSelectionBegin()) / 2;
if (selTime <= prevTime0 || selTime >= prevTime1) {
selTime = (prevTime0 + prevTime1) / 2;
}
public void zoomOut() {
long prevTime0 = fTimeProvider.getTime0();
long prevTime1 = fTimeProvider.getTime1();
- long selTime;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- ITimeDataProvider2 provider = ((ITimeDataProvider2) fTimeProvider);
- selTime = (provider.getSelectionEnd() + provider.getSelectionBegin()) / 2;
- } else {
- @SuppressWarnings("deprecation")
- long selectedTime = fTimeProvider.getSelectedTime();
- selTime = selectedTime;
- }
+ ITimeDataProvider provider = fTimeProvider;
+ long selTime = (provider.getSelectionEnd() + provider.getSelectionBegin()) / 2;
if (selTime <= prevTime0 || selTime >= prevTime1) {
selTime = (prevTime0 + prevTime1) / 2;
}
*
* @param hideArrows true to hide arrows
*
- * @since 3.0
+ * @since 2.1
*/
public void hideArrows(boolean hideArrows) {
fHideArrows = hideArrows;
}
+ /**
+ * Follow the arrow forward
+ *
+ * @since 2.1
+ */
+ public void followArrowFwd() {
+ ITimeGraphEntry trace = getSelectedTrace();
+ if (trace == null) {
+ return;
+ }
+ long selectedTime = fTimeProvider.getSelectionBegin();
+ for (ILinkEvent link : fItemData.fLinks) {
+ if (link.getEntry() == trace && link.getTime() == selectedTime) {
+ selectItem(link.getDestinationEntry(), false);
+ if (link.getDuration() != 0) {
+ fTimeProvider.setSelectedTimeNotify(link.getTime() + link.getDuration(), true);
+ // Notify if visible time window has been adjusted
+ fTimeProvider.setStartFinishTimeNotify(fTimeProvider.getTime0(), fTimeProvider.getTime1());
+ }
+ fireSelectionChanged();
+ return;
+ }
+ }
+ selectNextEvent();
+ }
+
+ /**
+ * Follow the arrow backward
+ *
+ * @since 2.1
+ */
+ public void followArrowBwd() {
+ ITimeGraphEntry trace = getSelectedTrace();
+ if (trace == null) {
+ return;
+ }
+ long selectedTime = fTimeProvider.getSelectionBegin();
+ for (ILinkEvent link : fItemData.fLinks) {
+ if (link.getDestinationEntry() == trace && link.getTime() + link.getDuration() == selectedTime) {
+ selectItem(link.getEntry(), false);
+ if (link.getDuration() != 0) {
+ fTimeProvider.setSelectedTimeNotify(link.getTime(), true);
+ // Notify if visible time window has been adjusted
+ fTimeProvider.setStartFinishTimeNotify(fTimeProvider.getTime0(), fTimeProvider.getTime1());
+ }
+ fireSelectionChanged();
+ return;
+ }
+ }
+ selectPrevEvent();
+ }
+
/**
* Return the currently selected trace
*
ITimeGraphEntry trace = null;
int idx = getSelectedIndex();
if (idx >= 0) {
- trace = fItemData.fExpandedItems[idx].fTrace;
+ trace = fItemData.fExpandedItems[idx].fEntry;
}
return trace;
}
adjustScrolls();
redraw();
toggled = true;
- fireTreeEvent(item.fTrace, item.fExpanded);
+ fireTreeEvent(item.fEntry, item.fExpanded);
}
}
return toggled;
}
- int getItemIndexAtY(int y) {
+ /**
+ * Gets the index of the item at the given location.
+ *
+ * @param y
+ * the y coordinate
+ * @return the index of the item at the given location, of -1 if none.
+ * @since 3.0
+ */
+ protected int getItemIndexAtY(int y) {
if (y < 0) {
return -1;
}
return Math.abs(x - nameWidth) < SNAP_WIDTH;
}
- ITimeGraphEntry getEntry(Point pt) {
+ /**
+ * Gets the {@link ITimeGraphEntry} at the given location.
+ *
+ * @param pt
+ * a point in the widget
+ * @return the {@link ITimeGraphEntry} at this point, or <code>null</code>
+ * if none.
+ * @since 3.0
+ */
+ protected ITimeGraphEntry getEntry(Point pt) {
int idx = getItemIndexAtY(pt.y);
- return idx >= 0 ? fItemData.fExpandedItems[idx].fTrace : null;
+ 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;
}
/**
* @return The expanded elements
*/
public ITimeGraphEntry[] getExpandedElements() {
- ArrayList<ITimeGraphEntry> elements = new ArrayList<ITimeGraphEntry>();
+ ArrayList<ITimeGraphEntry> elements = new ArrayList<>();
for (Item item : fItemData.fExpandedItems) {
- elements.add(item.fTrace);
+ elements.add(item.fEntry);
}
return elements.toArray(new ITimeGraphEntry[0]);
}
long time0 = fTimeProvider.getTime0();
long time1 = fTimeProvider.getTime1();
- long selectionBegin;
- long selectionEnd;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- selectionBegin = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- selectionEnd = ((ITimeDataProvider2) fTimeProvider).getSelectionEnd();
- } else {
- @SuppressWarnings("deprecation")
- long selectedTime = fTimeProvider.getSelectedTime();
- selectionBegin = selectedTime;
- selectionEnd = selectedTime;
- }
+ long selectionBegin = fTimeProvider.getSelectionBegin();
+ long selectionEnd = fTimeProvider.getSelectionEnd();
double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
int x0 = bounds.x + nameSpace + (int) ((selectionBegin - time0) * pixelsPerNanoSec);
int x1 = bounds.x + nameSpace + (int) ((selectionEnd - time0) * pixelsPerNanoSec);
* @param gc Graphics context
*/
protected void drawItem(Item item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {
- ITimeGraphEntry entry = item.fTrace;
+ ITimeGraphEntry entry = item.fEntry;
long time0 = timeProvider.getTime0();
long time1 = timeProvider.getTime1();
- long selectedTime;
- if (fTimeProvider instanceof ITimeDataProvider2) {
- selectedTime = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- } else {
- @SuppressWarnings("deprecation")
- long time = fTimeProvider.getSelectedTime();
- selectedTime = time;
- }
+ long selectedTime = fTimeProvider.getSelectionBegin();
Rectangle nameRect = getNameRect(bounds, i, nameSpace);
if (nameRect.y >= bounds.y + bounds.height) {
return;
}
- if (! item.fTrace.hasTimeEvents()) {
+ if (! item.fEntry.hasTimeEvents()) {
Rectangle statesRect = getStatesRect(bounds, i, nameSpace);
nameRect.width += statesRect.width;
drawName(item, nameRect, gc);
// K pixels per second
double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);
- if (item.fTrace.hasTimeEvents()) {
+ if (item.fEntry.hasTimeEvents()) {
+ gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
fillSpace(rect, gc, selected);
// Drawing rectangle is smaller than reserved space
stateRect.y += 3;
lastX = x;
}
}
+ gc.setClipping((Rectangle) null);
}
fTimeGraphProvider.postDrawEntry(entry, rect, gc);
}
* The width reserved for the names
* @param gc
* Reference to the SWT GC object
- * @since 3.0
+ * @since 2.1
*/
public void drawLinks(Rectangle bounds, ITimeDataProvider timeProvider,
List<ILinkEvent> links, int nameSpace, GC gc) {
if (fHideArrows) {
return;
}
+ gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
for (ILinkEvent event : links) {
drawLink(event, bounds, timeProvider, nameSpace, gc);
}
+ gc.setClipping((Rectangle) null);
}
/**
* the name space
* @param gc
* Graphics context
- * @since 3.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());
+
+ // limit the x-coordinates to prevent integer overflow in calculations
+ // and also GC.drawLine doesn't draw properly with large coordinates
+ final int limit = Integer.MAX_VALUE / 1024;
+ x0 = Math.max(-limit, Math.min(x0, limit));
+ x1 = Math.max(-limit, Math.min(x1, limit));
+
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);
}
/**
* @param gc
* Graphics context
* @return true if the state was drawn
- * @since 3.0
+ * @since 2.1
*/
protected boolean drawArrow(TimeGraphColorScheme colors, ITimeEvent event,
Rectangle rect, GC gc) {
+ if (rect == null) {
+ return false;
+ }
int colorIdx = fTimeGraphProvider.getStateTableIndex(event);
if (colorIdx < 0) {
return false;
int factor = 10;
double cos = 0.9510;
double sin = 0.3090;
- int lenx = x1 - x0;
- int leny = y1 - y0;
+ long lenx = x1 - x0;
+ long leny = y1 - y0;
double len = Math.sqrt(lenx * lenx + leny * leny);
double dx = factor * lenx / len;
* Graphics context
*/
protected void drawName(Item item, Rectangle bounds, GC gc) {
- boolean hasTimeEvents = item.fTrace.hasTimeEvents();
+ boolean hasTimeEvents = item.fEntry.hasTimeEvents();
if (! hasTimeEvents) {
gc.setBackground(getColorScheme().getBkColorGroup(item.fSelected, fIsInFocus));
gc.fillRectangle(bounds);
}
leftMargin += EXPAND_SIZE + MARGIN;
- Image img = fTimeGraphProvider.getItemImage(item.fTrace);
+ Image img = fTimeGraphProvider.getItemImage(item.fEntry);
if (img != null) {
// draw icon
int imgHeight = img.getImageData().height;
return false;
}
boolean visible = rect.width == 0 ? false : true;
+ Color black = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ gc.setForeground(black);
if (visible) {
if (colorIdx == ITimeGraphPresentationProvider.TRANSPARENT) {
// Only draw the top and bottom borders
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
if (rect.width == 1) {
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.drawPoint(rect.x, rect.y - 2);
}
return false;
if (colorIdx < fEventColorMap.length) {
stateColor = fEventColorMap[colorIdx];
} else {
- stateColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ stateColor = black;
}
boolean reallySelected = timeSelected && selected;
// fill all rect area
gc.setBackground(stateColor);
gc.fillRectangle(rect);
- // get the border color?
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
- // draw bounds
- if (!reallySelected) {
- // Draw the top and bottom borders i.e. no side borders
- gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
- gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
+ if (reallySelected) {
+ gc.drawLine(rect.x, rect.y - 1, rect.x + rect.width - 1, rect.y - 1);
+ gc.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width - 1, rect.y + rect.height);
}
} else {
- gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.drawPoint(rect.x, rect.y - 2);
}
fTimeGraphProvider.postDrawEvent(event, rect, gc);
cursor = fDragCursor;
} else if ((stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
cursor = fResizeCursor;
- } else {
- if (!isOverSplitLine(x) &&fTimeProvider instanceof ITimeDataProvider2) {
- long selectionBegin = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- long selectionEnd = ((ITimeDataProvider2) fTimeProvider).getSelectionEnd();
- int xBegin = getXForTime(selectionBegin);
- int xEnd = getXForTime(selectionEnd);
- if (Math.abs(x - xBegin) < SNAP_WIDTH || Math.abs(x - xEnd) < SNAP_WIDTH) {
- cursor = fResizeCursor;
- }
+ } else if (!isOverSplitLine(x)) {
+ long selectionBegin = fTimeProvider.getSelectionBegin();
+ long selectionEnd = fTimeProvider.getSelectionEnd();
+ int xBegin = getXForTime(selectionBegin);
+ int xEnd = getXForTime(selectionEnd);
+ if (Math.abs(x - xBegin) < SNAP_WIDTH || Math.abs(x - xEnd) < SNAP_WIDTH) {
+ cursor = fResizeCursor;
}
}
if (getCursor() != cursor) {
}
private void updateStatusLine(int x) {
- if (fStatusLineManager == null) {
+ // use the time provider of the time graph scale for the status line
+ ITimeDataProvider tdp = fTimeGraphScale.getTimeProvider();
+ if (fStatusLineManager == null || null == tdp ||
+ tdp.getTime0() == tdp.getTime1()) {
return;
}
+ TimeFormat tf = tdp.getTimeFormat();
+ Resolution res = Resolution.NANOSEC;
StringBuilder message = new StringBuilder();
if (x >= 0 && fDragState == DRAG_NONE) {
long time = getTimeAtX(x);
if (time >= 0) {
- message.append("T: "); //$NON-NLS-1$
- message.append(new TmfNanoTimestamp(time).toString());
- message.append(" T1: "); //$NON-NLS-1$
- if (fTimeProvider instanceof ITimeDataProvider2) {
- long selectionBegin = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- long selectionEnd = ((ITimeDataProvider2) fTimeProvider).getSelectionEnd();
- message.append(new TmfNanoTimestamp(Math.min(selectionBegin, selectionEnd)).toString());
- if (selectionBegin != selectionEnd) {
- message.append(" T2: "); //$NON-NLS-1$
- message.append(new TmfNanoTimestamp(Math.max(selectionBegin, selectionEnd)).toString());
- message.append(" \u0394: "); //$NON-NLS-1$
- message.append(new TmfTimestampDelta(Math.abs(selectionBegin - selectionEnd), ITmfTimestamp.NANOSECOND_SCALE));
- }
- } else {
- @SuppressWarnings("deprecation")
- long selectedTime = fTimeProvider.getSelectedTime();
- message.append(new TmfNanoTimestamp(selectedTime));
+ if (tdp instanceof ITimeDataProviderConverter) {
+ time = ((ITimeDataProviderConverter) tdp).convertTime(time);
+ }
+ long selectionBegin = tdp.getSelectionBegin();
+ long selectionEnd = tdp.getSelectionEnd();
+ message.append(NLS.bind("T: {0}{1} T1: {2}{3}", //$NON-NLS-1$
+ new Object[] {
+ tf == TimeFormat.CALENDAR ? Utils.formatDate(time) + ' ' : "", //$NON-NLS-1$
+ Utils.formatTime(time, tf, res),
+ tf == TimeFormat.CALENDAR ? Utils.formatDate(Math.min(selectionBegin, selectionEnd)) + ' ' : "", //$NON-NLS-1$
+ Utils.formatTime(Math.min(selectionBegin, selectionEnd), tf, res)
+ }));
+ if (selectionBegin != selectionEnd) {
+ message.append(NLS.bind(" T2: {0}{1} \u0394: {2}", //$NON-NLS-1$
+ new Object[] {
+ tf == TimeFormat.CALENDAR ? Utils.formatDate(Math.max(selectionBegin, selectionEnd)) + ' ' : "", //$NON-NLS-1$
+ Utils.formatTime(Math.max(selectionBegin, selectionEnd), tf, res),
+ Utils.formatDelta(Math.abs(selectionBegin - selectionEnd), tf, res)
+ }));
}
}
} else if (fDragState == DRAG_SELECTION || fDragState == DRAG_ZOOM) {
long time0 = fDragTime0;
long time = getTimeAtX(fDragX);
- message.append("T1: "); //$NON-NLS-1$
- message.append(new TmfNanoTimestamp(Math.min(time, time0)).toString());
- if (time != time0) {
- message.append(" T2: "); //$NON-NLS-1$
- message.append(new TmfNanoTimestamp(Math.max(time, time0)).toString());
- message.append(" \u0394: "); //$NON-NLS-1$
- message.append(new TmfTimestampDelta(Math.abs(time - time0), ITmfTimestamp.NANOSECOND_SCALE));
- }
+ if (tdp instanceof ITimeDataProviderConverter) {
+ time0 = ((ITimeDataProviderConverter) tdp).convertTime(time0);
+ time = ((ITimeDataProviderConverter) tdp).convertTime(time);
+ }
+ message.append(NLS.bind("T1: {0}{1} T2: {2}{3} \u0394: {4}", //$NON-NLS-1$
+ new Object[] {
+ tf == TimeFormat.CALENDAR ? Utils.formatDate(Math.min(time, time0)) + ' ' : "", //$NON-NLS-1$
+ Utils.formatTime(Math.min(time, time0), tf, res),
+ tf == TimeFormat.CALENDAR ? Utils.formatDate(Math.max(time, time0)) + ' ' : "", //$NON-NLS-1$
+ Utils.formatTime(Math.max(time, time0), tf, res),
+ Utils.formatDelta(Math.abs(time - time0), tf, res)
+ }));
}
fStatusLineManager.setMessage(message.toString());
}
fDragX = e.x;
fTimeProvider.setNameSpace(e.x);
} else if (DRAG_SELECTION == fDragState) {
- if (fTimeProvider instanceof ITimeDataProvider2) {
- fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), size.x - RIGHT_MARGIN);
- redraw();
- fTimeGraphScale.setDragRange(fDragX0, fDragX);
- }
+ fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), size.x - RIGHT_MARGIN);
+ redraw();
+ fTimeGraphScale.setDragRange(fDragX0, fDragX);
+ fireDragSelectionChanged(getTimeAtX(fDragX0), getTimeAtX(fDragX));
} else if (DRAG_ZOOM == fDragState) {
fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), size.x - RIGHT_MARGIN);
redraw();
@Override
public void mouseDown(MouseEvent e) {
- if (fDragState != DRAG_NONE || null == fTimeProvider) {
+ if (fDragState != DRAG_NONE || null == fTimeProvider ||
+ fTimeProvider.getTime0() == fTimeProvider.getTime1() ||
+ getCtrlSize().x - fTimeProvider.getNameSpace() <= 0) {
return;
}
int idx;
fDragX = e.x;
fDragX0 = fDragX;
fDragTime0 = getTimeAtX(fDragX0);
- if (fTimeProvider instanceof ITimeDataProvider2) {
- long selectionBegin = ((ITimeDataProvider2) fTimeProvider).getSelectionBegin();
- long selectionEnd = ((ITimeDataProvider2) fTimeProvider).getSelectionEnd();
- int xBegin = getXForTime(selectionBegin);
- int xEnd = getXForTime(selectionEnd);
- if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
- long time = getTimeAtX(e.x);
- if (Math.abs(time - selectionBegin) < Math.abs(time - selectionEnd)) {
- fDragX0 = xEnd;
- fDragTime0 = selectionEnd;
- } else {
- fDragX0 = xBegin;
- fDragTime0 = selectionBegin;
- }
+ long selectionBegin = fTimeProvider.getSelectionBegin();
+ long selectionEnd = fTimeProvider.getSelectionEnd();
+ int xBegin = getXForTime(selectionBegin);
+ int xEnd = getXForTime(selectionEnd);
+ if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
+ long time = getTimeAtX(e.x);
+ if (Math.abs(time - selectionBegin) < Math.abs(time - selectionEnd)) {
+ fDragX0 = xEnd;
+ fDragTime0 = selectionEnd;
} else {
- long time = getTimeAtX(e.x);
- if (Math.abs(e.x - xBegin) < SNAP_WIDTH && Math.abs(time - selectionBegin) <= Math.abs(time - selectionEnd)) {
- fDragX0 = xEnd;
- fDragTime0 = selectionEnd;
- } else if (Math.abs(e.x - xEnd) < SNAP_WIDTH && Math.abs(time - selectionEnd) <= Math.abs(time - selectionBegin)) {
- fDragX0 = xBegin;
- fDragTime0 = selectionBegin;
- }
+ fDragX0 = xBegin;
+ fDragTime0 = selectionBegin;
+ }
+ } else {
+ long time = getTimeAtX(e.x);
+ if (Math.abs(e.x - xBegin) < SNAP_WIDTH && Math.abs(time - selectionBegin) <= Math.abs(time - selectionEnd)) {
+ fDragX0 = xEnd;
+ fDragTime0 = selectionEnd;
+ } else if (Math.abs(e.x - xEnd) < SNAP_WIDTH && Math.abs(time - selectionEnd) <= Math.abs(time - selectionBegin)) {
+ fDragX0 = xBegin;
+ fDragTime0 = selectionBegin;
}
}
fTime0bak = fTimeProvider.getTime0();
updateCursor(e.x, e.stateMask);
}
} else if (3 == e.button) {
- if (fTimeProvider.getTime0() == fTimeProvider.getTime1() || getCtrlSize().x - fTimeProvider.getNameSpace() <= 0) {
- return;
- }
setCapture(true);
fDragX = Math.min(Math.max(e.x, fTimeProvider.getNameSpace()), getCtrlSize().x - RIGHT_MARGIN);
fDragX0 = fDragX;
+ fDragTime0 = getTimeAtX(fDragX0);
fDragState = DRAG_ZOOM;
fDragButton = e.button;
redraw();
long time0 = fDragTime0;
long time1 = getTimeAtX(fDragX);
if (time0 <= time1) {
- ((ITimeDataProvider2) fTimeProvider).setSelectionRangeNotify(time0, time1);
+ fTimeProvider.setSelectionRangeNotify(time0, time1);
} else {
- ((ITimeDataProvider2) fTimeProvider).setSelectionRangeNotify(time1, time0);
+ fTimeProvider.setSelectionRangeNotify(time1, time0);
}
}
fDragState = DRAG_NONE;
* The height
* @return true if the height is successfully stored, false otherwise
*
- * @since 3.0
+ * @since 2.1
*/
public boolean setItemHeight(ITimeGraphEntry entry, int rowHeight) {
Item item = fItemData.findItem(entry);
fFilters.remove(filter);
}
+ /**
+ * @since 3.0
+ */
+ @Override
+ public void colorSettingsChanged(StateItem[] stateItems) {
+ /* Destroy previous colors from the resource manager */
+ if (fEventColorMap != null) {
+ for (Color color : fEventColorMap) {
+ fResourceManager.destroyColor(color.getRGB());
+ }
+ }
+ if (stateItems != null) {
+ fEventColorMap = new Color[stateItems.length];
+ for (int i = 0; i < stateItems.length; i++) {
+ fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());
+ }
+ } else {
+ fEventColorMap = new Color[] { };
+ }
+ redraw();
+ }
+
private class ItemData {
+ private final Map<ITimeGraphEntry, Item> fItemMap = new LinkedHashMap<>();
private Item[] fExpandedItems = new Item[0];
private Item[] fItems = new Item[0];
- private ITimeGraphEntry fTraces[] = new ITimeGraphEntry[0];
- private List<ILinkEvent> fLinks = new ArrayList<ILinkEvent>();
- private boolean fTraceFilter[] = new boolean[0];
- private final ArrayList<ITimeGraphEntry> fFilteredOut = new ArrayList<ITimeGraphEntry>();
+ private ITimeGraphEntry fRootEntries[] = new ITimeGraphEntry[0];
+ private List<ILinkEvent> fLinks = new ArrayList<>();
+ private boolean fEntryFilter[] = new boolean[0];
+ private final ArrayList<ITimeGraphEntry> fFilteredOut = new ArrayList<>();
public ItemData() {
}
- Item findItem(ITimeGraphEntry entry) {
- if (entry == null) {
- return null;
- }
-
- for (int i = 0; i < fItems.length; i++) {
- Item item = fItems[i];
- if (item.fTrace == entry) {
- return item;
- }
- }
-
- return null;
+ public Item findItem(ITimeGraphEntry entry) {
+ return fItemMap.get(entry);
}
- int findItemIndex(ITimeGraphEntry trace) {
- if (trace == null) {
+ public int findItemIndex(ITimeGraphEntry entry) {
+ Item item = fItemMap.get(entry);
+ if (item == null) {
return -1;
}
-
- for (int i = 0; i < fExpandedItems.length; i++) {
- Item item = fExpandedItems[i];
- if (item.fTrace == trace) {
- return i;
- }
- }
-
- return -1;
+ return item.fExpandedIndex;
}
public void refreshData() {
- List<Item> itemList = new ArrayList<Item>();
+ fItemMap.clear();
fFilteredOut.clear();
ITimeGraphEntry selection = getSelectedTrace();
- for (int i = 0; i < fTraces.length; i++) {
- ITimeGraphEntry entry = fTraces[i];
- refreshData(itemList, null, 0, entry);
+ for (int i = 0; i < fRootEntries.length; i++) {
+ ITimeGraphEntry entry = fRootEntries[i];
+ refreshData(fItemMap, null, 0, entry);
}
- fItems = itemList.toArray(new Item[0]);
+ fItems = fItemMap.values().toArray(new Item[0]);
updateExpandedItems();
if (selection != null) {
for (Item item : fExpandedItems) {
- if (item.fTrace == selection) {
+ if (item.fEntry == selection) {
item.fSelected = true;
break;
}
}
}
- private void refreshData(List<Item> itemList, Item parent, int level, ITimeGraphEntry entry) {
+ private void refreshData(Map<ITimeGraphEntry, Item> itemMap, Item parent, int level, ITimeGraphEntry entry) {
Item item = new Item(entry, entry.getName(), level);
if (parent != null) {
parent.fChildren.add(item);
} else {
item.fItemHeight = fGlobalItemHeight;
}
- itemList.add(item);
+ itemMap.put(entry, item);
if (entry.hasChildren()) {
- item.fExpanded = true;
+ item.fExpanded = fAutoExpandLevel == ALL_LEVELS || level < fAutoExpandLevel;
item.fHasChildren = true;
for (ITimeGraphEntry child : entry.getChildren()) {
- refreshData(itemList, item, level + 1, child);
+ refreshData(itemMap, item, level + 1, child);
}
}
}
public void updateExpandedItems() {
- List<Item> expandedItemList = new ArrayList<Item>();
- for (int i = 0; i < fTraces.length; i++) {
- ITimeGraphEntry entry = fTraces[i];
+ for (Item item : fItems) {
+ item.fExpandedIndex = -1;
+ }
+ List<Item> expandedItemList = new ArrayList<>();
+ for (int i = 0; i < fRootEntries.length; i++) {
+ ITimeGraphEntry entry = fRootEntries[i];
Item item = findItem(entry);
refreshExpanded(expandedItemList, item);
}
fExpandedItems = expandedItemList.toArray(new Item[0]);
+ fTopIndex = Math.min(fTopIndex, Math.max(0, fExpandedItems.length - 1));
}
private void refreshExpanded(List<Item> expandedItemList, Item item) {
// Check for filters
boolean display = true;
for (ViewerFilter filter : fFilters) {
- if (!filter.select(null, item.fTrace.getParent(), item.fTrace)) {
+ if (!filter.select(null, item.fEntry.getParent(), item.fEntry)) {
display = false;
break;
}
}
if (display) {
+ item.fExpandedIndex = expandedItemList.size();
expandedItemList.add(item);
if (item.fHasChildren && item.fExpanded) {
for (Item child : item.fChildren) {
}
}
- public void refreshData(ITimeGraphEntry traces[]) {
- if (traces == null) {
- fTraceFilter = null;
- fTraces = null;
+ public void refreshData(ITimeGraphEntry[] entries) {
+ if (entries == null) {
+ fEntryFilter = null;
+ fRootEntries = null;
} else {
- if (traces.length == 0) {
- fTraceFilter = null;
- } else if (fTraceFilter == null || traces.length != fTraceFilter.length) {
- fTraceFilter = new boolean[traces.length];
- java.util.Arrays.fill(fTraceFilter, true);
+ if (entries.length == 0) {
+ fEntryFilter = null;
+ } else if (fEntryFilter == null || entries.length != fEntryFilter.length) {
+ fEntryFilter = new boolean[entries.length];
+ java.util.Arrays.fill(fEntryFilter, true);
}
- fTraces = Arrays.copyOf(traces, traces.length);
+ fRootEntries = Arrays.copyOf(entries, entries.length);
}
refreshData();
if (events != null) {
fLinks = events;
} else {
- fLinks = new ArrayList<ILinkEvent>();
+ fLinks = new ArrayList<>();
}
}
- public ITimeGraphEntry[] getTraces() {
- return fTraces;
+ public ITimeGraphEntry[] getEntries() {
+ return fRootEntries;
}
- public boolean[] getTraceFilter() {
- return fTraceFilter;
+ public boolean[] getEntryFilter() {
+ return fEntryFilter;
}
public List<ITimeGraphEntry> getFilteredOut() {
private class Item {
private boolean fExpanded;
+ private int fExpandedIndex;
private boolean fSelected;
private boolean fHasChildren;
private int fItemHeight;
- private int fLevel;
- private List<Item> fChildren;
- private String fName;
- private ITimeGraphEntry fTrace;
+ private final int fLevel;
+ private final List<Item> fChildren;
+ private final String fName;
+ private final ITimeGraphEntry fEntry;
- public Item(ITimeGraphEntry trace, String name, int level) {
- this.fTrace = trace;
+ public Item(ITimeGraphEntry entry, String name, int level) {
+ this.fEntry = entry;
this.fName = name;
this.fLevel = level;
- this.fChildren = new ArrayList<Item>();
+ this.fChildren = new ArrayList<>();
}
@Override
int idx = getItemIndexAtY(p.y);
if (idx >= 0 && idx < fItemData.fExpandedItems.length) {
Item item = fItemData.fExpandedItems[idx];
- ITimeGraphEntry entry = item.fTrace;
+ ITimeGraphEntry entry = item.fEntry;
if (entry.hasTimeEvents()) {
ITimeEvent event = Utils.findEvent(entry, getTimeAtX(p.x), 2);
if (event != null) {