import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
* this class typically need to override the getColumnText method if they
* have more than one column to display
*/
- protected static class TreeLabelProvider implements ITableLabelProvider {
+ protected static class TreeLabelProvider implements ITableLabelProvider, ILabelProvider {
@Override
public void addListener(ILabelProviderListener listener) {
return new String();
}
+ /**
+ * @since 3.1
+ */
+ @Override
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ /**
+ * @since 3.1
+ */
+ @Override
+ public String getText(Object element) {
+ TimeGraphEntry entry = (TimeGraphEntry) element;
+ return entry.getName();
+ }
+
}
private class BuildThread extends Thread {
fTimeGraphViewer.refresh();
fInhibitTreeSelection = false;
alignTreeItems(true);
- // Reset selection to first entry
+ // Reset selection
if (fFilterDialog.getResult().length > 0) {
- setSelection((ITimeGraphEntry) fFilterDialog.getResult()[0]);
+ setSelection(null);
}
}
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 Inria
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Generoso Pagano, Inria - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckable;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * A <code>FilteredTree</code> wrapping a <code>CheckboxTreeViewer</code>.
+ *
+ * This tree keeps the check state of the nodes in sync, regardless of the fact
+ * that a node is filtered or not. This way, even if an node is filtered (not
+ * visible), the caller can get and set the check state.
+ *
+ * Note that all the "uncheck" operations act only on what is not filtered and
+ * what is child of something not filtered (even if such a child is filtered).
+ * On the contrary, all the "check" operations act only on what is not filtered.
+ *
+ * @author "Generoso Pagano <generoso.pagano@inria.fr>"
+ * @since 3.1
+ */
+public class FilteredCheckboxTree extends FilteredTree implements ICheckable {
+
+ /**
+ * Set containing only the tree items that are checked
+ */
+ private Set<Object> fObjects = new HashSet<>();
+
+ /**
+ * Handle to the tree viewer
+ */
+ private CheckboxTreeViewer fCheckboxTreeViewer;
+
+ /**
+ * Create a new instance of the receiver.
+ *
+ * @param parent
+ * the parent <code>Composite</code>
+ * @param treeStyle
+ * the style bits for the <code>Tree</code>
+ * @param filter
+ * the filter to be used
+ * @param useNewLook
+ * <code>true</code> if the new <code>FilteredTree</code> look
+ * should be used
+ */
+ public FilteredCheckboxTree(Composite parent, int treeStyle, PatternFilter filter,
+ boolean useNewLook) {
+ super(parent, treeStyle, filter, useNewLook);
+ }
+
+ @Override
+ protected TreeViewer doCreateTreeViewer(Composite parentComposite, int style) {
+ fCheckboxTreeViewer = new CheckboxTreeViewer(parentComposite, style);
+ fCheckboxTreeViewer.addCheckStateListener(new ICheckStateListener() {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ if (event.getChecked()) {
+ fObjects.add(event.getElement());
+ } else {
+ fObjects.remove(event.getElement());
+ }
+ }
+ });
+ return fCheckboxTreeViewer;
+ }
+
+ @Override
+ protected WorkbenchJob doCreateRefreshJob() {
+ WorkbenchJob job = super.doCreateRefreshJob();
+ job.addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(IJobChangeEvent event) {
+ fCheckboxTreeViewer.expandAll();
+ fCheckboxTreeViewer.setCheckedElements(getCheckedElements());
+ }
+ });
+ return job;
+ }
+
+ @Override
+ public boolean getChecked(Object element) {
+ return fObjects.contains(element);
+ }
+
+ @Override
+ public boolean setChecked(Object element, boolean state) {
+ boolean checkable = fCheckboxTreeViewer.setChecked(element, state);
+ if (!state) {
+ fObjects.remove(element);
+ } else if (checkable) {
+ fObjects.add(element);
+ }
+ return checkable;
+ }
+
+ @Override
+ public void addCheckStateListener(ICheckStateListener listener) {
+ fCheckboxTreeViewer.addCheckStateListener(listener);
+ }
+
+ @Override
+ public void removeCheckStateListener(ICheckStateListener listener) {
+ fCheckboxTreeViewer.addCheckStateListener(listener);
+ }
+
+ /**
+ * Returns all the checked elements of this tree, either visible or not.
+ *
+ * @return an array containing all the checked elements
+ */
+ public Object[] getCheckedElements() {
+ return fObjects.toArray();
+ }
+
+ /**
+ * Checks all the passed elements and unchecks all the other.
+ *
+ * @param elements
+ * the elements to check
+ */
+ public void setCheckedElements(Object[] elements) {
+ fObjects = new HashSet<>();
+ for (Object element : elements) {
+ fObjects.add(element);
+ }
+ fCheckboxTreeViewer.setCheckedElements(elements);
+ }
+
+ /**
+ * Sets the check state for the given element and its children in this
+ * viewer. The unchecked state is always set, while the checked state is set
+ * only on visible elements.
+ *
+ * @param element
+ * the element
+ * @param state
+ * the check state to set
+ * @return <code>true</code> if the check state could be set, and
+ * <code>false</code> otherwise
+ */
+ public boolean setSubtreeChecked(Object element, boolean state) {
+ checkSubtree(element, state);
+ return fCheckboxTreeViewer.setSubtreeChecked(element, state);
+ }
+
+ /**
+ * Recursively sets the check state on an element and its children, using
+ * the politic specified in {@link #setSubtreeChecked(Object, boolean)}
+ * documentation.
+ *
+ * @param element
+ * the element
+ * @param state
+ * the check state to set
+ */
+ private void checkSubtree(Object element, boolean state) {
+ if (!state || (fCheckboxTreeViewer.testFindItem(element) != null)) {
+ if (state) {
+ fObjects.add(element);
+ } else {
+ fObjects.remove(element);
+ }
+ for (Object o : ((ITreeContentProvider) fCheckboxTreeViewer.getContentProvider()).getChildren(element)) {
+ checkSubtree(o, state);
+ }
+ }
+ }
+
+}
* align the selection buttons to the right
* François Rajotte - Support for multiple columns + selection control
* Patrick Tasse - Fix Sonar warnings
+ * Generoso Pagano - Add tree filter
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.dialogs.SelectionStatusDialog;
/**
- * Filter dialog for the time graphs
- * This class is derived from the CheckedTreeSelectionDialog
- * It was necessary to develop this similar dialog to allow multiple columns
+ * Filter dialog for the time graphs This class is derived from the
+ * CheckedTreeSelectionDialog It was necessary to develop this similar dialog to
+ * allow multiple columns
*
* @version 1.0
* @since 2.0
private static final int DEFAULT_WIDTH = 60;
private static final int DEFAULT_HEIGHT = 18;
- private CheckboxTreeViewer fViewer;
+ private FilteredCheckboxTree fTree;
private IBaseLabelProvider fLabelProvider;
}
/**
- * @param contentProvider The content provider for the table
+ * @param contentProvider
+ * The content provider for the table
*/
public void setContentProvider(ITreeContentProvider contentProvider) {
fContentProvider = contentProvider;
}
/**
- * @param labelProvider The label provider for the table
+ * @param labelProvider
+ * The label provider for the table
*/
public void setLabelProvider(IBaseLabelProvider labelProvider) {
fLabelProvider = labelProvider;
}
/**
- * @param columnNames An array of column names to display
+ * @param columnNames
+ * An array of column names to display
*/
public void setColumnNames(String[] columnNames) {
if (columnNames != null) {
protected void updateOKStatus() {
if (!fIsEmpty) {
if (fValidator != null) {
- fCurrStatus = fValidator.validate(fViewer.getCheckedElements());
+ fCurrStatus = fValidator.validate(fTree.getCheckedElements());
updateStatus(fCurrStatus);
} else if (!fCurrStatus.isOK()) {
fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
@Override
protected void computeResult() {
- setResult(Arrays.asList(fViewer.getCheckedElements()));
+ setResult(Arrays.asList(fTree.getCheckedElements()));
}
@Override
@Override
public void run() {
TimeGraphFilterDialog.super.create();
- fViewer.setCheckedElements(getInitialElementSelections()
+ fTree.setCheckedElements(getInitialElementSelections()
.toArray());
if (fExpandedElements != null) {
- fViewer.setExpandedElements(fExpandedElements);
+ fTree.getViewer().setExpandedElements(fExpandedElements);
}
updateOKStatus();
}
* @return the tree viewer
*/
protected CheckboxTreeViewer createTreeViewer(Composite parent) {
- fViewer = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.MULTI);
+ PatternFilter filter = new TreePatternFilter();
+ filter.setIncludeLeadingWildcard(true);
+ fTree = new FilteredCheckboxTree(parent, SWT.BORDER | SWT.MULTI, filter, true);
- Tree tree = fViewer.getTree();
+ Tree tree = fTree.getViewer().getTree();
tree.setHeaderVisible(true);
for (String columnName : fColumnNames) {
TreeColumn column = new TreeColumn(tree, SWT.LEFT);
column.pack();
}
- fViewer.setContentProvider(fContentProvider);
- fViewer.setLabelProvider(fLabelProvider);
- fViewer.addCheckStateListener(new CheckStateListener());
- fViewer.addCheckStateListener(new ICheckStateListener() {
- @Override
- public void checkStateChanged(CheckStateChangedEvent event) {
- updateOKStatus();
- }
- });
- fViewer.setComparator(fComparator);
+ fTree.getViewer().setContentProvider(fContentProvider);
+ fTree.getViewer().setLabelProvider(fLabelProvider);
+ fTree.addCheckStateListener(new CheckStateListener());
+ fTree.getViewer().setComparator(fComparator);
if (fFilters != null) {
for (int i = 0; i != fFilters.size(); i++) {
- fViewer.addFilter(fFilters.get(i));
+ fTree.getViewer().addFilter(fFilters.get(i));
}
}
- fViewer.setInput(fInput);
+ fTree.getViewer().setInput(fInput);
- //pack the columns again for a nice view...
+ // pack the columns again for a nice view...
for (TreeColumn column : tree.getColumns()) {
column.pack();
}
- return fViewer;
+ return (CheckboxTreeViewer) fTree.getViewer();
}
/**
* @return the tree viewer
*/
protected CheckboxTreeViewer getTreeViewer() {
- return fViewer;
+ return (CheckboxTreeViewer) fTree.getViewer();
}
/**
IDialogConstants.DESELECT_ALL_ID, Messages.TmfTimeFilterDialog_UNCHECK_ALL,
false);
-
/*
* Apply the layout again after creating the buttons to override
* createButton messing with the columns
checkSelectedButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- TreeSelection selection = (TreeSelection) fViewer.getSelection();
+ TreeSelection selection = (TreeSelection) fTree.getViewer().getSelection();
for (Object element : selection.toArray()) {
checkElement(element);
checkSubtreeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- TreeSelection selection = (TreeSelection) fViewer.getSelection();
+ TreeSelection selection = (TreeSelection) fTree.getViewer().getSelection();
for (Object element : selection.toArray()) {
checkElementAndSubtree(element);
Object[] viewerElements = fContentProvider.getElements(fInput);
for (int i = 0; i < viewerElements.length; i++) {
- fViewer.setSubtreeChecked(viewerElements[i], true);
+ fTree.setSubtreeChecked(viewerElements[i], true);
}
updateOKStatus();
uncheckSelectedButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- TreeSelection selection = (TreeSelection) fViewer.getSelection();
+ TreeSelection selection = (TreeSelection) fTree.getViewer().getSelection();
for (Object element : selection.toArray()) {
uncheckElement(element);
uncheckSubtreeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- TreeSelection selection = (TreeSelection) fViewer.getSelection();
+ TreeSelection selection = (TreeSelection) fTree.getViewer().getSelection();
for (Object element : selection.toArray()) {
uncheckElement(element);
uncheckAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- fViewer.setCheckedElements(new Object[0]);
+ Object[] viewerElements = fContentProvider.getElements(fInput);
+ for (Object element : viewerElements) {
+ if (fTree.getViewer().testFindItem(element) != null) {
+ // uncheck only visible roots and their children
+ uncheckElement(element);
+ }
+ }
updateOKStatus();
}
});
* The element to check.
*/
private void checkElement(Object element) {
- fViewer.setChecked(element, true);
+ fTree.setChecked(element, true);
Object parent = fContentProvider.getParent(element);
- if (parent != null) {
+ if (parent != null && !fTree.getChecked(parent)) {
checkElement(parent);
}
}
* The element to uncheck.
*/
private void uncheckElement(Object element) {
- fViewer.setChecked(element, false);
+ fTree.setChecked(element, false);
for (Object child : fContentProvider.getChildren(element)) {
uncheckElement(child);
if (elements.length > 0 && fFilters != null) {
for (int i = 0; i < fFilters.size(); i++) {
ViewerFilter curr = fFilters.get(i);
- elements = curr.filter(fViewer, input, elements);
+ elements = curr.filter(fTree.getViewer(), input, elements);
}
}
return elements.length == 0;
}
} catch (ClassCastException e) {
return;
+ } finally {
+ updateOKStatus();
}
}
+
}
-}
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2014 Inria
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Generoso Pagano, Inria - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.dialogs;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.dialogs.PatternFilter;
+
+/**
+ * A filter extending the <code>org.eclipse.ui.dialogs.PatternFilter<code>.
+ *
+ * It redefines the {@link #isElementVisible(Viewer, Object)}} method in order
+ * to have a match on a node if: the node matches or one of the children matches
+ * or one of the parents matches.
+ *
+ * @author "Generoso Pagano <generoso.pagano@inria.fr>"
+ * @since 3.1
+ */
+public class TreePatternFilter extends PatternFilter {
+
+ @Override
+ public boolean isElementVisible(Viewer viewer, Object element) {
+ return super.isElementVisible(viewer, element) || isChildMatch(viewer, element);
+ }
+
+ /**
+ * Check if at least one of the parents of this element is a match with the
+ * filter text.
+ *
+ * @param viewer
+ * the viewer that contains the element
+ * @param element
+ * the tree element to check
+ * @return true if the given element has a parent that matches the filter
+ * text
+ */
+ private boolean isChildMatch(Viewer viewer, Object element) {
+ Object parent = ((ITreeContentProvider) ((AbstractTreeViewer) viewer).getContentProvider())
+ .getParent(element);
+ while (parent != null) {
+ if (isLeafMatch(viewer, parent)) {
+ return true;
+ }
+ parent = ((ITreeContentProvider) ((AbstractTreeViewer) viewer).getContentProvider())
+ .getParent(parent);
+ }
+ return false;
+ }
+
+}