Add entry filter support for TimegraphCombo via dialog
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
index 202d5bb1bceea035fe3a95922141fc141562e84f..a9e8483729b753fabbbc98e84150215687d88986 100644 (file)
@@ -25,6 +25,7 @@ import org.eclipse.jface.resource.LocalResourceManager;
 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.ui.widgets.timegraph.ITimeGraphPresentationProvider;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;
 import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;
@@ -38,6 +39,8 @@ import org.eclipse.swt.events.FocusEvent;
 import org.eclipse.swt.events.FocusListener;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MenuDetectEvent;
+import org.eclipse.swt.events.MenuDetectListener;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.events.MouseMoveListener;
@@ -48,6 +51,7 @@ import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.events.TraverseEvent;
 import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.events.TypedEvent;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Cursor;
 import org.eclipse.swt.graphics.GC;
@@ -67,15 +71,22 @@ 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 {
+public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider, MenuDetectListener {
+
+    /** Max scrollbar size */
+    public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
+
+    /** Resource manager */
+    protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
+
+    /** Color map for event types */
+    protected Color[] fEventColorMap = null;
 
     private static final int DRAG_NONE = 0;
     private static final int DRAG_TRACE_ITEM = 1;
     private static final int DRAG_SPLIT_LINE = 2;
-    public static final boolean DEFAULT_DRAW_THREAD_JOIN = true;
-    public static final boolean DEFAULT_DRAW_THREAD_WAIT = true;
-    public static final boolean DEFAULT_DRAW_THREAD_RELEASE = true;
-    public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;
+    private static final int DRAG_ZOOM = 3;
+
     private static final int CUSTOM_ITEM_HEIGHT = -1; // get item height from provider
 
     private static final double zoomCoeff = 1.5;
@@ -100,8 +111,11 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     private List<SelectionListener> _selectionListeners;
     private final List<ISelectionChangedListener> _selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
     private final List<ITimeGraphTreeListener> _treeListeners = new ArrayList<ITimeGraphTreeListener>();
+    private final List<MenuDetectListener> _timeGraphEntryMenuListeners = new ArrayList<MenuDetectListener>();
+    private final List<MenuDetectListener> _timeEventMenuListeners = new ArrayList<MenuDetectListener>();
     private final Cursor _dragCursor3;
     private final Cursor _WaitCursor;
+    private final List<ViewerFilter> _filters = new ArrayList<ViewerFilter>();
 
     // Vertical formatting formatting for the state control view
     private final boolean _visibleVerticalScroll = true;
@@ -110,9 +124,6 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     private Listener mouseScrollFilterListener;
 
-    protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
-    protected Color[] fEventColorMap = null;
-
     private MouseScrollNotifier fMouseScrollNotifier;
     private final Object fMouseScrollNotifierLock = new Object();
     private class MouseScrollNotifier extends Thread {
@@ -172,6 +183,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         addTraverseListener(this);
         addKeyListener(this);
         addControlListener(this);
+        addMenuDetectListener(this);
         ScrollBar scrollHor = getHorizontalBar();
 
         if (scrollHor != null) {
@@ -356,18 +368,19 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     boolean ensureVisibleItem(int idx, boolean redraw) {
         boolean changed = false;
-        if (idx < 0) {
-            for (idx = 0; idx < _data._expandedItems.length; idx++) {
-                if (_data._expandedItems[idx]._selected) {
+        int index = idx;
+        if (index < 0) {
+            for (index = 0; index < _data._expandedItems.length; index++) {
+                if (_data._expandedItems[index]._selected) {
                     break;
                 }
             }
         }
-        if (idx >= _data._expandedItems.length) {
+        if (index >= _data._expandedItems.length) {
             return changed;
         }
-        if (idx < _topIndex) {
-            setTopIndex(idx);
+        if (index < _topIndex) {
+            setTopIndex(index);
             //FIXME:getVerticalBar().setSelection(_topItem);
             if (redraw) {
                 redraw();
@@ -375,8 +388,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             changed = true;
         } else {
             int page = countPerPage();
-            if (idx >= _topIndex + page) {
-                setTopIndex(idx - page + 1);
+            if (index >= _topIndex + page) {
+                setTopIndex(index - page + 1);
                 //FIXME:getVerticalBar().setSelection(_topItem);
                 if (redraw) {
                     redraw();
@@ -394,9 +407,9 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *            The index
      */
     public void setTopIndex(int idx) {
-        idx = Math.min(idx, _data._expandedItems.length - countPerPage());
-        idx = Math.max(0,  idx);
-        _topIndex = idx;
+        int index = Math.min(idx, _data._expandedItems.length - countPerPage());
+        index = Math.max(0,  index);
+        _topIndex = index;
         redraw();
     }
 
@@ -486,6 +499,81 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
     }
 
+    /**
+     * Add a menu listener on {@link ITimeGraphEntry}s
+     * @param listener
+     *            The listener to add
+     * @since 1.2
+     */
+    public void addTimeGraphEntryMenuListener(MenuDetectListener listener) {
+        if (!_timeGraphEntryMenuListeners.contains(listener)) {
+            _timeGraphEntryMenuListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove a menu listener on {@link ITimeGraphEntry}s
+     *
+     * @param listener
+     *            The listener to remove
+     * @since 1.2
+     */
+    public void removeTimeGraphEntryMenuListener(MenuDetectListener listener) {
+        if (_timeGraphEntryMenuListeners.contains(listener)) {
+            _timeGraphEntryMenuListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Menu event callback on {@link ITimeGraphEntry}s
+     *
+     * @param event
+     *            The MenuDetectEvent, with field {@link TypedEvent#data} set to the selected {@link ITimeGraphEntry}
+     */
+    private void fireMenuEventOnTimeGraphEntry(MenuDetectEvent event) {
+        for (MenuDetectListener listener : _timeGraphEntryMenuListeners) {
+            listener.menuDetected(event);
+        }
+    }
+
+    /**
+     * Add a menu listener on {@link ITimeEvent}s
+     *
+     * @param listener
+     *            The listener to add
+     * @since 1.2
+     */
+    public void addTimeEventMenuListener(MenuDetectListener listener) {
+        if (!_timeEventMenuListeners.contains(listener)) {
+            _timeEventMenuListeners.add(listener);
+        }
+    }
+
+    /**
+     * Remove a menu listener on {@link ITimeEvent}s
+     *
+     * @param listener
+     *            The listener to remove
+     * @since 1.2
+     */
+    public void removeTimeEventMenuListener(MenuDetectListener listener) {
+        if (_timeEventMenuListeners.contains(listener)) {
+            _timeEventMenuListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Menu event callback on {@link ITimeEvent}s
+     *
+     * @param event
+     *            The MenuDetectEvent, with field {@link TypedEvent#data} set to the selected {@link ITimeEvent}
+     */
+    private void fireMenuEventOnTimeEvent(MenuDetectEvent event) {
+        for (MenuDetectListener listener : _timeEventMenuListeners) {
+            listener.menuDetected(event);
+        }
+    }
+
     @Override
     public ISelection getSelection() {
         TimeGraphSelection sel = new TimeGraphSelection();
@@ -821,7 +909,36 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         return idx >= 0 ? _data._expandedItems[idx]._trace : null;
     }
 
-    long getTimeAtX(int x) {
+    /**
+     * Return the x coordinate corresponding to a time
+     *
+     * @param time the time
+     * @return the x coordinate corresponding to the time
+     *
+     * @since 2.0
+     */
+    public int getXForTime(long time) {
+        if (null == _timeProvider) {
+            return -1;
+        }
+        long time0 = _timeProvider.getTime0();
+        long time1 = _timeProvider.getTime1();
+        int width = getCtrlSize().x;
+        int nameSpace = _timeProvider.getNameSpace();
+        double pixelsPerNanoSec = (width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (width - nameSpace - RIGHT_MARGIN) / (time1 - time0);
+        int x = getBounds().x + nameSpace + (int) ((time - time0) * pixelsPerNanoSec);
+        return x;
+    }
+
+    /**
+     * Return the time corresponding to an x coordinate
+     *
+     * @param coord The X coordinate
+     * @return The time corresponding to the x coordinate
+     *
+     * @since 2.0
+     */
+    public long getTimeAtX(int coord) {
         if (null == _timeProvider) {
             return -1;
         }
@@ -830,7 +947,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         long time0 = _timeProvider.getTime0();
         long time1 = _timeProvider.getTime1();
         int nameWidth = _timeProvider.getNameSpace();
-        x -= nameWidth;
+        final int x = coord - nameWidth;
         int timeWidth = size.x - nameWidth - RIGHT_MARGIN;
         if (x >= 0 && size.x >= nameWidth) {
             if (time1 - time0 > timeWidth) {
@@ -1000,6 +1117,16 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         gc.setBackground(_colors.getBkColor(false, false, true));
         drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);
 
+        if (_dragState == DRAG_ZOOM) {
+            // draw selected zoom region background
+            gc.setBackground(_colors.getBkColor(false, false, true));
+            if (_dragX0 < _dragX) {
+                gc.fillRectangle(new Rectangle(_dragX0, bounds.y, _dragX - _dragX0, bounds.height));
+            } else if (_dragX0 > _dragX) {
+                gc.fillRectangle(new Rectangle(_dragX, bounds.y, _dragX0 - _dragX, bounds.height));
+            }
+        }
+
         drawItems(bounds, _timeProvider, _data._expandedItems, _topIndex, nameSpace, gc);
 
         // draw selected time
@@ -1017,6 +1144,10 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         if (DRAG_SPLIT_LINE == _dragState) {
             gc.setForeground(_colors.getColor(TimeGraphColorScheme.BLACK));
             gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
+        } else if (DRAG_ZOOM == _dragState && Math.max(_dragX, _dragX0) > nameSpace) {
+            gc.setForeground(_colors.getColor(TimeGraphColorScheme.TOOL_FOREGROUND));
+            gc.drawLine(_dragX0, bounds.y, _dragX0, bounds.y + bounds.height - 1);
+            gc.drawLine(_dragX, bounds.y, _dragX, bounds.y + bounds.height - 1);
         } else if (DRAG_NONE == _dragState && _mouseOverSplitLine && _timeProvider.getNameSpace() > 0) {
             gc.setForeground(_colors.getColor(TimeGraphColorScheme.RED));
             gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);
@@ -1053,9 +1184,10 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
      *
      * @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
+     * @param gc Graphics context
      */
     protected void drawItem(Item item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {
         ITimeGraphEntry entry = item._trace;
@@ -1131,6 +1263,16 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         fTimeGraphProvider.postDrawEntry(entry, rect, gc);
     }
 
+    /**
+     * Draw the name of an item.
+     *
+     * @param item
+     *            Item object
+     * @param bounds
+     *            Where to draw the name
+     * @param gc
+     *            Graphics context
+     */
     protected void drawName(Item item, Rectangle bounds, GC gc) {
         boolean hasTimeEvents = item._trace.hasTimeEvents();
         if (! hasTimeEvents) {
@@ -1221,6 +1363,23 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
     }
 
+    /**
+     * Draw the state (color fill)
+     *
+     * @param colors
+     *            Color scheme
+     * @param event
+     *            Time event for which we're drawing the state
+     * @param rect
+     *            Where to draw
+     * @param gc
+     *            Graphics context
+     * @param selected
+     *            Is this time event currently selected (so it appears
+     *            highlighted)
+     * @param timeSelected
+     *            Is the timestamp currently selected
+     */
     protected void drawState(TimeGraphColorScheme colors, ITimeEvent event,
             Rectangle rect, GC gc, boolean selected, boolean timeSelected) {
 
@@ -1238,8 +1397,8 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                 stateColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
             }
 
-            timeSelected = timeSelected && selected;
-            if (timeSelected) {
+            boolean reallySelected = timeSelected && selected;
+            if (reallySelected) {
                 // modify the color?
             }
             // fill all rect area
@@ -1249,7 +1408,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
             gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
 
             // draw bounds
-            if (!timeSelected) {
+            if (!reallySelected) {
                 // Draw the top and bottom borders i.e. no side borders
                 // top
                 gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
@@ -1285,9 +1444,27 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         fTimeGraphProvider.postDrawEvent(event, rect, gc);
     }
 
+    /**
+     * Fill the space between two contiguous time events
+     *
+     * @param rect
+     *            Rectangle to fill
+     * @param gc
+     *            Graphics context
+     * @param selected
+     *            Is this time event selected or not
+     */
     protected void fillSpace(Rectangle rect, GC gc, boolean selected) {
         gc.setBackground(_colors.getBkColor(selected, _isInFocus, false));
         gc.fillRectangle(rect);
+        if (_dragState == DRAG_ZOOM) {
+            gc.setBackground(_colors.getBkColor(selected, _isInFocus, true));
+            if (_dragX0 < _dragX) {
+                gc.fillRectangle(new Rectangle(_dragX0, rect.y, _dragX - _dragX0, rect.height));
+            } else if (_dragX0 > _dragX) {
+                gc.fillRectangle(new Rectangle(_dragX, rect.y, _dragX0 - _dragX, rect.height));
+            }
+        }
         // draw middle line
         gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));
         int midy = rect.y + rect.height / 2;
@@ -1482,6 +1659,9 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         } else if (DRAG_SPLIT_LINE == _dragState) {
             _dragX = e.x;
             _timeProvider.setNameSpace(e.x);
+        } else if (DRAG_ZOOM == _dragState) {
+            _dragX = Math.min(Math.max(e.x, _timeProvider.getNameSpace()), size.x - RIGHT_MARGIN);
+            redraw();
         } else if (DRAG_NONE == _dragState) {
             boolean mouseOverSplitLine = isOverSplitLine(e.x);
             if (_mouseOverSplitLine != mouseOverSplitLine) {
@@ -1497,7 +1677,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         if (null == _timeProvider) {
             return;
         }
-        if (1 == e.button) {
+        if (1 == e.button && (e.stateMask & SWT.BUTTON_MASK) == 0) {
             if (isOverSplitLine(e.x) && _timeProvider.getNameSpace() != 0) {
                 _timeProvider.setNameSpace(_idealNameSpace);
                 boolean mouseOverSplitLine = isOverSplitLine(e.x);
@@ -1517,7 +1697,7 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     @Override
     public void mouseDown(MouseEvent e) {
-        if (null == _timeProvider) {
+        if (_dragState != DRAG_NONE || null == _timeProvider) {
             return;
         }
         int idx;
@@ -1557,6 +1737,13 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
                 redraw();
                 fireSelectionChanged();
             }
+        } else if (3 == e.button) {
+            if (_timeProvider.getTime0() == _timeProvider.getTime1() || getCtrlSize().x - _timeProvider.getNameSpace() <= 0) {
+                return;
+            }
+            setCapture(true);
+            _dragX = _dragX0 = Math.min(Math.max(e.x, _timeProvider.getNameSpace()), getCtrlSize().x - RIGHT_MARGIN);
+            _dragState = DRAG_ZOOM;
         }
     }
 
@@ -1564,18 +1751,34 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
     public void mouseUp(MouseEvent e) {
         if (DRAG_NONE != _dragState) {
             setCapture(false);
-            if (DRAG_TRACE_ITEM == _dragState) {
-                // Notify time provider to check the need for listener
-                // notification
-                _timeProvider.notifyStartFinishTime();
+            if (e.button == 1 && DRAG_TRACE_ITEM == _dragState) {
                 if (_dragX == _dragX0) { // click without drag
                     long time = getTimeAtX(e.x);
                     _timeProvider.setSelectedTimeNotify(time, false);
+                } else {
+                    // Notify time provider to check the need for listener
+                    // notification
+                    _timeProvider.notifyStartFinishTime();
                 }
-            } else if (DRAG_SPLIT_LINE == _dragState) {
+                _dragState = DRAG_NONE;
+            } else if (e.button == 1 && DRAG_SPLIT_LINE == _dragState) {
                 redraw();
+                _dragState = DRAG_NONE;
+            } else if (e.button == 3 && DRAG_ZOOM == _dragState) {
+                int nameWidth = _timeProvider.getNameSpace();
+                if (Math.max(_dragX, _dragX0) > nameWidth && _dragX != _dragX0) {
+                    long time0 = getTimeAtX(_dragX0);
+                    long time1 = getTimeAtX(_dragX);
+                    if (time0 < time1) {
+                        _timeProvider.setStartFinishTimeNotify(time0, time1);
+                    } else {
+                        _timeProvider.setStartFinishTimeNotify(time1, time0);
+                    }
+                } else {
+                    redraw();
+                }
+                _dragState = DRAG_NONE;
             }
-            _dragState = DRAG_NONE;
         }
     }
 
@@ -1778,6 +1981,24 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
 
     }
 
+    /**
+     * @param filter The filter object to be attached to the view
+     * @since 2.0
+     */
+    public void addFilter(ViewerFilter filter) {
+        if (!_filters.contains(filter)) {
+            _filters.add(filter);
+        }
+    }
+
+    /**
+     * @param filter The filter object to be attached to the view
+     * @since 2.0
+     */
+    public void removeFilter(ViewerFilter filter) {
+        _filters.remove(filter);
+    }
+
     private class ItemData {
         public Item[] _expandedItems = new Item[0];
         public Item[] _items = new Item[0];
@@ -1857,10 +2078,20 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
 
         private void refreshExpanded(List<Item> expandedItemList, Item item) {
-            expandedItemList.add(item);
-            if (item._hasChildren && item._expanded) {
-                for (Item child : item.children) {
-                    refreshExpanded(expandedItemList, child);
+            // Check for filters
+            boolean display = true;
+            for (ViewerFilter filter : _filters) {
+                if (!filter.select(null, item._trace.getParent(), item._trace)) {
+                    display = false;
+                    break;
+                }
+            }
+            if (display) {
+                expandedItemList.add(item);
+                if (item._hasChildren && item._expanded) {
+                    for (Item child : item.children) {
+                        refreshExpanded(expandedItemList, child);
+                    }
                 }
             }
         }
@@ -1913,5 +2144,32 @@ public class TimeGraphControl extends TimeGraphBaseControl implements FocusListe
         }
     }
 
+    /**
+     * @since 1.2
+     */
+    @Override
+    public void menuDetected(MenuDetectEvent e) {
+        if (null == _timeProvider) {
+            return;
+        }
+        Point p = toControl(e.x, e.y);
+        int idx = getItemIndexAtY(p.y);
+        if (idx >= 0 && idx < _data._expandedItems.length) {
+            Item item = _data._expandedItems[idx];
+            ITimeGraphEntry entry = item._trace;
+            if (entry.hasTimeEvents()) {
+                ITimeEvent event = Utils.findEvent(entry, getTimeAtX(p.x), 2);
+                if (event != null) {
+                    e.data = event;
+                    fireMenuEventOnTimeEvent(e);
+                    return;
+                }
+            }
+            e.data = entry;
+            fireMenuEventOnTimeGraphEntry(e);
+        }
+    }
+
 }
 
+
This page took 0.030704 seconds and 5 git commands to generate.