/*****************************************************************************
* Copyright (c) 2012 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.strategy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.papyrus.infra.tools.util.ListHelper;
import org.eclipse.papyrus.infra.widgets.Activator;
import org.eclipse.papyrus.infra.widgets.providers.EncapsulatedContentProvider;
import org.eclipse.papyrus.infra.widgets.providers.IHierarchicContentProvider;
public class ProviderBasedBrowseStrategy extends EncapsulatedContentProvider implements TreeBrowseStrategy {
protected ITreeContentProvider provider;
protected boolean filterElements = false;
protected final Map<Object, Boolean> cache = new HashMap<Object, Boolean>();
protected final Map<Object, Boolean> visibleChildCache = new HashMap<Object, Boolean>();
public ProviderBasedBrowseStrategy(ITreeContentProvider provider) {
setProvider(provider);
}
public ProviderBasedBrowseStrategy() {
}
public void setProvider(ITreeContentProvider provider) {
encapsulated = provider;
this.provider = provider;
filterElements = provider instanceof IHierarchicContentProvider;
clearCache();
}
@Override
public Object[] getElements() {
return getValidElements(super.getElements());
}
@Override
public Object[] getElements(Object inputElement) {
return getValidElements(super.getElements(inputElement));
}
/**
* Filters the valid root elements, ie. the root elements containing
* at least one valid child (Or being valid themselves)
*
* @param roots
* @return
*/
protected Object[] getValidElements(Object[] roots) {
if(filterElements) {
List<Object> rootsList = ListHelper.asList(roots);
Iterator<?> iterator = rootsList.iterator();
while(iterator.hasNext()) {
if(!isValid(iterator.next(), new HashSet<Object>())) {
iterator.remove();
}
}
return rootsList.toArray();
}
return roots;
}
@Override
public Object[] getChildren(Object parent) {
if(provider == null) {
Activator.log.warn("The provider has not been initialized");
return new Object[0];
}
return getValidElements(super.getChildren(parent));
}
@Override
public boolean hasChildren(Object parent) {
//May be expensive
return getChildren(parent).length > 0;
}
protected boolean isValid(Object containerElement, Set<Object> visitedElements) {
if(!cache.containsKey(containerElement)) {
boolean isVisible;
if(browseElement(containerElement)) {
isVisible = isValidValue(containerElement) || hasOneVisibleChild(containerElement, visitedElements);
} else {
isVisible = false;
}
cache.put(containerElement, isVisible);
}
return cache.get(containerElement);
}
protected boolean browseElement(Object containerElement) {
return true;
}
protected boolean hasOneVisibleChild(Object element, Set<Object> visitedElements) {
if(!visibleChildCache.containsKey(element)) {
boolean result = false;
if(visitedElements.add(element)) {
for(Object child : super.getChildren(element)) {
if(isValid(child, visitedElements)) {
result = true;
break;
}
}
}
visibleChildCache.put(element, result);
}
return visibleChildCache.get(element);
}
public TreePath findPath(Object semanticElement, Object[] rootElements) {
return TreePath.EMPTY; //TODO : Naive search
}
protected void clearCache() {
cache.clear();
visibleChildCache.clear();
}
@Override
public void dispose() {
super.dispose();
clearCache();
}
/**
* {@inheritDoc}
*
* The basic implementation is a naive tree search
*
* @param elementToReveal
*/
@Override
public void revealSemanticElement(List<?> elementsToReveal) {
if(viewer != null) {
//FIXME: TreeViewers cannot do this search when the items have not yet be expanded.
//We need to search on the ContentProvider and pass a TreeSelection to the viewer
viewer.setSelection(new StructuredSelection(elementsToReveal), true);
}
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
super.inputChanged(viewer, oldInput, newInput);
this.viewer = viewer;
}
protected Viewer viewer;
}