| /******************************************************************************* |
| * Copyright (c) 2000, 2017 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 |
| * Martin Oberhuber (Wind River) - [325557] Perspective "none" is not persisted |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.ui.launchConfigurations; |
| |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.TransformerException; |
| |
| import org.eclipse.core.commands.contexts.Context; |
| import org.eclipse.core.resources.ISaveContext; |
| import org.eclipse.core.resources.ISaveParticipant; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.debug.core.ILaunchConfigurationType; |
| import org.eclipse.debug.core.ILaunchDelegate; |
| import org.eclipse.debug.core.ILaunchListener; |
| import org.eclipse.debug.core.ILaunchManager; |
| import org.eclipse.debug.internal.core.IConfigurationElementConstants; |
| import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; |
| import org.eclipse.debug.internal.core.LaunchManager; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; |
| import org.eclipse.debug.internal.ui.viewers.AsynchronousSchedulingRuleFactory; |
| import org.eclipse.debug.internal.ui.views.ViewContextManager; |
| import org.eclipse.debug.internal.ui.views.ViewContextService; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.debug.ui.contexts.ISuspendTrigger; |
| import org.eclipse.debug.ui.contexts.ISuspendTriggerListener; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.dialogs.MessageDialogWithToggle; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IPerspectiveDescriptor; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.WorkbenchException; |
| import org.eclipse.ui.contexts.IContextActivation; |
| import org.eclipse.ui.contexts.IContextService; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * The perspective manager manages the 'perspective' settings |
| * defined by launch configurations. Specifically it: |
| * <ul> |
| * <li>changes perspectives as launches are registered</li> |
| * <li>change perspective when a thread suspends</li> |
| * </ul> |
| * |
| * Since 3.3 the Perspectives Manager is an <code>ISaveParticipant</code>, allowing it to participate in |
| * workspace persistence life-cycles. |
| * |
| * @see IDebugUIContants.ATTR_RUN_PERSPECTIVE |
| * @see IDebugUIContants.ATTR_DEBUG_PERSPECTIVE |
| * @see ISaveParticipant |
| * @see ISuspendTriggerListener |
| * @see ILaunchListener |
| * @see org.eclipse.debug.internal.ui.preferences.LaunchPerspectivePreferencePage |
| * @see DebugUIPlugin |
| */ |
| public class PerspectiveManager implements ILaunchListener, ISuspendTriggerListener, ISaveParticipant { |
| |
| /** |
| * Describes exactly one perspective context, which is composed of an <code>ILaunchCOnfigurationType</code>, and set of modes |
| * and an <code>ILaunchDelegate</code>. Perspective ids are then cached for a context based on mode set. |
| * |
| * @since 3.3 |
| */ |
| class PerspectiveContext { |
| |
| private ILaunchConfigurationType fType = null; |
| private ILaunchDelegate fDelegate = null; |
| private Map<Set<String>, String> fPerspectives = null; |
| |
| /** |
| * Constructor |
| * @param type |
| * @param delegate |
| * @param modes |
| */ |
| public PerspectiveContext(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes) { |
| fType = type; |
| fDelegate = delegate; |
| fPerspectives = new HashMap<Set<String>, String>(); |
| fPerspectives.put(modes, null); |
| } |
| |
| /** |
| * We can specially compare two cases: |
| * <ol> |
| * <li>a launch object</li> |
| * <li>an object array of the form [IlaunchConfigurationType, ILaunchDelegate, Set]</li> |
| * </ol> |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object object) { |
| ILaunchDelegate delegate = null; |
| ILaunchConfigurationType type = null; |
| if(object instanceof ILaunch) { |
| try { |
| ILaunch launch = (ILaunch) object; |
| type = launch.getLaunchConfiguration().getType(); |
| delegate = resolveLaunchDelegate(launch); |
| } |
| catch (CoreException e) {return false;} |
| } |
| else if(object instanceof PerspectiveContext) { |
| PerspectiveContext context = (PerspectiveContext) object; |
| type = context.getLaunchConfigurationType(); |
| delegate = context.getLaunchDelegate(); |
| } |
| if(fType != null && type != null && fType.getIdentifier().equals(type.getIdentifier())) { |
| if(fDelegate == null) { |
| return delegate == null; |
| } |
| else { |
| return fDelegate.equals(delegate); |
| } |
| } |
| return super.equals(object); |
| } |
| |
| @Override |
| public int hashCode() { |
| if (fType != null) { |
| int hash = fType.getIdentifier().hashCode(); |
| if (fDelegate != null) { |
| hash += fDelegate.hashCode(); |
| } |
| return hash; |
| } |
| return super.hashCode(); |
| } |
| |
| public ILaunchConfigurationType getLaunchConfigurationType() {return fType;} |
| public ILaunchDelegate getLaunchDelegate() {return fDelegate;} |
| |
| public Map<Set<String>, String> getPersepctiveMap() { |
| return fPerspectives; |
| } |
| |
| /** |
| * Creates a new mapping of the specified perspective id to the specified mode set. |
| * If a mapping for the modeset already exists it is over-written. |
| * @param modes the set of modes |
| * @param pid the id of the perspective |
| */ |
| public void setPerspective(Set<String> modes, String pid) { |
| if(fPerspectives == null) { |
| fPerspectives = new HashMap<Set<String>, String>(); |
| } |
| fPerspectives.put(modes, pid); |
| } |
| |
| /** |
| * Returns the perspective id associated with the given mode set |
| * @param modes the set of mode |
| * @return the perspective id associated with the given mode set, or |
| * <code>null</code>, if there isn't one |
| */ |
| public String getPerspective(Set<String> modes) { |
| if(fPerspectives != null) { |
| return fPerspectives.get(modes); |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Use a customized UI job so that nested jobs with a scheduling rule are |
| * not prevented from running. |
| * See bug 377593 |
| */ |
| private abstract class MyUIJob extends Job { |
| public MyUIJob(String name) { |
| super(name); |
| setSystem(true); |
| setPriority(Job.INTERACTIVE); |
| setRule(AsynchronousSchedulingRuleFactory.getDefault().newSerialPerObjectRule(this)); |
| } |
| |
| @Override |
| protected IStatus run(final IProgressMonitor monitor) { |
| if (monitor.isCanceled()) { |
| return Status.CANCEL_STATUS; |
| } |
| Display asyncDisplay = DebugUIPlugin.getStandardDisplay(); |
| if (asyncDisplay == null || asyncDisplay.isDisposed()) { |
| return Status.CANCEL_STATUS; |
| } |
| asyncDisplay.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| IStatus result = null; |
| Throwable throwable = null; |
| try { |
| if (monitor.isCanceled()) { |
| result = Status.CANCEL_STATUS; |
| } else { |
| result = runInUIThread(monitor); |
| } |
| |
| } catch(Throwable t){ |
| throwable = t; |
| } finally { |
| if (result == null) { |
| result = new Status(IStatus.ERROR, |
| PlatformUI.PLUGIN_ID, IStatus.ERROR, |
| LaunchConfigurationsMessages.PerspectiveManager_Error_1, |
| throwable); |
| } |
| done(result); |
| } |
| } |
| }); |
| return Job.ASYNC_FINISH; |
| } |
| |
| public abstract IStatus runInUIThread(IProgressMonitor monitor); |
| |
| } |
| |
| /** |
| * A listing of <code>PerspectiveContext</code>s |
| * |
| * @since 3.3 |
| */ |
| private Set<PerspectiveContext> fPerspectiveContexts = null; |
| |
| /** |
| * id for the 'delegate' attribute |
| * |
| * @since 3.3 |
| */ |
| public static final String ATTR_DELEGATE_ID = "delegate"; //$NON-NLS-1$ |
| |
| /** |
| * Flag used to indicate that the user is already being prompted to |
| * switch perspectives. This flag allows us to not open multiple |
| * prompts at the same time. |
| */ |
| private boolean fPrompting; |
| |
| /** |
| * Maps each launch to its perspective context activation. These |
| * are disabled when a launch terminates. |
| */ |
| private Map<ILaunch, IContextActivation[]> fLaunchToContextActivations = new HashMap<ILaunch, IContextActivation[]>(); |
| |
| /** |
| * Called by the debug ui plug-in on startup. |
| * The perspective manager starts listening for |
| * launches to be registered. |
| */ |
| public void startup() { |
| DebugUIPlugin.getDefault().addSaveParticipant(this); |
| DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); |
| initPerspectives(); |
| } |
| |
| /** |
| * Called by the debug ui plug-in on shutdown. |
| * The perspective manager de-registers as a |
| * launch listener. |
| */ |
| public void shutdown() { |
| DebugUIPlugin.getDefault().removeSaveParticipant(this); |
| DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); |
| } |
| |
| /** |
| * If there are no launches, remove the Suspend Trigger Listener |
| * |
| * @see ILaunchListener#launchRemoved(ILaunch) |
| */ |
| @Override |
| public synchronized void launchRemoved(final ILaunch launch) { |
| ISuspendTrigger trigger = launch.getAdapter(ISuspendTrigger.class); |
| if (trigger != null) { |
| trigger.removeSuspendTriggerListener(this); |
| } |
| Runnable r= new Runnable() { |
| @Override |
| public void run() { |
| IContextActivation[] activations = fLaunchToContextActivations.remove(launch); |
| if (activations != null) { |
| for (int i = 0; i < activations.length; i++) { |
| IContextActivation activation = activations[i]; |
| activation.getContextService().deactivateContext(activation); |
| } |
| } |
| } |
| }; |
| async(r); |
| } |
| |
| /** |
| * Do nothing. |
| * |
| * @see ILaunchListener#launchChanged(ILaunch) |
| */ |
| @Override |
| public void launchChanged(ILaunch launch) {} |
| |
| /** |
| * Switch to the perspective specified by the |
| * launch configuration. |
| * |
| * @see ILaunchListener#launchAdded(ILaunch) |
| */ |
| @Override |
| public synchronized void launchAdded(ILaunch launch) { |
| ISuspendTrigger trigger = launch.getAdapter(ISuspendTrigger.class); |
| if (trigger != null) { |
| trigger.addSuspendTriggerListener(this); |
| } |
| String perspectiveId = null; |
| // check event filters |
| try { |
| perspectiveId = getPerspectiveId(launch); |
| } |
| catch (CoreException e) { |
| String name = DebugUIPlugin.getModelPresentation().getText(launch); |
| switchFailed(e, name); |
| } |
| // don't switch if a private config |
| ILaunchConfiguration configuration = launch.getLaunchConfiguration(); |
| if (configuration != null) { |
| if (!LaunchConfigurationManager.isVisible(configuration)) { |
| perspectiveId = null; |
| } |
| } |
| final String id = perspectiveId; |
| // switch |
| Job switchJob = new MyUIJob("Perspective Switch Job") { //$NON-NLS-1$ |
| @Override |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| IWorkbenchWindow window = getWindowForPerspective(id); |
| if (id != null && window != null && shouldSwitchPerspective(window, id, IInternalDebugUIConstants.PREF_SWITCH_TO_PERSPECTIVE)) { |
| switchToPerspective(window, id); |
| } |
| return Status.OK_STATUS; |
| } |
| }; |
| switchJob.setSystem(true); |
| switchJob.setPriority(Job.INTERACTIVE); |
| //switchJob.setRule(AsynchronousSchedulingRuleFactory.getDefault().newSerialPerObjectRule(this)); |
| switchJob.schedule(); |
| } |
| |
| |
| /** |
| * Switches to the specified perspective |
| * |
| * @param id perspective identifier |
| */ |
| protected void switchToPerspective(IWorkbenchWindow window, String id) { |
| try { |
| // don't loose the focus dialog if there is one |
| Shell dialog = getModalDialogOpen(window.getShell()); |
| window.getWorkbench().showPerspective(id, window); |
| if (dialog != null) { |
| dialog.setFocus(); |
| } |
| } catch (WorkbenchException e) { |
| DebugUIPlugin.errorDialog(DebugUIPlugin.getShell(), |
| LaunchConfigurationsMessages.PerspectiveManager_Error_1, |
| MessageFormat.format(LaunchConfigurationsMessages.PerspectiveManager_Unable_to_switch_to_perspective___0__2, new Object[] { id }), |
| e); |
| } |
| } |
| |
| /** |
| * Utility method to submit an asynchronous runnable to the UI |
| */ |
| protected void async(Runnable r) { |
| Display d = DebugUIPlugin.getStandardDisplay(); |
| if (d != null && !d.isDisposed()) { |
| d.asyncExec(r); |
| } |
| } |
| |
| /** |
| * Utility method to submit a synchronous runnable to the UI |
| */ |
| protected void sync(Runnable r) { |
| Display d = DebugUIPlugin.getStandardDisplay(); |
| if (d != null && !d.isDisposed()) { |
| d.syncExec(r); |
| } |
| } |
| |
| /** |
| * Reports failure to switch perspectives to the user |
| * |
| * @param status exception status describing failure |
| * @param launchName the name of the launch that the |
| * failure is associated with |
| */ |
| protected void switchFailed(final Throwable t, final String launchName) { |
| sync(new Runnable() { |
| @Override |
| public void run() { |
| DebugUIPlugin.errorDialog(DebugUIPlugin.getShell(), LaunchConfigurationsMessages.PerspectiveManager_Error_1, |
| MessageFormat.format(LaunchConfigurationsMessages.PerspectiveManager_Unable_to_switch_perpsectives_as_specified_by_launch___0__4, new Object[] { launchName }), |
| t); |
| }}); |
| } |
| |
| /** |
| * A breakpoint has been hit. Carry out perspective switching |
| * as appropriate for the given debug event. |
| * |
| * @param event the suspend event |
| */ |
| private void handleBreakpointHit(final ILaunch launch) { |
| |
| String perspectiveId = null; |
| try { |
| perspectiveId = getPerspectiveId(launch); |
| } |
| catch (CoreException e) {DebugUIPlugin.log(e);} |
| // if no perspective specified, always switch to debug |
| // perspective |
| |
| // this has to be done in an async, such that the workbench |
| // window can be accessed |
| final String targetId = perspectiveId; |
| Job switchJob = new MyUIJob("Perspective Switch Job") { //$NON-NLS-1$ |
| @Override |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| IWorkbenchWindow window = null; |
| if (targetId != null) { |
| // get the window to open the perspective in |
| window = getWindowForPerspective(targetId); |
| if (window == null) { |
| return Status.OK_STATUS; |
| } |
| |
| // switch the perspective if user preference is set |
| if (shouldSwitchPerspective(window, targetId, IInternalDebugUIConstants.PREF_SWITCH_PERSPECTIVE_ON_SUSPEND)) { |
| switchToPerspective(window, targetId); |
| window = getWindowForPerspective(targetId); |
| if (window == null) { |
| return Status.OK_STATUS; |
| } |
| } |
| |
| // make sure the shell is active |
| Shell shell= window.getShell(); |
| if (shell != null) { |
| if (DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_ACTIVATE_WORKBENCH)) { |
| Shell dialog = getModalDialogOpen(shell); |
| if (shell.getMinimized()) { |
| shell.setMinimized(false); |
| if (dialog != null) { |
| dialog.setFocus(); |
| } |
| } |
| // If a model dialog is open on the shell, don't activate it |
| if (dialog == null) { |
| shell.forceActive(); |
| } |
| } |
| } |
| |
| // Activate a context for the launch |
| Object ca = fLaunchToContextActivations.get(launch); |
| if (ca == null) { |
| ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration(); |
| if (launchConfiguration != null) { |
| try { |
| String type = launchConfiguration.getType().getIdentifier(); |
| ViewContextService service = ViewContextManager.getDefault().getService(window); |
| if (service != null) { |
| IContextService contextServce = PlatformUI.getWorkbench().getAdapter(IContextService.class); |
| String[] ids = service.getEnabledPerspectives(); |
| IContextActivation[] activations = new IContextActivation[ids.length]; |
| for (int i = 0; i < ids.length; i++) { |
| // Include the word '.internal.' so the context is filtered from the key binding pref page (Bug 144019) also see ViewContextService.contextActivated() |
| Context context = contextServce.getContext(type + ".internal." + ids[i]); //$NON-NLS-1$ |
| if (!context.isDefined()) { |
| context.define(context.getId(), null, null); |
| } |
| IContextActivation activation = contextServce.activateContext(context.getId()); |
| activations[i] = activation; |
| } |
| fLaunchToContextActivations.put(launch, activations); |
| } |
| } catch (CoreException e) { |
| DebugUIPlugin.log(e); |
| } |
| } |
| } |
| |
| } |
| if (window != null && DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IInternalDebugUIConstants.PREF_ACTIVATE_DEBUG_VIEW)) { |
| ViewContextService service = ViewContextManager.getDefault().getService(window); |
| service.showViewQuiet(IDebugUIConstants.ID_DEBUG_VIEW); |
| } |
| return Status.OK_STATUS; |
| } |
| }; |
| |
| switchJob.setSystem(true); |
| switchJob.setPriority(Job.INTERACTIVE); |
| switchJob.setRule(AsynchronousSchedulingRuleFactory.getDefault().newSerialPerObjectRule(this)); |
| switchJob.schedule(); |
| } |
| |
| /** |
| * Returns a modal dialog currently open on the given shell or <code>null</code> if none. |
| * |
| * @param shell shell to check |
| * @return a modal dialog currently open on the given shell or <code>null</code> if none |
| */ |
| private Shell getModalDialogOpen(Shell shell) { |
| Shell[] shells = shell.getShells(); |
| for (int i = 0; i < shells.length; i++) { |
| Shell dialog = shells[i]; |
| if ((dialog.getStyle() & (SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL)) > 0) { |
| return dialog; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the workbench window in which the given perspective |
| * should be shown. First, check the current window to see if it |
| * is already showing the perspective. Then check any other windows. |
| * |
| * @param perspectiveId the perspective identifier |
| * @return which window the given perspective should be shown in |
| * or <code>null</code> if there are no windows available |
| */ |
| private IWorkbenchWindow getWindowForPerspective(String perspectiveId) { |
| IWorkbenchWindow window = DebugUIPlugin.getActiveWorkbenchWindow(); |
| if (isWindowShowingPerspective(window, perspectiveId)) { |
| return window; |
| } |
| IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); |
| for (int i = 0; i < windows.length; i++) { |
| window = windows[i]; |
| if (isWindowShowingPerspective(window, perspectiveId)) { |
| return window; |
| } |
| } |
| window = DebugUIPlugin.getActiveWorkbenchWindow(); |
| if (window != null) { |
| return window; |
| } |
| if (windows.length > 0) { |
| return windows[0]; |
| } |
| return null; |
| } |
| |
| /** |
| * Returns if the specified window is showing the perspective denoted by the specified id |
| * @param window the window to query |
| * @param perspectiveId the perspective to ask about |
| * @return true if the specified window is showing the perspective, false otherwise |
| */ |
| private boolean isWindowShowingPerspective(IWorkbenchWindow window, String perspectiveId) { |
| if (window != null) { |
| IWorkbenchPage page = window.getActivePage(); |
| if (page != null) { |
| IPerspectiveDescriptor perspectiveDescriptor = page.getPerspective(); |
| if (perspectiveDescriptor != null && perspectiveDescriptor.getId().equals(perspectiveId)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns whether or not the user wishes to switch to the specified |
| * perspective when a launch occurs. |
| * |
| * @param perspectiveName the name of the perspective that will be presented |
| * to the user for confirmation if they've asked to be prompted about |
| * perspective switching |
| * @param message a message to be presented to the user. This message is expected to |
| * contain a slot for the perspective name to be inserted ("{0}"). |
| * @param preferenceKey the preference key of the perspective switching preference |
| * @return whether or not the user wishes to switch to the specified perspective |
| * automatically |
| */ |
| private boolean shouldSwitchPerspective(IWorkbenchWindow window, String perspectiveId, String preferenceKey) { |
| if (isCurrentPerspective(window, perspectiveId)) { |
| return false; |
| } |
| String perspectiveName = getPerspectiveLabel(perspectiveId); |
| if (perspectiveName == null) { |
| return false; |
| } |
| String perspectiveDesc = getPerspectiveDescription(perspectiveId); |
| Object[] args; |
| if (perspectiveDesc != null) { |
| args = new String[] { perspectiveName , perspectiveDesc }; |
| } |
| else { |
| args = new String[] { perspectiveName }; |
| } |
| String switchPerspective = DebugUIPlugin.getDefault().getPreferenceStore().getString(preferenceKey); |
| if (MessageDialogWithToggle.ALWAYS.equals(switchPerspective)) { |
| return true; |
| } else if (MessageDialogWithToggle.NEVER.equals(switchPerspective)) { |
| return false; |
| } |
| |
| Shell shell= window.getShell(); |
| if (shell == null || fPrompting) { |
| return false; |
| } |
| fPrompting= true; |
| // Activate the shell if necessary so the prompt is visible |
| Shell modal = getModalDialogOpen(shell); |
| if (shell.getMinimized()) { |
| shell.setMinimized(false); |
| if (modal != null) { |
| modal.setFocus(); |
| } |
| } |
| if (DebugUIPlugin.getDefault().getPreferenceStore().getBoolean(IDebugUIConstants.PREF_ACTIVATE_WORKBENCH)) { |
| if (modal == null) { |
| shell.forceActive(); |
| } |
| } |
| String message = IInternalDebugCoreConstants.EMPTY_STRING; |
| if(IInternalDebugUIConstants.PREF_SWITCH_PERSPECTIVE_ON_SUSPEND.equals(preferenceKey)) { |
| if (getPerspectiveDescription(perspectiveId) != null) { |
| message = LaunchConfigurationsMessages.PerspectiveManager_suspend_description; |
| } |
| else { |
| message = LaunchConfigurationsMessages.PerspectiveManager_13; |
| } |
| } |
| else if(IInternalDebugUIConstants.PREF_SWITCH_TO_PERSPECTIVE.equals(preferenceKey)) { |
| if (getPerspectiveDescription(perspectiveId) != null) { |
| message = LaunchConfigurationsMessages.PerspectiveManager_launch_description; |
| } |
| else { |
| message = LaunchConfigurationsMessages.PerspectiveManager_15; |
| } |
| } |
| LinkedHashMap<String, Integer> buttonLabelToId = new LinkedHashMap<>(); |
| buttonLabelToId.put(LaunchConfigurationsMessages.PerspectiveManager_switch, IDialogConstants.YES_ID); |
| buttonLabelToId.put(IDialogConstants.CANCEL_LABEL, IDialogConstants.CANCEL_ID); |
| MessageDialogWithToggle dialog = MessageDialogWithToggle.open(MessageDialog.QUESTION, shell, LaunchConfigurationsMessages.PerspectiveManager_12, MessageFormat.format(message, args), null, false, DebugUIPlugin.getDefault().getPreferenceStore(), preferenceKey, SWT.NONE, buttonLabelToId); |
| boolean answer = (dialog.getReturnCode() == IDialogConstants.YES_ID); |
| synchronized (this) { |
| fPrompting= false; |
| notifyAll(); |
| } |
| if (isCurrentPerspective(window, perspectiveId)) { |
| answer = false; |
| } |
| return answer; |
| } |
| |
| /** |
| * Returns whether the given perspective identifier matches the |
| * identifier of the current perspective. |
| * |
| * @param perspectiveId the identifier |
| * @return whether the given perspective identifier matches the |
| * identifier of the current perspective |
| */ |
| protected boolean isCurrentPerspective(IWorkbenchWindow window, String perspectiveId) { |
| boolean isCurrent= false; |
| if (window != null) { |
| IWorkbenchPage page = window.getActivePage(); |
| if (page != null) { |
| IPerspectiveDescriptor perspectiveDescriptor = page.getPerspective(); |
| if (perspectiveDescriptor != null) { |
| isCurrent= perspectiveId.equals(perspectiveDescriptor.getId()); |
| } |
| } |
| } |
| return isCurrent; |
| } |
| |
| /** |
| * Returns the label of the perspective with the given identifier or |
| * <code>null</code> if no such perspective exists. |
| * |
| * @param perspectiveId the identifier |
| * @return the label of the perspective with the given identifier or |
| * <code>null</code> if no such perspective exists |
| */ |
| protected String getPerspectiveLabel(String perspectiveId) { |
| IPerspectiveDescriptor newPerspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId); |
| if (newPerspective == null) { |
| return null; |
| } |
| return newPerspective.getLabel(); |
| } |
| |
| |
| /** |
| * Returns the label of the perspective with the given identifier or |
| * <code>null</code> if no such perspective exists. |
| * |
| * @param perspectiveId the identifier |
| * @return the label of the perspective with the given identifier or |
| * <code>null</code> if no such perspective exists |
| */ |
| protected String getPerspectiveDescription(String perspectiveId) { |
| IPerspectiveDescriptor newPerspective = PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(perspectiveId); |
| if (newPerspective == null) { |
| return null; |
| } |
| return newPerspective.getDescription(); |
| } |
| |
| /** |
| * Returns the perspective associated with the |
| * given launch, or <code>null</code> if none. |
| * |
| * @param launch a launch |
| * @return the perspective associated with the launch, |
| * or <code>null</code> |
| * @exception CoreException if unable to retrieve a required |
| * launch configuration attribute |
| */ |
| protected String getPerspectiveId(ILaunch launch) throws CoreException { |
| if (launch == null) { |
| return null; |
| } |
| ILaunchConfiguration config = launch.getLaunchConfiguration(); |
| if (config == null) { |
| return null; |
| } |
| Set<String> modes = launch.getLaunchConfiguration().getModes(); |
| modes.add(launch.getLaunchMode()); |
| String perspectiveId = getLaunchPerspective(config.getType(), modes, resolveLaunchDelegate(launch)); |
| if (perspectiveId != null && perspectiveId.equals(IDebugUIConstants.PERSPECTIVE_NONE)) { |
| perspectiveId = null; |
| } |
| return perspectiveId; |
| } |
| |
| /** |
| * Returns the id of the perspective associated with the given type and set of modes. Passing <code>null</code> for |
| * the launch delegate results in the default perspective id being returned (if there is one). |
| * @param type the type we are launching |
| * @param modes the set of modes the type was launched with |
| * @param delegate the delegate performing the launch for this type and modeset |
| * @return the id of the perspective for the given launch configuration type, modeset and launch delegate |
| * |
| * @since 3.3 |
| */ |
| public String getLaunchPerspective(ILaunchConfigurationType type, Set<String> modes, ILaunchDelegate delegate) { |
| String id = null; |
| PerspectiveContext context = findContext(new PerspectiveContext(type, delegate, modes)); |
| if(context == null || (context != null && !context.getPersepctiveMap().containsKey(modes))) { |
| //try with a null delegate, denoting the perspective for the type |
| context = findContext(new PerspectiveContext(type, null, modes)); |
| if(context == null || (context != null && !context.getPersepctiveMap().containsKey(modes))) { |
| //last resort, try the default perspective |
| return getDefaultLaunchPerspective(type, delegate, modes); |
| } |
| } |
| if(context != null) { |
| id = context.getPerspective(modes); |
| } |
| return id; |
| } |
| |
| /** |
| * Returns the perspective to switch to when a configuration of the given type |
| * is launched in the given mode, or <code>null</code> if no switch should take |
| * place. |
| * <p> |
| * This method is equivalent to calling <code>getLaunchPerspective(ILaunchConfigurationType type, Set modes, ILaunchDelegate delegate)</code>, |
| * with the 'mode' parameter comprising a single element set and passing <code>null</code> as the launch delegate. |
| * </p> |
| * @param type launch configuration type |
| * @param mode launch mode identifier |
| * @return perspective identifier or <code>null</code> |
| * @since 3.0 |
| */ |
| public String getLaunchPerspective(ILaunchConfigurationType type, String mode) { |
| HashSet<String> modes = new HashSet<String>(); |
| modes.add(mode); |
| return getLaunchPerspective(type, modes, null); |
| } |
| |
| /** |
| * Sets the perspective to switch to when a configuration of the given type |
| * is launched in the given mode. <code>PERSPECTIVE_NONE</code> indicates no |
| * perspective switch should take place. <code>PERSPECTIVE_DEFAULT</code> indicates |
| * a default perspective switch should take place, as defined by the associated |
| * launch tab group extension. |
| * <p> |
| * Calling this method is equivalent to calling <code>setLaunchPerspective(ILaunchConfigurationType type, Set modes, ILaunchDelegate delegate, String perspectiveid)</code>, |
| * with the parameter 'mode' used in the set modes, and null passed as the delegate |
| * </p> |
| * @param type launch configuration type |
| * @param mode launch mode identifier |
| * @param perspective identifier, <code>PERSPECTIVE_NONE</code>, or |
| * <code>PERSPECTIVE_DEFAULT</code> |
| * @since 3.0 |
| */ |
| public void setLaunchPerspective(ILaunchConfigurationType type, String mode, String perspective) { |
| HashSet<String> modes = new HashSet<String>(); |
| modes.add(mode); |
| setLaunchPerspective(type, modes, null, perspective); |
| } |
| |
| /** |
| * Sets the perspective that should be switched to when a configuration of the given type is launched with the |
| * specified modes set by the given launch delegate. |
| * <p> |
| * Passing <code>null</code> as a launch delegate will set the default perspective switch for that type and modeset, where |
| * <code>PERSPECTIVE_NONE</code> indicates no perspective switch should take place. |
| * </p> |
| * @param type the type to set a perspective context for |
| * @param modes the set of modes |
| * @param delegate the delegate, or <code>null</code> if the default perspective should be used |
| * |
| * @since 3.3 |
| */ |
| public void setLaunchPerspective(ILaunchConfigurationType type, Set<String> modes, ILaunchDelegate delegate, String perspectiveid) { |
| PerspectiveContext context = new PerspectiveContext(type, delegate, modes); |
| String id = null; |
| if(!IDebugUIConstants.PERSPECTIVE_NONE.equals(perspectiveid)) { |
| if(IDebugUIConstants.PERSPECTIVE_DEFAULT.equals(perspectiveid)) { |
| id = getDefaultLaunchPerspective(type, delegate, modes); |
| } |
| else { |
| id = perspectiveid; |
| } |
| } |
| PerspectiveContext item = findContext(context); |
| if(item != null) { |
| item.setPerspective(modes, id); |
| } |
| else { |
| context.setPerspective(modes, id); |
| item = context; |
| } |
| fPerspectiveContexts.add(item); |
| } |
| |
| /** |
| * Searches the listing of perspective contexts to see if the specified one already exists |
| * @param context the context to compare |
| * @return the matching <code>PerspectiveContext</code> or <code>null</code> if none |
| * |
| * @since 3.3 |
| */ |
| private PerspectiveContext findContext(PerspectiveContext context) { |
| for (PerspectiveContext c : fPerspectiveContexts) { |
| if (context.equals(c)) { |
| return c; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Generates XML for the user specified perspective settings. |
| * |
| * @return XML |
| * @exception IOException if unable to generate the XML |
| * @exception TransformerException if unable to generate the XML |
| * @exception ParserConfigurationException if unable to generate the XML |
| */ |
| private String generatePerspectiveXML() throws ParserConfigurationException, CoreException { |
| Document doc = DebugUIPlugin.getDocument(); |
| Element root = doc.createElement(IConfigurationElementConstants.LAUNCH_PERSPECTIVES); |
| doc.appendChild(root); |
| Map<Set<String>, String> modesets = null; |
| Element element = null; |
| String id = null; |
| ILaunchConfigurationType type = null; |
| ILaunchDelegate delegate = null; |
| for (PerspectiveContext context : fPerspectiveContexts) { |
| modesets = context.getPersepctiveMap(); |
| type = context.getLaunchConfigurationType(); |
| delegate = context.getLaunchDelegate(); |
| for (Set<String> modes : modesets.keySet()) { |
| id = context.getPerspective(modes); |
| String defaultId = getDefaultLaunchPerspective(type, delegate, modes); |
| if(id == null && defaultId != null) { |
| //bug 325557: Override of a default perspective |
| id = IDebugUIConstants.PERSPECTIVE_NONE; |
| } |
| if(id != null && !id.equals(defaultId)) { |
| element = doc.createElement(IConfigurationElementConstants.LAUNCH_PERSPECTIVE); |
| element.setAttribute(IConfigurationElementConstants.MODE, createModesetString(modes)); |
| if(delegate != null) { |
| element.setAttribute(ATTR_DELEGATE_ID, delegate.getId()); |
| } |
| element.setAttribute(IConfigurationElementConstants.CONFIGURATION_TYPES, type.getIdentifier()); |
| element.setAttribute(IConfigurationElementConstants.PERSPECTIVE, id); |
| root.appendChild(element); |
| } |
| } |
| |
| } |
| return DebugPlugin.serializeDocument(doc); |
| } |
| |
| /** |
| * Returns the default perspective to switch to when a configuration of the given type is launched by the specified |
| * launch delegate in the given mode set, or <code>null</code> if none |
| * @param type the type |
| * @param delegate the associated delegate, or <code>null</code> to specify that the default perspective id for that given type and mode set should be returned |
| * @param modes the set of modes this applies to |
| * @return the default perspective id for the given type, delegate and mode set combination, or <code>null</code> if none |
| * |
| * @since 3.3 |
| */ |
| public String getDefaultLaunchPerspective(ILaunchConfigurationType type, ILaunchDelegate delegate, Set<String> modes) { |
| String id = null; |
| if(delegate != null) { |
| id = delegate.getPerspectiveId(modes); |
| } |
| if(id == null) { |
| LaunchConfigurationTabGroupExtension extension = LaunchConfigurationPresentationManager.getDefault().getExtension(type.getIdentifier(), modes); |
| if (extension != null) { |
| id = extension.getPerspective(modes); |
| if (id == null) { |
| if (modes.contains(ILaunchManager.DEBUG_MODE)) { |
| id = IDebugUIConstants.ID_DEBUG_PERSPECTIVE; |
| } |
| } |
| } |
| } |
| return id; |
| } |
| |
| /** |
| * Resolves the <code>ILaunchDelegate</code> from the given <code>ILaunch</code> |
| * @param launch the launch |
| * @return |
| * @throws CoreException |
| */ |
| private ILaunchDelegate resolveLaunchDelegate(ILaunch launch) throws CoreException { |
| Set<String> modes = launch.getLaunchConfiguration().getModes(); |
| modes.add(launch.getLaunchMode()); |
| ILaunchConfigurationType type = launch.getLaunchConfiguration().getType(); |
| ILaunchDelegate[] delegates = LaunchConfigurationManager.filterLaunchDelegates(type, modes); |
| ILaunchDelegate delegate = null; |
| if(delegates.length == 1) { |
| delegate = delegates[0]; |
| } |
| else if(delegates.length > 1) { |
| delegate = launch.getLaunchConfiguration().getPreferredDelegate(modes); |
| if(delegate == null) { |
| delegate = type.getPreferredDelegate(modes); |
| } |
| } |
| return delegate; |
| } |
| |
| /** |
| * Initialize the preference set with settings from user preferences |
| */ |
| private void initPerspectives() { |
| if(fPerspectiveContexts == null) { |
| fPerspectiveContexts = new HashSet<PerspectiveContext>(); |
| String xml = DebugUIPlugin.getDefault().getPreferenceStore().getString(IInternalDebugUIConstants.PREF_LAUNCH_PERSPECTIVES); |
| if (xml != null && xml.length() > 0) { |
| try { |
| Element root = DebugPlugin.parseDocument(xml); |
| NodeList list = root.getChildNodes(); |
| LaunchManager lm = (LaunchManager) DebugPlugin.getDefault().getLaunchManager(); |
| ILaunchConfigurationType lctype = null; |
| ILaunchDelegate ldelegate = null; |
| Set<String> modes = null; |
| Node node = null; |
| Element element = null; |
| for (int i = 0; i < list.getLength(); ++i) { |
| node = list.item(i); |
| if (node.getNodeType() == Node.ELEMENT_NODE) { |
| element = (Element) node; |
| String nodeName = element.getNodeName(); |
| if (nodeName.equalsIgnoreCase(IConfigurationElementConstants.LAUNCH_PERSPECTIVE)) { |
| String type = element.getAttribute(IConfigurationElementConstants.CONFIGURATION_TYPES); |
| String mode = element.getAttribute(IConfigurationElementConstants.MODE); |
| String perspective = element.getAttribute(IConfigurationElementConstants.PERSPECTIVE); |
| String delegate = element.getAttribute(ATTR_DELEGATE_ID); |
| lctype = lm.getLaunchConfigurationType(type); |
| ldelegate = lm.getLaunchDelegate(delegate); |
| modes = parseModes(mode); |
| if(lctype != null && !modes.isEmpty() && !IInternalDebugCoreConstants.EMPTY_STRING.equals(perspective)) { |
| setLaunchPerspective(lctype, modes, ldelegate, perspective); |
| } |
| } |
| } |
| } |
| } |
| catch (CoreException e) {DebugUIPlugin.log(e);} |
| } |
| } |
| } |
| |
| /** |
| * Parses a string argument into a set of modes |
| * @param modes the string to parse |
| * @return a set of modes parsed from the specified string of the empty set, never null |
| * |
| * @since 3.3 |
| */ |
| private Set<String> parseModes(String modes) { |
| HashSet<String> modeset = new HashSet<String>(); |
| String[] ms = modes.split(","); //$NON-NLS-1$ |
| for(int i = 0; i < ms.length; i++) { |
| modeset.add(ms[i].trim()); |
| } |
| return modeset; |
| } |
| |
| /** |
| * Creates a standard comma separated list of the modes from the specified |
| * set |
| * |
| * @param modes the set to write to string |
| * @return the mode set as a string |
| */ |
| private String createModesetString(Set<String> modes) { |
| String str = IInternalDebugCoreConstants.EMPTY_STRING; |
| if(modes != null) { |
| for (Iterator<String> iter = modes.iterator(); iter.hasNext();) { |
| str += iter.next(); |
| if(iter.hasNext()) { |
| str += ","; //$NON-NLS-1$ |
| } |
| } |
| } |
| return str; |
| } |
| |
| /** |
| * Schedules the given job after perspective switching is complete, or |
| * immediately if a perspective switch is not in progress. |
| * |
| * @param job job to run after perspective switching |
| */ |
| public void schedulePostSwitch(Job job) { |
| job.setRule(AsynchronousSchedulingRuleFactory.getDefault().newSerialPerObjectRule(this)); |
| job.schedule(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.ui.contexts.ISuspendTriggerListener#suspended(org.eclipse.debug.core.ILaunch, java.lang.Object) |
| */ |
| @Override |
| public void suspended(ILaunch launch, Object context) { |
| handleBreakpointHit(launch); |
| } |
| |
| /** |
| * @see org.eclipse.core.resources.ISaveParticipant#doneSaving(org.eclipse.core.resources.ISaveContext) |
| */ |
| @Override |
| public void doneSaving(ISaveContext context) {} |
| |
| /** |
| * @see org.eclipse.core.resources.ISaveParticipant#prepareToSave(org.eclipse.core.resources.ISaveContext) |
| */ |
| @Override |
| public void prepareToSave(ISaveContext context) throws CoreException {} |
| |
| /** |
| * @see org.eclipse.core.resources.ISaveParticipant#rollback(org.eclipse.core.resources.ISaveContext) |
| */ |
| @Override |
| public void rollback(ISaveContext context) {} |
| |
| /** |
| * @see org.eclipse.core.resources.ISaveParticipant#saving(org.eclipse.core.resources.ISaveContext) |
| */ |
| @Override |
| public void saving(ISaveContext context) throws CoreException { |
| try { |
| DebugUIPlugin.getDefault().getPreferenceStore().putValue(IInternalDebugUIConstants.PREF_LAUNCH_PERSPECTIVES, generatePerspectiveXML()); |
| } catch (ParserConfigurationException e) { |
| throw new CoreException(DebugUIPlugin.newErrorStatus("Exception occurred while generating launch perspectives preference XML", e)); //$NON-NLS-1$ |
| } |
| } |
| } |