blob: 97d6a84a931aec18484a755da217f090e005daa3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.debug.ui;
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.debug.core.IJavaReferenceType;
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.jface.window.Window;
import org.eclipse.osgi.util.NLS;
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.
* </p>
* @since 2.0
* @deprecated In 3.0, the debug platform provides source lookup facilities that
* should be used in place of the Java source lookup support provided in 2.0.
* The new facilities provide a source lookup director that coordinates source
* lookup among a set of participants, searching a set of source containers.
* See the following packages: <code>org.eclipse.debug.core.sourcelookup</code>
* and <code>org.eclipse.debug.core.sourcelookup.containers</code>. This class
* has been replaced by a Java source lookup director and Java source lookup
* participant. To migrate to the new source lookup support clients should
* add two new attributes to their launch configuration type extensions:<ul>
* <li>sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"</li>
* <li>sourcePathComputerId="org.eclipse.jdt.launching.sourceLookup.javaSourcePathComputer"</li>
* </ul>
* The source locator id attribute specifies to use the Java source lookup director
* for launch configurations of the associated type, and the source path computer id
* attribute specifies the class to use when computing a default source lookup
* path for a launch configuration. The path computer referenced/provided (by the
* above id), computes a default source lookup path based on the support provided in
* the 2.0 release - i.e. a configuration's <code>ATTR_SOURCE_PATH_PROVIDER</code>
* attribute (if present), or a default source lookup path based on a configuration's
* runtime classpath. This class has been replaced by the Java source lookup
* director which is an internal class, but can be used via the
* <code>sourceLocatorId</code> attribute on a launch configuration type extension.
* @noextend This class is not intended to be sub-classed by clients.
*/
@Deprecated
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
* duplicates), 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<IJavaReferenceType, Object> 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
* @throws CoreException if the underlying {@link JavaSourceLocator} fails to be created
*/
public JavaUISourceLocator(IJavaProject[] projects, boolean includeRequired) throws CoreException {
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)
*/
@Override
public Object getSourceElement(IStackFrame stackFrame) {
Object res = findSourceElement(stackFrame);
if (res == null && fAllowedToAsk) {
IJavaStackFrame frame =
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 || sourceElements.length == 0) {
return null;
}
if (sourceElements.length == 1) {
return sourceElements[0];
}
try {
IJavaStackFrame frame = (IJavaStackFrame)stackFrame;
IJavaReferenceType type = frame.getReferenceType();
Object cachedSource = getSourceElement(type);
if (cachedSource != null) {
return cachedSource;
}
// prompt
TwoPaneElementSelector dialog = new TwoPaneElementSelector(JDIDebugUIPlugin.getActiveWorkbenchShell(), new SourceElementLabelProvider(),new SourceElementQualifierProvider());
dialog.setTitle(DebugUIMessages.JavaUISourceLocator_Select_Source_1);
dialog.setMessage(NLS.bind(DebugUIMessages.JavaUISourceLocator__Select_the_source_that_corresponds_to__0__2, new String[]{type.getName()}));
dialog.setElements(sourceElements);
dialog.setMultipleSelection(false);
dialog.setUpperListLabel(DebugUIMessages.JavaUISourceLocator__Matching_files__3);
dialog.setLowerListLabel(DebugUIMessages.JavaUISourceLocator__Location__4);
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];
}
}
return fSourceLocator.getSourceElement(stackFrame);
}
private Object getSourceElement(IJavaReferenceType type) {
if (fTypesToSource == null) {
return null;
}
return fTypesToSource.get(type);
}
private void cacheSourceElement(Object sourceElement, IJavaReferenceType 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 frame the stack frame to show source for
* could not be located
*/
private void showDebugSourcePage(final IJavaStackFrame frame) {
Runnable prompter = new Runnable() {
@Override
public void run() {
try {
String message = NLS.bind(LauncherMessages.JavaUISourceLocator_selectprojects_message, new String[] {frame.getDeclaringTypeName()});
ILaunchConfiguration configuration =
frame.getLaunch().getLaunchConfiguration();
JavaSourceLookupDialog dialog =
new JavaSourceLookupDialog(
JDIDebugUIPlugin.getActiveWorkbenchShell(),
message,
configuration);
int result = dialog.open();
if (result == Window.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()
*/
@Override
public String getMemento() throws CoreException {
String memento = fSourceLocator.getMemento();
String handle = fJavaProject.getHandleIdentifier();
String findAll = Boolean.valueOf(isFindAllSourceElements()).toString();
StringBuilder buffer = new StringBuilder();
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)
*/
@Override
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)
*/
@Override
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 = Boolean.valueOf(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);
}
}
/**
* Returns the locations that this source locator is currently
* searching, in the order that they are searched.
*
* @return the locations that this source locator is currently
* searching, in the order that they are searched
*/
public IJavaSourceLocation[] getSourceLocations() {
return fSourceLocator.getSourceLocations();
}
/**
* /**
* Sets the locations that will be searched, in the order
* to be searched.
*
* @param locations the locations that will be searched, in the order
* to be searched
*/
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;
}
}