/*******************************************************************************
- * Copyright (c) 2012 Ericsson
+ * Copyright (c) 2012, 2013 Ericsson, others
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
*
* Contributors:
* Patrick Tasse - Initial API and implementation
+ * François Rajotte - Filter implementation
+ * Geneviève Bastien - Add event links between entries
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.widgets.timegraph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.linuxtools.internal.tmf.ui.Activator;
+import org.eclipse.linuxtools.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs.TimeGraphFilterDialog;
+import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ILinkEvent;
import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
// Fields
// ------------------------------------------------------------------------
- // The tree viewer
+ /** The tree viewer */
private TreeViewer fTreeViewer;
- // The time viewer
+ /** The time viewer */
private TimeGraphViewer fTimeGraphViewer;
- // The selection listener map
- private final HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
+ /** The top-level input (children excluded) */
+ private List<? extends ITimeGraphEntry> fTopInput;
- // Flag to block the tree selection changed listener when triggered by the time graph combo
+ /** The selection listener map */
+ private final Map<ITimeGraphSelectionListener, SelectionListenerWrapper> fSelectionListenerMap = new HashMap<ITimeGraphSelectionListener, SelectionListenerWrapper>();
+
+ /** The map of viewer filters */
+ private final Map<ViewerFilter, ViewerFilter> fViewerFilterMap = new HashMap<ViewerFilter, ViewerFilter>();
+
+ /**
+ * Flag to block the tree selection changed listener when triggered by the
+ * time graph combo
+ */
private boolean fInhibitTreeSelection = false;
- // Number of filler rows used by the tree content provider
+ /** Number of filler rows used by the tree content provider */
private int fNumFillerRows;
- // Calculated item height for Linux workaround
+ /** Calculated item height for Linux workaround */
private int fLinuxItemHeight = 0;
+ /** The button that opens the filter dialog */
+ private Action showFilterAction;
+
+ /** The filter dialog */
+ private TimeGraphFilterDialog fFilterDialog;
+
+ /** The filter generated from the filter dialog */
+ private RawViewerFilter fFilter;
+
+ /** Default weight of each part of the sash */
+ private static final int[] DEFAULT_WEIGHTS = { 1, 1 };
+
// ------------------------------------------------------------------------
// Classes
// ------------------------------------------------------------------------
public Object[] getElements(Object inputElement) {
Object[] elements = contentProvider.getElements(inputElement);
// add filler elements to ensure alignment with time analysis viewer
- Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, new Object[0].getClass());
+ Object[] oElements = Arrays.copyOf(elements, elements.length + fNumFillerRows, Object[].class);
for (int i = 0; i < fNumFillerRows; i++) {
oElements[elements.length + i] = FILLER;
}
}
}
+ /**
+ * The ViewerFilterWrapper is used to intercept the filler items from
+ * the time graph combo's real ViewerFilters. These filler items should
+ * always be visible.
+ */
+ private class ViewerFilterWrapper extends ViewerFilter {
+
+ private ViewerFilter fWrappedFilter;
+
+ ViewerFilterWrapper(ViewerFilter filter) {
+ super();
+ this.fWrappedFilter = filter;
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (element instanceof ITimeGraphEntry) {
+ return fWrappedFilter.select(viewer, parentElement, element);
+ }
+ return true;
+ }
+
+ }
+
+ /**
+ * This filter simply keeps a list of elements that should be filtered out.
+ * All the other elements will be shown.
+ * By default and when the list is set to null, all elements are shown.
+ */
+ private class RawViewerFilter extends ViewerFilter {
+
+ private List<Object> fFiltered = null;
+
+ public void setFiltered(List<Object> objects) {
+ fFiltered = objects;
+ }
+
+ public List<Object> getFiltered() {
+ return fFiltered;
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ if (fFiltered == null) {
+ return true;
+ }
+ return !fFiltered.contains(element);
+ }
+ }
+
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
* @param style the style of widget to construct
*/
public TimeGraphCombo(Composite parent, int style) {
+ this(parent, style, DEFAULT_WEIGHTS);
+ }
+
+ /**
+ * Constructs a new instance of this class given its parent and a style
+ * value describing its behavior and appearance.
+ *
+ * @param parent
+ * a widget which will be the parent of the new instance (cannot
+ * be null)
+ * @param style
+ * the style of widget to construct
+ * @param weights
+ * The relative weights of each side of the sash form
+ * @since 2.1
+ */
+ public TimeGraphCombo(Composite parent, int style, int[] weights) {
super(parent, style);
setLayout(new FillLayout());
fTimeGraphViewer.setBorderWidth(tree.getBorderWidth());
fTimeGraphViewer.setNameWidthPref(0);
+ fFilter = new RawViewerFilter();
+ addFilter(fFilter);
+
+ fFilterDialog = new TimeGraphFilterDialog(getShell());
+
// Feature in Windows. The tree vertical bar reappears when
// the control is resized so we need to hide it again.
// Bug in Linux. The tree header height is 0 in constructor,
// so we need to reset it later when the control is resized.
tree.addControlListener(new ControlAdapter() {
- int depth = 0;
+ private int depth = 0;
@Override
public void controlResized(ControlEvent e) {
if (depth == 0) {
@Override
public void treeCollapsed(TreeExpansionEvent event) {
fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), false);
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
@Override
public void treeExpanded(TreeExpansionEvent event) {
- fTimeGraphViewer.setExpandedState((ITimeGraphEntry) event.getElement(), true);
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ ITimeGraphEntry entry = (ITimeGraphEntry) event.getElement();
+ fTimeGraphViewer.setExpandedState(entry, true);
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ boolean expanded = fTreeViewer.getExpandedState(child);
+ fTimeGraphViewer.setExpandedState(child, expanded);
+ }
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
@Override
public void treeExpanded(TimeGraphTreeExpansionEvent event) {
- fTreeViewer.setExpandedState(event.getEntry(), true);
+ ITimeGraphEntry entry = event.getEntry();
+ fTreeViewer.setExpandedState(entry, true);
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ boolean expanded = fTreeViewer.getExpandedState(child);
+ fTimeGraphViewer.setExpandedState(child, expanded);
+ }
}
});
TreeItem treeItem = tree.getItem(new Point(event.x, event.y));
if (treeItem == null || treeItem.getData() == FILLER) {
event.doit = false;
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
fTreeViewer.setSelection(new StructuredSelection());
fTimeGraphViewer.setSelection(null);
event.doit = false;
Slider scrollBar = fTimeGraphViewer.getVerticalBar();
fTimeGraphViewer.setTopIndex(scrollBar.getSelection() - event.count);
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
tree.addListener(SWT.KeyDown, new Listener() {
@Override
public void handleEvent(Event event) {
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
fTreeViewer.setSelection(new StructuredSelection());
event.doit = false;
fTimeGraphViewer.getTimeGraphControl().addControlListener(new ControlAdapter() {
@Override
public void controlResized(ControlEvent e) {
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
if (selection instanceof ITimeGraphEntry) {
fTimeGraphViewer.setSelection((ITimeGraphEntry) selection);
}
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
fTreeViewer.setSelection(new StructuredSelection());
}
fInhibitTreeSelection = false;
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
fTimeGraphViewer.getVerticalBar().addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
fTimeGraphViewer.getTimeGraphControl().addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseScrolled(MouseEvent e) {
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() == 0) {
return;
}
// to a value that would cause blank space to be drawn at the bottom of the tree.
fNumFillerRows = Display.getDefault().getBounds().height / getItemHeight(tree);
- sash.setWeights(new int[] { 1, 1 });
+ sash.setWeights(weights);
}
// ------------------------------------------------------------------------
return fTimeGraphViewer;
}
+ /**
+ * Callback for the show filter action
+ *
+ * @since 2.0
+ */
+ public void showFilterDialog() {
+ if(fTopInput != null) {
+ List<? extends ITimeGraphEntry> allElements = listAllInputs(fTopInput);
+ fFilterDialog.setInput(fTopInput.toArray(new ITimeGraphEntry[0]));
+ fFilterDialog.setTitle(Messages.TmfTimeFilterDialog_WINDOW_TITLE);
+ fFilterDialog.setMessage(Messages.TmfTimeFilterDialog_MESSAGE);
+ fFilterDialog.setExpandedElements(allElements.toArray());
+ if (fFilter.getFiltered() != null) {
+ ArrayList<? extends ITimeGraphEntry> nonFilteredElements = new ArrayList<ITimeGraphEntry>(allElements);
+ nonFilteredElements.removeAll(fFilter.getFiltered());
+ fFilterDialog.setInitialElementSelections(nonFilteredElements);
+ } else {
+ fFilterDialog.setInitialElementSelections(allElements);
+ }
+ fFilterDialog.create();
+ fFilterDialog.open();
+ // Process selected elements
+ if (fFilterDialog.getResult() != null) {
+ fInhibitTreeSelection = true;
+ if (fFilterDialog.getResult().length != allElements.size()) {
+ ArrayList<Object> filteredElements = new ArrayList<Object>(allElements);
+ filteredElements.removeAll(Arrays.asList(fFilterDialog.getResult()));
+ fFilter.setFiltered(filteredElements);
+ } else {
+ fFilter.setFiltered(null);
+ }
+ fTreeViewer.refresh();
+ fTreeViewer.expandAll();
+ fTimeGraphViewer.refresh();
+ fInhibitTreeSelection = false;
+ // Reset selection to first entry
+ if (fFilterDialog.getResult().length > 0) {
+ setSelection((ITimeGraphEntry) fFilterDialog.getResult()[0]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the show filter action.
+ *
+ * @return The Action object
+ * @since 2.0
+ */
+ public Action getShowFilterAction() {
+ if (showFilterAction == null) {
+ // showFilter
+ showFilterAction = new Action() {
+ @Override
+ public void run() {
+ showFilterDialog();
+ }
+ };
+ showFilterAction.setText(Messages.TmfTimeGraphCombo_FilterActionNameText);
+ showFilterAction.setToolTipText(Messages.TmfTimeGraphCombo_FilterActionToolTipText);
+ // TODO find a nice, distinctive icon
+ showFilterAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
+ }
+
+ return showFilterAction;
+ }
+
// ------------------------------------------------------------------------
// Control
// ------------------------------------------------------------------------
- /* (non-Javadoc)
- * @see org.eclipse.swt.widgets.Control#redraw()
- */
@Override
public void redraw() {
fTimeGraphViewer.getControl().redraw();
fTreeViewer.setLabelProvider(new TreeLabelProviderWrapper(labelProvider));
}
+ /**
+ * Sets the tree content provider used by the filter dialog
+ *
+ * @param contentProvider the tree content provider
+ * @since 2.0
+ */
+ public void setFilterContentProvider(ITreeContentProvider contentProvider) {
+ fFilterDialog.setContentProvider(contentProvider);
+ }
+
+ /**
+ * Sets the tree label provider used by the filter dialog
+ *
+ * @param labelProvider the tree label provider
+ * @since 2.0
+ */
+ public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
+ fFilterDialog.setLabelProvider(labelProvider);
+ }
+
/**
* Sets the tree columns for this time graph combo.
*
}
}
+ /**
+ * Sets the tree columns for this time graph combo's filter dialog.
+ *
+ * @param columnNames the tree column names
+ * @since 2.0
+ */
+ public void setFilterColumns(String[] columnNames) {
+ fFilterDialog.setColumnNames(columnNames);
+ }
+
/**
* Sets the time graph provider used by this time graph combo.
*
* @param input the input of this time graph combo, or <code>null</code> if none
*/
public void setInput(ITimeGraphEntry[] input) {
+ fTopInput = new ArrayList<ITimeGraphEntry>(Arrays.asList(input));
+ fFilter.setFiltered(null);
fInhibitTreeSelection = true;
fTreeViewer.setInput(input);
for (SelectionListenerWrapper listenerWrapper : fSelectionListenerMap.values()) {
fTimeGraphViewer.setInput(input);
}
+ /**
+ * Sets or clears the list of links to display on this combo
+ *
+ * @param links the links to display in this time graph combo
+ * @since 2.1
+ */
+ public void setLinks(List<ILinkEvent> links) {
+ fTimeGraphViewer.setLinks(links);
+ }
+
+ /**
+ * @param filter The filter object to be attached to the view
+ * @since 2.0
+ */
+ public void addFilter(ViewerFilter filter) {
+ ViewerFilter wrapper = new ViewerFilterWrapper(filter);
+ fTreeViewer.addFilter(wrapper);
+ fTimeGraphViewer.addFilter(wrapper);
+ fViewerFilterMap.put(filter, wrapper);
+ }
+
+ /**
+ * @param filter The filter object to be removed from the view
+ * @since 2.0
+ */
+ public void removeFilter(ViewerFilter filter) {
+ ViewerFilter wrapper = fViewerFilterMap.get(filter);
+ fTreeViewer.removeFilter(wrapper);
+ fTimeGraphViewer.removeFilter(wrapper);
+ fViewerFilterMap.remove(filter);
+ }
+
/**
* Refreshes this time graph completely with information freshly obtained from its model.
*/
fTreeViewer.setSelection(new StructuredSelection());
}
fInhibitTreeSelection = false;
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
+ List<TreeItem> treeItems = getVisibleExpandedItems(fTreeViewer.getTree());
if (treeItems.size() == 0) {
return;
}
// Internal
// ------------------------------------------------------------------------
- private ArrayList<TreeItem> getVisibleExpandedItems(Tree tree) {
+ private List<TreeItem> getVisibleExpandedItems(Tree tree) {
ArrayList<TreeItem> items = new ArrayList<TreeItem>();
for (TreeItem item : tree.getItems()) {
if (item.getData() == FILLER) {
return items;
}
- private ArrayList<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
+ private List<TreeItem> getVisibleExpandedItems(TreeItem treeItem) {
ArrayList<TreeItem> items = new ArrayList<TreeItem>();
for (TreeItem item : treeItem.getItems()) {
items.add(item);
return items;
}
+ /**
+ * Explores the list of top-level inputs and returns all the inputs
+ *
+ * @param inputs The top-level inputs
+ * @return All the inputs
+ */
+ private List<? extends ITimeGraphEntry> listAllInputs(List<? extends ITimeGraphEntry> inputs) {
+ ArrayList<ITimeGraphEntry> items = new ArrayList<ITimeGraphEntry>();
+ for (ITimeGraphEntry entry : inputs) {
+ items.add(entry);
+ if (entry.hasChildren()) {
+ items.addAll(listAllInputs(entry.getChildren()));
+ }
+ }
+ return items;
+ }
+
private int getItemHeight(final Tree tree) {
/*
* Bug in Linux. The method getItemHeight doesn't always return the correct value.
if (fLinuxItemHeight != 0) {
return fLinuxItemHeight;
}
- ArrayList<TreeItem> treeItems = getVisibleExpandedItems(tree);
+ List<TreeItem> treeItems = getVisibleExpandedItems(tree);
if (treeItems.size() > 1) {
final TreeItem treeItem0 = treeItems.get(0);
final TreeItem treeItem1 = treeItems.get(1);