diff options
Diffstat (limited to 'plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/AbstractTreeFilter.java')
-rw-r--r-- | plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/AbstractTreeFilter.java | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/AbstractTreeFilter.java b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/AbstractTreeFilter.java new file mode 100644 index 00000000000..6d1a42c2492 --- /dev/null +++ b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/AbstractTreeFilter.java @@ -0,0 +1,182 @@ +/***************************************************************************** + * Copyright (c) 2011 CEA LIST. + * + * 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: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.infra.widgets.providers; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.papyrus.infra.widgets.strategy.IStrategyBasedContentProvider; +import org.eclipse.papyrus.infra.widgets.strategy.ProviderBasedBrowseStrategy; +import org.eclipse.papyrus.infra.widgets.strategy.TreeBrowseStrategy; + +/** + * An abstract ViewerFilter for TreeViewers. + * + * You should extend this class whenever you want to implement a filter + * for a Tree. An element is visible : + * - If the method isVisible() returns true + * - If one of its children is visible + * - Optionally, if one of its parents is visible ({@link #showIfHasVisibleParent}) + * + * This class can implements a cache, which should be cleaned each time + * a parameter influencing the result of the {@link #isVisible(Viewer, Object, Object)} method is changed ({@link #clearCache()}). + * + * @author Camille Letavernier + */ +public abstract class AbstractTreeFilter extends ViewerFilter { + + /** + * If set to true, the results of the filter will be cached, to improve + * performance. + * + * Implementers are responsible of cleaning the cache (by calling {@link #clearCache()} when the result of the filter on a given + * element might change. + * + * For example, a string-pattern-based filter should clear the cache when + * the pattern changes. The viewer should also be refreshed. + */ + protected boolean useCache = true; + + /** + * Indicates if an element should be visible when one its parents is visible. + * This may be useful, for example, when you want to display all the contents + * of a given package, by entering a filter that will match this package. + */ + protected boolean showIfHasVisibleParent = false; + + /** + * Cache + */ + protected final Map<Object, Boolean> visibleElement = new HashMap<Object, Boolean>(); + + /** + * Cache + */ + protected final Map<Object, Boolean> visibleParent = new HashMap<Object, Boolean>(); + + /** + * Cache + */ + protected final Map<Object, Boolean> visibleChild = new HashMap<Object, Boolean>(); + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + + TreeBrowseStrategy strategy = null; + + if (viewer instanceof StructuredViewer) { + IContentProvider baseContentProvider = ((StructuredViewer) viewer).getContentProvider(); + if (baseContentProvider instanceof IStrategyBasedContentProvider) { + strategy = ((IStrategyBasedContentProvider) baseContentProvider).getRevealStrategy(); + } + + if (strategy == null && baseContentProvider instanceof ITreeContentProvider) { + strategy = new ProviderBasedBrowseStrategy((ITreeContentProvider) baseContentProvider); + } + } + + if (strategy == null) { // The contentProvider is not a TreeContentProvider + return isVisible(viewer, parentElement, element); + } + + return select(viewer, parentElement, element, strategy); + } + + protected boolean select(Viewer viewer, Object parentElement, Object element, TreeBrowseStrategy strategy) { + Set<Object> visitedChildren = new HashSet<Object>(); + Set<Object> visitedParents = new HashSet<Object>(); + if (useCache && visibleElement.containsKey(element)) { + return visibleElement.get(element); + } + + boolean isVisible = isVisible(viewer, parentElement, element) || hasOneVisibleChild(viewer, element, strategy, visitedChildren); + + if (showIfHasVisibleParent) { + isVisible = isVisible || hasOneVisibleParent(viewer, element, strategy, visitedParents); + } + + if (useCache) { + visibleElement.put(element, isVisible); + } + + return isVisible; + } + + protected boolean hasOneVisibleChild(Viewer viewer, Object element, TreeBrowseStrategy strategy, Set<Object> visitedElements) { + // TODO : separate this method in -hasOneVisibleChild() and #doHasOneVisibleChild(), to handle the cache management in a private method, + // while letting the opportunity to override the method + if (useCache && visibleChild.containsKey(element)) { + return visibleChild.get(element); + } + + boolean result = false; + if (!visitedElements.contains(element)) { + visitedElements.add(element); + + for (Object childElement : strategy.getChildren(element)) { + if (isVisible(viewer, element, childElement) || hasOneVisibleChild(viewer, childElement, strategy, visitedElements)) { + result = true; + break; + } + } + } + + if (useCache) { + visibleChild.put(element, result); + } + return result; + } + + protected boolean hasOneVisibleParent(Viewer viewer, Object element, TreeBrowseStrategy strategy, Set<Object> visitedElements) { + if (useCache && visibleParent.containsKey(element)) { + return visibleParent.get(element); + } + + boolean result = false; + if (!visitedElements.contains(element)) { + + visitedElements.add(element); + + Object parentElement = strategy.getParent(element); + if (parentElement == element || parentElement == null) { + result = isVisible(viewer, parentElement, element); + } else { + result = isVisible(viewer, null, parentElement) || hasOneVisibleParent(viewer, parentElement, strategy, visitedElements); + } + } + + if (useCache) { + visibleParent.put(element, result); + } + + return result; + } + + protected void clearCache() { + visibleElement.clear(); + visibleParent.clear(); + visibleChild.clear(); + } + + public abstract boolean isVisible(Viewer viewer, Object parentElement, Object element); + + public void setShowIfHasVisibleParent(boolean showIfHasVisibleParent) { + this.showIfHasVisibleParent = showIfHasVisibleParent; + } +} |