tmf: Add generics to ITmfEventAspect
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / events / TmfEventsTable.java
index dcbc7908c804cace2fe13111460d83a68528ee73..12299f726d41824708525b91f9bff9406abfc5b1 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2015 Ericsson
+ * Copyright (c) 2010, 2016 Ericsson and others.
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -18,8 +18,7 @@
 
 package org.eclipse.tracecompass.tmf.ui.viewers.events;
 
-import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
-
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
@@ -39,6 +38,8 @@ import org.eclipse.core.commands.NotHandledException;
 import org.eclipse.core.commands.ParameterizedCommand;
 import org.eclipse.core.commands.common.NotDefinedException;
 import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IResource;
@@ -69,6 +70,9 @@ import org.eclipse.jface.resource.ColorRegistry;
 import org.eclipse.jface.resource.FontRegistry;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.OpenStrategy;
 import org.eclipse.jface.util.PropertyChangeEvent;
@@ -134,9 +138,10 @@ import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfModelLookup;
 import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfSourceLookup;
 import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
 import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
-import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
 import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterMatchesNode;
 import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterObjectNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterRootNode;
 import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType;
 import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
 import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker;
@@ -155,7 +160,9 @@ import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
+import org.eclipse.tracecompass.tmf.core.util.Pair;
 import org.eclipse.tracecompass.tmf.ui.viewers.events.TmfEventsCache.CachedEvent;
+import org.eclipse.tracecompass.tmf.ui.viewers.events.TmfEventsTableHeader.IEventsTableHeaderListener;
 import org.eclipse.tracecompass.tmf.ui.viewers.events.columns.TmfEventTableColumn;
 import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting;
 import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
@@ -163,6 +170,7 @@ import org.eclipse.tracecompass.tmf.ui.views.colors.IColorSettingsListener;
 import org.eclipse.tracecompass.tmf.ui.views.filter.FilterManager;
 import org.eclipse.tracecompass.tmf.ui.widgets.rawviewer.TmfRawEventViewer;
 import org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.TmfVirtualTable;
+import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IEditorSite;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPartSite;
@@ -172,6 +180,7 @@ import org.eclipse.ui.dialogs.ListDialog;
 import org.eclipse.ui.handlers.IHandlerService;
 import org.eclipse.ui.ide.IDE;
 import org.eclipse.ui.ide.IGotoMarker;
+import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.themes.ColorUtil;
 import org.eclipse.ui.themes.IThemeManager;
 
@@ -193,7 +202,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     /**
      * Empty string array, used by {@link #getItemStrings}.
      */
-    protected static final @NonNull String[] EMPTY_STRING_ARRAY = new String[0];
+    protected static final String @NonNull [] EMPTY_STRING_ARRAY = new String[0];
 
     /**
      * Empty string
@@ -213,9 +222,9 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     private static final Image SEARCH_MATCH_BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
             "icons/elcl16/search_match_bookmark.gif"); //$NON-NLS-1$
     private static final Image FILTER_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/filter_items.gif"); //$NON-NLS-1$
+    private static final Image FILTER_ADD_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/filter_add.gif"); //$NON-NLS-1$
     private static final Image STOP_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/stop.gif"); //$NON-NLS-1$
     private static final String SEARCH_HINT = Messages.TmfEventsTable_SearchHint;
-    private static final String FILTER_HINT = Messages.TmfEventsTable_FilterHint;
     private static final int MAX_CACHE_SIZE = 1000;
 
     private static final int MARGIN_COLUMN_INDEX = 0;
@@ -408,7 +417,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         }
     }
 
-    private final class PainItemListener implements Listener {
+    private static final class PainItemListener implements Listener {
         @Override
         public void handleEvent(Event event) {
             TableItem item = (TableItem) event.item;
@@ -442,7 +451,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         }
     }
 
-    private final class EraseItemListener implements Listener {
+    private static final class EraseItemListener implements Listener {
         @Override
         public void handleEvent(Event event) {
             TableItem item = (TableItem) event.item;
@@ -508,15 +517,25 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                 if (item == null) {
                     return;
                 }
-                final Long rank = (Long) item.getData(Key.RANK);
-                if (rank == null) {
-                    return;
-                }
-                final String tooltipText = (String) item.getData(Key.BOOKMARK);
-                final Rectangle bounds = item.getImageBounds(0);
-                bounds.width = BOOKMARK_IMAGE.getBounds().width;
-                if (!bounds.contains(event.x, event.y)) {
-                    return;
+                String text;
+                if (fTable.indexOf(item) == 0) {
+                    if (fHeaderState == HeaderState.SEARCH && item.getBounds(0).contains(event.x, event.y)) {
+                        text = Messages.TmfEventsTable_AddAsFilterText;
+                    } else {
+                        return;
+                    }
+                } else {
+                    final Long rank = (Long) item.getData(Key.RANK);
+                    if (rank == null) {
+                        return;
+                    }
+                    final String tooltipText = (String) item.getData(Key.BOOKMARK);
+                    final Rectangle bounds = item.getImageBounds(0);
+                    bounds.width = BOOKMARK_IMAGE.getBounds().width;
+                    if (!bounds.contains(event.x, event.y)) {
+                        return;
+                    }
+                    text = rank.toString() + (tooltipText != null ? ": " + tooltipText : EMPTY_STRING); //$NON-NLS-1$
                 }
                 if ((tooltipShell != null) && !tooltipShell.isDisposed()) {
                     tooltipShell.dispose();
@@ -527,7 +546,6 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                 layout.marginWidth = 2;
                 tooltipShell.setLayout(layout);
                 final Label label = new Label(tooltipShell, SWT.WRAP);
-                String text = rank.toString() + (tooltipText != null ? ": " + tooltipText : EMPTY_STRING); //$NON-NLS-1$
                 label.setForeground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
                 label.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                 label.setText(text);
@@ -623,11 +641,12 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
      * @author Patrick Tasse
      */
     public static enum HeaderState {
-        /** A search is being run */
-        SEARCH,
+        /** No search filter is applied
+         * @since 2.0*/
+        NO_SEARCH,
 
-        /** A filter is applied */
-        FILTER
+        /** A search filter is applied */
+        SEARCH
     }
 
     interface Direction {
@@ -639,6 +658,9 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     // Table data
     // ------------------------------------------------------------------------
 
+    /** The header bar */
+    private TmfEventsTableHeader fHeaderBar;
+
     /** The virtual event table */
     protected TmfVirtualTable fTable;
 
@@ -647,7 +669,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     private TmfRawEventViewer fRawViewer;
     private ITmfTrace fTrace;
     private volatile boolean fPackDone = false;
-    private HeaderState fHeaderState = HeaderState.SEARCH;
+    private HeaderState fHeaderState = HeaderState.NO_SEARCH;
     private long fSelectedRank = -1;
     private long fSelectedBeginRank = -1;
     private ITmfTimestamp fSelectedBeginTimestamp = null;
@@ -661,6 +683,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     private final Object fFilterSyncObj = new Object();
     private SearchThread fSearchThread;
     private final Object fSearchSyncObj = new Object();
+    private boolean fCollapseFilterEnabled = false;
 
     /**
      * List of selection change listeners (element type:
@@ -748,17 +771,17 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     }
 
     @Deprecated
-    private static @NonNull Iterable<ITmfEventAspect> convertFromColumnData(
+    private static @NonNull Iterable<ITmfEventAspect<?>> convertFromColumnData(
             org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData[] columnData) {
 
-        ImmutableList.Builder<ITmfEventAspect> builder = new ImmutableList.Builder<>();
+        ImmutableList.Builder<ITmfEventAspect<?>> builder = new ImmutableList.Builder<>();
         for (org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData col : columnData) {
             String fieldName = col.header;
             if (fieldName != null) {
                 builder.add(new TmfContentFieldAspect(fieldName, fieldName));
             }
         }
-        return checkNotNull(builder.build());
+        return builder.build();
     }
 
     /**
@@ -777,11 +800,11 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
      *            </p>
      */
     public TmfEventsTable(final Composite parent, int cacheSize,
-            @NonNull Iterable<ITmfEventAspect> aspects) {
+            @NonNull Iterable<ITmfEventAspect<?>> aspects) {
         super("TmfEventsTable"); //$NON-NLS-1$
 
         fComposite = new Composite(parent, SWT.NONE);
-        final GridLayout gl = new GridLayout(1, false);
+        GridLayout gl = new GridLayout(1, false);
         gl.marginHeight = 0;
         gl.marginWidth = 0;
         gl.verticalSpacing = 0;
@@ -790,9 +813,45 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         fSashForm = new SashForm(fComposite, SWT.HORIZONTAL);
         fSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
 
+        // Create a composite for the table and its header bar
+        Composite tableComposite = new Composite(fSashForm, SWT.NONE);
+        tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        gl = new GridLayout(1, false);
+        gl.marginHeight = 0;
+        gl.marginWidth = 0;
+        gl.verticalSpacing = 0;
+        tableComposite.setLayout(gl);
+
+        // Create an events table header bar
+        fHeaderBar = new TmfEventsTableHeader(tableComposite, SWT.NONE, new IEventsTableHeaderListener() {
+            @Override
+            public void filterSelected(ITmfFilter filter) {
+                if (filter instanceof TmfFilterMatchesNode) {
+                    TmfFilterMatchesNode matchFilter = (TmfFilterMatchesNode) filter;
+                    for (TableColumn col : fTable.getColumns()) {
+                        if (col.getData(Key.ASPECT) == matchFilter.getEventAspect()) {
+                            col.setData(Key.FILTER_TXT, matchFilter.getRegex());
+                        } else {
+                            col.setData(Key.FILTER_TXT, null);
+                        }
+                    }
+                    fTable.refresh();
+                    fTable.redraw();
+                }
+            }
+
+            @Override
+            public void filterRemoved(ITmfFilter filter) {
+                for (TableColumn col : fTable.getColumns()) {
+                    col.setData(Key.FILTER_TXT, null);
+                }
+                removeFilter(filter);
+            }
+        });
+
         // Create a virtual table
         final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION;
-        fTable = new TmfVirtualTable(fSashForm, style);
+        fTable = new TmfVirtualTable(tableComposite, style);
 
         // Set the table layout
         final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
@@ -803,7 +862,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         fTable.setLinesVisible(true);
 
         // Setup the columns
-        for (ITmfEventAspect aspect : aspects) {
+        for (ITmfEventAspect<?> aspect : aspects) {
             if (aspect != null) {
                 fColumns.add(new TmfEventTableColumn(aspect));
             }
@@ -892,6 +951,10 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         fRawViewer.setVisible(false);
 
         createPopupMenu();
+
+        fComposite.addDisposeListener((e) -> {
+            internalDispose();
+        });
     }
 
     /**
@@ -1033,19 +1096,50 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                 final TableItem item = items[0];
 
                 final Object data = item.getData();
-                if (data instanceof ITmfSourceLookup) {
-                    ITmfSourceLookup event = (ITmfSourceLookup) data;
-                    ITmfCallsite cs = event.getCallsite();
-                    if (cs == null) {
-                        return;
-                    }
-                    IMarker marker = null;
-                    try {
-                        String fileName = cs.getFileName();
-                        final String trimmedPath = fileName.replaceAll("\\.\\./", EMPTY_STRING); //$NON-NLS-1$
-                        if (trimmedPath.isEmpty()) {
-                            return;
+                if (!(data instanceof ITmfSourceLookup)) {
+                    return;
+                }
+                ITmfSourceLookup event = (ITmfSourceLookup) data;
+                ITmfCallsite cs = event.getCallsite();
+                if (cs == null) {
+                    return;
+                }
+
+                String fileName = cs.getFileName();
+                final String trimmedPath = fileName.replaceAll("\\.\\./", EMPTY_STRING); //$NON-NLS-1$
+                File fileToOpen = new File(trimmedPath);
+
+                try {
+                    if (fileToOpen.exists() && fileToOpen.isFile()) {
+                        /*
+                         * The path points to a "real" file, attempt to open
+                         * that
+                         */
+                        IFileStore fileStore = EFS.getLocalFileSystem().getStore(fileToOpen.toURI());
+                        IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+                        IEditorPart editor = IDE.openEditorOnFileStore(page, fileStore);
+                        if (editor instanceof ITextEditor) {
+                            /*
+                             * Calculate the "document offset" corresponding to
+                             * the line number, then seek there.
+                             */
+                            ITextEditor textEditor = (ITextEditor) editor;
+                            int lineNumber = Long.valueOf(cs.getLineNumber()).intValue();
+                            IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
+
+                            IRegion region = document.getLineInformation(lineNumber - 1);
+                            if (region != null) {
+                                textEditor.selectAndReveal(region.getOffset(), region.getLength());
+                            }
                         }
+
+                    } else {
+                        /*
+                         * The file was not found on disk, attempt to find it in
+                         * the workspace instead.
+                         */
+                        IMarker marker = null;
                         final ArrayList<IFile> files = new ArrayList<>();
                         ResourcesPlugin.getWorkspace().getRoot().accept(new IResourceVisitor() {
                             @Override
@@ -1082,12 +1176,12 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                             marker.setAttribute(IMarker.LINE_NUMBER, Long.valueOf(cs.getLineNumber()).intValue());
                             IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), marker);
                             marker.delete();
-                        } else if (files.size() == 0) {
+                        } else if (files.isEmpty()) {
                             displayException(new FileNotFoundException('\'' + cs.toString() + '\'' + '\n' + Messages.TmfEventsTable_OpenSourceCodeNotFound));
                         }
-                    } catch (CoreException e) {
-                        displayException(e);
                     }
+                } catch (BadLocationException | CoreException e) {
+                    displayException(e);
                 }
             }
         };
@@ -1175,21 +1269,10 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
             }
         };
 
-        final IAction showSearchBarAction = new Action(Messages.TmfEventsTable_ShowSearchBarActionText) {
-            @Override
-            public void run() {
-                fHeaderState = HeaderState.SEARCH;
-                fTable.refresh();
-                fTable.redraw();
-            }
-        };
-
-        final IAction showFilterBarAction = new Action(Messages.TmfEventsTable_ShowFilterBarActionText) {
+        final IAction addAsFilterAction = new Action(Messages.TmfEventsTable_AddAsFilterText) {
             @Override
             public void run() {
-                fHeaderState = HeaderState.FILTER;
-                fTable.refresh();
-                fTable.redraw();
+                applySearchAsFilter();
             }
         };
 
@@ -1243,10 +1326,8 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
             public void menuAboutToShow(final IMenuManager manager) {
                 if (fTable.getSelectionIndices().length == 1 && fTable.getSelectionIndices()[0] == 0) {
                     // Right-click on header row
-                    if (fHeaderState == HeaderState.FILTER) {
-                        fTablePopupMenuManager.add(showSearchBarAction);
-                    } else {
-                        fTablePopupMenuManager.add(showFilterBarAction);
+                    if (fHeaderState == HeaderState.SEARCH) {
+                        fTablePopupMenuManager.add(addAsFilterAction);
                     }
                     return;
                 }
@@ -1326,7 +1407,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                     }
                 }
 
-                if (isCollapsible && !(fTable.getData(Key.FILTER_OBJ) instanceof TmfCollapseFilter)) {
+                if (isCollapsible && !fCollapseFilterEnabled) {
                     fTablePopupMenuManager.add(collapseAction);
                     fTablePopupMenuManager.add(new Separator());
                 }
@@ -1402,16 +1483,19 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
 
     @Override
     public void dispose() {
+        fComposite.dispose();
+    }
+
+    private void internalDispose() {
         stopSearchThread();
         stopFilterThread();
         PlatformUI.getWorkbench().getThemeManager().removePropertyChangeListener(this);
         ColorSettingsManager.removeColorSettingsListener(this);
-        fComposite.dispose();
+        fCache.clear();
         if ((fTrace != null) && fDisposeOnClose) {
             fTrace.dispose();
         }
         fResourceManager.dispose();
-        fRawViewer.dispose();
         if (fRawViewerPopupMenuManager != null) {
             fRawViewerPopupMenuManager.dispose();
         }
@@ -1537,10 +1621,12 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         for (int index = 0; index < fTable.getColumns().length; index++) {
             TableColumn column = fTable.getColumns()[index];
             String regex = null;
-            if (fHeaderState == HeaderState.FILTER) {
+            if (fHeaderState == HeaderState.SEARCH) {
+                if (searchMatch) {
+                    regex = (String) column.getData(Key.SEARCH_TXT);
+                }
+            } else {
                 regex = (String) column.getData(Key.FILTER_TXT);
-            } else if (searchMatch) {
-                regex = (String) column.getData(Key.SEARCH_TXT);
             }
             if (regex != null) {
                 String text = item.getText(index);
@@ -1580,25 +1666,18 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
      *            The item to use as table header
      */
     protected void setHeaderRowItemData(final TableItem item) {
-        String txtKey = null;
-        if (fHeaderState == HeaderState.SEARCH) {
+        if (fHeaderState == HeaderState.NO_SEARCH) {
             item.setImage(SEARCH_IMAGE);
-            txtKey = Key.SEARCH_TXT;
-        } else if (fHeaderState == HeaderState.FILTER) {
-            item.setImage(FILTER_IMAGE);
-            txtKey = Key.FILTER_TXT;
+        } else if (fHeaderState == HeaderState.SEARCH) {
+            item.setImage(FILTER_ADD_IMAGE);
         }
         item.setForeground(fGrayColor);
         // Ignore collapse and image column
         for (int i = EVENT_COLUMNS_START_INDEX; i < fTable.getColumns().length; i++) {
             final TableColumn column = fTable.getColumns()[i];
-            final String filter = (String) column.getData(txtKey);
+            final String filter = (String) column.getData(Key.SEARCH_TXT);
             if (filter == null) {
-                if (fHeaderState == HeaderState.SEARCH) {
-                    item.setText(i, SEARCH_HINT);
-                } else if (fHeaderState == HeaderState.FILTER) {
-                    item.setText(i, FILTER_HINT);
-                }
+                item.setText(i, SEARCH_HINT);
                 item.setForeground(i, fGrayColor);
                 item.setFont(i, fFont);
             } else {
@@ -1671,13 +1750,8 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                     // Margin column selected
                     if (item.getBounds(0).contains(point)) {
                         if (fHeaderState == HeaderState.SEARCH) {
-                            fHeaderState = HeaderState.FILTER;
-                        } else if (fHeaderState == HeaderState.FILTER) {
-                            fHeaderState = HeaderState.SEARCH;
+                            applySearchAsFilter();
                         }
-                        fTable.setSelection(0);
-                        fTable.refresh();
-                        fTable.redraw();
                         return;
                     }
 
@@ -1697,19 +1771,12 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
 
                     column = fTable.getColumns()[columnIndex];
 
-                    String txtKey = null;
-                    if (fHeaderState == HeaderState.SEARCH) {
-                        txtKey = Key.SEARCH_TXT;
-                    } else if (fHeaderState == HeaderState.FILTER) {
-                        txtKey = Key.FILTER_TXT;
-                    }
-
                     /*
                      * The control that will be the editor must be a child of
                      * the Table
                      */
                     final Text newEditor = (Text) fTable.createTableEditorControl(Text.class);
-                    final String headerString = (String) column.getData(txtKey);
+                    final String headerString = (String) column.getData(Key.SEARCH_TXT);
                     if (headerString != null) {
                         newEditor.setText(headerString);
                     }
@@ -1728,12 +1795,15 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                             if (e.character == SWT.CR) {
                                 updateHeader(newEditor.getText());
                                 applyHeader();
-
-                                /*
-                                 * Set focus on the table so that the next
-                                 * carriage return goes to the next result
-                                 */
-                                TmfEventsTable.this.getTable().setFocus();
+                                if ((e.stateMask & SWT.CTRL) != 0) {
+                                    applySearchAsFilter();
+                                } else {
+                                    /*
+                                     * Set focus on the table so that the next
+                                     * carriage return goes to the next result
+                                     */
+                                    TmfEventsTable.this.getTable().setFocus();
+                                }
                             } else if (e.character == SWT.ESC) {
                                 tableEditor.getEditor().dispose();
                             }
@@ -1749,28 +1819,19 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
              * returns true is value was changed
              */
             private boolean updateHeader(final String regex) {
-                String objKey = null;
-                String txtKey = null;
-                if (fHeaderState == HeaderState.SEARCH) {
-                    objKey = Key.SEARCH_OBJ;
-                    txtKey = Key.SEARCH_TXT;
-                } else if (fHeaderState == HeaderState.FILTER) {
-                    objKey = Key.FILTER_OBJ;
-                    txtKey = Key.FILTER_TXT;
-                }
                 if (regex.length() > 0) {
                     try {
                         Pattern.compile(regex);
-                        if (regex.equals(column.getData(txtKey))) {
+                        if (regex.equals(column.getData(Key.SEARCH_TXT))) {
                             tableEditor.getEditor().dispose();
                             return false;
                         }
                         final TmfFilterMatchesNode filter = new TmfFilterMatchesNode(null);
-                        ITmfEventAspect aspect = (ITmfEventAspect) column.getData(Key.ASPECT);
+                        ITmfEventAspect<?> aspect = (ITmfEventAspect<?>) column.getData(Key.ASPECT);
                         filter.setEventAspect(aspect);
                         filter.setRegex(regex);
-                        column.setData(objKey, filter);
-                        column.setData(txtKey, regex);
+                        column.setData(Key.SEARCH_OBJ, filter);
+                        column.setData(Key.SEARCH_TXT, regex);
                     } catch (final PatternSyntaxException ex) {
                         tableEditor.getEditor().dispose();
                         MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
@@ -1778,50 +1839,37 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                         return false;
                     }
                 } else {
-                    if (column.getData(txtKey) == null) {
+                    if (column.getData(Key.SEARCH_TXT) == null) {
                         tableEditor.getEditor().dispose();
                         return false;
                     }
-                    column.setData(objKey, null);
-                    column.setData(txtKey, null);
+                    column.setData(Key.SEARCH_OBJ, null);
+                    column.setData(Key.SEARCH_TXT, null);
                 }
                 return true;
             }
 
             private void applyHeader() {
-                if (fHeaderState == HeaderState.SEARCH) {
-                    stopSearchThread();
-                    final TmfFilterAndNode filter = new TmfFilterAndNode(null);
-                    for (final TableColumn col : fTable.getColumns()) {
-                        final Object filterObj = col.getData(Key.SEARCH_OBJ);
-                        if (filterObj instanceof ITmfFilterTreeNode) {
-                            filter.addChild((ITmfFilterTreeNode) filterObj);
-                        }
-                    }
-                    if (filter.getChildrenCount() > 0) {
-                        fTable.setData(Key.SEARCH_OBJ, filter);
-                        fTable.refresh();
-                        searchNext();
-                        fireSearchApplied(filter);
-                    } else {
-                        fTable.setData(Key.SEARCH_OBJ, null);
-                        fTable.refresh();
-                        fireSearchApplied(null);
-                    }
-                } else if (fHeaderState == HeaderState.FILTER) {
-                    final TmfFilterAndNode filter = new TmfFilterAndNode(null);
-                    for (final TableColumn col : fTable.getColumns()) {
-                        final Object filterObj = col.getData(Key.FILTER_OBJ);
-                        if (filterObj instanceof ITmfFilterTreeNode) {
-                            filter.addChild((ITmfFilterTreeNode) filterObj);
-                        }
-                    }
-                    if (filter.getChildrenCount() > 0) {
-                        applyFilter(filter);
-                    } else {
-                        clearFilters();
+                stopSearchThread();
+                final TmfFilterRootNode filter = new TmfFilterRootNode();
+                for (final TableColumn col : fTable.getColumns()) {
+                    final Object filterObj = col.getData(Key.SEARCH_OBJ);
+                    if (filterObj instanceof ITmfFilterTreeNode) {
+                        filter.addChild((ITmfFilterTreeNode) filterObj);
                     }
                 }
+                if (filter.getChildrenCount() > 0) {
+                    fHeaderState = HeaderState.SEARCH;
+                    fTable.setData(Key.SEARCH_OBJ, filter);
+                    fTable.refresh();
+                    searchNext();
+                    fireSearchApplied(filter);
+                } else {
+                    fHeaderState = HeaderState.NO_SEARCH;
+                    fTable.setData(Key.SEARCH_OBJ, null);
+                    fTable.refresh();
+                    fireSearchApplied(null);
+                }
 
                 tableEditor.getEditor().dispose();
             }
@@ -1837,19 +1885,28 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                     fTable.refresh();
                 } else if (e.character == SWT.DEL) {
                     if (fHeaderState == HeaderState.SEARCH) {
+                        fHeaderState = HeaderState.NO_SEARCH;
                         stopSearchThread();
                         for (final TableColumn column : fTable.getColumns()) {
                             column.setData(Key.SEARCH_OBJ, null);
                             column.setData(Key.SEARCH_TXT, null);
+                            column.setData(Key.FILTER_TXT, null);
                         }
                         fTable.setData(Key.SEARCH_OBJ, null);
                         fTable.refresh();
                         fireSearchApplied(null);
-                    } else if (fHeaderState == HeaderState.FILTER) {
-                        clearFilters();
+                    } else {
+                        for (final TableColumn column : fTable.getColumns()) {
+                            column.setData(Key.FILTER_TXT, null);
+                        }
+                        fTable.refresh();
                     }
                 } else if (e.character == SWT.CR) {
-                    if ((e.stateMask & SWT.SHIFT) == 0) {
+                    if ((e.stateMask & SWT.CTRL) != 0) {
+                        if (fHeaderState == HeaderState.SEARCH) {
+                            applySearchAsFilter();
+                        }
+                    } else if ((e.stateMask & SWT.SHIFT) == 0) {
                         searchNext();
                     } else {
                         searchPrevious();
@@ -1859,6 +1916,27 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         });
     }
 
+    /**
+     * Apply the current search condition as a new filter.
+     *
+     * @since 2.0
+     */
+    protected void applySearchAsFilter() {
+        Object searchObj = fTable.getData(Key.SEARCH_OBJ);
+        if (searchObj instanceof ITmfFilter) {
+            ITmfFilter filter = (ITmfFilter) searchObj;
+            fTable.setData(Key.SEARCH_OBJ, null);
+            fireSearchApplied(null);
+            fHeaderState = HeaderState.NO_SEARCH;
+            for (final TableColumn col : fTable.getColumns()) {
+                col.setData(Key.FILTER_TXT, col.getData(Key.SEARCH_TXT));
+                col.setData(Key.SEARCH_TXT, null);
+                col.setData(Key.SEARCH_OBJ, null);
+            }
+            applyFilter(filter);
+        }
+    }
+
     /**
      * Send an event indicating a filter has been applied.
      *
@@ -1912,7 +1990,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
     }
 
     /**
-     * Apply a filter.
+     * Apply a filter. It is added to the existing filters.
      *
      * @param filter
      *            The filter to apply
@@ -1922,13 +2000,78 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         stopSearchThread();
         fFilterMatchCount = 0;
         fFilterCheckCount = 0;
-        fCache.applyFilter(filter);
+        ITmfFilterTreeNode rootFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
+        if (rootFilter == null) {
+            rootFilter = new TmfFilterRootNode();
+        }
+        if (filter instanceof TmfFilterRootNode) {
+            TmfFilterRootNode parentFilter = (TmfFilterRootNode) filter;
+            for (ITmfFilterTreeNode child : parentFilter.getChildren()) {
+                rootFilter.addChild(child);
+            }
+        } else if (filter instanceof TmfCollapseFilter) {
+            fCollapseFilterEnabled = true;
+        } else if (filter instanceof ITmfFilterTreeNode) {
+            rootFilter.addChild((ITmfFilterTreeNode) filter);
+        } else {
+            rootFilter.addChild(new TmfFilterObjectNode(filter));
+        }
+        fCache.applyFilter(rootFilter, fCollapseFilterEnabled);
+        fHeaderBar.addFilter(filter);
         fTable.clearAll();
-        fTable.setData(Key.FILTER_OBJ, filter);
+        fTable.setData(Key.FILTER_OBJ, rootFilter);
         /* +1 for header row, +2 for top and bottom filter status rows */
         fTable.setItemCount(3);
         startFilterThread();
-        fireFilterApplied(filter);
+        fireFilterApplied(rootFilter);
+    }
+
+    /**
+     * Remove a filter. Any other existing filters remain applied.
+     *
+     * @param filter
+     *            The filter to remove
+     * @since 2.0
+     */
+    protected void removeFilter(ITmfFilter filter) {
+        ITmfFilterTreeNode rootFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
+        if (rootFilter == null) {
+            return;
+        }
+        stopFilterThread();
+        stopSearchThread();
+        fFilterMatchCount = 0;
+        fFilterCheckCount = 0;
+        if (filter instanceof TmfCollapseFilter) {
+            fCollapseFilterEnabled = false;
+        } else if (filter instanceof ITmfFilterTreeNode) {
+            rootFilter.removeChild((ITmfFilterTreeNode) filter);
+        } else {
+            for (ITmfFilterTreeNode child : rootFilter.getChildren()) {
+                if (child instanceof TmfFilterObjectNode) {
+                    if (((TmfFilterObjectNode) child).getFilter().equals(filter)) {
+                        rootFilter.removeChild(child);
+                        break;
+                    }
+                }
+            }
+        }
+        if (!rootFilter.hasChildren() && !fCollapseFilterEnabled) {
+            clearFilters();
+            return;
+        }
+        fCache.applyFilter(rootFilter, fCollapseFilterEnabled);
+        fHeaderBar.removeFilter(filter);
+        fTable.clearAll();
+        fTable.setData(Key.FILTER_OBJ, rootFilter);
+        /* +1 for header row, +2 for top and bottom filter status rows */
+        fTable.setItemCount(3);
+        startFilterThread();
+        fireFilterApplied(rootFilter);
+
+        // Set original width
+        fTable.getColumns()[MARGIN_COLUMN_INDEX].setWidth(0);
+        packMarginColumn();
     }
 
     /**
@@ -1941,6 +2084,8 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
         stopFilterThread();
         stopSearchThread();
         fCache.clearFilter();
+        fHeaderBar.clearFilters();
+        fCollapseFilterEnabled = false;
         fTable.clearAll();
         for (final TableColumn column : fTable.getColumns()) {
             column.setData(Key.FILTER_OBJ, null);
@@ -1975,6 +2120,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
      */
     protected class FilterThread extends Thread {
         private final ITmfFilterTreeNode filter;
+        private TmfCollapseFilter collapseFilter = null;
         private TmfEventRequest request;
         private boolean refreshBusy = false;
         private boolean refreshPending = false;
@@ -1996,6 +2142,9 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
             if (fTrace == null) {
                 return;
             }
+            if (fCollapseFilterEnabled) {
+                collapseFilter = new TmfCollapseFilter();
+            }
             final int nbRequested = (int) (fTrace.getNbEvents() - fFilterCheckCount);
             if (nbRequested <= 0) {
                 return;
@@ -2010,15 +2159,15 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                     }
                     boolean refresh = false;
                     if (filter.matches(event)) {
-                        final long rank = fFilterCheckCount;
-                        final int index = (int) fFilterMatchCount;
-                        fFilterMatchCount++;
-                        fCache.storeEvent(event, rank, index);
-                        refresh = true;
-                    } else {
-                        if (filter instanceof TmfCollapseFilter) {
+                        if (collapseFilter == null || collapseFilter.matches(event)) {
+                            final long rank = fFilterCheckCount;
+                            final int index = (int) fFilterMatchCount;
+                            fFilterMatchCount++;
+                            fCache.storeEvent(event, rank, index);
+                        } else if (collapseFilter != null) {
                             fCache.updateCollapsedEvent((int) fFilterMatchCount - 1);
                         }
+                        refresh = true;
                     }
 
                     if (refresh || (fFilterCheckCount % 100) == 0) {
@@ -2356,7 +2505,9 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
 
         @Override
         protected void canceling() {
-            request.cancel();
+            if (request != null) {
+                request.cancel();
+            }
             synchronized (fSearchSyncObj) {
                 fSearchThread = null;
             }
@@ -2409,10 +2560,16 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
 
     /**
      * Pack the columns.
+     *
+     * @return
+     *            Whether or not a pack was done in this call. Otherwise, it was already done by a
+     *            previous call
+     *
+     * @since 2.0
      */
-    protected void packColumns() {
+    protected boolean packColumns() {
         if (fPackDone) {
-            return;
+            return false;
         }
         fTable.setRedraw(false);
         try {
@@ -2427,6 +2584,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
             fTable.setRedraw(true);
         }
         fPackDone = true;
+        return true;
     }
 
     private void packMarginColumn() {
@@ -2444,8 +2602,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
          * search/filter row in TableColumn.pack() after having executed
          * TableItem.setImage(null) for other rows than search/filter row.
          */
-        boolean isCollapseFilter = fTable.getData(Key.FILTER_OBJ) instanceof TmfCollapseFilter;
-        if (IS_LINUX && (i == 0) && isCollapseFilter) {
+        if (IS_LINUX && (i == 0) && fCollapseFilterEnabled) {
             column.setWidth(column.getWidth() + SEARCH_IMAGE.getBounds().width);
         }
 
@@ -3037,11 +3194,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                     TmfTimeRange.ETERNITY, 0, 1, ExecutionType.FOREGROUND) {
 
                 TmfTimestamp ts = new TmfTimestamp(signal.getBeginTime());
-
-                @Override
-                public void handleData(final ITmfEvent event) {
-                    super.handleData(event);
-                }
+                TmfTimestamp tf = new TmfTimestamp(signal.getEndTime());
 
                 @Override
                 public void handleSuccess() {
@@ -3050,23 +3203,82 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                         return;
                     }
 
-                    /*
-                     * Verify if the event is within the trace range and adjust
-                     * if necessary
-                     */
-                    ITmfTimestamp timestamp = ts;
-                    if (timestamp.compareTo(fTrace.getStartTime()) == -1) {
-                        timestamp = fTrace.getStartTime();
+                    final Pair<Long, Long> selection = getSelectedRanks();
+                    updateDisplayWithSelection(selection.getFirst().longValue(), selection.getSecond().longValue());
+                }
+
+                /**
+                 * Verify if the event is within the trace range and adjust if
+                 * necessary.
+                 *
+                 * @return A pair of rank representing the selected area
+                 **/
+                private Pair<Long, Long> getSelectedRanks() {
+
+                    /* Clamp the timestamp value to fit inside of the trace */
+                    ITmfTimestamp timestampBegin = ts;
+                    if (timestampBegin.compareTo(fTrace.getStartTime()) < 0) {
+                        timestampBegin = fTrace.getStartTime();
                     }
-                    if (timestamp.compareTo(fTrace.getEndTime()) == 1) {
-                        timestamp = fTrace.getEndTime();
+                    if (timestampBegin.compareTo(fTrace.getEndTime()) > 0) {
+                        timestampBegin = fTrace.getEndTime();
                     }
 
-                    // Get the rank of the selected event in the table
-                    final ITmfContext context = fTrace.seekEvent(timestamp);
-                    final long rank = context.getRank();
-                    context.dispose();
+                    ITmfTimestamp timestampEnd = tf;
+                    if (timestampEnd.compareTo(fTrace.getStartTime()) < 0) {
+                        timestampEnd = fTrace.getStartTime();
+                    }
+                    if (timestampEnd.compareTo(fTrace.getEndTime()) > 0) {
+                        timestampEnd = fTrace.getEndTime();
+                    }
+
+                    ITmfTimestamp tb;
+                    ITmfTimestamp te;
+                    long rankBegin;
+                    long rankEnd;
+                    ITmfContext contextBegin;
+                    ITmfContext contextEnd;
+
+                    /* Adjust the rank of the selection to the right range */
+                    if (timestampBegin.compareTo(timestampEnd) > 0) {
+                        te = timestampEnd;
+                        contextEnd = fTrace.seekEvent(te);
+                        rankEnd = contextEnd.getRank();
+                        contextEnd.dispose();
+                        /* To include all events at the begin time, seek at the next nanosecond and then use the previous rank */
+                        tb = timestampBegin.normalize(1, ITmfTimestamp.NANOSECOND_SCALE);
+                        if (tb.compareTo(fTrace.getEndTime()) <= 0) {
+                            contextBegin = fTrace.seekEvent(tb);
+                            rankBegin = contextBegin.getRank();
+                            contextBegin.dispose();
+                        } else {
+                            rankBegin = ITmfContext.UNKNOWN_RANK;
+                        }
+                        rankBegin = (rankBegin == ITmfContext.UNKNOWN_RANK ? fTrace.getNbEvents() : rankBegin) - 1;
+                        /* If no events in selection range, select only the next event */
+                        rankBegin = rankBegin >= rankEnd ? rankBegin : rankEnd;
+                    } else {
+                        tb = timestampBegin;
+                        contextBegin = fTrace.seekEvent(tb);
+                        rankBegin = contextBegin.getRank();
+                        contextBegin.dispose();
+                        /* To include all events at the end time, seek at the next nanosecond and then use the previous rank */
+                        te = timestampEnd.normalize(1, ITmfTimestamp.NANOSECOND_SCALE);
+                        if (te.compareTo(fTrace.getEndTime()) <= 0) {
+                            contextEnd = fTrace.seekEvent(te);
+                            rankEnd = contextEnd.getRank();
+                            contextEnd.dispose();
+                        } else {
+                            rankEnd = ITmfContext.UNKNOWN_RANK;
+                        }
+                        rankEnd = (rankEnd == ITmfContext.UNKNOWN_RANK ? fTrace.getNbEvents() : rankEnd) - 1;
+                        /* If no events in selection range, select only the next event */
+                        rankEnd = rankEnd >= rankBegin ? rankEnd : rankBegin;
+                    }
+                    return new Pair<>(Long.valueOf(rankBegin), Long.valueOf(rankEnd));
+                }
 
+                private void updateDisplayWithSelection(final long rankBegin, final long rankEnd) {
                     PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                         @Override
                         public void run() {
@@ -3075,16 +3287,20 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
                                 return;
                             }
 
-                            fSelectedRank = rank;
-                            fSelectedBeginRank = fSelectedRank;
-                            int index = (int) rank;
+                            fSelectedRank = rankEnd;
+                            long toReveal = fSelectedBeginRank != rankBegin ? rankBegin : rankEnd;
+                            fSelectedBeginRank = rankBegin;
+                            int indexBegin = (int) rankBegin;
+                            int indexEnd = (int) rankEnd;
+
                             if (fTable.getData(Key.FILTER_OBJ) != null) {
                                 /* +1 for top filter status row */
-                                index = fCache.getFilteredEventIndex(rank) + 1;
+                                indexBegin = fCache.getFilteredEventIndex(rankBegin) + 1;
+                                indexEnd = rankEnd == rankBegin ? indexBegin : fCache.getFilteredEventIndex(rankEnd) + 1;
                             }
                             /* +1 for header row */
-                            fTable.setSelection(index + 1);
-                            fRawViewer.selectAndReveal(rank);
+                            fTable.setSelectionRange(indexBegin + 1, indexEnd + 1);
+                            fRawViewer.selectAndReveal(toReveal);
                             updateStatusLine(null);
                         }
                     });
@@ -3126,7 +3342,8 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS
      */
     private static final class TmfMarginColumn extends TmfEventTableColumn {
 
-        private static final @NonNull ITmfEventAspect MARGIN_ASPECT = new ITmfEventAspect() {
+        private static final @NonNull ITmfEventAspect<String> MARGIN_ASPECT =
+                new ITmfEventAspect<String>() {
 
             @Override
             public String getName() {
This page took 0.037163 seconds and 5 git commands to generate.