Eclipse : Using Standard Source Lookup Tab

If you are writing your own debugger in eclipse, you may want to allow users to provide source lookup paths. Eclipse framework provides a standard Source Tab ("org.eclipse.debug.ui.sourcelookup.SourceLookupTab") that you can add to your debug launch configration tab groups.
By default source tab include java classpath entries and allows users to add various java source paths such as Archive file etc. In your launch configuaration you may want to limit the kind of entries users can add to source tab and control default entries displayed in source tab.

To ensure that Source Tab allows users to add only specific types of entries, in your "source lookup director" class override following method.

public boolean supportsSourceContainerType(ISourceContainerType type);

Here is a sample implmenentaion of source lookup director that allows users to add only workspace projects , workspace folders and external directories.


public class MySourceLookupDirector extends AbstractSourceLookupDirector {

@Override
public boolean supportsSourceContainerType(ISourceContainerType type) {
if(type.getId().equals(ProjectSourceContainer.TYPE_ID))
return true;
if(type.getId().equals(FolderSourceContainer.TYPE_ID))
return true;
if(type.getId().equals(DirectorySourceContainer.TYPE_ID))
return true;
return false;
}
}


To control default entries in Source Tab, make sure that you provide implementaion for ISourcePathComputerDelegate interface. Here is a sample implementation that displays all workspace project as default entries in source Tab:


public class MySourcePathComputerDelegate implements
ISourcePathComputerDelegate {

public ISourceContainer[] computeSourceContainers(ILaunchConfiguration configuration,
IProgressMonitor monitor)throws CoreException
{
return createSourceContainers(configuration);
}

protected ISourceContainer[] createSourceContainers(ILaunchConfiguration configuration)
throws CoreException {

List containers = new ArrayList();
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();

for (IProject prj : projects) {
if(prj.isOpen())
containers.add(new ProjectSourceContainer(prj, true));
}
return (ISourceContainer[]) containers.toArray(new ISourceContainer[containers.size()]);
}
}


To perform the source lookup, implement ISourceLookupParticipant or extend from AbstractSourceLookupParticipant as below:


//used to when source is not found in specified source lookup paths
public class SampleSourceNotFound {

private Object artifact;
private String message;

public SampleSourceNotFound(Object artifact) {
this.artifact = artifact;
}

public SampleSourceNotFound(Object artifact,String message) {
this.artifact = artifact;
this.message = message;
}

public Object getArtifact() {
return artifact;
}

public String getMessage(){
return message;
}
}

public class MySourceLookupParticipant extends AbstractSourceLookupParticipant {

@Override
public Object[] findSourceElements(Object object) throws CoreException {

String name = getSourceName(object);
Object[] result = super.findSourceElements(name);
// super implmentaion will lookup using SourceContainers added by user and /
// or default provided by ISourcePathComputerDelegate

if (result == null || result.lenght == 0) {
result = new SampleSourceNotFound[1];
result[0] = new SampleSourceNotFound(object);
}
return result;
}
// object is generally stack frame or breakpoint instance.
// get the name of source file from object.
public String getSourceName(Object object) {
if (object instanceof MyStackFrame) {
return ((MyStackFrame)object).getSourceName();
}
return null;
}

}


For the returned result, eclipse debug framework will get the editor from debug model prensentation.
Eclipse provides a standard "source not found" editor (org.eclipse.debug.ui.sourcelookup.CommonSourceNotFoundEditorInput) that you can show when file is not found in user specified source lookup paths. e.g.


public class MyDebugModelPresentation implements IDebugModelPresentation {

public IEditorInput getEditorInput(Object element){
// you may want to add additional conditions based on type of sorce
// entries / containers supported by your source tab.

if (element instanceof IPath) {
IPath path = (IPath) element;
return getEditorInputFromPath(path);
}
if (element instanceof IFile) {
return new FileEditorInput((IFile) element);
}
if (element instanceof SampleSourceNotFound) {
return new CommonSourceNotFoundEditorInput(element);
}
}
}


You may want to show custom source not found editor (for various reasons such as displaying different message than the default one). In your debug model presentation, check if
result is instnace of SampleSourceNotFound and if so, return the id of your custom editor input.
Here is a sample implentation:


public class MySourceNotFoundEditorInput extends CommonSourceNotFoundEditorInput {

// The message to display in editor page instead of "Source not found.".
private String fMessage;

public MySourceNotFoundEditorInput(SampleSourceNotFound object) {

super(object.getArtifact());

// add getMessage() to SampleSourceNot Found or just use hardcode string
fMessage = object.getMessage();

//Or use something like :
fMessage = "Can not find" + object.getArtifact();
}

@Override
public String getToolTipText() {
// custom message to be displayed in the editor before Edit source lookup Button.
return fMessage;
}
}


To use this editor input, just modify your debug model presentation as below:


public class MyDebugModelPresentation implements IDebugModelPresentation {

public IEditorInput getEditorInput(Object element){
// :
// other conditions shown above
// :
if (element instanceof SampleSourceNotFound) {
return new MySourceNotFoundEditorInput(element);
}
}
}