| /******************************************************************************* |
| * Copyright (c) 2007, 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.launchConfigurations; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationType; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.ILaunchShortcut2; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; |
| import org.eclipse.jdt.internal.debug.ui.launcher.DebugTypeSelectionDialog; |
| import org.eclipse.jdt.internal.debug.ui.launcher.LauncherMessages; |
| import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.dialogs.ElementListSelectionDialog; |
| |
| /** |
| * Common behavior for Java launch shortcuts |
| * <p> |
| * This class may be sub-classed. |
| * </p> |
| * @since 3.3 |
| */ |
| public abstract class JavaLaunchShortcut implements ILaunchShortcut2 { |
| |
| /** |
| * Returns the type of configuration this shortcut is applicable to. |
| * |
| * @return the type of configuration this shortcut is applicable to |
| */ |
| protected abstract ILaunchConfigurationType getConfigurationType(); |
| |
| /** |
| * Creates and returns a new configuration based on the specified type. |
| * |
| * @param type type to create a launch configuration for |
| * @return launch configuration configured to launch the specified type |
| */ |
| protected abstract ILaunchConfiguration createConfiguration(IType type); |
| |
| /** |
| * Finds and returns the types in the given collection of elements that can be launched. |
| * |
| * @param elements scope to search for types that can be launched |
| * @param context progress reporting context |
| * @return collection of types that can be launched, possibly empty |
| * @exception InterruptedException if the search is canceled |
| * @exception CoreException if the search fails |
| */ |
| protected abstract IType[] findTypes(Object[] elements, IRunnableContext context) throws InterruptedException, CoreException; |
| |
| /** |
| * Returns a title for a type selection dialog used to prompt the user when there is more than |
| * one type that can be launched. |
| * |
| * @return type selection dialog title |
| */ |
| protected abstract String getTypeSelectionTitle(); |
| |
| /** |
| * Returns an error message to use when the editor does not contain a type that can be launched. |
| * |
| * @return error message when editor cannot be launched |
| */ |
| protected abstract String getEditorEmptyMessage(); |
| |
| /** |
| * Returns an error message to use when the selection does not contain a type that can be launched. |
| * |
| * @return error message when selection cannot be launched |
| */ |
| protected abstract String getSelectionEmptyMessage(); |
| |
| /** |
| * Resolves a type that can be launched from the given scope and launches in the |
| * specified mode. |
| * |
| * @param scope the java elements to consider for a type that can be launched |
| * @param mode launch mode |
| * @param selectTitle prompting title for choosing a type to launch |
| * @param emptyMessage error message when no types are resolved for launching |
| */ |
| private void searchAndLaunch(Object[] scope, String mode, String selectTitle, String emptyMessage) { |
| IType[] types = null; |
| try { |
| types = findTypes(scope, PlatformUI.getWorkbench().getProgressService()); |
| } |
| catch (InterruptedException e) {return;} |
| catch (CoreException e) { |
| JDIDebugUIPlugin.log(e); |
| String message = e.getMessage(); |
| if (message == null || message.isEmpty()) { |
| message = LauncherMessages.JavaLaunchShortcut_1; |
| } |
| MessageDialog.openError(getShell(), LauncherMessages.JavaLaunchShortcut_0, message); |
| return; |
| } |
| IType type = null; |
| if (types.length == 0) { |
| MessageDialog.openError(getShell(), LauncherMessages.JavaLaunchShortcut_1, emptyMessage); |
| } |
| else if (types.length > 1) { |
| type = chooseType(types, selectTitle); |
| } |
| else { |
| type = types[0]; |
| } |
| if (type != null) { |
| launch(type, mode); |
| } |
| } |
| |
| /** |
| * Prompts the user to select a type from the given types. |
| * |
| * @param types the types to choose from |
| * @param title the selection dialog title |
| * |
| * @return the selected type or <code>null</code> if none. |
| */ |
| protected IType chooseType(IType[] types, String title) { |
| DebugTypeSelectionDialog mmsd = new DebugTypeSelectionDialog(JDIDebugUIPlugin.getShell(), types, title); |
| if (mmsd.open() == Window.OK) { |
| return (IType)mmsd.getResult()[0]; |
| } |
| return null; |
| } |
| |
| /** |
| * Launches the given type in the specified mode. |
| * |
| * @param type type to launch |
| * @param mode launch mode |
| * @since 3.5 |
| */ |
| protected void launch(IType type, String mode) { |
| List<ILaunchConfiguration> configs = getCandidates(type, getConfigurationType()); |
| if(configs != null) { |
| ILaunchConfiguration config = null; |
| int count = configs.size(); |
| if(count == 1) { |
| config = configs.get(0); |
| } |
| else if(count > 1) { |
| config = chooseConfiguration(configs); |
| if(config == null) { |
| return; |
| } |
| } |
| if (config == null) { |
| config = createConfiguration(type); |
| } |
| if (config != null) { |
| DebugUITools.launch(config, mode); |
| } |
| } |
| } |
| |
| /** |
| * Collect the listing of {@link ILaunchConfiguration}s that apply to the given {@link IType} and {@link ILaunchConfigurationType} |
| * |
| * @param type the type |
| * @param ctype the {@link ILaunchConfigurationType} |
| * @return the list of {@link ILaunchConfiguration}s or an empty list, never <code>null</code> |
| * @since 3.8 |
| */ |
| List<ILaunchConfiguration> getCandidates(IType type, ILaunchConfigurationType ctype) { |
| List<ILaunchConfiguration> candidateConfigs = Collections.EMPTY_LIST; |
| try { |
| ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(ctype); |
| candidateConfigs = new ArrayList<>(configs.length); |
| for (int i = 0; i < configs.length; i++) { |
| ILaunchConfiguration config = configs[i]; |
| if (config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "").equals(type.getFullyQualifiedName())) { //$NON-NLS-1$ |
| if (config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "").equals(type.getJavaProject().getElementName())) { //$NON-NLS-1$ |
| candidateConfigs.add(config); |
| } |
| } |
| } |
| } catch (CoreException e) { |
| JDIDebugUIPlugin.log(e); |
| } |
| return candidateConfigs; |
| } |
| |
| /** |
| * Finds and returns an <b>existing</b> configuration to re-launch for the given type, |
| * or <code>null</code> if there is no existing configuration. |
| * |
| * @param type the {@link IType} to try and find the {@link ILaunchConfiguration} for |
| * @param configType the {@link ILaunchConfigurationType} to try and narrow down the search |
| * |
| * @return a configuration to use for launching the given type or <code>null</code> if none |
| */ |
| protected ILaunchConfiguration findLaunchConfiguration(IType type, ILaunchConfigurationType configType) { |
| List<ILaunchConfiguration> configs = getCandidates(type, configType); |
| int count = configs.size(); |
| if(count == 1) { |
| return configs.get(0); |
| } |
| if(count > 1) { |
| return chooseConfiguration(configs); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a configuration from the given collection of configurations that should be launched, |
| * or <code>null</code> to cancel. Default implementation opens a selection dialog that allows |
| * the user to choose one of the specified launch configurations. Returns the chosen configuration, |
| * or <code>null</code> if the user cancels. |
| * |
| * @param configList list of configurations to choose from |
| * @return configuration to launch or <code>null</code> to cancel |
| */ |
| protected ILaunchConfiguration chooseConfiguration(List<ILaunchConfiguration> configList) { |
| IDebugModelPresentation labelProvider = DebugUITools.newDebugModelPresentation(); |
| ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), labelProvider); |
| dialog.setElements(configList.toArray()); |
| dialog.setTitle(getTypeSelectionTitle()); |
| dialog.setMessage(LauncherMessages.JavaLaunchShortcut_2); |
| dialog.setMultipleSelection(false); |
| int result = dialog.open(); |
| labelProvider.dispose(); |
| if (result == Window.OK) { |
| return (ILaunchConfiguration) dialog.getFirstResult(); |
| } |
| return null; |
| } |
| |
| /** |
| * Convenience method to return the active workbench window shell. |
| * |
| * @return active workbench window shell |
| */ |
| protected Shell getShell() { |
| return JDIDebugUIPlugin.getActiveWorkbenchShell(); |
| } |
| |
| @Override |
| public void launch(IEditorPart editor, String mode) { |
| IEditorInput input = editor.getEditorInput(); |
| IJavaElement je = input.getAdapter(IJavaElement.class); |
| if (je != null) { |
| searchAndLaunch(new Object[] {je}, mode, getTypeSelectionTitle(), getEditorEmptyMessage()); |
| } |
| } |
| |
| @Override |
| public void launch(ISelection selection, String mode) { |
| if (selection instanceof IStructuredSelection) { |
| searchAndLaunch(((IStructuredSelection)selection).toArray(), mode, getTypeSelectionTitle(), getSelectionEmptyMessage()); |
| } |
| } |
| |
| @Override |
| public IResource getLaunchableResource(IEditorPart editorpart) { |
| return getLaunchableResource(editorpart.getEditorInput()); |
| } |
| |
| @Override |
| public IResource getLaunchableResource(ISelection selection) { |
| if (selection instanceof IStructuredSelection) { |
| IStructuredSelection ss = (IStructuredSelection) selection; |
| if (ss.size() == 1) { |
| Object element = ss.getFirstElement(); |
| if (element instanceof IAdaptable) { |
| return getLaunchableResource((IAdaptable)element); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the resource containing the Java element associated with the |
| * given adaptable, or <code>null</code>. |
| * |
| * @param adaptable adaptable object |
| * @return containing resource or <code>null</code> |
| */ |
| private IResource getLaunchableResource(IAdaptable adaptable) { |
| IJavaElement je = adaptable.getAdapter(IJavaElement.class); |
| if (je != null) { |
| return je.getResource(); |
| } |
| return null; |
| } |
| |
| @Override |
| public ILaunchConfiguration[] getLaunchConfigurations(IEditorPart editorpart) { |
| // let the framework resolve configurations based on resource mapping |
| return null; |
| } |
| |
| @Override |
| public ILaunchConfiguration[] getLaunchConfigurations(ISelection selection) { |
| // let the framework resolve configurations based on resource mapping |
| return null; |
| } |
| |
| |
| } |