| /******************************************************************************* |
| * Copyright (c) 2005, 2018 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.debug.ui.launcher; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationType; |
| import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
| import org.eclipse.debug.core.ILaunchManager; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.ILaunchShortcut; |
| import org.eclipse.dltk.compiler.util.Util; |
| import org.eclipse.dltk.core.IMethod; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IParent; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.IType; |
| import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin; |
| import org.eclipse.dltk.debug.ui.messages.ScriptLaunchMessages; |
| import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin; |
| import org.eclipse.dltk.launching.LaunchingMessages; |
| import org.eclipse.dltk.launching.ScriptLaunchConfigurationConstants; |
| import org.eclipse.dltk.launching.process.ScriptRuntimeProcessFactory; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| 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.IFileEditorInput; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.dialogs.ElementListSelectionDialog; |
| import org.eclipse.ui.model.WorkbenchLabelProvider; |
| |
| public abstract class AbstractScriptLaunchShortcut implements ILaunchShortcut { |
| @Override |
| public void launch(ISelection selection, String mode) { |
| if (selection instanceof IStructuredSelection) { |
| searchAndLaunch(((IStructuredSelection) selection).toArray(), mode, |
| getScriptSelectionTitle(), getSelectionEmptyMessage()); |
| } |
| } |
| |
| /** |
| * @param search |
| * the elements to search for a main script |
| * @param mode |
| * the mode to launch in |
| */ |
| public void searchAndLaunch(Object[] search, String mode, |
| String selectMessage, String emptyMessage) { |
| IResource[] scripts = null; |
| try { |
| scripts = findScripts(search, |
| PlatformUI.getWorkbench().getProgressService()); |
| } catch (InterruptedException e) { |
| return; |
| } catch (CoreException e) { |
| MessageDialog.openError(getShell(), |
| LaunchingMessages.ScriptLaunchShortcut_0, e.getMessage()); |
| return; |
| } |
| IResource script = null; |
| if (scripts.length == 0) { |
| MessageDialog.openError(getShell(), |
| LaunchingMessages.ScriptLaunchShortcut_1, emptyMessage); |
| } else if (scripts.length > 1) { |
| script = chooseScript(scripts, selectMessage); |
| } else { |
| script = scripts[0]; |
| } |
| if (script != null) { |
| launch(script, 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 IResource chooseScript(IResource[] scripts, String title) { |
| ElementListSelectionDialog dialog = new ElementListSelectionDialog( |
| getShell(), new WorkbenchLabelProvider()); |
| dialog.setElements(scripts); |
| dialog.setMessage( |
| LaunchingMessages.ScriptLaunchShortcut_Choose_a_main_script_to_launch); |
| dialog.setTitle(title); |
| if (dialog.open() == Window.OK) { |
| return (IResource) dialog.getResult()[0]; |
| } |
| return null; |
| } |
| |
| /** |
| * Opens an error dialog on the given excpetion. |
| * |
| * @param exception |
| */ |
| protected void reportErorr(CoreException exception) { |
| MessageDialog.openError(getShell(), |
| LaunchingMessages.ScriptLaunchShortcut_3, |
| exception.getStatus().getMessage()); |
| } |
| |
| @Override |
| public void launch(IEditorPart editor, String mode) { |
| IEditorInput editorInput = editor.getEditorInput(); |
| if (editorInput == null) |
| return; |
| IResource script = ((IFileEditorInput) editorInput).getFile(); |
| if (script != null) |
| launch(script, mode); |
| } |
| |
| protected void launch(IResource script, String mode) { |
| ILaunchConfiguration config = findLaunchConfiguration(script, |
| getConfigurationType()); |
| if (config != null) { |
| DebugUITools.launch(config, mode); |
| } |
| } |
| |
| protected ILaunchManager getLaunchManager() { |
| return DebugPlugin.getDefault().getLaunchManager(); |
| } |
| |
| /** |
| * Returns the type of configuration this shortcut is applicable to. |
| * |
| * @return the type of configuration this shortcut is applicable to |
| */ |
| protected abstract ILaunchConfigurationType getConfigurationType(); |
| |
| /** |
| * Locate a configuration to relaunch for the given type. If one cannot be |
| * found, create one. |
| * |
| * @return a re-useable config or <code>null</code> if none |
| */ |
| protected ILaunchConfiguration findLaunchConfiguration(IResource script, |
| ILaunchConfigurationType configType) { |
| List<ILaunchConfiguration> candidateConfigs = Collections.emptyList(); |
| try { |
| ILaunchConfiguration[] configs = DebugPlugin.getDefault() |
| .getLaunchManager().getLaunchConfigurations(configType); |
| candidateConfigs = new ArrayList<>(configs.length); |
| for (int i = 0; i < configs.length; i++) { |
| ILaunchConfiguration config = configs[i]; |
| if (config.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_MAIN_SCRIPT_NAME, |
| Util.EMPTY_STRING) |
| .equals(script.getProjectRelativePath().toString()) |
| && config.getAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, |
| Util.EMPTY_STRING) |
| .equals(script.getProject().getName())) { |
| candidateConfigs.add(config); |
| } |
| } |
| } catch (CoreException e) { |
| DLTKLaunchingPlugin.log(e); |
| } |
| |
| // If there are no existing configs associated with the script, create |
| // one. |
| // If there is exactly one config associated with the script, return it. |
| // Otherwise, if there is more than one config associated with the |
| // script, prompt the |
| // user to choose one. |
| int candidateCount = candidateConfigs.size(); |
| if (candidateCount < 1) { |
| return createConfiguration(script); |
| } else if (candidateCount == 1) { |
| return candidateConfigs.get(0); |
| } else { |
| // Prompt the user to choose a config. A null result means the user |
| // cancelled the dialog, in which case this method returns null, |
| // since cancelling the dialog should also cancel launching |
| // anything. |
| ILaunchConfiguration config = chooseConfiguration(candidateConfigs); |
| if (config != null) { |
| return config; |
| } |
| } |
| |
| return null; |
| } |
| |
| protected abstract String getNatureId(); |
| |
| protected ILaunchConfiguration createConfiguration(IResource script) { |
| ILaunchConfiguration config = null; |
| ILaunchConfigurationWorkingCopy wc = null; |
| try { |
| ILaunchConfigurationType configType = getConfigurationType(); |
| wc = configType.newInstance(null, getLaunchManager() |
| .generateLaunchConfigurationName(script.getName())); |
| wc.setAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_SCRIPT_NATURE, |
| getNatureId()); |
| wc.setAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_PROJECT_NAME, |
| script.getProject().getName()); |
| wc.setAttribute( |
| ScriptLaunchConfigurationConstants.ATTR_MAIN_SCRIPT_NAME, |
| script.getProjectRelativePath().toPortableString()); |
| wc.setAttribute(DebugPlugin.ATTR_PROCESS_FACTORY_ID, |
| ScriptRuntimeProcessFactory.PROCESS_FACTORY_ID); |
| // |
| // IEnvironment environment = |
| // EnvironmentManager.getEnvironment(script |
| // .getProject()); |
| // |
| // wc.setAttribute( |
| // ScriptLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, |
| // (String)null); |
| |
| wc.setMappedResources(new IResource[] { script }); |
| config = wc.doSave(); |
| } catch (CoreException exception) { |
| exception.printStackTrace(); |
| } |
| return config; |
| } |
| |
| /** |
| * Convenience method to get the window that owns this action's Shell. |
| */ |
| protected Shell getShell() { |
| return DLTKDebugUIPlugin.getActiveWorkbenchShell(); |
| } |
| |
| /** |
| * Show a selection dialog that allows the user to choose one of the |
| * specified launch configurations. Return the chosen config, or |
| * <code>null</code> if the user cancelled the dialog. |
| */ |
| protected ILaunchConfiguration chooseConfiguration( |
| List<ILaunchConfiguration> configList) { |
| IDebugModelPresentation labelProvider = DebugUITools |
| .newDebugModelPresentation(); |
| ElementListSelectionDialog dialog = new ElementListSelectionDialog( |
| getShell(), labelProvider); |
| dialog.setElements(configList.toArray()); |
| dialog.setTitle(ScriptLaunchMessages.scriptLaunchShortcut2_title); |
| dialog.setMessage(ScriptLaunchMessages.scriptLaunchShortcut2); |
| dialog.setMultipleSelection(false); |
| int result = dialog.open(); |
| labelProvider.dispose(); |
| if (result == Window.OK) { |
| return (ILaunchConfiguration) dialog.getFirstResult(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the model elements corresponding to the given objects. |
| * |
| * @param objects |
| * selected objects |
| * @return corresponding Script elements |
| */ |
| private IResource[] getScriptResources(Object[] objects, |
| IProgressMonitor pm) { |
| List<IResource> list = new ArrayList<>(objects.length); |
| for (int i = 0; i < objects.length; i++) { |
| Object object = objects[i]; |
| try { |
| if (object instanceof IFile) { |
| IFile f = (IFile) object; |
| if (!f.getName().startsWith(".")) //$NON-NLS-1$ |
| list.add(f); |
| } else if (object instanceof IContainer) { |
| IContainer f = (IContainer) object; |
| IResource[] mem = f.members(); |
| IResource[] res = getScriptResources(mem, pm); |
| for (int j = 0; j < res.length; j++) { |
| list.add(res[j]); |
| } |
| } else if (object instanceof IModelElement) { |
| IModelElement elem = (IModelElement) object; |
| if (elem instanceof ISourceModule) { |
| IResource res = ((ISourceModule) elem) |
| .getCorrespondingResource(); |
| if (res != null) |
| list.add(res); |
| } else if (elem instanceof IType) { |
| IResource res = ((IType) elem).getUnderlyingResource(); |
| if (res != null) |
| list.add(res); |
| } else if (elem instanceof IMethod) { |
| IResource res = ((IMethod) elem) |
| .getUnderlyingResource(); |
| if (res != null) |
| list.add(res); |
| } else if (elem instanceof IParent) { |
| IParent proj = (IParent) elem; |
| IResource[] res = getScriptResources(proj.getChildren(), |
| pm); |
| for (int j = 0; j < res.length; j++) { |
| list.add(res[j]); |
| } |
| } |
| } |
| } catch (CoreException e) { |
| } |
| } |
| return list.toArray(new IResource[list.size()]); |
| } |
| |
| /** |
| * Finds and returns the launchable scripts in the given selection of |
| * elements. |
| * |
| * @param elements |
| * scope to search for launchable types |
| * @param context |
| * progess reporting context |
| * @return launchable types, possibly empty |
| * @exception InterruptedException |
| * if the search is cancelled |
| * @exception org.eclipse.core.runtime.CoreException |
| * if the search fails |
| */ |
| protected IResource[] findScripts(final Object[] elements, |
| IRunnableContext context) |
| throws InterruptedException, CoreException { |
| try { |
| final IResource[][] res = new IResource[1][]; |
| |
| IRunnableWithProgress runnable = pm -> { |
| pm.beginTask( |
| LaunchingMessages.LaunchShortcut_searchingForScripts, |
| 1); |
| res[0] = getScriptResources(elements, pm); |
| pm.done(); |
| }; |
| context.run(true, true, runnable); |
| |
| return res[0]; |
| } catch (InvocationTargetException e) { |
| throw (CoreException) e.getTargetException(); |
| } |
| } |
| |
| /** |
| * Returns the title for type selection dialog for this launch shortcut. |
| * |
| * @return type selection dialog title |
| */ |
| protected String getScriptSelectionTitle() { |
| return LaunchingMessages.LaunchShortcut_selectScriptToLaunch; |
| } |
| |
| /** |
| * Returns an error message to use when the selection does not contain a |
| * launchable type. |
| * |
| * @return error message |
| */ |
| protected String getSelectionEmptyMessage() { |
| return LaunchingMessages.LaunchShortcut_selectionContainsNoScript; |
| } |
| } |