tmf: Add cycles time format and delta format in time graph
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
index c851355faa51ce7b22ae9dcc14449980cb486337..8b433a8ec612417d0c95ad6820303eeacc1aae71 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * 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
@@ -14,6 +14,8 @@
  *   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;
@@ -21,26 +23,32 @@ 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;
@@ -80,12 +88,18 @@ import org.eclipse.swt.widgets.ScrollBar;
  * @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;
@@ -99,6 +113,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     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;
 
@@ -128,17 +143,19 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     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;
@@ -229,22 +246,31 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
         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;
     }
 
     /**
@@ -264,7 +290,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *
      * @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) {
@@ -278,7 +304,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *
      * @param timeGraphScale
      *            The time graph scale
-     * @since 3.0
+     * @since 2.1
      */
     public void setTimeGraphScale(TimeGraphScale timeGraphScale) {
         fTimeGraphScale = timeGraphScale;
@@ -295,7 +321,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             SWT.error(SWT.ERROR_NULL_ARGUMENT);
         }
         if (null == fSelectionListeners) {
-            fSelectionListeners = new ArrayList<SelectionListener>();
+            fSelectionListeners = new ArrayList<>();
         }
         fSelectionListeners.add(listener);
     }
@@ -338,13 +364,72 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
     }
 
+    /**
+     * 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();
     }
 
     /**
@@ -353,7 +438,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      * @return The array of filters
      */
     public boolean[] getTraceFilter() {
-        return fItemData.getTraceFilter();
+        return fItemData.getEntryFilter();
     }
 
     /**
@@ -381,7 +466,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      * 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);
@@ -466,6 +551,37 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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
      *
@@ -627,18 +743,12 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
     }
 
-    @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);
@@ -723,14 +833,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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) {
@@ -842,15 +945,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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;
         }
@@ -879,15 +975,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     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;
         }
@@ -908,12 +997,64 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *
      * @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
      *
@@ -923,7 +1064,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         ITimeGraphEntry trace = null;
         int idx = getSelectedIndex();
         if (idx >= 0) {
-            trace = fItemData.fExpandedItems[idx].fTrace;
+            trace = fItemData.fExpandedItems[idx].fEntry;
         }
         return trace;
     }
@@ -955,13 +1096,21 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                 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;
         }
@@ -983,9 +1132,53 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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;
     }
 
     /**
@@ -1118,9 +1311,9 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      * @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]);
     }
@@ -1185,17 +1378,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
         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);
@@ -1294,24 +1478,17 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      * @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);
@@ -1336,7 +1513,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         // 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;
@@ -1370,6 +1548,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                     lastX = x;
                 }
             }
+            gc.setClipping((Rectangle) null);
         }
         fTimeGraphProvider.postDrawEntry(entry, rect, gc);
     }
@@ -1387,16 +1566,18 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *            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);
     }
 
     /**
@@ -1412,24 +1593,35 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *            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);
     }
 
     /**
@@ -1444,11 +1636,14 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      * @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;
@@ -1488,8 +1683,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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;
@@ -1513,7 +1708,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *            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);
@@ -1552,7 +1747,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
         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;
@@ -1629,15 +1824,15 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             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;
@@ -1646,24 +1841,19 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             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);
@@ -1849,15 +2039,13 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             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) {
@@ -1866,43 +2054,54 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     }
 
     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());
     }
@@ -1935,11 +2134,10 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             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();
@@ -1980,7 +2178,9 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     @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;
@@ -2022,29 +2222,27 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                 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();
@@ -2066,12 +2264,10 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                 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();
@@ -2103,9 +2299,9 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                     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;
@@ -2278,7 +2474,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *            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);
@@ -2359,60 +2555,65 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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;
                     }
@@ -2420,7 +2621,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             }
         }
 
-        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);
@@ -2430,36 +2631,41 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             } 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) {
@@ -2469,18 +2675,18 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             }
         }
 
-        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();
@@ -2491,16 +2697,16 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             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() {
@@ -2510,19 +2716,20 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     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
@@ -2561,7 +2768,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         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) {
This page took 0.039548 seconds and 5 git commands to generate.