blob: 7af0909e808b83e04d5b3cc71d76fde8dcf64dce [file] [log] [blame]
package org.eclipse.jdt.debug.ui;
/**********************************************************************
Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
This file is made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
**********************************************************************/
import java.text.MessageFormat;
import java.util.HashMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IPersistableSourceLocator;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaClassType;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.internal.debug.ui.DebugUIMessages;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.launcher.LauncherMessages;
import org.eclipse.jdt.internal.debug.ui.launcher.SourceElementLabelProvider;
import org.eclipse.jdt.internal.debug.ui.launcher.SourceElementQualifierProvider;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.sourcelookup.IJavaSourceLocation;
import org.eclipse.jdt.launching.sourcelookup.JavaSourceLocator;
import org.eclipse.ui.dialogs.TwoPaneElementSelector;
/**
* A source locator that prompts the user to find source when source cannot
* be found on the current source lookup path.
* <p>
* This class is intended to be instantiated. This class is not
* intended to be subclassed.
* </p>
* @since 2.0
*/
public class JavaUISourceLocator implements IPersistableSourceLocator {
/**
* Identifier for the 'Prompting Java Source Locator' extension
* (value <code>"org.eclipse.jdt.debug.ui.javaSourceLocator"</code>).
*/
public static final String ID_PROMPTING_JAVA_SOURCE_LOCATOR = IJavaDebugUIConstants.PLUGIN_ID + ".javaSourceLocator"; //$NON-NLS-1$
/**
* Launch configuration attribute indicating that this source locator should
* locate all source elements that correspond to a stack frame, rather than
* the first match. Default value is <code>false</code>.
*
* @since 2.1
*/
public static final String ATTR_FIND_ALL_SOURCE_ELEMENTS = IJavaDebugUIConstants.PLUGIN_ID + ".ATTR_FIND_ALL_SOURCE_ELEMENTS"; //$NON-NLS-1$
/**
* The project being debugged.
*/
private IJavaProject fJavaProject;
/**
* Underlying source locator.
*/
private JavaSourceLocator fSourceLocator;
/**
* Whether the user should be prompted for source.
* Initially true, until the user checks the 'do not
* ask again' box.
*/
private boolean fAllowedToAsk;
/**
* Whether to find all source elements for a stack frame (in case of
* dupliucates), or just the first match.
*/
private boolean fIsFindAllSourceElements = false;
/**
* A cache of types to associated source elements (when duplicates arise and
* the users chooses a source element, it is remembered).
*/
private HashMap fTypesToSource = null;
/**
* Constructs an empty source locator.
*/
public JavaUISourceLocator() {
fSourceLocator = new JavaSourceLocator();
fAllowedToAsk = true;
}
/**
* Constructs a new source locator that looks in the
* specified project for source, and required projects, if
* <code>includeRequired</code> is <code>true</code>.
*
* @param projects the projects in which to look for source
* @param includeRequired whether to look in required projects
* as well
*/
public JavaUISourceLocator(
IJavaProject[] projects,
boolean includeRequired)
throws JavaModelException {
fSourceLocator = new JavaSourceLocator(projects, includeRequired);
fAllowedToAsk = true;
}
/**
* Constructs a source locator that searches for source
* in the given Java project, and all of its required projects,
* as specified by its build path or default source lookup
* settings.
*
* @param project Java project
* @exception CoreException if unable to read the project's
* build path
*/
public JavaUISourceLocator(IJavaProject project) throws CoreException {
fJavaProject = project;
IJavaSourceLocation[] sls =
JavaSourceLocator.getDefaultSourceLocations(project);
fSourceLocator = new JavaSourceLocator(project);
if (sls != null) {
fSourceLocator.setSourceLocations(sls);
}
fAllowedToAsk = true;
}
/**
* @see org.eclipse.debug.core.model.ISourceLocator#getSourceElement(IStackFrame)
*/
public Object getSourceElement(IStackFrame stackFrame) {
Object res = findSourceElement(stackFrame);
if (res == null && fAllowedToAsk) {
IJavaStackFrame frame =
(IJavaStackFrame) stackFrame.getAdapter(IJavaStackFrame.class);
if (frame != null) {
try {
if (!frame.isObsolete()) {
showDebugSourcePage(frame);
res = fSourceLocator.getSourceElement(stackFrame);
}
} catch (DebugException e) {
}
}
}
return res;
}
private Object findSourceElement(IStackFrame stackFrame) {
if (isFindAllSourceElements()) {
Object[] sourceElements = fSourceLocator.getSourceElements(stackFrame);
if (sourceElements == null) {
return null;
}
if (sourceElements.length == 1) {
return sourceElements[0];
}
try {
IJavaStackFrame frame = (IJavaStackFrame)stackFrame;
IJavaClassType type = frame.getDeclaringType();
Object cachedSource = getSourceElement(type);
if (cachedSource != null) {
return cachedSource;
}
// prompt
TwoPaneElementSelector dialog = new TwoPaneElementSelector(JDIDebugUIPlugin.getActiveWorkbenchShell(), new SourceElementLabelProvider(),new SourceElementQualifierProvider());
dialog.setTitle(DebugUIMessages.getString("JavaUISourceLocator.Select_Source_1")); //$NON-NLS-1$
dialog.setMessage(MessageFormat.format(DebugUIMessages.getString("JavaUISourceLocator.&Select_the_source_that_corresponds_to_{0}_2"), new String[]{type.getName()})); //$NON-NLS-1$
dialog.setElements(sourceElements);
dialog.setMultipleSelection(false);
dialog.setUpperListLabel(DebugUIMessages.getString("JavaUISourceLocator.&Matching_files__3")); //$NON-NLS-1$
dialog.setLowerListLabel(DebugUIMessages.getString("JavaUISourceLocator.&Location__4")); //$NON-NLS-1$
dialog.open();
Object[] result = dialog.getResult();
if (result == null) {
return null;
}
Object sourceElement = result[0];
cacheSourceElement(sourceElement, type);
return sourceElement;
} catch (CoreException e) {
JDIDebugUIPlugin.log(e);
return sourceElements[0];
}
} else {
return fSourceLocator.getSourceElement(stackFrame);
}
}
private Object getSourceElement(IJavaClassType type) {
if (fTypesToSource == null) {
return null;
}
return fTypesToSource.get(type);
}
private void cacheSourceElement(Object sourceElement, IJavaClassType type) {
if (fTypesToSource == null) {
fTypesToSource = new HashMap();
}
fTypesToSource.put(type, sourceElement);
}
/**
* Prompts to locate the source of the given type. Prompts in the UI
* thread, since a source lookup could be the result of a conditional
* breakpoint looking up source for an evaluation, from the event
* dispatch thread.
*
* @param typeName the name of the type for which source
* could not be located
*/
private void showDebugSourcePage(final IJavaStackFrame frame) {
Runnable prompter = new Runnable() {
public void run() {
try {
String message = LauncherMessages.getFormattedString("JavaUISourceLocator.selectprojects.message", frame.getDeclaringTypeName()); //$NON-NLS-1$
ILaunchConfiguration configuration =
frame.getLaunch().getLaunchConfiguration();
JavaSourceLookupDialog dialog =
new JavaSourceLookupDialog(
JDIDebugUIPlugin.getActiveWorkbenchShell(),
message,
configuration);
int result = dialog.open();
if (result == JavaSourceLookupDialog.OK) {
fAllowedToAsk = !dialog.isNotAskAgain();
JavaUISourceLocator.this.initializeDefaults(
configuration);
}
} catch (CoreException e) {
// only report an error if the thread has not resumed
if (e.getStatus().getCode()
!= IJavaThread.ERR_THREAD_NOT_SUSPENDED) {
JDIDebugUIPlugin.log(e);
}
}
}
};
JDIDebugUIPlugin.getStandardDisplay().syncExec(prompter);
}
/**
* @see IPersistableSourceLocator#getMemento()
*/
public String getMemento() throws CoreException {
String memento = fSourceLocator.getMemento();
String handle = fJavaProject.getHandleIdentifier();
String findAll = new Boolean(isFindAllSourceElements()).toString();
StringBuffer buffer = new StringBuffer();
buffer.append("<project>"); //$NON-NLS-1$
buffer.append(handle);
buffer.append("</project>"); //$NON-NLS-1$
buffer.append("<findAll>"); //$NON-NLS-1$
buffer.append(findAll);
buffer.append("</findAll>"); //$NON-NLS-1$
buffer.append(memento);
return buffer.toString();
}
/**
* @see IPersistableSourceLocator#initializeDefaults(ILaunchConfiguration)
*/
public void initializeDefaults(ILaunchConfiguration configuration)
throws CoreException {
fSourceLocator.initializeDefaults(configuration);
fJavaProject = JavaRuntime.getJavaProject(configuration);
fIsFindAllSourceElements =
configuration.getAttribute(ATTR_FIND_ALL_SOURCE_ELEMENTS, false);
}
/**
* @see IPersistableSourceLocator#initializeFromMemento(String)
*/
public void initializeFromMemento(String memento) throws CoreException {
if (memento.startsWith("<project>")) { //$NON-NLS-1$
int index = memento.indexOf("</project>"); //$NON-NLS-1$
if (index > 0) {
String handle = memento.substring(9, index);
int start = index + 19;
index = memento.indexOf("</findAll>", start); //$NON-NLS-1$
if (index > 0) {
String findAll = memento.substring(start, index);
Boolean all = new Boolean(findAll);
String rest = memento.substring(index + 10);
fJavaProject = (IJavaProject) JavaCore.create(handle);
fIsFindAllSourceElements = all.booleanValue();
fSourceLocator.initializeFromMemento(rest);
}
}
} else {
// OLD FORMAT
int index = memento.indexOf('\n');
String handle = memento.substring(0, index);
String rest = memento.substring(index + 1);
fJavaProject = (IJavaProject) JavaCore.create(handle);
fIsFindAllSourceElements = false;
fSourceLocator.initializeFromMemento(rest);
}
}
/**
* @see JavaSourceLocator#getSourceLocations()
*/
public IJavaSourceLocation[] getSourceLocations() {
return fSourceLocator.getSourceLocations();
}
/**
* @see JavaSourceLocator#setSourceLocations(IJavaSourceLocation[])
*/
public void setSourceLocations(IJavaSourceLocation[] locations) {
fSourceLocator.setSourceLocations(locations);
}
/**
* Returns whether this source locator is configured to search for all
* source elements that correspond to a stack frame. When <code>false</code>
* is returned, searching stops on the first match. If there is more than
* one source element that corresponds to a stack frame, the user is
* prompted to choose a source element to open.
*
* @return whether this source locator is configured to search for all
* source elements that correspond to a stack frame
* @since 2.1
*/
public boolean isFindAllSourceElements() {
return fIsFindAllSourceElements;
}
/**
* Sets whether this source locator is configured to search for all source
* elements that correspond to a stack frame, or the first match.
*
* @param findAll whether this source locator should search for all source
* elements that correspond to a stack frame
* @since 2.1
*/
public void setFindAllSourceElement(boolean findAll) {
fIsFindAllSourceElements = findAll;
}
}