1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.debug.ui;
15 
16 
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.LinkedHashSet;
20 import java.util.List;
21 import java.util.Set;
22 
23 import org.eclipse.core.commands.ExecutionEvent;
24 import org.eclipse.core.commands.ExecutionException;
25 import org.eclipse.core.commands.operations.IOperationHistory;
26 import org.eclipse.core.commands.operations.IUndoContext;
27 import org.eclipse.core.commands.operations.IUndoableOperation;
28 import org.eclipse.core.commands.operations.ObjectUndoContext;
29 import org.eclipse.core.resources.IMarker;
30 import org.eclipse.core.resources.IResource;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.core.runtime.IAdaptable;
33 import org.eclipse.core.runtime.IConfigurationElement;
34 import org.eclipse.core.runtime.IExtension;
35 import org.eclipse.core.runtime.IExtensionPoint;
36 import org.eclipse.core.runtime.IProgressMonitor;
37 import org.eclipse.core.runtime.IStatus;
38 import org.eclipse.core.runtime.Platform;
39 import org.eclipse.core.runtime.Status;
40 import org.eclipse.debug.core.DebugException;
41 import org.eclipse.debug.core.DebugPlugin;
42 import org.eclipse.debug.core.ILaunch;
43 import org.eclipse.debug.core.ILaunchConfiguration;
44 import org.eclipse.debug.core.ILaunchConfigurationType;
45 import org.eclipse.debug.core.ILaunchDelegate;
46 import org.eclipse.debug.core.ILaunchManager;
47 import org.eclipse.debug.core.model.IBreakpoint;
48 import org.eclipse.debug.core.model.IDebugElement;
49 import org.eclipse.debug.core.model.IDebugTarget;
50 import org.eclipse.debug.core.model.IProcess;
51 import org.eclipse.debug.core.model.ISourceLocator;
52 import org.eclipse.debug.internal.core.IConfigurationElementConstants;
53 import org.eclipse.debug.internal.ui.DebugPluginImages;
54 import org.eclipse.debug.internal.ui.DebugUIPlugin;
55 import org.eclipse.debug.internal.ui.DefaultLabelProvider;
56 import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
57 import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
58 import org.eclipse.debug.internal.ui.LazyModelPresentation;
59 import org.eclipse.debug.internal.ui.TerminateToggleValue;
60 import org.eclipse.debug.internal.ui.actions.ActionMessages;
61 import org.eclipse.debug.internal.ui.actions.ToggleBreakpointsTargetManager;
62 import org.eclipse.debug.internal.ui.contextlaunching.LaunchingResourceManager;
63 import org.eclipse.debug.internal.ui.contexts.DebugContextManager;
64 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationDialog;
65 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
66 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationPropertiesDialog;
67 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationTabGroupViewer;
68 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsDialog;
69 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchGroupExtension;
70 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutExtension;
71 import org.eclipse.debug.internal.ui.memory.MemoryRenderingManager;
72 import org.eclipse.debug.internal.ui.sourcelookup.SourceLookupFacility;
73 import org.eclipse.debug.internal.ui.sourcelookup.SourceLookupUIUtils;
74 import org.eclipse.debug.internal.ui.stringsubstitution.SelectedResourceManager;
75 import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetManager;
76 import org.eclipse.debug.ui.contexts.IDebugContextListener;
77 import org.eclipse.debug.ui.contexts.IDebugContextManager;
78 import org.eclipse.debug.ui.contexts.IDebugContextService;
79 import org.eclipse.debug.ui.memory.IMemoryRenderingManager;
80 import org.eclipse.debug.ui.sourcelookup.ISourceContainerBrowser;
81 import org.eclipse.debug.ui.sourcelookup.ISourceLookupResult;
82 import org.eclipse.jface.preference.IPreferenceStore;
83 import org.eclipse.jface.resource.ImageDescriptor;
84 import org.eclipse.jface.viewers.ISelection;
85 import org.eclipse.jface.viewers.IStructuredSelection;
86 import org.eclipse.jface.viewers.TreePath;
87 import org.eclipse.jface.viewers.TreeSelection;
88 import org.eclipse.jface.window.Window;
89 import org.eclipse.osgi.util.NLS;
90 import org.eclipse.swt.custom.BusyIndicator;
91 import org.eclipse.swt.graphics.Color;
92 import org.eclipse.swt.graphics.Image;
93 import org.eclipse.swt.widgets.Shell;
94 import org.eclipse.ui.IEditorInput;
95 import org.eclipse.ui.IEditorPart;
96 import org.eclipse.ui.IViewSite;
97 import org.eclipse.ui.IWorkbenchPage;
98 import org.eclipse.ui.IWorkbenchPart;
99 import org.eclipse.ui.IWorkbenchPartSite;
100 import org.eclipse.ui.IWorkbenchWindow;
101 import org.eclipse.ui.PlatformUI;
102 import org.eclipse.ui.console.IConsole;
103 import org.eclipse.ui.handlers.HandlerUtil;
104 import org.eclipse.ui.ide.undo.DeleteMarkersOperation;
105 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
106 
107 
108 /**
109  * This class provides utilities for clients of the debug UI.
110  * <p>
111  * Images retrieved from this facility should not be disposed.
112  * The images will be disposed when this plug-in is shutdown.
113  * </p>
114  * <p>
115  * Note: all methods in this class are expected to be called
116  * on the Display thread unless otherwise noted.
117  * </p>
118  * @noinstantiate This class is not intended to be instantiated by clients.
119  * @noextend This class is not intended to be subclassed by clients.
120  */
121 public class DebugUITools {
122 
123 	/**
124 	 * The undo context for breakpoints.
125 	 *
126 	 * @since 3.7
127 	 */
128 	private static ObjectUndoContext fgBreakpointsUndoContext;
129 
130 	/**
131 	 * Returns the shared image managed under the given key, or <code>null</code>
132 	 * if none.
133 	 * <p>
134 	 * Note that clients <b>MUST NOT</b> dispose the image returned by this method.
135 	 * </p>
136 	 * <p>
137 	 * See <code>IDebugUIConstants</code> for available images.
138 	 * </p>
139 	 *
140 	 * @param key the image key
141 	 * @return the image, or <code>null</code> if none
142 	 * @see IDebugUIConstants
143 	 */
getImage(String key)144 	public static Image getImage(String key) {
145 		return DebugPluginImages.getImage(key);
146 	}
147 
148 	/**
149 	 * Returns the shared image descriptor managed under the given key, or
150 	 * <code>null</code> if none.
151 	 * <p>
152 	 * See <code>IDebugUIConstants</code> for available image descriptors.
153 	 * </p>
154 	 *
155 	 * @param key the image descriptor key
156 	 * @return the image descriptor, or <code>null</code> if none
157 	 * @see IDebugUIConstants
158 	 */
getImageDescriptor(String key)159 	public static ImageDescriptor getImageDescriptor(String key) {
160 		return DebugPluginImages.getImageDescriptor(key);
161 	}
162 
163 	/**
164 	 * Returns the default image descriptor for the given element.
165 	 *
166 	 * @param element the element
167 	 * @return the image descriptor or <code>null</code> if none
168 	 */
getDefaultImageDescriptor(Object element)169 	public static ImageDescriptor getDefaultImageDescriptor(Object element) {
170 		String imageKey= getDefaultImageKey(element);
171 		if (imageKey == null) {
172 			return null;
173 		}
174 		return DebugPluginImages.getImageDescriptor(imageKey);
175 	}
176 
getDefaultImageKey(Object element)177 	private static String getDefaultImageKey(Object element) {
178 		return ((DefaultLabelProvider)DebugUIPlugin.getDefaultLabelProvider()).getImageKey(element);
179 	}
180 
181 	/**
182 	 * Returns the preference store for the debug UI plug-in.
183 	 *
184 	 * @return preference store
185 	 */
getPreferenceStore()186 	public static IPreferenceStore getPreferenceStore() {
187 		return DebugUIPlugin.getDefault().getPreferenceStore();
188 	}
189 
190 	/**
191 	 * Returns a new debug model presentation that delegates to
192 	 * appropriate debug models.
193 	 * <p>
194 	 * It is the client's responsibility dispose the presentation.
195 	 * </p>
196 	 *
197 	 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
198 	 * @return a debug model presentation
199 	 * @since 2.0
200 	 */
newDebugModelPresentation()201 	public static IDebugModelPresentation newDebugModelPresentation() {
202 		return new DelegatingModelPresentation();
203 	}
204 
205 	/**
206 	 * Returns a new debug model presentation for specified
207 	 * debug model, or <code>null</code> if a presentation does
208 	 * not exist.
209 	 * <p>
210 	 * It is the client's responsibility dispose the presentation.
211 	 * </p>
212 	 *
213 	 * @param identifier debug model identifier
214 	 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
215 	 * @return a debug model presentation, or <code>null</code>
216 	 * @since 2.0
217 	 */
newDebugModelPresentation(String identifier)218 	public static IDebugModelPresentation newDebugModelPresentation(String identifier) {
219 		IExtensionPoint point= Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.ID_DEBUG_MODEL_PRESENTATION);
220 		if (point != null) {
221 			IExtension[] extensions= point.getExtensions();
222 			for (IExtension extension : extensions) {
223 				IConfigurationElement[] configElements= extension.getConfigurationElements();
224 				for (IConfigurationElement elt : configElements) {
225 					String id= elt.getAttribute("id"); //$NON-NLS-1$
226 					if (id != null && id.equals(identifier)) {
227 						return new LazyModelPresentation(elt);
228 					}
229 				}
230 			}
231 		}
232 		return null;
233 	}
234 
235 	/**
236 	 * Returns the element of the currently selected context in the
237 	 * active workbench window. Returns <code>null</code> if there is no
238 	 * current debug context.
239 	 * <p>
240 	 * This method used to return <code>null</code> when called from a non-UI thread,
241 	 * but since 3.1, this methods also works when called from a non-UI thread.
242 	 * </p>
243 	 * @return the currently selected debug context, or <code>null</code>
244 	 * @since 2.0
245 	 */
getDebugContext()246 	public static IAdaptable getDebugContext() {
247 		IWorkbenchWindow activeWindow = SelectedResourceManager.getDefault().getActiveWindow();
248 		if (activeWindow != null) {
249 			ISelection activeContext = DebugUITools.getDebugContextManager().getContextService(activeWindow).getActiveContext();
250 			return getDebugContextElementForSelection(activeContext);
251 		}
252 		return null;
253 	}
254 
255 	/**
256 	 * Returns the currently selected context in the given part or part's
257 	 * workbench window. Returns <code>null</code> if there is no current
258 	 * debug context.
259 	 * @param part workbench part where the active context is to be evaluated
260 	 * @return the currently selected debug context in the given workbench part,
261 	 * or <code>null</code>
262 	 * @since 3.8
263 	 * @see IDebugContextService#getActiveContext(String)
264 	 * @see IDebugContextService#getActiveContext(String, String)
265 	 */
getDebugContextForPart(IWorkbenchPart part)266 	public static ISelection getDebugContextForPart(IWorkbenchPart part) {
267 		IWorkbenchPartSite site = part.getSite();
268 		IWorkbenchWindow partWindow = site.getWorkbenchWindow();
269 		if (partWindow != null) {
270 			IDebugContextService contextService = DebugUITools.getDebugContextManager().getContextService(partWindow);
271 			if (site instanceof IViewSite) {
272 				return contextService.getActiveContext(site.getId(), ((IViewSite)site).getSecondaryId());
273 			} else {
274 				return contextService.getActiveContext(site.getId());
275 			}
276 		}
277 		return null;
278 	}
279 
280 	/**
281 	 * Return the undo context that should be used for operations involving breakpoints.
282 	 *
283 	 * @return the undo context for breakpoints
284 	 * @since 3.7
285 	 */
getBreakpointsUndoContext()286 	public static synchronized IUndoContext getBreakpointsUndoContext() {
287 		if (fgBreakpointsUndoContext == null) {
288 			fgBreakpointsUndoContext= new ObjectUndoContext(new Object(), "Breakpoints Context"); //$NON-NLS-1$
289 			fgBreakpointsUndoContext.addMatch(WorkspaceUndoUtil.getWorkspaceUndoContext());
290 		}
291 		return fgBreakpointsUndoContext;
292 	}
293 
294 	/**
295 	 * Deletes the given breakpoints using the operation history, which allows to undo the deletion.
296 	 *
297 	 * @param breakpoints the breakpoints to delete
298 	 * @param shell the shell used for potential user interactions, or <code>null</code> if unknown
299 	 * @param progressMonitor the progress monitor
300 	 * @throws CoreException if the deletion fails
301 	 * @since 3.7
302 	 */
deleteBreakpoints(IBreakpoint[] breakpoints, final Shell shell, IProgressMonitor progressMonitor)303 	public static void deleteBreakpoints(IBreakpoint[] breakpoints, final Shell shell, IProgressMonitor progressMonitor) throws CoreException {
304 		IMarker[] markers= new IMarker[breakpoints.length];
305 		int markerCount;
306 		for (markerCount= 0; markerCount < breakpoints.length; markerCount++) {
307 			if (!breakpoints[markerCount].isRegistered()) {
308 				break;
309 			}
310 			markers[markerCount]= breakpoints[markerCount].getMarker();
311 			if (markers[markerCount] == null) {
312 				break;
313 			}
314 		}
315 
316 		// We only offer undo support if all breakpoints are registered and have associated markers
317 		boolean allowUndo= markerCount == breakpoints.length;
318 
319 		DebugPlugin.getDefault().getBreakpointManager().removeBreakpoints(breakpoints, !allowUndo);
320 
321 		if (allowUndo) {
322 
323 			for (IMarker marker : markers) {
324 				marker.setAttribute(DebugPlugin.ATTR_BREAKPOINT_IS_DELETED, true);
325 			}
326 
327 			IAdaptable context= null;
328 			if (shell != null) {
329 				context= new IAdaptable() {
330 					@SuppressWarnings("unchecked")
331 					@Override
332 					public <T> T getAdapter(Class<T> adapter) {
333 						if (adapter == Shell.class) {
334 							return (T) shell;
335 						}
336 						return null;
337 					}
338 				};
339 			}
340 
341 			String operationName= markers.length == 1 ? ActionMessages.DeleteBreakpointOperationName : ActionMessages.DeleteBreakpointsOperationName;
342 			IUndoableOperation deleteMarkerOperation= new DeleteMarkersOperation(markers, operationName);
343 			deleteMarkerOperation.removeContext(WorkspaceUndoUtil.getWorkspaceUndoContext());
344 			deleteMarkerOperation.addContext(DebugUITools.getBreakpointsUndoContext());
345 			IOperationHistory operationHistory= PlatformUI.getWorkbench().getOperationSupport().getOperationHistory();
346 			try {
347 				operationHistory.execute(deleteMarkerOperation, progressMonitor, context);
348 			} catch (ExecutionException e) {
349 				throw new CoreException(DebugUIPlugin.newErrorStatus("Exception while deleting breakpoint markers", e)); //$NON-NLS-1$
350 			}
351 		}
352 	}
353 
354 	/**
355 	 * Returns the currently active context for the given workbench part. Returns
356 	 * <code>null</code> if there is no current debug context.
357 	 *
358 	 * @param site the part's site where to look up the active context
359 	 * @return the currently active debug context in the given part, or
360 	 *         <code>null</code>
361 	 * @since 3.7
362 	 */
getPartDebugContext(IWorkbenchPartSite site)363 	public static IAdaptable getPartDebugContext(IWorkbenchPartSite site) {
364 		IDebugContextService service = DebugUITools.getDebugContextManager().getContextService(site.getWorkbenchWindow());
365 		String id = null;
366 		String secondaryId = null;
367 		id = site.getId();
368 		if (site instanceof IViewSite) {
369 			secondaryId = ((IViewSite)site).getSecondaryId();
370 		}
371 		ISelection activeContext = service.getActiveContext(id, secondaryId);
372 		return getDebugContextElementForSelection(activeContext);
373 	}
374 
375 	/**
376 	 * Adds the given debug context listener as a listener to the debug context changed events, in
377 	 * the context of the given workbench part.
378 	 * <p>
379 	 * This method is a utility method which ultimately calls
380 	 * {@link IDebugContextService#addDebugContextListener(IDebugContextListener, String, String)}
381 	 * using the part id parameters extracted from the given part parameter.
382 	 * </p>
383 	 *
384 	 * @param site the part's site to get the part ID and part secondary ID from
385 	 * @param listener Debug context listener to add
386 	 *
387 	 * @see IDebugContextService#addDebugContextListener(IDebugContextListener, String, String)
388 	 * @see IDebugContextManager#addDebugContextListener(IDebugContextListener)
389 	 * @since 3.7
390 	 */
addPartDebugContextListener(IWorkbenchPartSite site, IDebugContextListener listener)391 	public static void addPartDebugContextListener(IWorkbenchPartSite site, IDebugContextListener listener) {
392 		IDebugContextService service = DebugUITools.getDebugContextManager().getContextService(site.getWorkbenchWindow());
393 		String id = site.getId();
394 		String secondaryId = null;
395 		if (site instanceof IViewSite) {
396 			secondaryId = ((IViewSite)site).getSecondaryId();
397 		}
398 		service.addDebugContextListener(listener, id, secondaryId);
399 	}
400 
401 	/**
402 	 * Removes the given debug context listener as a listener to the debug context changed events,
403 	 * in the context of the given workbench part.
404 	 * <p>
405 	 * This method is a utility method which ultimately calls
406 	 * {@link IDebugContextService#removeDebugContextListener(IDebugContextListener, String, String)}
407 	 * using the part id parameters extracted from the given part parameter.
408 	 * </p>
409 	 *
410 	 * @param site the part's site to get the part ID and part secondary ID from
411 	 * @param listener Debug context listener to remove
412 	 *
413 	 * @see IDebugContextService#removeDebugContextListener(IDebugContextListener, String, String)
414 	 * @see IDebugContextManager#removeDebugContextListener(IDebugContextListener)
415 	 * @since 3.7
416 	 */
removePartDebugContextListener(IWorkbenchPartSite site, IDebugContextListener listener)417 	public static void removePartDebugContextListener(IWorkbenchPartSite site, IDebugContextListener listener) {
418 		IDebugContextService service = DebugUITools.getDebugContextManager().getContextService(site.getWorkbenchWindow());
419 		String id = site.getId();
420 		String secondaryId = null;
421 		if (site instanceof IViewSite) {
422 			secondaryId = ((IViewSite)site).getSecondaryId();
423 		}
424 		service.removeDebugContextListener(listener, id, secondaryId);
425 	}
426 
427 	/**
428 	 * Extracts the first element from the given selection and casts it to IAdaptable.
429 	 *
430 	 * @param activeContext the selection
431 	 * @return an adaptable
432 	 */
getDebugContextElementForSelection(ISelection activeContext)433 	private static IAdaptable getDebugContextElementForSelection(ISelection activeContext) {
434 		if (activeContext instanceof IStructuredSelection) {
435 			IStructuredSelection selection = (IStructuredSelection) activeContext;
436 			if (!selection.isEmpty()) {
437 				Object firstElement = selection.getFirstElement();
438 				if (firstElement instanceof IAdaptable) {
439 					return (IAdaptable) firstElement;
440 				}
441 			}
442 		}
443 		return null;
444 	}
445 
446 	/**
447 	 * Returns the currently selected resource in the active workbench window,
448 	 * or <code>null</code> if none. If an editor is active, the resource adapter
449 	 * associated with the editor is returned, if any.
450 	 *
451 	 * @return selected resource or <code>null</code>
452 	 * @since 3.0
453 	 */
getSelectedResource()454 	public static IResource getSelectedResource() {
455 		return SelectedResourceManager.getDefault().getSelectedResource();
456 	}
457 
458 	/**
459 	 * Returns the process associated with the current debug context.
460 	 * If there is no debug context currently, the most recently
461 	 * launched process is returned. If there is no current process
462 	 * <code>null</code> is returned.
463 	 *
464 	 * @return the current process, or <code>null</code>
465 	 * @since 2.0
466 	 */
getCurrentProcess()467 	public static IProcess getCurrentProcess() {
468 		IAdaptable context = getDebugContext();
469 		if (context == null) {
470 			ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches();
471 			if (launches.length > 0) {
472 				context = launches[launches.length - 1];
473 			}
474 		}
475 
476 		if (context instanceof IDebugElement) {
477 			return ((IDebugElement)context).getDebugTarget().getProcess();
478 		}
479 
480 		if (context instanceof IProcess) {
481 			return (IProcess)context;
482 		}
483 
484 		if (context instanceof ILaunch) {
485 			ILaunch launch= (ILaunch)context;
486 			IDebugTarget target= launch.getDebugTarget();
487 			if (target != null) {
488 				IProcess process = target.getProcess();
489 				if (process != null) {
490 					return process;
491 				}
492 			}
493 			IProcess[] ps = launch.getProcesses();
494 			if (ps.length > 0) {
495 				return ps[ps.length - 1];
496 			}
497 		}
498 
499 		if (context != null) {
500 			return context.getAdapter(IProcess.class);
501 		}
502 
503 		return null;
504 	}
505 
506 	/**
507 	 * Open the launch configuration dialog with the specified initial selection.
508 	 * The selection may be <code>null</code>, or contain any mix of
509 	 * <code>ILaunchConfiguration</code> or <code>ILaunchConfigurationType</code>
510 	 * elements.
511 	 * <p>
512 	 * Before opening a new dialog, this method checks if there is an existing open
513 	 * launch configuration dialog.  If there is, this dialog is used with the
514 	 * specified selection.  If there is no existing dialog, a new one is created.
515 	 * </p>
516 	 * <p>
517 	 * Note that if an existing dialog is reused, the <code>mode</code> argument is ignored
518 	 * and the existing dialog keeps its original mode.
519 	 * </p>
520 	 *
521 	 * @param shell the parent shell for the launch configuration dialog
522 	 * @param selection the initial selection for the dialog
523 	 * @param mode the mode (run or debug) in which to open the launch configuration dialog.
524 	 *  This should be one of the constants defined in <code>ILaunchManager</code>.
525 	 * @return the return code from opening the launch configuration dialog -
526 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
527 	 *  is returned if an invalid launch group identifier is provided.
528 	 * @see ILaunchGroup
529 	 * @since 2.0
530 	 * @deprecated use openLaunchConfigurationDialogOnGroup(Shell, IStructuredSelection, String)
531 	 *  to specify the launch group that the dialog should be opened on. This method will open
532 	 *  on the launch group with the specified mode and a <code>null</code> category
533 	 */
534 	@Deprecated
openLaunchConfigurationDialog(Shell shell, IStructuredSelection selection, String mode)535 	public static int openLaunchConfigurationDialog(Shell shell, IStructuredSelection selection, String mode) {
536 		ILaunchGroup[] groups = getLaunchGroups();
537 		for (ILaunchGroup group : groups) {
538 			if (group.getMode().equals(mode) && group.getCategory() == null) {
539 				return openLaunchConfigurationDialogOnGroup(shell, selection, group.getIdentifier());
540 			}
541 		}
542 		return Window.CANCEL;
543 	}
544 
545 	/**
546 	 * Open the launch configuration dialog with the specified initial selection.
547 	 * The selection may be <code>null</code>, or contain any mix of
548 	 * <code>ILaunchConfiguration</code> or <code>ILaunchConfigurationType</code>
549 	 * elements.
550 	 * <p>
551 	 * Before opening a new dialog, this method checks if there is an existing open
552 	 * launch configuration dialog.  If there is, this dialog is used with the
553 	 * specified selection.  If there is no existing dialog, a new one is created.
554 	 * </p>
555 	 * <p>
556 	 * Note that if an existing dialog is reused, the <code>mode</code> argument is ignored
557 	 * and the existing dialog keeps its original mode.
558 	 * </p>
559 	 *
560 	 * @param shell the parent shell for the launch configuration dialog
561 	 * @param selection the initial selection for the dialog
562 	 * @param groupIdentifier the identifier of the launch group to display (corresponds to
563 	 * the identifier of a launch group extension)
564 	 * @return The return code from opening the launch configuration dialog -
565 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
566 	 *  is returned if an invalid launch group identifier is provided.
567 	 * @see ILaunchGroup
568 	 * @since 2.1
569 	 */
openLaunchConfigurationDialogOnGroup(Shell shell, IStructuredSelection selection, String groupIdentifier)570 	public static int openLaunchConfigurationDialogOnGroup(Shell shell, IStructuredSelection selection, String groupIdentifier) {
571 		return openLaunchConfigurationDialogOnGroup(shell, selection, groupIdentifier, null);
572 	}
573 
574 	/**
575 	 * Open the launch configuration dialog with the specified initial selection.
576 	 * The selection may be <code>null</code>, or contain any mix of
577 	 * <code>ILaunchConfiguration</code> or <code>ILaunchConfigurationType</code>
578 	 * elements.
579 	 * <p>
580 	 * Before opening a new dialog, this method checks if there is an existing open
581 	 * launch configuration dialog.  If there is, this dialog is used with the
582 	 * specified selection.  If there is no existing dialog, a new one is created.
583 	 * </p>
584 	 * <p>
585 	 * Note that if an existing dialog is reused, the <code>mode</code> argument is ignored
586 	 * and the existing dialog keeps its original mode.
587 	 * </p>
588 	 * <p>
589 	 * If a status is specified, a status handler is consulted to handle the
590 	 * status. The status handler is passed the instance of the launch
591 	 * configuration dialog that is opened. This gives the status handler an
592 	 * opportunity to perform error handling/initialization as required.
593 	 * </p>
594 	 * @param shell the parent shell for the launch configuration dialog
595 	 * @param selection the initial selection for the dialog
596 	 * @param groupIdentifier the identifier of the launch group to display (corresponds to
597 	 * the identifier of a launch group extension)
598 	 * @param status the status to display in the dialog, or <code>null</code>
599 	 * if none
600 	 * @return the return code from opening the launch configuration dialog -
601 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
602 	 *  is returned if an invalid launch group identifier is provided.
603 	 * @see org.eclipse.debug.core.IStatusHandler
604 	 * @see ILaunchGroup
605 	 * @since 2.1
606 	 */
openLaunchConfigurationDialogOnGroup(final Shell shell, final IStructuredSelection selection, final String groupIdentifier, final IStatus status)607 	public static int openLaunchConfigurationDialogOnGroup(final Shell shell, final IStructuredSelection selection, final String groupIdentifier, final IStatus status) {
608 		final int[] result = new int[1];
609 		Runnable r = () -> {
610 			LaunchConfigurationsDialog dialog = (LaunchConfigurationsDialog) LaunchConfigurationsDialog
611 					.getCurrentlyVisibleLaunchConfigurationDialog();
612 			if (dialog != null) {
613 				dialog.setInitialSelection(selection);
614 				dialog.doInitialTreeSelection();
615 				if (status != null) {
616 					dialog.handleStatus(status);
617 				}
618 				result[0] = Window.OK;
619 			} else {
620 				LaunchGroupExtension ext = DebugUIPlugin.getDefault().getLaunchConfigurationManager()
621 						.getLaunchGroup(groupIdentifier);
622 				if (ext != null) {
623 					dialog = new LaunchConfigurationsDialog(shell, ext);
624 					dialog.setOpenMode(LaunchConfigurationsDialog.LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION);
625 					dialog.setInitialSelection(selection);
626 					dialog.setInitialStatus(status);
627 					result[0] = dialog.open();
628 				} else {
629 					result[0] = Window.CANCEL;
630 				}
631 			}
632 		};
633 		BusyIndicator.showWhile(DebugUIPlugin.getStandardDisplay(), r);
634 		return result[0];
635 	}
636 
637 	/**
638 	 * Open the launch configuration properties dialog on the specified launch
639 	 * configuration.
640 	 *
641 	 * @param shell the parent shell for the launch configuration dialog
642 	 * @param configuration the configuration to display
643 	 * @param groupIdentifier group identifier of the launch group the launch configuration
644 	 * belongs to
645 	 * @return the return code from opening the launch configuration dialog -
646 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
647 	 *  is returned if an invalid launch group identifier is provided.
648 	 * @see ILaunchGroup
649 	 * @since 2.1
650 	 */
openLaunchConfigurationPropertiesDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier)651 	public static int openLaunchConfigurationPropertiesDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier) {
652 		return openLaunchConfigurationPropertiesDialog(shell, configuration, groupIdentifier, null);
653 	}
654 
655 	/**
656 	 * Open the launch configuration properties dialog on the specified launch
657 	 * configuration.
658 	 *
659 	 * @param shell the parent shell for the launch configuration dialog
660 	 * @param configuration the configuration to display
661 	 * @param groupIdentifier group identifier of the launch group the launch configuration
662 	 * belongs to
663 	 * @param status the status to display, or <code>null</code> if none
664 	 * @return the return code from opening the launch configuration dialog -
665 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
666 	 *  is returned if an invalid launch group identifier is provided.
667 	 * @see ILaunchGroup
668 	 * @since 3.0
669 	 */
openLaunchConfigurationPropertiesDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier, IStatus status)670 	public static int openLaunchConfigurationPropertiesDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier, IStatus status) {
671 		LaunchGroupExtension group = DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchGroup(groupIdentifier);
672 		if (group != null) {
673 			LaunchConfigurationPropertiesDialog dialog = new LaunchConfigurationPropertiesDialog(shell, configuration, group);
674 			dialog.setInitialStatus(status);
675 			return dialog.open();
676 		}
677 
678 		return Window.CANCEL;
679 	}
680 
681 	/**
682 	 * Open the launch configuration dialog on the specified launch
683 	 * configuration. The dialog displays the tabs for a single configuration
684 	 * only (a tree of launch configuration is not displayed), and provides a
685 	 * launch (run or debug) button.
686 	 * <p>
687 	 * If a status is specified, a status handler is consulted to handle the
688 	 * status. The status handler is passed the instance of the launch
689 	 * configuration dialog that is opened. This gives the status handler an
690 	 * opportunity to perform error handling/initialization as required.
691 	 * </p>
692 	 * @param shell the parent shell for the launch configuration dialog
693 	 * @param configuration the configuration to display
694 	 * @param groupIdentifier group identifier of the launch group the launch configuration
695 	 * belongs to
696 	 * @param status the status to display, or <code>null</code> if none
697 	 * @return the return code from opening the launch configuration dialog -
698 	 *  one  of <code>Window.OK</code> or <code>Window.CANCEL</code>. <code>Window.CANCEL</code>
699 	 *  is returned if an invalid launch group identifier is provided.
700 	 * @see ILaunchGroup
701 	 * @since 2.1
702 	 */
openLaunchConfigurationDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier, IStatus status)703 	public static int openLaunchConfigurationDialog(Shell shell, ILaunchConfiguration configuration, String groupIdentifier, IStatus status) {
704 		LaunchGroupExtension group = DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchGroup(groupIdentifier);
705 		if (group != null) {
706 			LaunchConfigurationDialog dialog = new LaunchConfigurationDialog(shell, configuration, group);
707 			dialog.setInitialStatus(status);
708 			return dialog.open();
709 		}
710 
711 		return Window.CANCEL;
712 	}
713 
714 	/**
715 	 * Saves all dirty editors and builds the workspace according to current
716 	 * preference settings, and returns whether a launch should proceed.
717 	 * <p>
718 	 * The following preferences affect whether dirty editors are saved, and/or if
719 	 * the user is prompted to save dirty editors:
720 	 * </p>
721 	 * <ul>
722 	 * <li>PREF_NEVER_SAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
723 	 * <li>PREF_PROMPT_SAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
724 	 * <li>PREF_AUTOSAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
725 	 * </ul>
726 	 * The following preference affects whether a build is performed before
727 	 * launching (if required):
728 	 * <ul>
729 	 * <li>PREF_BUILD_BEFORE_LAUNCH</li>
730 	 * </ul>
731 	 *
732 	 * @return whether a launch should proceed
733 	 * @since 2.0
734 	 * @deprecated Saving has been moved to the launch delegate
735 	 *             <code>LaunchConfigurationDelegate</code> to allow for scoped
736 	 *             saving of resources that are only involved in the current launch,
737 	 *             no longer the entire workspace
738 	 */
739 	@Deprecated
saveAndBuildBeforeLaunch()740 	public static boolean saveAndBuildBeforeLaunch() {
741 		return DebugUIPlugin.saveAndBuild();
742 	}
743 
744 	/**
745 	 * Saves all dirty editors according to current preference settings, and returns
746 	 * whether a launch should proceed.
747 	 * <p>
748 	 * The following preferences affect whether dirty editors are saved, and/or if
749 	 * the user is prompted to save dirty editors:
750 	 * </p>
751 	 * <ul>
752 	 * <li>PREF_NEVER_SAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
753 	 * <li>PREF_PROMPT_SAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
754 	 * <li>PREF_AUTOSAVE_DIRTY_EDITORS_BEFORE_LAUNCH</li>
755 	 * </ul>
756 	 *
757 	 *
758 	 * @return whether a launch should proceed
759 	 * @since 2.1
760 	 * @deprecated Saving has been moved to the launch delegate
761 	 *             <code>LaunchConfigurationDelegate</code> to allow for scoped
762 	 *             saving of resources that are only involved in the current launch,
763 	 *             no longer the entire workspace
764 	 */
765 	@Deprecated
saveBeforeLaunch()766 	public static boolean saveBeforeLaunch() {
767 		return DebugUIPlugin.preLaunchSave();
768 	}
769 
770 	/**
771 	 * Saves and builds the workspace according to current preference settings,
772 	 * and launches the given launch configuration in the specified mode. It
773 	 * terminates the current launch for the same configuration if it was
774 	 * specified via Preferences or toggled by Shift.
775 	 * <p>
776 	 * This method must be called in the UI thread.
777 	 * </p>
778 	 *
779 	 * @param configuration the configuration to launch
780 	 * @param mode launch mode - run or debug
781 	 * @since 2.1
782 	 */
launch(final ILaunchConfiguration configuration, final String mode)783 	public static void launch(final ILaunchConfiguration configuration, final String mode) {
784 		launch(configuration, mode, DebugUITools.findToggleLaunchForConfig(configuration, mode));
785 	}
786 
787 	private static HashMap<Object, Object> fgLaunchToggleTerminateMap = new HashMap<>();
788 
789 	/**
790 	 * Stores the toggle data for launch in a Map to be used while launching to
791 	 * decide if previous launch for same configuration can be terminated.
792 	 *
793 	 * @param data the editor or selected tree node
794 	 * @param isShift is Shift pressed (use <code>false</code> if no support for
795 	 *            Shift)
796 	 * @since 3.12
797 	 */
storeLaunchToggleTerminate(Object data, Object isShift)798 	public static void storeLaunchToggleTerminate(Object data, Object isShift) {
799 		synchronized (fgLaunchToggleTerminateMap) {
800 			fgLaunchToggleTerminateMap.put(data, isShift);
801 		}
802 	}
803 
804 	/**
805 	 * Stores the toggle data for launch in a Map to be used while launching to
806 	 * decide if previous launch for same configuration can be terminated.
807 	 *
808 	 * @param data the editor or selected tree node
809 	 * @since 3.12
810 	 */
removeLaunchToggleTerminate(Object data)811 	public static void removeLaunchToggleTerminate(Object data) {
812 		synchronized (fgLaunchToggleTerminateMap) {
813 			if (fgLaunchToggleTerminateMap.containsKey(data)) {
814 				fgLaunchToggleTerminateMap.remove(data);
815 			}
816 		}
817 	}
818 
819 	/**
820 	 * @since 3.12
821 	 */
isShiftTerminateLaunch(Object data)822 	private static boolean isShiftTerminateLaunch(Object data) {
823 		Object value;
824 		synchronized (fgLaunchToggleTerminateMap) {
825 			value = fgLaunchToggleTerminateMap.get(data);
826 		}
827 		if (value instanceof TerminateToggleValue) {
828 			return ((TerminateToggleValue) value).isShift();
829 		} else if (value instanceof Boolean) {
830 			return ((Boolean) value).booleanValue();
831 		}
832 		return Boolean.FALSE;
833 	}
834 
835 	/**
836 	 * @since 3.12
837 	 */
838 
getToggleTerminateValue(Object data)839 	private static Object getToggleTerminateValue(Object data) {
840 		Object value;
841 		synchronized (fgLaunchToggleTerminateMap) {
842 			value = fgLaunchToggleTerminateMap.get(data);
843 		}
844 		return value;
845 	}
846 
847 	/**
848 	 * @since 3.12
849 	 */
findToggleLaunchForConfig(ILaunchConfiguration configuration, String mode)850 	private static boolean findToggleLaunchForConfig(ILaunchConfiguration configuration, String mode) {
851 		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
852 		ILaunch[] launches = launchManager.getLaunches();
853 		for (ILaunch iLaunch : launches) {
854 			if (configuration.contentsEqual(iLaunch.getLaunchConfiguration())) {
855 				try {
856 					IResource[] configResource = iLaunch.getLaunchConfiguration().getMappedResources();
857 					if (configResource != null && configResource.length == 1) {
858 						for (Object key : fgLaunchToggleTerminateMap.keySet()) {
859 							if (key instanceof IEditorPart) {
860 								IEditorInput input = ((IEditorPart) key).getEditorInput();
861 								if (input.getAdapter(IResource.class).equals(configResource[0])) {
862 									return isShiftTerminateLaunch(key);
863 								}
864 							} else if (key instanceof TreeSelection) {
865 								TreeSelection selection = (TreeSelection) key;
866 								TreePath[] treePath = selection.getPaths();
867 								if (treePath != null && treePath.length == 1) {
868 									Object lastSegmentObj = treePath[0].getLastSegment();
869 									IResource selectedResource = ((IAdaptable) lastSegmentObj).getAdapter(IResource.class);
870 									if (selectedResource!= null && selectedResource.equals(configResource[0])) {
871 										return isShiftTerminateLaunch(key);
872 									}
873 								}
874 							}
875 						}
876 					} else {
877 						for (Object key : fgLaunchToggleTerminateMap.keySet()) {
878 							if (key instanceof IStructuredSelection) {
879 								Object toggleValue = getToggleTerminateValue(key);
880 								if (toggleValue instanceof TerminateToggleValue) {
881 									LaunchingResourceManager lrm = DebugUIPlugin.getDefault().getLaunchingResourceManager();
882 									ArrayList<LaunchShortcutExtension> shortcuts = new ArrayList<>();
883 									LaunchShortcutExtension shortcut = ((TerminateToggleValue) toggleValue).getShortcut();
884 									shortcuts.add(shortcut);
885 									IResource resource = SelectedResourceManager.getDefault().getSelectedResource();
886 									if (resource == null) {
887 										resource = lrm.getLaunchableResource(shortcuts, (IStructuredSelection) key);
888 									}
889 									List<ILaunchConfiguration> configs = lrm.getParticipatingLaunchConfigurations((IStructuredSelection) key, resource, shortcuts, mode);
890 									if (configs.contains(configuration)) {
891 										return ((TerminateToggleValue) toggleValue).isShift();
892 									}
893 								}
894 							}
895 						}
896 					}
897 
898 				} catch (CoreException e) {
899 					DebugUIPlugin.log(e);
900 				}
901 			}
902 		}
903 		return false;
904 
905 	}
906 
907 	/**
908 	 * Saves and builds the workspace according to current preference settings,
909 	 * and launches the given launch configuration in the specified mode.
910 	 * <p>
911 	 * This method must be called in the UI thread.
912 	 * </p>
913 	 *
914 	 * @param configuration the configuration to launch
915 	 * @param mode launch mode - run or debug
916 	 * @since 3.12
917 	 */
reLaunch(final ILaunchConfiguration configuration, final String mode)918 	public static void reLaunch(final ILaunchConfiguration configuration, final String mode) {
919 		boolean launchInBackground = true;
920 		try {
921 			launchInBackground = configuration.getAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, true);
922 		} catch (CoreException e) {
923 			DebugUIPlugin.log(e);
924 		}
925 		if (launchInBackground) {
926 			DebugUIPlugin.launchInBackground(configuration, mode);
927 		} else {
928 			DebugUIPlugin.launchInForeground(configuration, mode);
929 		}
930 
931 	}
932 
933 
934 	/**
935 	 * Saves and builds the workspace according to current preference settings,
936 	 * and launches the given launch configuration in the specified mode. It
937 	 * terminates the current launch for the same configuration if it was
938 	 * specified via Preferences or toggled by Shift
939 	 * <p>
940 	 * This method must be called in the UI thread.
941 	 * </p>
942 	 *
943 	 * @param configuration the configuration to launch
944 	 * @param mode launch mode - run or debug
945 	 * @param isShift is Shift pressed (use <code>false</code> if no support for
946 	 *            Shift)
947 	 * @since 3.12
948 	 */
launch(final ILaunchConfiguration configuration, final String mode, boolean isShift)949 	public static void launch(final ILaunchConfiguration configuration, final String mode, boolean isShift) {
950 		if (DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IInternalDebugUIConstants.PREF_TERMINATE_AND_RELAUNCH_LAUNCH_ACTION) != isShift) {
951 			ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
952 			ILaunch[] launches = launchManager.getLaunches();
953 			for (ILaunch iLaunch : launches) {
954 				if (configuration.contentsEqual(iLaunch.getLaunchConfiguration())) {
955 					synchronized (fgLaunchList) {
956 						fgLaunchList.add(iLaunch);
957 					}
958 				}
959 			}
960 		}
961 		if (!fgLaunchList.isEmpty()) {
962 			Thread t = new Thread(fgLaunchTerminate);
963 			t.start();
964 			try {
965 				t.join();
966 			} catch (InterruptedException e1) {
967 				DebugUIPlugin.log(e1);
968 				return;
969 			}
970 		}
971 		boolean launchInBackground = true;
972 		try {
973 			launchInBackground = configuration.getAttribute(IDebugUIConstants.ATTR_LAUNCH_IN_BACKGROUND, true);
974 		} catch (CoreException e) {
975 			DebugUIPlugin.log(e);
976 		}
977 		if (launchInBackground) {
978 			DebugUIPlugin.launchInBackground(configuration, mode);
979 		} else {
980 			DebugUIPlugin.launchInForeground(configuration, mode);
981 		}
982 	}
983 
984 
985 	private static Set<ILaunch> fgLaunchList = new LinkedHashSet<>();
986 	private static Runnable fgLaunchTerminate = () -> {
987 		String launchConfigName = null;
988 		Set<ILaunch> launchList;
989 		try {
990 			synchronized (fgLaunchList) {
991 				launchList = new LinkedHashSet<>(fgLaunchList);
992 				fgLaunchList.clear();
993 			}
994 			for (ILaunch iLaunch : launchList) {
995 				launchConfigName = iLaunch.getLaunchConfiguration().getName();
996 				iLaunch.terminate();
997 			}
998 
999 		} catch (DebugException e) {
1000 			DebugUIPlugin.log(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(),
1001 					NLS.bind(ActionMessages.TerminateAndLaunchFailure, launchConfigName), e));
1002 		}
1003 	};
1004 
1005 
1006 	/**
1007 	 * Builds the workspace according to current preference settings, and launches
1008 	 * the given configuration in the specified mode, returning the resulting launch
1009 	 * object.
1010 	 * <p>
1011 	 * The following preference affects whether a build is performed before
1012 	 * launching (if required):
1013 	 * </p>
1014 	 * <ul>
1015 	 * <li>PREF_BUILD_BEFORE_LAUNCH</li>
1016 	 * </ul>
1017 	 *
1018 	 *
1019 	 * @param configuration the configuration to launch
1020 	 * @param mode          the mode to launch in
1021 	 * @param monitor       progress monitor
1022 	 * @return the resulting launch object
1023 	 * @throws CoreException if building or launching fails
1024 	 * @since 2.1
1025 	 */
buildAndLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor)1026 	public static ILaunch buildAndLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
1027 		return DebugUIPlugin.buildAndLaunch(configuration, mode, monitor);
1028 	}
1029 
1030 	/**
1031 	 * Returns the perspective to switch to when a configuration of the given type
1032 	 * is launched in the given mode, or <code>null</code> if no switch should take
1033 	 * place.
1034 	 *
1035 	 * In 3.3 this method is equivalent to calling <code>getLaunchPerspective(ILaunchConfigurationType type, Set modes, ILaunchDelegate delegate)</code>,
1036 	 * with the 'mode' parameter comprising a single element set and passing <code>null</code> as the launch delegate.
1037 	 *
1038 	 * @param type launch configuration type
1039 	 * @param mode launch mode identifier
1040 	 * @return perspective identifier or <code>null</code>
1041 	 * @since 3.0
1042 	 */
getLaunchPerspective(ILaunchConfigurationType type, String mode)1043 	public static String getLaunchPerspective(ILaunchConfigurationType type, String mode) {
1044 		return DebugUIPlugin.getDefault().getPerspectiveManager().getLaunchPerspective(type, mode);
1045 	}
1046 
1047 	/**
1048 	 * Returns the perspective id to switch to when a configuration of the given type launched with the specified delegate
1049 	 * is launched in the given mode set, or <code>null</code> if no switch should occurr.
1050 	 * @param type the configuration type
1051 	 * @param delegate the launch delegate
1052 	 * @param modes the set of modes
1053 	 * @return the perspective id or <code>null</code> if no switch should occur
1054 	 *
1055 	 * @since 3.3
1056 	 */
getLaunchPerspective(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes)1057 	public static String getLaunchPerspective(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes) {
1058 		return DebugUIPlugin.getDefault().getPerspectiveManager().getLaunchPerspective(type, modes, delegate);
1059 	}
1060 
1061 	/**
1062 	 * Sets the perspective to switch to when a configuration of the given type
1063 	 * is launched in the given mode. <code>PERSPECTIVE_NONE</code> indicates no
1064 	 * perspective switch should take place. <code>PERSPECTIVE_DEFAULT</code> indicates
1065 	 * a default perspective switch should take place, as defined by the associated
1066 	 * launch tab group extension.
1067 	 *
1068 	 * In 3.3 this method is equivalent to calling <code>setLaunchPerspective(ILaunchConfigurationType type, Set modes, ILaunchDelegate delegate, String perspectiveid)</code>,
1069 	 * with the parameter 'mode' used in the set modes, and null passed as the delegate
1070 	 *
1071 	 * @param type launch configuration type
1072 	 * @param mode launch mode identifier
1073 	 * @param perspective identifier, <code>PERSPECTIVE_NONE</code>, or
1074 	 *   <code>PERSPECTIVE_DEFAULT</code>
1075 	 * @since 3.0
1076 	 */
setLaunchPerspective(ILaunchConfigurationType type, String mode, String perspective)1077 	public static void setLaunchPerspective(ILaunchConfigurationType type, String mode, String perspective) {
1078 		DebugUIPlugin.getDefault().getPerspectiveManager().setLaunchPerspective(type, mode, perspective);
1079 	}
1080 
1081 	/**
1082 	 * Sets the perspective to switch to when a configuration of the specified type and launched using the
1083 	 * specified launch delegate is launched in the specified modeset. <code>PERSPECTIVE_NONE</code> indicates no
1084 	 * perspective switch should take place.
1085 	 *
1086 	 * Passing <code>null</code> for the launch delegate is quivalent to using the default perspective for the specified
1087 	 * type.
1088 	 * @param type the configuration type
1089 	 * @param delegate the launch delegate
1090 	 * @param modes the set of modes
1091 	 * @param perspectiveid identifier or <code>PERSPECTIVE_NONE</code>
1092 	 *
1093 	 * @since 3.3
1094 	 */
setLaunchPerspective(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes, String perspectiveid)1095 	public static void setLaunchPerspective(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes, String perspectiveid) {
1096 		DebugUIPlugin.getDefault().getPerspectiveManager().setLaunchPerspective(type, modes, delegate, perspectiveid);
1097 	}
1098 
1099 	/**
1100 	 * Returns whether the given launch configuration is private. Generally,
1101 	 * private launch configurations should not be displayed to the user. The
1102 	 * private status of a launch configuration is determined by the
1103 	 * <code>IDebugUIConstants.ATTR_PRIVATE</code> attribute.
1104 	 *
1105 	 * @param configuration launch configuration
1106 	 * @return whether the given launch configuration is private
1107 	 * @since 3.0
1108 	 */
isPrivate(ILaunchConfiguration configuration)1109 	public static boolean isPrivate(ILaunchConfiguration configuration) {
1110 		return !LaunchConfigurationManager.isVisible(configuration);
1111 	}
1112 
1113 	/**
1114 	 * Sets whether step filters should be applied to step commands. This
1115 	 * setting is a global option applied to all registered debug targets.
1116 	 * <p>
1117 	 * Since 3.3, this is equivalent to calling <code>DebugPlugin.setUseStepFilters(boolean)</code>.
1118 	 * </p>
1119 	 * @param useStepFilters whether step filters should be applied to step
1120 	 *  commands
1121 	 * @since 3.0
1122 	 * @see org.eclipse.debug.core.model.IStepFilters
1123 	 */
setUseStepFilters(boolean useStepFilters)1124 	public static void setUseStepFilters(boolean useStepFilters) {
1125 		DebugPlugin.setUseStepFilters(useStepFilters);
1126 	}
1127 
1128 	/**
1129 	 * Returns whether step filters are applied to step commands.
1130 	 * <p>
1131 	 * Since 3.3, this is equivalent to calling <code>DebugPlugin.isUseStepFilters()</code>.
1132 	 * </p>
1133 	 * @return whether step filters are applied to step commands
1134 	 * @since 3.0
1135 	 * @see org.eclipse.debug.core.model.IStepFilters
1136 	 */
isUseStepFilters()1137 	public static boolean isUseStepFilters() {
1138 		return DebugPlugin.isUseStepFilters();
1139 	}
1140 
1141 	/**
1142 	 * Returns the console associated with the given process, or
1143 	 * <code>null</code> if none.
1144 	 *
1145 	 * @param process a process
1146 	 * @return console associated with the given process, or
1147 	 * <code>null</code> if none
1148 	 * @since 3.0
1149 	 */
getConsole(IProcess process)1150 	public static IConsole getConsole(IProcess process) {
1151 		return DebugUIPlugin.getDefault().getProcessConsoleManager().getConsole(process);
1152 	}
1153 
1154 	/**
1155 	 * Returns the console associated with the given debug element, or
1156 	 * <code>null</code> if none.
1157 	 *
1158 	 * @param element a debug model element
1159 	 * @return console associated with the given element, or
1160 	 * <code>null</code> if none
1161 	 * @since 3.0
1162 	 */
getConsole(IDebugElement element)1163 	public static IConsole getConsole(IDebugElement element) {
1164 		IProcess process = element.getDebugTarget().getProcess();
1165 		if (process != null) {
1166 			return getConsole(process);
1167 		}
1168 		return null;
1169 	}
1170 
1171 	/**
1172 	 * Returns all registered launch group extensions.
1173 	 *
1174 	 * @return all registered launch group extensions
1175 	 * @since 3.0
1176 	 */
getLaunchGroups()1177 	public static ILaunchGroup[] getLaunchGroups() {
1178 		return DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchGroups();
1179 	}
1180 
1181 	/**
1182 	 * Returns the last configuration that was launched for specified launch group or
1183 	 * <code>null</code>, if there is not one. This method does not provide any form of
1184 	 * filtering on the returned launch configurations.
1185 	 *
1186 	 * @param groupId the unique identifier of a launch group
1187 	 * @return the last launched configuration for the specified group or <code>null</code>.
1188 	 * @see DebugUITools#getLaunchGroups()
1189 	 * @since 3.3
1190 	 */
getLastLaunch(String groupId)1191 	public static ILaunchConfiguration getLastLaunch(String groupId) {
1192 		return DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLastLaunch(groupId);
1193 	}
1194 
1195 	/**
1196 	 * Returns the launch group that the given launch configuration belongs to, for the specified
1197 	 * mode, or <code>null</code> if none.
1198 	 *
1199 	 * @param configuration the launch configuration
1200 	 * @param mode the mode
1201 	 * @return the launch group the given launch configuration belongs to, for the specified mode,
1202 	 *         or <code>null</code> if none
1203 	 * @since 3.0
1204 	 */
getLaunchGroup(ILaunchConfiguration configuration, String mode)1205 	public static ILaunchGroup getLaunchGroup(ILaunchConfiguration configuration, String mode) {
1206 		try {
1207 			return DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchGroup(configuration.getType(), mode);
1208 		}
1209 		catch(CoreException ce) {
1210 			return null;
1211 		}
1212 	}
1213 
1214 	/**
1215 	 * Performs source lookup on the given artifact and returns the result.
1216 	 * Optionally, a source locator may be specified.
1217 	 *
1218 	 * @param artifact object for which source is to be resolved
1219 	 * @param locator the source locator to use, or <code>null</code>. When <code>null</code>
1220 	 *   a source locator is determined from the artifact, if possible. If the artifact
1221 	 *   is a debug element, the source locator from its associated launch is used.
1222 	 * @return a source lookup result
1223 	 * @since 3.1
1224 	 */
lookupSource(Object artifact, ISourceLocator locator)1225 	public static ISourceLookupResult lookupSource(Object artifact, ISourceLocator locator) {
1226 		return SourceLookupFacility.getDefault().lookup(artifact, locator, false);
1227 	}
1228 
1229 	/**
1230 	 * Displays the given source lookup result in an editor in the given workbench
1231 	 * page. Has no effect if the result has an unknown editor id or editor input.
1232 	 * The editor is opened, positioned, and annotated.
1233 	 * <p>
1234 	 * Honors user preference for editors re-use.
1235 	 * </p>
1236 	 * @param result source lookup result to display
1237 	 * @param page the page to display the result in
1238 	 * @since 3.1
1239 	 */
displaySource(ISourceLookupResult result, IWorkbenchPage page)1240 	public static void displaySource(ISourceLookupResult result, IWorkbenchPage page) {
1241 		SourceLookupFacility.getDefault().display(result, page);
1242 	}
1243 
1244 	/**
1245 	 * Returns the memory rendering manager.
1246 	 *
1247 	 * @return the memory rendering manager
1248 	 * @since 3.1
1249 	 */
getMemoryRenderingManager()1250 	public static IMemoryRenderingManager getMemoryRenderingManager() {
1251 		return MemoryRenderingManager.getDefault();
1252 	}
1253 
1254 	/**
1255 	 * Returns the image associated with the specified type of source container
1256 	 * or <code>null</code> if none.
1257 	 *
1258 	 * @param id unique identifier for a source container type
1259 	 * @return image associated with the specified type of source container
1260 	 *    or <code>null</code> if none
1261 	 * @since 3.2
1262 	 * @see org.eclipse.debug.core.sourcelookup.ISourceContainerType
1263 	 */
getSourceContainerImage(String id)1264 	public static Image getSourceContainerImage(String id){
1265 		return SourceLookupUIUtils.getSourceContainerImage(id);
1266 	}
1267 
1268 	/**
1269 	 * Returns a new source container browser for the specified type of source container
1270 	 * or <code>null</code> if a browser has not been registered.
1271 	 *
1272 	 * @param id unique identifier for a source container type
1273 	 * @return source container browser or <code>null</code> if none
1274 	 * @since 3.2
1275 	 * @see org.eclipse.debug.ui.sourcelookup.ISourceContainerBrowser
1276 	 */
getSourceContainerBrowser(String id)1277 	public static ISourceContainerBrowser getSourceContainerBrowser(String id) {
1278 		return SourceLookupUIUtils.getSourceContainerBrowser(id);
1279 	}
1280 
1281 	/**
1282 	 * Returns the color associated with the specified preference identifier or
1283 	 * <code>null</code> if none.
1284 	 *
1285 	 * @param id preference identifier of the color
1286 	 * @return the color associated with the specified preference identifier
1287 	 * 	or <code>null</code> if none
1288 	 * @since 3.2
1289 	 * @see IDebugUIConstants
1290 	 */
getPreferenceColor(String id)1291 	public static Color getPreferenceColor(String id) {
1292 		return DebugUIPlugin.getPreferenceColor(id);
1293 	}
1294 
1295 	/**
1296 	 * Returns the debug context manager.
1297 	 *
1298 	 * @return debug context manager
1299 	 * @since 3.3
1300 	 */
getDebugContextManager()1301 	public static IDebugContextManager getDebugContextManager() {
1302 		return DebugContextManager.getDefault();
1303 	}
1304 
1305 	/**
1306 	 * Return the debug context for the given executionEvent or <code>null</code> if none.
1307 	 *
1308 	 * @param event The execution event that contains the application context
1309 	 * @return the current debug context, or <code>null</code>.
1310 	 *
1311 	 * @since 3.5
1312 	 */
getDebugContextForEvent(ExecutionEvent event)1313 	public static ISelection getDebugContextForEvent(ExecutionEvent event) {
1314 		Object o = HandlerUtil.getVariable(event, IConfigurationElementConstants.DEBUG_CONTEXT);
1315 		if (o instanceof ISelection) {
1316 			return (ISelection) o;
1317 		}
1318 		return null;
1319 	}
1320 
1321 	/**
1322 	 * Return the debug context for the given executionEvent.
1323 	 *
1324 	 * @param event The execution event that contains the application context
1325 	 * @return the debug context. Will not return <code>null</code>.
1326 	 * @throws ExecutionException If the current selection variable is not found.
1327 	 *
1328 	 * @since 3.5
1329 	 */
getDebugContextForEventChecked(ExecutionEvent event)1330 	public static ISelection getDebugContextForEventChecked(ExecutionEvent event)
1331 			throws ExecutionException {
1332 		Object o = HandlerUtil.getVariableChecked(event, IConfigurationElementConstants.DEBUG_CONTEXT);
1333 		if (!(o instanceof ISelection)) {
1334 			throw new ExecutionException("Incorrect type for " //$NON-NLS-1$
1335 				+ IConfigurationElementConstants.DEBUG_CONTEXT
1336 				+ " found while executing " //$NON-NLS-1$
1337 				+ event.getCommand().getId()
1338 				+ ", expected " + ISelection.class.getName() //$NON-NLS-1$
1339 				+ " found " + o.getClass().getName()); //$NON-NLS-1$
1340 		}
1341 		return (ISelection) o;
1342 	}
1343 
1344 	/**
1345 	 * Returns the global instance of toggle breakpoints target manager.
1346 	 *
1347 	 * @return toggle breakpoints target manager
1348 	 *
1349 	 * @since 3.8
1350 	 */
getToggleBreakpointsTargetManager()1351 	public static IToggleBreakpointsTargetManager getToggleBreakpointsTargetManager() {
1352 		return ToggleBreakpointsTargetManager.getDefault();
1353 	}
1354 
1355 	/**
1356 	 * Returns the ILaunchConfiguration corresponding to
1357 	 * ILaunchConfigurationDialog
1358 	 *
1359 	 * @param dialog The input launch configuration dialog
1360 	 * @return {@link ILaunchConfiguration} Corresponding launch configuration
1361 	 * @since 3.13
1362 	 */
getLaunchConfiguration(ILaunchConfigurationDialog dialog)1363 	public static ILaunchConfiguration getLaunchConfiguration(ILaunchConfigurationDialog dialog) {
1364 		if (dialog instanceof LaunchConfigurationsDialog) {
1365 			LaunchConfigurationTabGroupViewer tabViewer = ((LaunchConfigurationsDialog) dialog).getTabViewer();
1366 			if (tabViewer != null) {
1367 				Object input = tabViewer.getInput();
1368 				if (input instanceof ILaunchConfiguration) {
1369 					ILaunchConfiguration configuration = (ILaunchConfiguration) input;
1370 					return configuration;
1371 				}
1372 			}
1373 		}
1374 		return null;
1375 	}
1376 
1377 }
1378