blob: c30dc217edbbf247d3490d5e66ce1022b36b5009 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 - 2006 University Of British Columbia and others.
* 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:
* University Of British Columbia - initial API and implementation
*******************************************************************************/
/*
* Created on Jan 26, 2005
*/
package org.eclipse.mylyn.internal.dltk.search;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IMember;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.search.IDLTKSearchConstants;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.internal.ui.search.DLTKSearchQuery;
import org.eclipse.dltk.internal.ui.search.DLTKSearchResult;
import org.eclipse.dltk.ui.search.ElementQuerySpecification;
import org.eclipse.dltk.ui.search.QuerySpecification;
import org.eclipse.mylyn.context.core.AbstractContextStructureBridge;
import org.eclipse.mylyn.context.core.IInteractionElement;
import org.eclipse.mylyn.internal.context.core.AbstractRelationProvider;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.internal.context.core.IActiveSearchListener;
import org.eclipse.mylyn.internal.context.core.IActiveSearchOperation;
import org.eclipse.mylyn.internal.dltk.DLTKStructureBridge;
import org.eclipse.mylyn.internal.dltk.MylynStatusHandler;
import org.eclipse.mylyn.internal.resources.ui.ResourcesUiBridgePlugin;
import org.eclipse.search.ui.ISearchResult;
import org.eclipse.search2.internal.ui.InternalSearchUI;
public abstract class AbstractDLTKRelationProvider extends
AbstractRelationProvider {
public static final String ID_GENERIC = "org.eclipse.dltk.mylyn.relation";
public static final String NAME = "DLTK relationships";
private static final int DEFAULT_DEGREE = 2;
private static final List runningJobs = new ArrayList();
public String getGenericId() {
return ID_GENERIC;
}
protected AbstractDLTKRelationProvider(String structureKind, String id) {
super(structureKind, id);
}
protected void findRelated(final IInteractionElement node,
int degreeOfSeparation) {
if (node == null)
return;
if (node.getContentType() == null) {
MylynStatusHandler.log("null content type for: " + node, this);
return;
}
if (!node.getContentType().equals(DLTKStructureBridge.CONTENT_TYPE))
return;
IModelElement modelElement = DLTKCore
.create(node.getHandleIdentifier());
if (!acceptElement(modelElement) || !modelElement.exists()) {
return;
}
IDLTKSearchScope scope = createSearchScope(modelElement,
degreeOfSeparation);
if (scope != null)
runJob(node, degreeOfSeparation, getId());
}
private IDLTKSearchScope createSearchScope(IModelElement element,
int degreeOfSeparation) {
Set landmarks = ContextCorePlugin.getContextManager()
.getActiveLandmarks();
List interestingElements = ContextCorePlugin.getContextManager()
.getActiveContext().getInteresting();
Set searchElements = new HashSet();
int includeMask = IDLTKSearchScope.SOURCES;
if (degreeOfSeparation == 1) {
// for (IInteractionElement landmark : landmarks) {
for (Iterator it = landmarks.iterator(); it.hasNext();) {
IInteractionElement landmark = (IInteractionElement) it.next();
AbstractContextStructureBridge bridge = ContextCorePlugin
.getDefault().getStructureBridge(
landmark.getContentType());
if (includeNodeInScope(landmark, bridge)) {
Object o = bridge.getObjectForHandle(landmark
.getHandleIdentifier());
if (o instanceof IModelElement) {
IModelElement landmarkElement = (IModelElement) o;
if (landmarkElement.exists()) {
if (landmarkElement instanceof IMember
&& !landmark.getInterest().isPropagated()) {
searchElements.add(((IMember) landmarkElement)
.getSourceModule());
} else if (landmarkElement instanceof ISourceModule) {
searchElements.add(landmarkElement);
}
}
}
}
}
} else if (degreeOfSeparation == 2) {
// for (IInteractionElement interesting : interestingElements) {
for (Iterator it = interestingElements.iterator(); it.hasNext();) {
IInteractionElement interesting = (IInteractionElement) it
.next();
AbstractContextStructureBridge bridge = ContextCorePlugin
.getDefault().getStructureBridge(
interesting.getContentType());
if (includeNodeInScope(interesting, bridge)) {
Object object = bridge.getObjectForHandle(interesting
.getHandleIdentifier());
if (object instanceof IModelElement) {
IModelElement interestingElement = (IModelElement) object;
if (interestingElement.exists()) {
if (interestingElement instanceof IMember
&& !interesting.getInterest()
.isPropagated()) {
searchElements
.add(((IMember) interestingElement)
.getSourceModule());
} else if (interestingElement instanceof ISourceModule) {
searchElements.add(interestingElement);
}
}
}
}
}
} else if (degreeOfSeparation == 3 || degreeOfSeparation == 4) {
// for (IInteractionElement interesting : interestingElements) {
for (Iterator it = interestingElements.iterator(); it.hasNext();) {
IInteractionElement interesting = (IInteractionElement) it
.next();
AbstractContextStructureBridge bridge = ContextCorePlugin
.getDefault().getStructureBridge(
interesting.getContentType());
if (includeNodeInScope(interesting, bridge)) {
IResource resource = ResourcesUiBridgePlugin.getDefault()
.getResourceForElement(interesting, true);
if (resource != null) {
IProject project = resource.getProject();
// if (project != null &&
// DLTKProject.hasScriptNature(project) &&
// project.exists()) {
if (project != null && project.exists()) {
IScriptProject scriptProject = DLTKCore
.create(project);// ((IModelElement)o).
if (scriptProject != null && scriptProject.exists())
searchElements.add(scriptProject);
}
}
}
}
if (degreeOfSeparation == 4) {
includeMask = IDLTKSearchScope.SOURCES
| IDLTKSearchScope.APPLICATION_LIBRARIES
| IDLTKSearchScope.SYSTEM_LIBRARIES;
}
} else if (degreeOfSeparation == 5) {
return SearchEngine.createWorkspaceScope(null);
}
if (searchElements.size() == 0) {
return null;
} else {
IModelElement[] elements = new IModelElement[searchElements.size()];
int j = 0;
// for (IModelElement searchElement : searchElements) {
for (Iterator it = searchElements.iterator(); it.hasNext();) {
IModelElement searchElement = (IModelElement) it.next();
elements[j] = searchElement;
j++;
}
return SearchEngine.createSearchScope(elements, includeMask, null);
}
}
/**
* Only include Script elements and files.
*/
private boolean includeNodeInScope(IInteractionElement interesting,
AbstractContextStructureBridge bridge) {
if (interesting == null || bridge == null) {
return false;
} else {
if (interesting.getContentType() == null) {
// TODO: remove
MylynStatusHandler.log("null content type for: "
+ interesting.getHandleIdentifier(), this);
return false;
} else {
return interesting.getContentType().equals(
DLTKStructureBridge.CONTENT_TYPE)
|| bridge.isDocument(interesting.getHandleIdentifier());
}
}
}
protected boolean acceptResultElement(IModelElement element) {
return true;
}
protected boolean acceptElement(IModelElement modelElement) {
return modelElement != null
&& (modelElement instanceof IMember || modelElement instanceof IType);
}
private void runJob(final IInteractionElement node,
final int degreeOfSeparation, final String kind) {
int limitTo = 0;
if (kind.equals(DLTKReferencesProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
} else if (kind.equals(DLTKImplementorsProvider.ID)) {
// limitTo = IDLTKSearchConstants.IMPLEMENTORS;
} else if (kind.equals(DLTKTestingReferencesProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
} else if (kind.equals(DLTKReadAccessProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
} else if (kind.equals(DLTKWriteAccessProvider.ID)) {
limitTo = IDLTKSearchConstants.REFERENCES;
}
final DLTKSearchOperation query = (DLTKSearchOperation) getSearchOperation(
node, limitTo, degreeOfSeparation);
if (query == null)
return;
DLTKSearchJob job = new DLTKSearchJob(query.getLabel(), query);
query.addListener(new IActiveSearchListener() {
private boolean gathered = false;
public boolean resultsGathered() {
return gathered;
}
public void searchCompleted(List l) {
if (l == null)
return;
List relatedHandles = new ArrayList();
Object[] elements = l.toArray();
for (int i = 0; i < elements.length; i++) {
if (elements[i] instanceof IModelElement)
relatedHandles.add((IModelElement) elements[i]);
}
// for (IModelElement element : relatedHandles) {
for (ListIterator it = relatedHandles.listIterator(); it
.hasNext();) {
IModelElement element = (IModelElement) it.next();
if (!acceptResultElement(element))
continue;
incrementInterest(node, DLTKStructureBridge.CONTENT_TYPE,
element.getHandleIdentifier(), degreeOfSeparation);
}
gathered = true;
AbstractDLTKRelationProvider.this.searchCompleted(node);
}
});
InternalSearchUI.getInstance();
runningJobs.add(job);
job.setPriority(Job.DECORATE - 10);
job.schedule();
}
public IActiveSearchOperation getSearchOperation(IInteractionElement node,
int limitTo, int degreeOfSeparation) {
IModelElement modelElement = DLTKCore
.create(node.getHandleIdentifier());
if (modelElement == null || !modelElement.exists())
return null;
IDLTKSearchScope scope = createSearchScope(modelElement,
degreeOfSeparation);
if (scope == null)
return null;
QuerySpecification specs = new ElementQuerySpecification(modelElement,
limitTo, scope, "Mylyn degree of separation: "
+ degreeOfSeparation);
return new DLTKSearchOperation(specs);
}
protected static class DLTKSearchJob extends Job {
private DLTKSearchOperation op;
public DLTKSearchJob(String name, DLTKSearchOperation op) {
super(name);
this.op = op;
}
/**
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
protected IStatus run(IProgressMonitor monitor) {
return op.run(monitor);
}
}
protected static class DLTKSearchOperation extends DLTKSearchQuery
implements IActiveSearchOperation {
private ISearchResult result = null;
public ISearchResult getSearchResult() {
if (result == null)
result = new DLTKSearchResult(this);
new DLTKActiveSearchResultUpdater((DLTKSearchResult) result);
return result;
}
public IStatus run(IProgressMonitor monitor) {
try {
IStatus runStatus = super.run(monitor);
ISearchResult result = getSearchResult();
if (result instanceof DLTKSearchResult) {
// TODO make better
Object[] objs = ((DLTKSearchResult) result).getElements();
if (objs == null) {
notifySearchCompleted(null);
} else {
List l = new ArrayList();
for (int i = 0; i < objs.length; i++) {
l.add(objs[i]);
}
notifySearchCompleted(l);
}
}
return runStatus;
} catch (ConcurrentModificationException cme) {
MylynStatusHandler.log(cme, "script search failed");
} catch (Throwable t) {
MylynStatusHandler.log(t, "script search failed");
}
IStatus status = new Status(IStatus.WARNING,
ContextCorePlugin.PLUGIN_ID, IStatus.OK,
"could not run Script search", null);
notifySearchCompleted(null);
return status;
}
/**
* Constructor
*
* @param data
*/
public DLTKSearchOperation(QuerySpecification data) {
super(data);
}
/** List of listeners wanting to know about the searches */
private List listeners = new ArrayList();
/**
* Add a listener for when the bugzilla search is completed
*
* @param l
* The listener to add
*/
public void addListener(IActiveSearchListener l) {
// add the listener to the list
listeners.add(l);
}
/**
* Remove a listener for when the bugzilla search is completed
*
* @param l
* The listener to remove
*/
public void removeListener(IActiveSearchListener l) {
// remove the listener from the list
listeners.remove(l);
}
/**
* Notify all of the listeners that the bugzilla search is completed
*
* @param doiList
* A list of BugzillaSearchHitDoiInfo
* @param member
* The IMember that the search was performed on
*/
public void notifySearchCompleted(List l) {
// go through all of the listeners and call
// searchCompleted(colelctor,
// member)
// for (IActiveSearchListener listener : listeners) {
for (ListIterator it = listeners.listIterator(); it.hasNext();) {
IActiveSearchListener listener = (IActiveSearchListener) it
.next();
listener.searchCompleted(l);
}
}
}
public void stopAllRunningJobs() {
// for (Job j : runningJobs) {
for (ListIterator it = runningJobs.listIterator(); it.hasNext();) {
Job j = (Job) it.next();
j.cancel();
}
runningJobs.clear();
}
protected int getDefaultDegreeOfSeparation() {
return DEFAULT_DEGREE;
}
}