/**
* Copyright (c) 2012 Cloudsmith Inc. and other contributors, as listed below.
* 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:
* itemis AG - intial API and implementation
* Cloudsmith
*
*/
package org.cloudsmith.geppetto.pp.dsl.ui.editor.findrefs;
import java.util.Iterator;
import java.util.List;
import org.cloudsmith.geppetto.pp.dsl.linking.PPResourceDescription;
import org.cloudsmith.geppetto.pp.dsl.ui.editor.findrefs.PPReferenceSearchResultEvents.Added;
import org.cloudsmith.geppetto.pp.dsl.ui.editor.findrefs.PPReferenceSearchResultEvents.Reset;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.search.ui.ISearchResultListener;
import org.eclipse.search.ui.SearchResultEvent;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IReferenceDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescription.Delta;
import org.eclipse.xtext.resource.IResourceDescription.Event;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.ui.editor.StatefulResourceDescription;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
/**
* @author Jan Koehnlein - Initial contribution and API
*/
public class ReferenceSearchResultContentProvider implements ITreeContentProvider, ISearchResultListener,
IResourceDescription.Event.Listener {
private class UIUpdater extends UIJob {
public UIUpdater() {
super("PPReferenceSearchViewUpdater");
setSystem(true);
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
isUIUpdateScheduled = false;
List<SearchResultEvent> events;
synchronized(batchedSearchResultEvents) {
events = Lists.newArrayList(batchedSearchResultEvents);
batchedSearchResultEvents.clear();
}
SubMonitor progress = SubMonitor.convert(monitor, events.size());
for(SearchResultEvent event : events) {
if(event instanceof Added) {
addReference(((Added) event).getReferenceDescription(), true);
}
else if(event instanceof Reset) {
if(rootNodes != null && !rootNodes.isEmpty()) {
synchronized(viewer) {
viewer.remove(
viewer.getInput(), Iterables.toArray(rootNodes, ReferenceSearchViewTreeNode.class));
rootNodes = null;
}
}
}
progress.worked(1);
}
viewer.refresh();
viewer.expandToLevel(1);
return Status.OK_STATUS;
}
}
private IResourceDescriptions resourceDescriptions;
private List<ReferenceSearchViewTreeNode> rootNodes;
private TreeViewer viewer;
private List<SearchResultEvent> batchedSearchResultEvents;
private volatile boolean isUIUpdateScheduled;
@Inject
public ReferenceSearchResultContentProvider(IResourceDescriptions resourceDescriptions) {
batchedSearchResultEvents = Lists.newArrayList();
this.resourceDescriptions = resourceDescriptions;
if(resourceDescriptions instanceof PPResourceDescription.Event.Source) {
((PPResourceDescription.Event.Source) resourceDescriptions).addListener(this);
}
}
private void addReference(IReferenceDescription referenceDescription, boolean isUpdateViewer) {
URI containerEObjectURI = referenceDescription.getContainerEObjectURI();
// IEObjectDescription sourceContainer = referenceDescription.getSourceContainer(); // getContainerEObjectURI();
// URI containerEObjectURI = sourceContainer == null
// ? null
// : sourceContainer.getEObjectURI();
final URI eObjectURI = (containerEObjectURI == null)
? referenceDescription.getSourceEObjectUri()
: containerEObjectURI;
IResourceDescription resourceDescription = resourceDescriptions.getResourceDescription(eObjectURI.trimFragment());
if(resourceDescription != null) {
ReferenceSearchViewTreeNode resourceNode = resourceNode(resourceDescription, isUpdateViewer);
ReferenceSearchViewTreeNode referenceNode = null;
for(IEObjectDescription eObjectDescription : resourceDescription.getExportedObjects()) {
if(eObjectDescription.getEObjectURI().equals(eObjectURI)) {
referenceNode = new ReferenceSearchViewTreeNode(
resourceNode, referenceDescription, eObjectDescription);
break;
}
}
if(referenceNode == null)
referenceNode = new ReferenceSearchViewTreeNode(
resourceNode, referenceDescription, referenceDescription);
}
}
public void descriptionsChanged(final Event event) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if(rootNodes != null) {
for(Delta delta : event.getDeltas()) {
if(!(delta.getNew() instanceof StatefulResourceDescription)) {
for(Iterator<ReferenceSearchViewTreeNode> i = rootNodes.iterator(); i.hasNext();) {
ReferenceSearchViewTreeNode rootNode = i.next();
if(((IResourceDescription) rootNode.getDescription()).getURI().equals(delta.getUri())) {
if(delta.getNew() == null) {
i.remove();
viewer.remove(rootNode);
break;
}
Iterable<IReferenceDescription> newReferenceDescriptions = delta.getNew().getReferenceDescriptions();
List<ReferenceSearchViewTreeNode> removedReferenceNodes = Lists.newArrayList();
for(ReferenceSearchViewTreeNode referenceNode : rootNode.getChildren()) {
final IReferenceDescription refDesc = ((IReferenceDescription) referenceNode.getDescription());
final URI referenceSourceURI = refDesc.getSourceEObjectUri();
final URI referenceTargetURI = refDesc.getTargetEObjectUri();
if(Iterables.isEmpty(Iterables.filter(
newReferenceDescriptions, new Predicate<IReferenceDescription>() {
public boolean apply(IReferenceDescription input) {
return input.getSourceEObjectUri().equals(referenceSourceURI) &&
input.getTargetEObjectUri().equals(referenceTargetURI);
}
}))) {
removedReferenceNodes.add(referenceNode);
}
}
for(ReferenceSearchViewTreeNode removedReferenceNode : removedReferenceNodes) {
rootNode.removeChild(removedReferenceNode);
}
if(rootNode.getChildren().isEmpty()) {
i.remove();
viewer.remove(rootNode);
break;
}
viewer.remove(
rootNode,
Iterables.toArray(removedReferenceNodes, ReferenceSearchViewTreeNode.class));
}
}
}
}
}
}
});
}
public void dispose() {
rootNodes = null;
}
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof ReferenceSearchViewTreeNode) {
return Iterables.toArray(
((ReferenceSearchViewTreeNode) parentElement).getChildren(), ReferenceSearchViewTreeNode.class);
}
return null;
}
public Object[] getElements(Object inputElement) {
if(rootNodes == null || rootNodes.isEmpty()) {
return new Object[0];
}
return Iterables.toArray(rootNodes, ReferenceSearchViewTreeNode.class);
}
public Object getParent(Object element) {
if(element instanceof ReferenceSearchViewTreeNode) {
return ((ReferenceSearchViewTreeNode) element).getParent();
}
return null;
}
public boolean hasChildren(Object element) {
if(element instanceof ReferenceSearchViewTreeNode) {
return !((ReferenceSearchViewTreeNode) element).getChildren().isEmpty();
}
return false;
}
public void inputChanged(final Viewer viewer, Object oldInput, Object newInput) {
synchronized(viewer) {
if(rootNodes != null) {
rootNodes.clear();
}
if(oldInput instanceof PPReferenceSearchResult) {
((PPReferenceSearchResult) oldInput).removeListener(this);
}
if(newInput instanceof PPReferenceSearchResult && viewer instanceof TreeViewer) {
((PPReferenceSearchResult) newInput).addListener(this);
this.viewer = (TreeViewer) viewer;
for(IReferenceDescription referenceDescription : ((PPReferenceSearchResult) newInput).getMatchingReferences()) {
addReference(referenceDescription, false);
}
}
}
}
private ReferenceSearchViewTreeNode resourceNode(IResourceDescription resourceDescription, boolean isUpdateViewer) {
if(rootNodes == null) {
rootNodes = Lists.newArrayList();
}
for(ReferenceSearchViewTreeNode node : rootNodes) {
Object nodeDescription = node.getDescription();
if(nodeDescription instanceof IResourceDescription) {
if(((IResourceDescription) nodeDescription).getURI().equals(resourceDescription.getURI())) {
return node;
}
}
}
ReferenceSearchViewTreeNode node = new ReferenceSearchViewTreeNode(
null, resourceDescription, resourceDescription);
rootNodes.add(node);
if(isUpdateViewer) {
viewer.add(viewer.getInput(), node);
}
return node;
}
public void searchResultChanged(final SearchResultEvent e) {
synchronized(batchedSearchResultEvents) {
batchedSearchResultEvents.add(e);
}
if(!isUIUpdateScheduled) {
isUIUpdateScheduled = true;
new UIUpdater().schedule();
}
}
}