tmf: Add keyboard shortcuts for Next/Previous Marker
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
index af63f1da43208bcaaf84fc60009ce3211178ba9c..b2edddd4fe208e821a42cccf0e2128a0e7ffea05 100644 (file)
@@ -77,11 +77,14 @@ import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem;
 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
  *
@@ -114,6 +117,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private static final int NO_STATUS = -1;
     private static final int STATUS_WITHOUT_CURSOR_TIME = -2;
 
+    private static final int MAX_LABEL_LENGTH = 256;
+
     /** Resource manager */
     private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
 
@@ -141,6 +146,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     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<>();
@@ -153,6 +160,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private final Cursor fZoomCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_SIZEWE);
     private final List<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;
 
@@ -378,15 +387,6 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return fItemData.getEntries();
     }
 
-    /**
-     * Get the on/off trace filters
-     *
-     * @return The array of filters
-     */
-    public boolean[] getTraceFilter() {
-        return fItemData.getEntryFilter();
-    }
-
     /**
      * Refresh the data for the thing
      */
@@ -420,7 +420,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      *
      * @return The unmodifiable link event list
      *
-     * @since 2.0
+     * @since 1.1
      */
     public List<ILinkEvent> getArrows() {
         return Collections.unmodifiableList(fItemData.fLinks);
@@ -472,15 +472,16 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * 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
+     * Sets the auto-expand level to be used for new entries discovered when
+     * calling {@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
@@ -500,6 +501,19 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return fAutoExpandLevel;
     }
 
+    /**
+     * Get the expanded state of a given entry.
+     *
+     * @param entry
+     *            The entry
+     * @return true if the entry is expanded, false if collapsed
+     * @since 1.1
+     */
+    public boolean getExpandedState(ITimeGraphEntry entry) {
+        Item item = fItemData.fItemMap.get(entry);
+        return (item != null ? item.fExpanded : false);
+    }
+
     /**
      * Set the expanded state of a given entry
      *
@@ -942,6 +956,92 @@ public class TimeGraphControl extends TimeGraphBaseControl
         fTimeProvider.setStartFinishTimeNotify(time0, time1);
     }
 
+    /**
+     * 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
      *
@@ -1249,18 +1349,18 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * Get the number of expanded items
+     * Get the number of expanded (visible) items
      *
-     * @return The count of expanded items
+     * @return The count of expanded (visible) items
      */
     public int getExpandedElementCount() {
         return fItemData.fExpandedItems.length;
     }
 
     /**
-     * Get an array of all expanded elements
+     * Get an array of all expanded (visible) elements
      *
-     * @return The expanded elements
+     * @return The expanded (visible) elements
      */
     public ITimeGraphEntry[] getExpandedElements() {
         ArrayList<ITimeGraphEntry> elements = new ArrayList<>();
@@ -1270,16 +1370,20 @@ public class TimeGraphControl extends TimeGraphBaseControl
         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++) {
@@ -1290,16 +1394,14 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 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;
@@ -1308,13 +1410,24 @@ public class TimeGraphControl extends TimeGraphBaseControl
         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 items
+        // draw the background markers
+        drawMarkers(bounds, fTimeProvider, fMarkers, false, nameSpace, gc);
+
+        // 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();
@@ -1388,20 +1501,170 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * 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) {
@@ -1414,45 +1677,36 @@ public class TimeGraphControl extends TimeGraphBaseControl
     /**
      * 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);
@@ -1460,9 +1714,14 @@ public class TimeGraphControl extends TimeGraphBaseControl
         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;
+            /*
+             * State rectangle is smaller than item bounds. Use a margin height
+             * of 3 pixels, keep at least 3 pixels for the state, but not more
+             * than the item height. Favor the top margin for the remainder.
+             */
+            int height = Math.min(rect.height, Math.max(3, rect.height - 6));
+            int margin = (rect.height - height + 1) / 2;
+            Rectangle stateRect = new Rectangle(rect.x, rect.y + margin, rect.width, height);
 
             long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();
             Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);
@@ -1501,15 +1760,15 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * Draw the links
      *
      * @param bounds
-     *            The rectangle of the area
+     *            The bounds of the control
      * @param timeProvider
      *            The time provider
      * @param links
-     *            The array items to draw
+     *            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) {
@@ -1517,23 +1776,24 @@ public class TimeGraphControl extends TimeGraphBaseControl
             return;
         }
         gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
-        for (ILinkEvent event : links) {
-            drawLink(event, bounds, timeProvider, nameSpace, gc);
+        /* the list can grow concurrently but cannot shrink */
+        for (int i = 0; i < links.size(); i++) {
+            drawLink(links.get(i), bounds, timeProvider, nameSpace, gc);
         }
         gc.setClipping((Rectangle) null);
     }
 
     /**
-     * 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
      */
@@ -1567,17 +1827,17 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * 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) {
@@ -1644,24 +1904,12 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @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) {
@@ -1725,15 +1973,13 @@ public class TimeGraphControl extends TimeGraphBaseControl
             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);
             }
         }
     }
@@ -1746,7 +1992,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @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
@@ -1810,27 +2056,28 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     /**
-     * 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);
@@ -1989,6 +2236,15 @@ public class TimeGraphControl extends TimeGraphBaseControl
         }
     }
 
+    /**
+     * 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();
@@ -2402,6 +2658,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
      */
     public void setItemHeight(int rowHeight) {
         this.fGlobalItemHeight = rowHeight;
+        for (Item item : fItemData.fItems) {
+            item.fItemHeight = rowHeight;
+        }
     }
 
     /**
@@ -2446,19 +2705,12 @@ public class TimeGraphControl extends TimeGraphBaseControl
      *
      * @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;
     }
 
-    /**
-     * @return The entries that are currently filtered out
-     */
-    public List<ITimeGraphEntry> getFilteredOut() {
-        return fItemData.getFilteredOut();
-    }
-
     @Override
     public void addSelectionChangedListener(ISelectionChangedListener listener) {
         if (listener != null && !fSelectionChangedListeners.contains(listener)) {
@@ -2502,6 +2754,30 @@ public class TimeGraphControl extends TimeGraphBaseControl
         fFilters.remove(filter);
     }
 
+    /**
+     * Returns this control's filters.
+     *
+     * @return an array of viewer filters
+     * @since 2.0
+     */
+    public 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(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 */
@@ -2522,13 +2798,11 @@ public class TimeGraphControl extends TimeGraphBaseControl
     }
 
     private class ItemData {
-        private final Map<ITimeGraphEntry, Item> fItemMap = new LinkedHashMap<>();
+        private Map<ITimeGraphEntry, Item> fItemMap = new LinkedHashMap<>();
         private Item[] fExpandedItems = new Item[0];
         private Item[] fItems = new Item[0];
         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() {
         }
@@ -2546,13 +2820,13 @@ public class TimeGraphControl extends TimeGraphBaseControl
         }
 
         public void refreshData() {
-            fItemMap.clear();
-            fFilteredOut.clear();
             ITimeGraphEntry selection = getSelectedTrace();
+            Map<ITimeGraphEntry, Item> itemMap = new LinkedHashMap<>();
             for (int i = 0; i < fRootEntries.length; i++) {
                 ITimeGraphEntry entry = fRootEntries[i];
-                refreshData(fItemMap, null, 0, entry);
+                refreshData(itemMap, null, 0, entry);
             }
+            fItemMap = itemMap;
             fItems = fItemMap.values().toArray(new Item[0]);
             updateExpandedItems();
             if (selection != null) {
@@ -2577,7 +2851,14 @@ public class TimeGraphControl extends TimeGraphBaseControl
             }
             itemMap.put(entry, item);
             if (entry.hasChildren()) {
-                item.fExpanded = fAutoExpandLevel == ALL_LEVELS || level < fAutoExpandLevel;
+                Item oldItem = fItemMap.get(entry);
+                if (oldItem != null && oldItem.fHasChildren && level == oldItem.fLevel && entry.getParent() == oldItem.fEntry.getParent()) {
+                    /* existing items keep their old expanded state */
+                    item.fExpanded = oldItem.fExpanded;
+                } else {
+                    /* new items set the expanded state according to auto-expand level */
+                    item.fExpanded = fAutoExpandLevel == ALL_LEVELS || level < fAutoExpandLevel;
+                }
                 item.fHasChildren = true;
                 for (ITimeGraphEntry child : entry.getChildren()) {
                     refreshData(itemMap, item, level + 1, child);
@@ -2621,15 +2902,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
         public void refreshData(ITimeGraphEntry[] entries) {
             if (entries == null) {
-                fEntryFilter = null;
                 fRootEntries = null;
             } else {
-                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);
-                }
                 fRootEntries = Arrays.copyOf(entries, entries.length);
             }
 
@@ -2648,14 +2922,6 @@ public class TimeGraphControl extends TimeGraphBaseControl
         public ITimeGraphEntry[] getEntries() {
             return fRootEntries;
         }
-
-        public boolean[] getEntryFilter() {
-            return fEntryFilter;
-        }
-
-        public List<ITimeGraphEntry> getFilteredOut() {
-            return fFilteredOut;
-        }
     }
 
     private class Item {
@@ -2750,5 +3016,3 @@ public class TimeGraphControl extends TimeGraphBaseControl
         return new TmfTimeViewAlignmentInfo(getShell(), toDisplay(0, 0), fTimeProvider.getNameSpace());
     }
 }
-
-
This page took 0.037739 seconds and 5 git commands to generate.