package org.jbpm.ui.editor.search;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.search.internal.ui.text.IFileSearchContentProvider;
import org.jbpm.ui.common.model.GraphElement;
import org.jbpm.ui.common.model.ProcessDefinition;
public class GPDTreeContentProvider implements ITreeContentProvider, IFileSearchContentProvider {
private final Object[] EMPTY_ARR = new Object[0];
private GPDSearchResult result;
private AbstractTreeViewer treeViewer;
private Map<Object, Set<Object>> fChildrenMap;
public GPDTreeContentProvider(AbstractTreeViewer viewer) {
this.treeViewer = viewer;
}
public Object[] getElements(Object inputElement) {
Object[] children = getChildren(inputElement);
int elementLimit = getElementLimit();
if (elementLimit != -1 && elementLimit < children.length) {
Object[] limitedChildren = new Object[elementLimit];
System.arraycopy(children, 0, limitedChildren, 0, elementLimit);
return limitedChildren;
}
return children;
}
private int getElementLimit() {
return 1000;
}
public void dispose() {
// nothing to do
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (newInput instanceof GPDSearchResult) {
initialize((GPDSearchResult) newInput);
}
}
protected synchronized void initialize(GPDSearchResult result) {
this.result = result;
fChildrenMap = new HashMap<Object, Set<Object>>();
if (result != null) {
Object[] elements = result.getElements();
for (int i = 0; i < elements.length; i++) {
insert(elements[i], false);
}
}
}
protected void insert(Object child, boolean refreshViewer) {
Object parent = getParent(child);
while (parent != null) {
if (insertChild(parent, child)) {
if (refreshViewer)
treeViewer.add(parent, child);
} else {
if (refreshViewer)
treeViewer.refresh(parent);
return;
}
child = parent;
parent = getParent(child);
}
if (insertChild(result, child)) {
if (refreshViewer)
treeViewer.add(result, child);
}
}
/**
* returns true if the child already was a child of parent.
*
* @param parent
* @param child
* @return Returns <code>true</code> if the child was added
*/
private boolean insertChild(Object parent, Object child) {
Set<Object> children = fChildrenMap.get(parent);
if (children == null) {
children = new HashSet<Object>();
fChildrenMap.put(parent, children);
}
return children.add(child);
}
protected void remove(Object element, boolean refreshViewer) {
// precondition here: fResult.getMatchCount(child) <= 0
if (hasChildren(element)) {
if (refreshViewer)
treeViewer.refresh(element);
} else {
if (result.getMatchCount(element) == 0) {
fChildrenMap.remove(element);
Object parent = getParent(element);
if (parent != null) {
removeFromSiblings(element, parent);
remove(parent, refreshViewer);
} else {
removeFromSiblings(element, result);
if (refreshViewer)
treeViewer.refresh();
}
} else {
if (refreshViewer) {
treeViewer.refresh(element);
}
}
}
}
private void removeFromSiblings(Object element, Object parent) {
Set<Object> siblings = fChildrenMap.get(parent);
if (siblings != null) {
siblings.remove(element);
}
}
public Object[] getChildren(Object parentElement) {
Set<Object> children = fChildrenMap.get(parentElement);
if (children == null)
return EMPTY_ARR;
return children.toArray();
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
public synchronized void elementsChanged(Object[] updatedElements) {
for (int i = 0; i < updatedElements.length; i++) {
if (result.getMatchCount(updatedElements[i]) > 0)
insert(updatedElements[i], true);
else
remove(updatedElements[i], true);
}
}
public void clear() {
initialize(result);
treeViewer.refresh();
}
public Object getParent(Object element) {
ElementMatch elementMatch = (ElementMatch) element;
GraphElement graphElement = elementMatch.getGraphElement();
if (graphElement instanceof ProcessDefinition)
return null;
if (elementMatch.getParent() != null) {
return elementMatch.getParent();
}
return new ElementMatch(graphElement.getParent());
}
}