import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import com.google.common.collect.Iterables;
+
/**
* Time graph control implementation
*
private static final int NO_STATUS = -1;
private static final int STATUS_WITHOUT_CURSOR_TIME = -2;
+ private static final int MAX_LABEL_LENGTH = 256;
+
+ private static final int PPI = 72; // points per inch
+ private static final int DPI = Display.getDefault().getDPI().y;
+
/** Resource manager */
private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
private boolean fIsInFocus = false;
private boolean fMouseOverSplitLine = false;
private int fGlobalItemHeight = CUSTOM_ITEM_HEIGHT;
+ private int fHeightAdjustment = 0;
+ private Map<Integer, Font> fFonts = new HashMap<>();
private boolean fBlendSubPixelEvents = false;
private int fMinimumItemWidth = 0;
private int fTopIndex = 0;
private long fTime1bak;
private ITimeGraphPresentationProvider fTimeGraphProvider = null;
private ItemData fItemData = null;
+ private List<IMarkerEvent> fMarkers = null;
+ private boolean fMarkersVisible = true;
private List<SelectionListener> fSelectionListeners;
private List<ITimeGraphTimeListener> fDragSelectionListeners;
private final List<ISelectionChangedListener> fSelectionChangedListeners = new ArrayList<>();
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<>();
+ private final List<@NonNull ViewerFilter> fFilters = new ArrayList<>();
private MenuDetectEvent fPendingMenuDetectEvent = null;
+ private boolean fGridLinesVisible = true;
+ private Color fGridLineColor = Display.getDefault().getSystemColor(SWT.COLOR_GRAY);
private boolean fHideArrows = false;
private int fAutoExpandLevel = ALL_LEVELS;
public void dispose() {
super.dispose();
fResourceManager.dispose();
+ for (Font font : fFonts.values()) {
+ font.dispose();
+ }
}
/**
*
* @return The unmodifiable link event list
*
- * @since 2.0
+ * @since 1.1
*/
public List<ILinkEvent> getArrows() {
return Collections.unmodifiableList(fItemData.fLinks);
* @param entry
* The entry
* @return true if the entry is expanded, false if collapsed
- * @since 2.0
+ * @since 1.1
*/
public boolean getExpandedState(ITimeGraphEntry entry) {
Item item = fItemData.fItemMap.get(entry);
nextTime = nextEvent.getTime() + nextEvent.getDuration();
}
if (extend) {
- fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), nextTime);
+ fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), nextTime, true);
} else {
fTimeProvider.setSelectedTimeNotify(nextTime, true);
}
fireSelectionChanged();
} else if (n == 1) {
if (extend) {
- fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), endTime);
+ fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), endTime, true);
} else {
fTimeProvider.setSelectedTimeNotify(endTime, true);
}
fTimeProvider.setStartFinishTimeNotify(time0, time1);
}
+ /**
+ * Zoom vertically.
+ *
+ * @param zoomIn
+ * true to zoom in, false to zoom out
+ * @since 2.0
+ */
+ public void verticalZoom(boolean zoomIn) {
+ if (zoomIn) {
+ fHeightAdjustment++;
+ } else {
+ fHeightAdjustment--;
+ }
+ fItemData.refreshData();
+ redraw();
+ }
+
+ /**
+ * Reset the vertical zoom to default.
+ *
+ * @since 2.0
+ */
+ public void resetVerticalZoom() {
+ fHeightAdjustment = 0;
+ fItemData.refreshData();
+ redraw();
+ }
+
+ /**
+ * Set the grid lines visibility. The default is true.
+ *
+ * @param visible
+ * true to show the grid lines, false otherwise
+ * @since 2.0
+ */
+ public void setGridLinesVisible(boolean visible) {
+ fGridLinesVisible = visible;
+ }
+
+ /**
+ * Get the grid lines visibility.
+ *
+ * @return true if the grid lines are visible, false otherwise
+ * @since 2.0
+ */
+ public boolean getGridLinesVisible() {
+ return fGridLinesVisible;
+ }
+
+ /**
+ * Set the grid line color. The default is SWT.COLOR_GRAY.
+ *
+ * @param color
+ * the grid line color
+ * @since 2.0
+ */
+ public void setGridLineColor(Color color) {
+ fGridLineColor = color;
+ }
+
+ /**
+ * Get the grid line color.
+ *
+ * @return the grid line color
+ * @since 2.0
+ */
+ public Color getGridLineColor() {
+ return fGridLineColor;
+ }
+
+ /**
+ * Set the markers list.
+ *
+ * @param markers
+ * The markers list, or null
+ * @since 2.0
+ */
+ public void setMarkers(List<IMarkerEvent> markers) {
+ fMarkers = markers;
+ fTimeGraphScale.setMarkers(markers);
+ }
+
+ /**
+ * Get the markers list.
+ *
+ * @return The markers list, or null
+ * @since 2.0
+ */
+ public List<IMarkerEvent> getMarkers() {
+ return fMarkers;
+ }
+
+ /**
+ * Set the markers visibility. The default is true.
+ *
+ * @param visible
+ * true to show the markers, false otherwise
+ * @since 2.0
+ */
+ public void setMarkersVisible(boolean visible) {
+ fMarkersVisible = visible;
+ fTimeGraphScale.setMarkersVisible(visible);
+ }
+
+ /**
+ * Get the markers visibility.
+ *
+ * @return true if the markers are visible, false otherwise
+ * @since 2.0
+ */
+ public boolean getMarkersVisible() {
+ return fMarkersVisible;
+ }
+
/**
* Hide arrows
*
selectItem(link.getDestinationEntry(), false);
if (link.getDuration() != 0) {
if (extend) {
- fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), link.getTime() + link.getDuration());
+ fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), link.getTime() + link.getDuration(), true);
} else {
fTimeProvider.setSelectedTimeNotify(link.getTime() + link.getDuration(), true);
}
selectItem(link.getEntry(), false);
if (link.getDuration() != 0) {
if (extend) {
- fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), link.getTime());
+ fTimeProvider.setSelectionRangeNotify(fTimeProvider.getSelectionBegin(), link.getTime(), true);
} else {
fTimeProvider.setSelectedTimeNotify(link.getTime(), true);
}
return elements.toArray(new ITimeGraphEntry[0]);
}
- Rectangle getNameRect(Rectangle bound, int idx, int nameWidth) {
- Rectangle rect = getStatesRect(bound, idx, nameWidth);
- rect.x = bound.x;
+ Rectangle getNameRect(Rectangle bounds, int idx, int nameWidth) {
+ Rectangle rect = getItemRect(bounds, idx);
rect.width = nameWidth;
return rect;
}
- Rectangle getStatesRect(Rectangle bound, int idx, int nameWidth) {
- int x = bound.x + nameWidth;
- int width = bound.width - x;
+ Rectangle getStatesRect(Rectangle bounds, int idx, int nameWidth) {
+ Rectangle rect = getItemRect(bounds, idx);
+ rect.x += nameWidth;
+ rect.width -= nameWidth;
+ return rect;
+ }
+
+ Rectangle getItemRect(Rectangle bounds, int idx) {
int ySum = 0;
if (idx >= fTopIndex) {
for (int i = fTopIndex; i < idx; i++) {
ySum -= fItemData.fExpandedItems[i].fItemHeight;
}
}
- int y = bound.y + ySum;
+ int y = bounds.y + ySum;
int height = fItemData.fExpandedItems[idx].fItemHeight;
- return new Rectangle(x, y, width, height);
+ return new Rectangle(bounds.x, y, bounds.width, height);
}
@Override
void paint(Rectangle bounds, PaintEvent e) {
GC gc = e.gc;
- gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.BACKGROUND));
- drawBackground(gc, bounds.x, bounds.y, bounds.width, bounds.height);
if (bounds.width < 2 || bounds.height < 2 || null == fTimeProvider) {
return;
fIdealNameSpace = 0;
int nameSpace = fTimeProvider.getNameSpace();
- // draw empty name space background
- gc.setBackground(getColorScheme().getBkColor(false, false, true));
- drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);
+ // draw the background layer
+ drawBackground(bounds, nameSpace, gc);
+
+ // draw the grid lines
+ drawGridLines(bounds, gc);
+
+ // draw the background markers
+ drawMarkers(bounds, fTimeProvider, fMarkers, false, nameSpace, gc);
- // draw items
+ // draw the items
drawItems(bounds, fTimeProvider, fItemData.fExpandedItems, fTopIndex, nameSpace, gc);
+
+ // draw the foreground markers
+ drawMarkers(bounds, fTimeProvider, fMarkers, true, nameSpace, gc);
+
+ // draw the links (arrows)
drawLinks(bounds, fTimeProvider, fItemData.fLinks, nameSpace, gc);
+
fTimeGraphProvider.postDrawControl(bounds, gc);
int alpha = gc.getAlpha();
}
/**
- * Draw many items at once
+ * Draw the background layer. Fills the background of the control's name
+ * space and states space, updates the background of items if necessary,
+ * and draws the item's name text and middle line.
+ *
+ * @param bounds
+ * The bounds of the control
+ * @param nameSpace
+ * The name space width
+ * @param gc
+ * Graphics context
+ * @since 2.0
+ */
+ protected void drawBackground(Rectangle bounds, int nameSpace, GC gc) {
+ // draw empty name space background
+ gc.setBackground(getColorScheme().getBkColor(false, false, true));
+ drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);
+
+ // draw empty states space background
+ gc.setBackground(getColorScheme().getColor(TimeGraphColorScheme.BACKGROUND));
+ drawBackground(gc, bounds.x + nameSpace, bounds.y, bounds.width - nameSpace, bounds.height);
+
+ for (int i = fTopIndex; i < fItemData.fExpandedItems.length; i++) {
+ Rectangle itemRect = getItemRect(bounds, i);
+ if (itemRect.y >= bounds.y + bounds.height) {
+ break;
+ }
+ Item item = fItemData.fExpandedItems[i];
+ // draw the background of selected item and items with no time events
+ if (! item.fEntry.hasTimeEvents()) {
+ gc.setBackground(getColorScheme().getBkColorGroup(item.fSelected, fIsInFocus));
+ gc.fillRectangle(itemRect);
+ } else if (item.fSelected) {
+ gc.setBackground(getColorScheme().getBkColor(true, fIsInFocus, true));
+ gc.fillRectangle(itemRect.x, itemRect.y, nameSpace, itemRect.height);
+ gc.setBackground(getColorScheme().getBkColor(true, fIsInFocus, false));
+ gc.fillRectangle(nameSpace, itemRect.y, itemRect.width - nameSpace, itemRect.height);
+ }
+ // draw the name and middle line
+ if (! item.fEntry.hasTimeEvents()) {
+ drawName(item, itemRect, gc);
+ } else {
+ Rectangle nameRect = new Rectangle(itemRect.x, itemRect.y, nameSpace, itemRect.height);
+ drawName(item, nameRect, gc);
+ Rectangle rect = new Rectangle(nameSpace, itemRect.y, itemRect.width - nameSpace, itemRect.height);
+ drawMidLine(rect, gc);
+ }
+ }
+ }
+
+ /**
+ * Draw the grid lines
+ *
+ * @param bounds
+ * The bounds of the control
+ * @param gc
+ * Graphics context
+ * @since 2.0
+ */
+ public void drawGridLines(Rectangle bounds, GC gc) {
+ if (!fGridLinesVisible) {
+ return;
+ }
+ gc.setForeground(fGridLineColor);
+ gc.setAlpha(fGridLineColor.getAlpha());
+ for (int x : fTimeGraphScale.getTickList()) {
+ gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);
+ }
+ gc.setAlpha(255);
+ }
+
+ /**
+ * Draw the markers
*
* @param bounds
* The rectangle of the area
* @param timeProvider
* The time provider
+ * @param markers
+ * The list of markers
+ * @param foreground
+ * true to draw the foreground markers, false otherwise
+ * @param nameSpace
+ * The width reserved for the names
+ * @param gc
+ * Reference to the SWT GC object
+ * @since 2.0
+ */
+ protected void drawMarkers(Rectangle bounds, ITimeDataProvider timeProvider, List<IMarkerEvent> markers, boolean foreground, int nameSpace, GC gc) {
+ if (!fMarkersVisible || markers == null || markers.isEmpty()) {
+ return;
+ }
+ gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
+ /* the list can grow concurrently but cannot shrink */
+ for (int i = 0; i < markers.size(); i++) {
+ IMarkerEvent marker = markers.get(i);
+ if (marker.isForeground() == foreground) {
+ drawMarker(marker, bounds, timeProvider, nameSpace, gc);
+ }
+ }
+ gc.setClipping((Rectangle) null);
+ }
+
+ /**
+ * Draw a single marker
+ *
+ * @param marker
+ * The marker event
+ * @param bounds
+ * The bounds of the control
+ * @param timeProvider
+ * The time provider
+ * @param nameSpace
+ * The width reserved for the name
+ * @param gc
+ * Reference to the SWT GC object
+ * @since 2.0
+ */
+ protected void drawMarker(IMarkerEvent marker, Rectangle bounds, ITimeDataProvider timeProvider, int nameSpace, GC gc) {
+ Rectangle rect = Utils.clone(bounds);
+ if (marker.getEntry() != null) {
+ int index = fItemData.findItemIndex(marker.getEntry());
+ if (index == -1) {
+ return;
+ }
+ rect = getStatesRect(bounds, index, nameSpace);
+ if (rect.y < 0 || rect.y > bounds.height) {
+ return;
+ }
+ }
+ int x0 = getXForTime(marker.getTime());
+ int x1 = getXForTime(marker.getTime() + marker.getDuration());
+ if (x0 > bounds.width || x1 < nameSpace) {
+ return;
+ }
+ rect.x = Math.max(nameSpace, Math.min(bounds.width, x0));
+ rect.width = Math.max(1, Math.min(bounds.width, x1) - rect.x);
+
+ gc.setBackground(marker.getColor());
+ gc.setAlpha(marker.getColor().getAlpha());
+ gc.fillRectangle(rect);
+ gc.setAlpha(255);
+ String label = marker.getLabel();
+ if (label != null && marker.getEntry() != null) {
+ label = label.substring(0, Math.min(label.indexOf('\n') != -1 ? label.indexOf('\n') : label.length(), MAX_LABEL_LENGTH));
+ gc.setForeground(marker.getColor());
+ Utils.drawText(gc, label, rect.x - gc.textExtent(label).x, rect.y, true);
+ }
+ }
+
+ /**
+ * Draw many items at once
+ *
+ * @param bounds
+ * The bounds of the control
+ * @param timeProvider
+ * The time provider
* @param items
* The array items to draw
* @param topIndex
* The index of the first element to draw
* @param nameSpace
- * The width reserved for the names
+ * The name space width
* @param gc
- * Reference to the SWT GC object
+ * Graphics context
*/
public void drawItems(Rectangle bounds, ITimeDataProvider timeProvider,
Item[] items, int topIndex, int nameSpace, GC gc) {
/**
* Draws the item
*
- * @param item the item to draw
- * @param bounds the container rectangle
- * @param timeProvider Time provider
- * @param i the item index
- * @param nameSpace the name space
- * @param gc Graphics context
+ * @param item
+ * The item to draw
+ * @param bounds
+ * The bounds of the control
+ * @param timeProvider
+ * The time provider
+ * @param i
+ * The expanded item index
+ * @param nameSpace
+ * The name space width
+ * @param gc
+ * Graphics context
*/
protected void drawItem(Item item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {
+ Rectangle itemRect = getItemRect(bounds, i);
+ if (itemRect.y >= bounds.y + bounds.height) {
+ return;
+ }
+
ITimeGraphEntry entry = item.fEntry;
long time0 = timeProvider.getTime0();
long time1 = timeProvider.getTime1();
long selectedTime = fTimeProvider.getSelectionEnd();
- Rectangle nameRect = getNameRect(bounds, i, nameSpace);
- if (nameRect.y >= bounds.y + bounds.height) {
- return;
- }
-
- if (! item.fEntry.hasTimeEvents()) {
- Rectangle statesRect = getStatesRect(bounds, i, nameSpace);
- nameRect.width += statesRect.width;
- drawName(item, nameRect, gc);
- } else {
- drawName(item, nameRect, gc);
- }
- Rectangle rect = getStatesRect(bounds, i, nameSpace);
- if (rect.isEmpty()) {
- fTimeGraphProvider.postDrawEntry(entry, rect, gc);
- return;
- }
- if (time1 <= time0) {
- gc.setBackground(getColorScheme().getBkColor(false, false, false));
- gc.fillRectangle(rect);
+ Rectangle rect = new Rectangle(nameSpace, itemRect.y, itemRect.width - nameSpace, itemRect.height);
+ if (rect.isEmpty() || (time1 <= time0)) {
fTimeGraphProvider.postDrawEntry(entry, rect, gc);
return;
}
- // Initialize _rect1 to same values as enclosing rectangle rect
- Rectangle stateRect = Utils.clone(rect);
boolean selected = item.fSelected;
// K pixels per second
double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);
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;
- stateRect.height -= 6;
+
+ int margins = getMarginForHeight(rect.height);
+ int height = rect.height - margins;
+ int topMargin = (margins + 1) / 2;
+ Rectangle stateRect = new Rectangle(rect.x, rect.y + topMargin, rect.width, height);
+
+ /* Set the font for this item */
+ setFontForHeight(height, gc);
long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();
Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);
* Draw the links
*
* @param bounds
- * The rectangle of the area
+ * The bounds of the control
* @param timeProvider
* The time provider
* @param links
* The list of link events
* @param nameSpace
- * The width reserved for the names
+ * The name space width
* @param gc
- * Reference to the SWT GC object
+ * Graphics context
*/
public void drawLinks(Rectangle bounds, ITimeDataProvider timeProvider,
List<ILinkEvent> links, int nameSpace, GC gc) {
}
/**
- * Draws the link type events of this item
+ * Draws a link type event
*
* @param event
- * the item to draw
+ * The link event to draw
* @param bounds
- * the container rectangle
+ * The bounds of the control
* @param timeProvider
- * Time provider
+ * The time provider
* @param nameSpace
- * the name space
+ * The name space width
* @param gc
* Graphics context
*/
}
/**
- * Draw the state (color fill)
+ * Draw an arrow
*
* @param colors
* Color scheme
* @param event
- * Time event for which we're drawing the state
+ * Time event for which we're drawing the arrow
* @param rect
- * Where to draw
+ * The arrow rectangle
* @param gc
* Graphics context
- * @return true if the state was drawn
+ * @return true if the arrow was drawn
*/
protected boolean drawArrow(TimeGraphColorScheme colors, ITimeEvent event,
Rectangle rect, GC gc) {
* @param item
* Item object
* @param bounds
- * Where to draw the name
+ * The bounds of the item's name space
* @param gc
* Graphics context
*/
protected void drawName(Item item, Rectangle bounds, GC gc) {
boolean hasTimeEvents = item.fEntry.hasTimeEvents();
- if (! hasTimeEvents) {
- gc.setBackground(getColorScheme().getBkColorGroup(item.fSelected, fIsInFocus));
- gc.fillRectangle(bounds);
- if (item.fSelected && fIsInFocus) {
- gc.setForeground(getColorScheme().getBkColor(item.fSelected, fIsInFocus, false));
- gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
- }
- } else {
- gc.setBackground(getColorScheme().getBkColor(item.fSelected, fIsInFocus, true));
- gc.setForeground(getColorScheme().getFgColor(item.fSelected, fIsInFocus));
- gc.fillRectangle(bounds);
- }
// No name to be drawn
if (fTimeProvider.getNameSpace() == 0) {
return;
}
+ int height = bounds.height - getMarginForHeight(bounds.height);
+ setFontForHeight(height, gc);
+
int leftMargin = MARGIN + item.fLevel * EXPAND_SIZE;
if (item.fHasChildren) {
gc.setForeground(getColorScheme().getFgColorGroup(false, false));
gc.setForeground(getColorScheme().getFgColor(item.fSelected, fIsInFocus));
int textWidth = Utils.drawText(gc, name, rect, true);
leftMargin += textWidth + MARGIN;
- rect.y -= 2;
if (hasTimeEvents) {
// draw middle line
- int x = bounds.x + leftMargin;
- int width = bounds.width - x;
- int midy = bounds.y + bounds.height / 2;
- gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.MID_LINE));
- gc.drawLine(x, midy, x + width, midy);
+ rect.x = bounds.x + leftMargin;
+ rect.y = bounds.y;
+ rect.width = bounds.width - rect.x;
+ drawMidLine(rect, gc);
}
}
}
* @param event
* Time event for which we're drawing the state
* @param rect
- * Where to draw
+ * The state rectangle
* @param gc
* Graphics context
* @param selected
}
/**
- * Fill the space between two contiguous time events
+ * Fill an item's states rectangle
*
* @param rect
- * Rectangle to fill
+ * The states rectangle
* @param gc
* Graphics context
* @param selected
- * Is this time event selected or not
+ * true if the item is selected
*/
protected void fillSpace(Rectangle rect, GC gc, boolean selected) {
- gc.setBackground(getColorScheme().getBkColor(selected, fIsInFocus, false));
- gc.fillRectangle(rect);
- if (fDragState == DRAG_ZOOM) {
- gc.setBackground(getColorScheme().getBkColor(selected, fIsInFocus, true));
- if (fDragX0 < fDragX) {
- gc.fillRectangle(new Rectangle(fDragX0, rect.y, fDragX - fDragX0, rect.height));
- } else if (fDragX0 > fDragX) {
- gc.fillRectangle(new Rectangle(fDragX, rect.y, fDragX0 - fDragX, rect.height));
- }
- }
- // draw middle line
+ /* Nothing to draw */
+ }
+
+ /**
+ * Draw a line at the middle height of a rectangle
+ *
+ * @param rect
+ * The rectangle
+ * @param gc
+ * Graphics context
+ */
+ private void drawMidLine(Rectangle rect, GC gc) {
gc.setForeground(getColorScheme().getColor(TimeGraphColorScheme.MID_LINE));
int midy = rect.y + rect.height / 2;
gc.drawLine(rect.x, midy, rect.x + rect.width, midy);
}
+ private static int getMarginForHeight(int height) {
+ /*
+ * State rectangle is smaller than the item bounds when height is > 4.
+ * Don't use any margin if the height is below or equal that threshold.
+ * Use a maximum of 6 pixels for both margins, otherwise try to use 13
+ * pixels for the state height, but with a minimum margin of 1.
+ */
+ final int MARGIN_THRESHOLD = 4;
+ final int PREFERRED_HEIGHT = 13;
+ final int MIN_MARGIN = 1;
+ final int MAX_MARGIN = 6;
+ return height <= MARGIN_THRESHOLD ? 0 :
+ Math.max(Math.min(height - PREFERRED_HEIGHT, MAX_MARGIN), MIN_MARGIN);
+ }
+
+ private void setFontForHeight(int pixels, GC gc) {
+ /* convert font height from pixels to points */
+ int height = Math.max(pixels * PPI / DPI, 1);
+ Font font = fFonts.get(height);
+ if (font == null) {
+ FontData fontData = gc.getFont().getFontData()[0];
+ fontData.setHeight(height);
+ font = new Font(gc.getDevice(), fontData);
+ fFonts.put(height, font);
+ }
+ gc.setFont(font);
+ }
+
@Override
public void keyTraversed(TraverseEvent e) {
if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
}
}
idx = -1;
+ } else if ((e.character == '+' || e.character == '=') && ((e.stateMask & SWT.CTRL) != 0)) {
+ verticalZoom(true);
+ } else if (e.character == '-' && ((e.stateMask & SWT.CTRL) != 0)) {
+ verticalZoom(false);
+ } else if (e.character == '0' && ((e.stateMask & SWT.CTRL) != 0)) {
+ resetVerticalZoom();
}
if (idx >= 0) {
selectItem(idx, false);
}
}
+ /**
+ * Update the status line following a change of selection.
+ *
+ * @since 2.0
+ */
+ public void updateStatusLine() {
+ updateStatusLine(STATUS_WITHOUT_CURSOR_TIME);
+ }
+
private void updateStatusLine(int x) {
// use the time provider of the time graph scale for the status line
ITimeDataProvider tdp = fTimeGraphScale.getTimeProvider();
} else {
long time0 = fDragBeginMarker ? getTimeAtX(fDragX0) : fDragTime0;
long time1 = fDragBeginMarker ? fDragTime0 : getTimeAtX(fDragX);
- fTimeProvider.setSelectionRangeNotify(time0, time1);
+ fTimeProvider.setSelectionRangeNotify(time0, time1, false);
}
fDragState = DRAG_NONE;
redraw();
if (fDragState != DRAG_NONE) {
return;
}
- boolean zoomScroll = false;
+ boolean horizontalZoom = false;
boolean horizontalScroll = false;
+ boolean verticalZoom = false;
Point p = getParent().toControl(getDisplay().getCursorLocation());
Point parentSize = getParent().getSize();
if (p.x >= 0 && p.x < parentSize.x && p.y >= 0 && p.y < parentSize.y) {
// over the parent control
if (e.x > getSize().x) {
// over the vertical scroll bar
- zoomScroll = false;
+ if ((e.stateMask & SWT.MODIFIER_MASK) == (SWT.SHIFT | SWT.CTRL)) {
+ verticalZoom = true;
+ }
} else if (e.y < 0) {
// over the time scale
- zoomScroll = true;
+ horizontalZoom = true;
} else if (e.y >= getSize().y) {
// over the horizontal scroll bar
if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL) {
- zoomScroll = true;
+ horizontalZoom = true;
} else {
horizontalScroll = true;
}
} else {
- if (e.x < fTimeProvider.getNameSpace()) {
+ if ((e.stateMask & SWT.MODIFIER_MASK) == (SWT.SHIFT | SWT.CTRL)) {
+ verticalZoom = true;
+ } else if (e.x < fTimeProvider.getNameSpace()) {
// over the name space
- zoomScroll = false;
+ horizontalZoom = false;
} else {
// over the state area
if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL) {
// over the state area, CTRL pressed
- zoomScroll = true;
+ horizontalZoom = true;
} else {
// over the state area, CTRL not pressed
- zoomScroll = false;
+ horizontalZoom = false;
}
}
}
}
- if (zoomScroll && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
+ if (verticalZoom) {
+ if (e.count > 0) {
+ verticalZoom(true);
+ } else if (e.count < 0) {
+ verticalZoom(false);
+ }
+ } else if (horizontalZoom && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
if (e.count > 0) {
zoom(true);
} else if (e.count < 0) {
*/
public void setItemHeight(int rowHeight) {
this.fGlobalItemHeight = rowHeight;
+ for (Item item : fItemData.fItems) {
+ item.fItemHeight = rowHeight;
+ }
}
/**
*
* @param blend
* true if sub-pixel events should be blended, false otherwise.
- * @since 2.0
+ * @since 1.1
*/
public void setBlendSubPixelEvents(boolean blend) {
fBlendSubPixelEvents = blend;
/**
* @param filter The filter object to be attached to the view
*/
- public void addFilter(ViewerFilter filter) {
+ public void addFilter(@NonNull ViewerFilter filter) {
if (!fFilters.contains(filter)) {
fFilters.add(filter);
}
/**
* @param filter The filter object to be attached to the view
*/
- public void removeFilter(ViewerFilter filter) {
+ public void removeFilter(@NonNull ViewerFilter filter) {
fFilters.remove(filter);
}
+ /**
+ * Returns this control's filters.
+ *
+ * @return an array of viewer filters
+ * @since 2.0
+ */
+ public @NonNull ViewerFilter[] getFilters() {
+ return Iterables.toArray(fFilters, ViewerFilter.class);
+ }
+
+ /**
+ * Sets the filters, replacing any previous filters.
+ *
+ * @param filters
+ * an array of viewer filters, or null
+ * @since 2.0
+ */
+ public void setFilters(@NonNull ViewerFilter[] filters) {
+ fFilters.clear();
+ if (filters != null) {
+ fFilters.addAll(Arrays.asList(filters));
+ }
+ }
+
@Override
public void colorSettingsChanged(StateItem[] stateItems) {
/* Destroy previous colors from the resource manager */
} else {
item.fItemHeight = fGlobalItemHeight;
}
+ item.fItemHeight = Math.max(1, item.fItemHeight + fHeightAdjustment);
itemMap.put(entry, item);
if (entry.hasChildren()) {
Item oldItem = fItemMap.get(entry);