| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation 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: |
| * 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<IJavaReferenceType, Object>(); |
| } |
| 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(); |
| |
| 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) |
| */ |
| @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; |
| } |
| |
| } |