| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.ui.views.launch; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.model.IDebugElement; |
| import org.eclipse.debug.core.model.IDebugModelProvider; |
| import org.eclipse.debug.core.model.IProcess; |
| import org.eclipse.debug.core.model.IStackFrame; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; |
| import org.eclipse.debug.internal.ui.launchConfigurations.PerspectiveManager; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.ui.IPerspectiveDescriptor; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IViewReference; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPartReference; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.activities.ActivityManagerEvent; |
| import org.eclipse.ui.activities.IActivity; |
| import org.eclipse.ui.activities.IActivityManager; |
| import org.eclipse.ui.activities.IActivityManagerListener; |
| import org.eclipse.ui.activities.IActivityPatternBinding; |
| import org.eclipse.ui.activities.IWorkbenchActivitySupport; |
| import org.eclipse.ui.contexts.ContextManagerEvent; |
| import org.eclipse.ui.contexts.EnabledSubmission; |
| import org.eclipse.ui.contexts.IContext; |
| import org.eclipse.ui.contexts.IContextManager; |
| import org.eclipse.ui.contexts.IContextManagerListener; |
| import org.eclipse.ui.contexts.IWorkbenchContextSupport; |
| import org.eclipse.ui.contexts.NotDefinedException; |
| import org.eclipse.ui.progress.UIJob; |
| |
| /** |
| * A context listener which automatically opens/closes/activates views in |
| * response to debug context changes and automatically enables activities |
| * as appropriate. |
| * |
| * The context listener updates for selection changes in the LaunchView, |
| * enabling/disabling contexts and enabling activities based on the |
| * org.eclipse.debug.ui.debugModelContextBindings and |
| * org.eclipse.ui.activities extension points. |
| * |
| * Activity pattern bindings with patterns of the form: |
| * <debug model identifier>/debugModel |
| * are treated as bindings between a debug model and an activity. When |
| * an element with the specified debug model identifier is selected, |
| * the specified activity will be enabled. |
| */ |
| public class LaunchViewContextListener implements IContextManagerListener, IActivityManagerListener { |
| |
| private static final String DEBUG_MODEL_ACTIVITY_SUFFIX = "/debugModel"; //$NON-NLS-1$ |
| public static final String ID_CONTEXT_VIEW_BINDINGS= "contextViewBindings"; //$NON-NLS-1$ |
| public static final String ID_DEBUG_MODEL_CONTEXT_BINDINGS= "debugModelContextBindings"; //$NON-NLS-1$ |
| public static final String ATTR_CONTEXT_ID= "contextId"; //$NON-NLS-1$ |
| public static final String ATTR_VIEW_ID= "viewId"; //$NON-NLS-1$ |
| public static final String ATTR_DEBUG_MODEL_ID= "debugModelId"; //$NON-NLS-1$ |
| public static final String ATTR_AUTO_OPEN= "autoOpen"; //$NON-NLS-1$ |
| public static final String ATTR_AUTO_CLOSE= "autoClose"; //$NON-NLS-1$ |
| |
| /** |
| * The launch view that this context listener works for |
| */ |
| private LaunchView launchView; |
| /** |
| * A mapping of debug models IDs (String) to a collection |
| * of context IDs (List<String>). |
| */ |
| private Map modelsToContexts= new HashMap(); |
| |
| /** |
| * A cache of activity pattern bindings for debug models. |
| */ |
| private List modelPatternBindings = new ArrayList(); |
| |
| /** |
| * Currently enabled activities |
| */ |
| private Set enabledActivities; |
| |
| /** |
| * A mapping of debug model IDs (String) to a collection |
| * of resolved activity IDs (Set<String>). |
| */ |
| private Map modelsToActivities= new HashMap(); |
| /** |
| * A mapping of context IDs (Strings) to a collection |
| * of context-view bindings (IConfigurationElements). |
| */ |
| private Map contextViews= new HashMap(); |
| /** |
| * Collection of all views that might be opened or closed automatically. |
| */ |
| private Set managedViewIds= new HashSet(); |
| /** |
| * Collection of views which have been manually closed by the |
| * user. Views which are in this collection should not be |
| * automatically opened. |
| */ |
| private Set viewIdsToNotOpen= new HashSet(); |
| /** |
| * Map of views which have been automatically opened. |
| * Only views which are in this collection should be automatically |
| * closed. |
| * |
| * Key: perspective id |
| * Value: HashSet of view ids open in a perspective |
| */ |
| private Map openedViewIds= new HashMap(); |
| |
| /** |
| * Map of ILaunch objects to the List of EnabledSubmissions that were |
| * submitted for them. |
| * Key: ILaunch |
| * Value: List <EnabledSubmission> |
| */ |
| private Map fContextSubmissions= new HashMap(); |
| public static final String DEBUG_CONTEXT= "org.eclipse.debug.ui.debugging"; //$NON-NLS-1$ |
| /** |
| * String preference specifying which views should not be |
| * automatically opened by the launch view. |
| * The value is a comma-separated list of view identifiers. |
| * |
| * @since 3.0 |
| */ |
| public static final String PREF_VIEWS_TO_NOT_OPEN= IDebugUIConstants.PLUGIN_ID + ".views_to_not_open"; //$NON-NLS-1$ |
| /** |
| * String preference specifying which views have been |
| * automatically opened by the launch view. Only views which |
| * have been automatically opened will be automatically closed. |
| * The value is a comma-separated list of view identifiers. |
| * |
| * @since 3.0 |
| */ |
| public static final String PREF_OPENED_VIEWS= IDebugUIConstants.PLUGIN_ID + ".opened_views"; //$NON-NLS-1$ |
| /** |
| * The collection of context ids which were most recently enabled. |
| */ |
| private List lastEnabledIds= new ArrayList(); |
| /** |
| * Boolean flag controlling whether or not this listener is |
| * tracking part changes. This is necessary since this class |
| * doesn't implement its own listener, but it informed of |
| * perspective change events by the LaunchView. |
| */ |
| private boolean fIsTrackingPartChanges; |
| /** |
| * Collection of perspectives in which views should be |
| * automatically opened and closed. |
| */ |
| private List fAutoManagePerspectives= new ArrayList(); |
| |
| /** |
| * Creates a fully initialized context listener. |
| * |
| * @param view a fully initialized launch view |
| */ |
| public LaunchViewContextListener(LaunchView view) { |
| launchView= view; |
| loadTrackViews(); |
| loadDebugModelContextExtensions(); |
| loadDebugModelActivityExtensions(); |
| loadContextToViewExtensions(true); |
| loadOpenedViews(); |
| loadViewsToNotOpen(); |
| loadAutoManagePerspectives(); |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| workbench.getContextSupport().getContextManager().addContextManagerListener(this); |
| IActivityManager activityManager = workbench.getActivitySupport().getActivityManager(); |
| activityManager.addActivityManagerListener(this); |
| enabledActivities = activityManager.getEnabledActivityIds(); |
| } |
| |
| /** |
| * Loads extensions which map context ids to views. This information |
| * is used to open the appropriate views when a context is activated. |
| */ |
| private void loadContextToViewExtensions(boolean reloadContextMappings) { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), ID_CONTEXT_VIEW_BINDINGS); |
| IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); |
| for (int i = 0; i < configurationElements.length; i++) { |
| IConfigurationElement element = configurationElements[i]; |
| String viewId = getViewId(element); |
| if (reloadContextMappings) { |
| String contextId = element.getAttribute(ATTR_CONTEXT_ID); |
| if (contextId == null || viewId == null) { |
| continue; |
| } |
| List elements= (List) contextViews.get(contextId); |
| if (elements == null) { |
| elements= new ArrayList(); |
| contextViews.put(contextId, elements); |
| } |
| elements.add(element); |
| } |
| managedViewIds.add(viewId); |
| } |
| } |
| |
| /** |
| * Loads the extensions which map debug model identifiers |
| * to context ids. This information is used to activate the |
| * appropriate context when a debug element is selected. |
| * |
| * When a context associated with a debug model is enabled, we |
| * also activate all parent contexts. Since the context manager |
| * does not do this automatically, we cache all parent context |
| * identifiers in the modelToContexts map as well |
| */ |
| private void loadDebugModelContextExtensions() { |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), ID_DEBUG_MODEL_CONTEXT_BINDINGS); |
| IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); |
| for (int i = 0; i < configurationElements.length; i++) { |
| IConfigurationElement element = configurationElements[i]; |
| String modelIdentifier = element.getAttribute(ATTR_DEBUG_MODEL_ID); |
| String contextId = element.getAttribute(ATTR_CONTEXT_ID); |
| if (modelIdentifier != null && contextId != null) { |
| List contextIds = (List) modelsToContexts.get(modelIdentifier); |
| if (contextIds == null) { |
| contextIds = new ArrayList(); |
| modelsToContexts.put(modelIdentifier, contextIds); |
| } |
| contextIds.add(contextId); |
| } |
| } |
| } |
| |
| /** |
| * Loads the extensions which map debug model patterns |
| * to activity ids. This information is used to activate the |
| * appropriate activities when a debug element is selected. |
| */ |
| private void loadDebugModelActivityExtensions() { |
| IActivityManager activityManager = PlatformUI.getWorkbench().getActivitySupport().getActivityManager(); |
| Set activityIds = activityManager.getDefinedActivityIds(); |
| Iterator activityIterator = activityIds.iterator(); |
| while (activityIterator.hasNext()) { |
| String activityId= (String) activityIterator.next(); |
| IActivity activity = activityManager.getActivity(activityId); |
| if (activity != null) { |
| Set patternBindings = activity.getActivityPatternBindings(); |
| Iterator patternIterator= patternBindings.iterator(); |
| while (patternIterator.hasNext()) { |
| IActivityPatternBinding patternBinding= (IActivityPatternBinding) patternIterator.next(); |
| String pattern = patternBinding.getPattern().pattern(); |
| if (pattern.endsWith(DEBUG_MODEL_ACTIVITY_SUFFIX)) { |
| modelPatternBindings.add(patternBinding); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Lists the contextViews configuration elements for the |
| * given context ID and all its parent context IDs. The |
| * list only contains one configuration element per view |
| * such that if a child context provides a binding for a view |
| * it will override any bindings provided for that same view by |
| * parent contexts. |
| * |
| * @param contextId the context ID |
| * @return the configuration elements for the given context ID and |
| * all parent context IDs. |
| */ |
| private List getConfigurationElements(String contextId) { |
| // Collection of view ids for which configuration |
| // elements have been found. |
| List configuredViewIds= new ArrayList(); |
| List allConfigurationElements= new ArrayList(); |
| IContextManager contextManager = PlatformUI.getWorkbench().getContextSupport().getContextManager(); |
| while (contextId != null) { |
| List configurationElements= (List) contextViews.get(contextId); |
| if (configurationElements != null) { |
| ListIterator iter= configurationElements.listIterator(); |
| while (iter.hasNext()) { |
| // Only add the element if configuredViewIds do not already |
| // contain viewId. |
| // This allows child contexts to override parent |
| // bindings. |
| IConfigurationElement element= (IConfigurationElement) iter.next(); |
| String viewId = element.getAttribute(ATTR_VIEW_ID); |
| if (viewId != null) { |
| if (!configuredViewIds.contains(viewId)) { |
| allConfigurationElements.add(element); |
| } |
| configuredViewIds.add(viewId); |
| } |
| } |
| } |
| IContext context = contextManager.getContext(contextId); |
| if (context != null) { |
| try { |
| contextId= context.getParentId(); |
| } catch (NotDefinedException e) { |
| contextId= null; |
| } |
| } |
| } |
| return allConfigurationElements; |
| } |
| |
| /** |
| * Persist the collection of views to not automatically open. |
| */ |
| private void saveViewsToNotOpen() { |
| saveViewCollection(LaunchViewContextListener.PREF_VIEWS_TO_NOT_OPEN, viewIdsToNotOpen); |
| } |
| |
| /** |
| * Persist the collection of views which have been automatically |
| * opened. |
| */ |
| private void saveOpenedViews() { |
| saveViewMap(LaunchViewContextListener.PREF_OPENED_VIEWS, openedViewIds); |
| } |
| |
| /** |
| * Persist the view identifiers that the user has manually |
| * opened/closed so that we continue to not automatically |
| * open/close them. |
| * @param attribute the preference key in which to store the |
| * view id collection |
| * @param collection the view identifier collection |
| */ |
| public void saveViewCollection(String attribute, Set collection) { |
| StringBuffer views= new StringBuffer(); |
| Iterator iter= collection.iterator(); |
| while (iter.hasNext()) { |
| views.append((String) iter.next()).append(','); |
| } |
| if (views.length() > 0) { |
| IPreferenceStore preferenceStore = DebugUITools.getPreferenceStore(); |
| preferenceStore.removePropertyChangeListener(launchView); |
| preferenceStore.setValue(attribute, views.toString()); |
| preferenceStore.addPropertyChangeListener(launchView); |
| } |
| } |
| |
| |
| /** |
| * Persist the view identifiers that the user has manually |
| * opened/closed so that we continue to not automatically |
| * open/close them. |
| * |
| * key: perspective id |
| * value: ArrayList of view ids |
| * |
| * The map is saved in the following format: |
| * key1:arrayElm(0),arrayElm(1)/key2:arrayElm(0),arrayElm(1) |
| * Perspective settings are delimited by "/". |
| * view Ids are delimited by "," |
| * |
| * @param attribute attribute the preference key in which to store the |
| * view id map |
| * @param map that maps a persective to a list of view ids |
| */ |
| private void saveViewMap(String attribute, Map map) { |
| StringBuffer views= new StringBuffer(); |
| Iterator iter= map.keySet().iterator(); |
| while (iter.hasNext()) { |
| String perspId = (String) iter.next(); |
| Set viewIds = (Set)map.get(perspId); |
| views.append("/"); //$NON-NLS-1$ |
| views.append(perspId); |
| if (viewIds != null && !viewIds.isEmpty()) |
| { |
| views.append(":"); //$NON-NLS-1$ |
| Iterator viewsIter = viewIds.iterator(); |
| while (viewsIter.hasNext()) |
| { |
| String viewId = (String)viewsIter.next(); |
| views.append(viewId); |
| views.append(","); //$NON-NLS-1$ |
| } |
| } |
| } |
| if (views.length() > 0) { |
| IPreferenceStore preferenceStore = DebugUITools.getPreferenceStore(); |
| preferenceStore.removePropertyChangeListener(launchView); |
| preferenceStore.setValue(attribute, views.toString()); |
| preferenceStore.addPropertyChangeListener(launchView); |
| } |
| } |
| |
| /** |
| * Load the collection of views to not open. |
| */ |
| public void loadViewsToNotOpen() { |
| loadViewCollection(LaunchViewContextListener.PREF_VIEWS_TO_NOT_OPEN, viewIdsToNotOpen); |
| } |
| |
| /** |
| * Load the collection of views that have been automatically |
| * opened. |
| */ |
| public void loadOpenedViews() { |
| loadViewMap(LaunchViewContextListener.PREF_OPENED_VIEWS, openedViewIds); |
| } |
| |
| /** |
| * Loads a collection of view ids from the preferences keyed to |
| * the given attribute, and stores them in the given collection |
| * |
| * @param attribute the attribute of the view ids |
| * @param collection the collection to store the view ids into. |
| */ |
| public void loadViewCollection(String attribute, Set collection) { |
| collection.clear(); |
| String views = DebugUITools.getPreferenceStore().getString(attribute); |
| int startIndex= 0; |
| int endIndex= views.indexOf(','); |
| if (endIndex == -1) { |
| endIndex= views.length(); |
| } |
| while (startIndex < views.length() - 1) { |
| String viewId= views.substring(startIndex, endIndex); |
| if (viewId.length() > 0) { |
| collection.add(viewId); |
| } |
| startIndex= endIndex + 1; |
| endIndex= views.indexOf(',', startIndex); |
| } |
| } |
| |
| /** |
| * Loads a map of view ids from the preferences keyed to |
| * the given attribute, and stores them in the given map |
| * |
| * The map is saved in the following format: |
| * key1:arrayElm(0),arrayElm(1)/key2:arrayElm(0)+arrayElm(1) |
| * Perspective settings are delimited by "/". |
| * Key is the perspective id |
| * ArrayElm's are the view Ids and are delimited by "," |
| * |
| * @param attribute the attribute of the view ids |
| * @param map the map to store the view ids into. |
| */ |
| private void loadViewMap(String attribute, Map map) { |
| map.clear(); |
| String views = DebugUITools.getPreferenceStore().getString(attribute); |
| |
| if (views.startsWith("/")) //$NON-NLS-1$ |
| { |
| // list of views ids in this format: |
| // perspective1Id:viewIdA,viewIdB/persective2Id:viewIda,viewIdB |
| String[] viewsStr = views.split("/"); //$NON-NLS-1$ |
| |
| for (int i=0; i<viewsStr.length; i++) |
| { |
| if (viewsStr[i].length() == 0) |
| continue; |
| |
| // split perpectiveId and viewId |
| String[] data = viewsStr[i].split(":"); //$NON-NLS-1$ |
| |
| // data[0] = perspective |
| // data[1] = list of view ids delimited by "," |
| |
| if (data.length == 2) |
| { |
| String perspId = data[0]; |
| |
| String[] viewIds = data[1].split(","); //$NON-NLS-1$ |
| Set list = new HashSet(); |
| for (int j=0; j<viewIds.length; j++) |
| { |
| list.add(viewIds[j]); |
| } |
| |
| openedViewIds.put(perspId, list); |
| } |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.contexts.IContextManagerListener#contextManagerChanged(org.eclipse.ui.contexts.ContextManagerEvent) |
| */ |
| public void contextManagerChanged(ContextManagerEvent contextManagerEvent) { |
| Set enabled = getNewlyEnabledContexts(contextManagerEvent); |
| Set disabled = getNewlyDisabledContexts(contextManagerEvent); |
| contextEnabled(enabled); |
| contextsDisabled(disabled); |
| } |
| |
| private Set getNewlyEnabledContexts(ContextManagerEvent contextManagerEvent) { |
| Set set = new HashSet(contextManagerEvent.getContextManager().getEnabledContextIds()); |
| set.removeAll(contextManagerEvent.getPreviouslyEnabledContextIds()); |
| return set; |
| } |
| |
| private Set getNewlyDisabledContexts(ContextManagerEvent contextManagerEvent) { |
| Set set = new HashSet(contextManagerEvent.getPreviouslyEnabledContextIds()); |
| set.removeAll(contextManagerEvent.getContextManager().getEnabledContextIds()); |
| return set; |
| } |
| |
| /** |
| * The context with the given ID has been enabled. |
| * Activate the appropriate views. |
| * |
| * @param contextId the ID of the context that has been |
| * enabled |
| */ |
| public void contextEnabled(final Set contextIds) { |
| if (!isAutoManageViews()) { |
| return; |
| } |
| |
| final UIJob openViewsJob = new UIJob("Open Context-Enabled Views") { //$NON-NLS-1$ |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| IWorkbenchPage page = getPage(); |
| if (page == null) |
| return Status.OK_STATUS; |
| |
| // Since we run this job asynchronously on the UI Thread, |
| // #getPerspective() may return null when this job is run |
| // when the workbench is shutting down. |
| if (page.getPerspective() == null) |
| return Status.OK_STATUS; |
| |
| // We ignore the "Debugging" context since we use it |
| // to provide a base set of views for other context |
| // bindings to inherit. If we don't ignore it, we'll |
| // end up opening those views whenever a debug session |
| // starts, which is not the desired behavior. |
| contextIds.remove(DEBUG_CONTEXT); |
| if (page == null || contextIds.size() == 0) { |
| return Status.OK_STATUS; |
| } |
| Set viewsToShow = new HashSet(); |
| Set viewsToOpen = new HashSet(); |
| computeViewActivation(contextIds, viewsToOpen, viewsToShow); |
| |
| boolean resetTrackingPartChanges = false; |
| if (fIsTrackingPartChanges) { |
| // only change the flag if it is currently |
| // tracking part changes. |
| fIsTrackingPartChanges = false; |
| resetTrackingPartChanges = true; |
| } |
| |
| Iterator iterator = viewsToOpen.iterator(); |
| |
| String id = page.getPerspective().getId(); |
| Set views = (Set) openedViewIds.get(id); |
| if (views == null) { |
| views = new HashSet(); |
| } |
| |
| while (iterator.hasNext()) { |
| String viewId = (String) iterator.next(); |
| try { |
| IViewPart view = page.showView(viewId, null, |
| IWorkbenchPage.VIEW_CREATE); |
| views.add(viewId); |
| |
| viewsToShow.add(view); |
| } catch (PartInitException e) { |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| } |
| |
| if (!viewsToOpen.isEmpty()) { |
| openedViewIds.put(id, views); |
| saveOpenedViews(); |
| } |
| iterator = viewsToShow.iterator(); |
| while (iterator.hasNext()) { |
| boolean activate = true; |
| IViewPart view = (IViewPart) iterator.next(); |
| IViewPart[] stackedViews = page.getViewStack(view); |
| if (stackedViews == null) { |
| continue; |
| } |
| // For each applicable view, iterate through the view stack. |
| // If we find that view before any other applicable views, |
| // show it. Otherwise, don't. |
| for (int i = 0; i < stackedViews.length; i++) { |
| IViewPart stackedView = stackedViews[i]; |
| if (view == stackedView) { |
| break; |
| } else if (viewsToShow.contains(stackedView)) { |
| // If this view is below an appropriate view, don't |
| // show it |
| activate = false; |
| break; |
| } |
| } |
| if (activate) { |
| page.bringToTop(view); |
| } |
| } |
| |
| // Reset if we have previously changed this setting |
| if (resetTrackingPartChanges) |
| loadTrackViews(); |
| |
| return Status.OK_STATUS; |
| } |
| }; |
| |
| openViewsJob.setSystem(true); |
| |
| final PerspectiveManager manager = DebugUIPlugin.getDefault().getPerspectiveManager(); |
| if (isBoundToViews(contextIds)) { |
| manager.schedulePostSwitch(openViewsJob); |
| } |
| } |
| |
| /** |
| * @param contextIds |
| * @return if the specified the context ids are tied |
| * to any context-enabled views. |
| */ |
| private boolean isBoundToViews(Set contextIds) |
| { |
| Set possibleViewsToShow = new HashSet(); |
| Iterator iter = contextIds.iterator(); |
| while (iter.hasNext()) |
| { |
| String contextId = (String)iter.next(); |
| Set viewIds = getApplicableViewIds(contextId); |
| possibleViewsToShow.addAll(viewIds); |
| } |
| |
| return !possibleViewsToShow.isEmpty(); |
| } |
| |
| /** |
| * Compute which views should be automatically opened and which should be |
| * automatically brought to top when the given contexts are enabled. |
| * |
| * @param contextIds the contexts that have been enabled |
| * @param viewIdsToOpen a Set into which this method can store the |
| * collection of view identifiers (String) that should be opened |
| * @param viewIdsShow a Set into which this method can store the |
| * collection of view identifiers (String) that should be brought to top |
| */ |
| private void computeViewActivation(Set contextIds, Set viewIdsToOpen, Set viewIdsShow) { |
| IWorkbenchPage page = getPage(); |
| if (page == null) { |
| return; |
| } |
| Iterator contexts = contextIds.iterator(); |
| while (contexts.hasNext()) { |
| String contextId = (String) contexts.next(); |
| Iterator configurationElements= getConfigurationElements(contextId).iterator(); |
| while (configurationElements.hasNext()) { |
| IConfigurationElement element = (IConfigurationElement) configurationElements.next(); |
| String viewId= getViewId(element); |
| if (viewId == null) { |
| continue; |
| } |
| IViewReference reference = page.findViewReference(viewId); |
| if (reference != null && reference.isFastView()) { |
| continue; |
| } |
| IViewPart view = page.findView(viewId); |
| if (view != null) { |
| viewIdsShow.add(view); |
| } else if (isAutoOpen(element) && !viewIdsToNotOpen.contains(viewId)) { |
| // Don't open automatically if specified not to. |
| viewIdsToOpen.add(viewId); |
| } |
| } |
| } |
| } |
| |
| /** |
| * The given contexts have been disabled. Close all views |
| * associated with these contexts that aren't associated |
| * with other active contexts. |
| * |
| * @param contexts |
| */ |
| public void contextsDisabled(Set contexts) { |
| IWorkbenchPage page= getPage(); |
| if (page == null || contexts.size() == 0 || !isAutoManageViews()) { |
| return; |
| } |
| Set viewsToClose= getViewIdsToClose(contexts); |
| if (viewsToClose.isEmpty()) { |
| return; |
| } |
| |
| // only set this to false if fIsTrackingPartChanges is true |
| // otherwise, we may override the setting that is set |
| // by other event handlers. e.g. in #contextEnabled(...) |
| boolean resetTrackingPartChanges = false; |
| if (fIsTrackingPartChanges) |
| { |
| fIsTrackingPartChanges= false; |
| resetTrackingPartChanges = true; |
| } |
| Iterator iter= viewsToClose.iterator(); |
| |
| String perspId = page.getPerspective().getId(); |
| Set viewIds = (Set)openedViewIds.get(perspId); |
| |
| while (iter.hasNext()) { |
| String viewId= (String) iter.next(); |
| IViewReference view = page.findViewReference(viewId); |
| if (view != null) { |
| page.hideView(view); |
| if (viewIds != null) |
| { |
| // remove opened view from perspective |
| viewIds.remove(viewId); |
| } |
| } |
| } |
| saveOpenedViews(); |
| |
| // reset if this setting is previously changed |
| if (resetTrackingPartChanges) |
| loadTrackViews(); |
| } |
| |
| /** |
| * Returns a collection of view IDs which should be closed |
| * when the given context IDs are disabled. |
| * |
| * @param contextIds the context identifiers |
| * @return the identifiers of the views which should be closed |
| * when the given contexts disable |
| */ |
| public Set getViewIdsToClose(Set contextIds) { |
| Set viewIdsToClose= new HashSet(); |
| Set viewIdsToKeepOpen= getViewIdsForEnabledContexts(); |
| Iterator contexts = contextIds.iterator(); |
| IWorkbenchPage page = getPage(); |
| if (page == null) |
| return viewIdsToClose; |
| if (page.getPerspective() == null) |
| return viewIdsToClose; |
| String currentPerspId = page.getPerspective().getId(); |
| Set viewIds = (Set)openedViewIds.get(currentPerspId); |
| while (contexts.hasNext()) { |
| String contextId = (String) contexts.next(); |
| List list = getConfigurationElements(contextId); |
| Iterator iter = list.iterator(); |
| while (iter.hasNext()) { |
| IConfigurationElement element = (IConfigurationElement) iter.next(); |
| if (!isAutoClose(element)) { |
| continue; |
| } |
| String viewId = getViewId(element); |
| |
| if (viewId == null || viewIds == null || !viewIds.contains(viewId) || viewIdsToKeepOpen.contains(viewId)) { |
| // Don't close views that the user has manually opened or views |
| // which are associated with contexts that are still enabled. |
| continue; |
| } |
| viewIdsToClose.add(viewId); |
| } |
| } |
| return viewIdsToClose; |
| } |
| |
| /** |
| * Returns the set of view identifiers that are bound to |
| * contexts which are enabled in the workbench. |
| * |
| * @return the set of view identifiers bound to enabled contexts |
| */ |
| protected Set getViewIdsForEnabledContexts() { |
| Set viewIds= new HashSet(); |
| Iterator enabledContexts = PlatformUI.getWorkbench().getContextSupport().getContextManager().getEnabledContextIds().iterator(); |
| while (enabledContexts.hasNext()) { |
| String contextId = (String) enabledContexts.next(); |
| if (contextId.equals(DEBUG_CONTEXT)) { |
| // Ignore the "Debugging" context. See comment in contextEnabled(...) |
| continue; |
| } |
| viewIds.addAll(getApplicableViewIds(contextId)); |
| } |
| return viewIds; |
| } |
| |
| /** |
| * Returns the set of view identifiers that are bound to the |
| * given context. |
| * |
| * @param contextId the context identifier |
| * @return the set of view identifiers bound to the given context |
| */ |
| public Set getApplicableViewIds(String contextId) { |
| Set viewIds= new HashSet(); |
| Iterator elements = getConfigurationElements(contextId).iterator(); |
| while (elements.hasNext()) { |
| String viewId = getViewId((IConfigurationElement) elements.next()); |
| if (viewId != null) { |
| viewIds.add(viewId); |
| } |
| } |
| return viewIds; |
| } |
| |
| /** |
| * Determines the debug context associated with the selected |
| * stack frame's debug model (if any) and activates that |
| * context. This triggers this view's context listener |
| * to automatically open/close/activate views as appropriate. |
| */ |
| public void updateForSelection(Object selection) { |
| ILaunch launch= getLaunch(selection); |
| if (launch == null) { |
| return; |
| } |
| String[] modelIds= getDebugModelIdsForSelection(selection); |
| enableContexts(getContextsForModels(modelIds), launch); |
| enableActivitiesFor(modelIds); |
| } |
| |
| /** |
| * Returns the ILaunch associated with the given selection or |
| * <code>null</code> if none can be determined. |
| * |
| * @param selection the selection or <code>null</code> |
| * @return the ILaunch associated with the given selection or <code>null</code> |
| */ |
| protected static ILaunch getLaunch(Object selection) { |
| ILaunch launch= null; |
| if (selection instanceof ILaunch) { |
| launch= (ILaunch) selection; |
| } else if (selection instanceof IDebugElement) { |
| launch= ((IDebugElement) selection).getLaunch(); |
| } else if (selection instanceof IProcess) { |
| launch= ((IProcess) selection).getLaunch(); |
| } |
| return launch; |
| } |
| |
| /** |
| * Returns the debug model identifiers associated with the given selection. |
| * |
| * @param selection the selection |
| * @return the debug model identifiers associated with the given selection |
| */ |
| protected String[] getDebugModelIdsForSelection(Object selection) { |
| if (selection instanceof IAdaptable) { |
| IDebugModelProvider modelProvider= (IDebugModelProvider) Platform.getAdapterManager().getAdapter(selection, IDebugModelProvider.class); |
| if (modelProvider != null) { |
| String[] modelIds= modelProvider.getModelIdentifiers(); |
| if (modelIds != null) { |
| return modelIds; |
| } |
| } |
| } |
| if (selection instanceof IStackFrame) { |
| return new String[] { ((IStackFrame) selection).getModelIdentifier() }; |
| } |
| return new String[0]; |
| } |
| |
| /** |
| * Returns the context identifiers associated with the |
| * given model identifiers. |
| * |
| * @param modelIds the model identifiers |
| * @return the contexts associated with the given model identifiers |
| */ |
| protected List getContextsForModels(String[] modelIds) { |
| List contextIds= new ArrayList(); |
| for (int i = 0; i < modelIds.length; i++) { |
| List ids= (List) modelsToContexts.get(modelIds[i]); |
| if (ids == null) { |
| // seed with base debug context |
| ids = new ArrayList(); |
| ids.add(DEBUG_CONTEXT); |
| modelsToContexts.put(modelIds[i], ids); |
| } |
| contextIds.addAll(ids); |
| } |
| return contextIds; |
| } |
| |
| /** |
| * Enables activities in the workbench associated with the given debug |
| * model ids that are not already enabled. |
| * |
| * @param debug model ids for which to enable activities |
| */ |
| protected void enableActivitiesFor(String[] modelIds) { |
| Set newActivities = null; |
| for (int i = 0; i < modelIds.length; i++) { |
| String id = modelIds[i]; |
| Set ids= (Set) modelsToActivities.get(id); |
| if (ids == null) { |
| // first time the model has been seen, perform pattern matching |
| ids = new HashSet(); |
| modelsToActivities.put(id, ids); |
| Iterator bindings = modelPatternBindings.iterator(); |
| while (bindings.hasNext()) { |
| IActivityPatternBinding binding = (IActivityPatternBinding) bindings.next(); |
| String regex = binding.getPattern().pattern(); |
| regex = regex.substring(0, regex.length() - DEBUG_MODEL_ACTIVITY_SUFFIX.length()); |
| if (Pattern.matches(regex, id)) { |
| ids.add(binding.getActivityId()); |
| } |
| } |
| } |
| if (!enabledActivities.containsAll(ids)) { |
| if (newActivities == null) { |
| newActivities = new HashSet(); |
| } |
| newActivities.addAll(ids); |
| } |
| } |
| if (newActivities != null) { |
| IWorkbenchActivitySupport activitySupport = PlatformUI.getWorkbench().getActivitySupport(); |
| Set idsToEnable= new HashSet(enabledActivities.size() + newActivities.size()); |
| idsToEnable.addAll(enabledActivities); |
| idsToEnable.addAll(newActivities); |
| activitySupport.setEnabledActivityIds(idsToEnable); |
| } |
| } |
| |
| /** |
| * Enable the given contexts for the given launch. Context |
| * IDs which are not currently enabled in the workbench will be |
| * submitted to the workbench. Simulate a context enablement |
| * callback (by calling contextActivated) for contexts that are already enabled so that |
| * their views can be promoted. |
| * |
| * @param contextIds the contexts to enable |
| * @param launch the launch for which the contexts are being enabled |
| */ |
| protected void enableContexts(List contextIds, ILaunch launch) { |
| if (contextIds.isEmpty()) { |
| return; |
| } |
| Set enabledContexts = PlatformUI.getWorkbench().getContextSupport().getContextManager().getEnabledContextIds(); |
| Set contextsAlreadyEnabled= new HashSet(); |
| Iterator iter= contextIds.iterator(); |
| while (iter.hasNext()) { |
| String contextId= (String) iter.next(); |
| if (enabledContexts.contains(contextId) && !lastEnabledIds.contains(contextId)) { |
| // If a context is already enabled, submitting it won't |
| // generate a callback from the workbench. So we inform |
| // our context listener ourselves. |
| // This covers the case where the user is selecting |
| // among elements from several enabled contexts. |
| contextsAlreadyEnabled.add(contextId); |
| } |
| } |
| lastEnabledIds.clear(); |
| lastEnabledIds.addAll(contextIds); |
| submitContexts(contextIds, launch); |
| contextEnabled(contextsAlreadyEnabled); |
| } |
| |
| /** |
| * Submits the given context IDs to the workbench context support |
| * on behalf of the given launch. When the launch terminates, |
| * the context submissions will be automatically removed. |
| * |
| * @param contextIds the contexts to submit |
| * @param launch the launch for which the contexts are being submitted |
| */ |
| protected void submitContexts(List contextIds, ILaunch launch) { |
| List submissions = (List) fContextSubmissions.get(launch); |
| if (submissions == null) { |
| submissions= new ArrayList(); |
| fContextSubmissions.put(launch, submissions); |
| } |
| List newSubmissions= new ArrayList(); |
| Iterator iter= contextIds.iterator(); |
| while (iter.hasNext()) { |
| newSubmissions.add(new EnabledSubmission(null, null, null, (String) iter.next())); |
| } |
| IWorkbenchContextSupport contextSupport = PlatformUI.getWorkbench().getContextSupport(); |
| if (!newSubmissions.isEmpty()) { |
| contextSupport.addEnabledSubmissions(newSubmissions); |
| // After adding the new submissions, remove any old submissions |
| // that exist for the same context IDs. This prevents us from |
| // building up a ton of redundant submissions. |
| List submissionsToRemove= new ArrayList(); |
| ListIterator oldSubmissions= submissions.listIterator(); |
| while (oldSubmissions.hasNext()) { |
| EnabledSubmission oldSubmission= (EnabledSubmission) oldSubmissions.next(); |
| String contextId = oldSubmission.getContextId(); |
| if (contextIds.contains(contextId)) { |
| oldSubmissions.remove(); |
| submissionsToRemove.add(oldSubmission); |
| } |
| } |
| contextSupport.removeEnabledSubmissions(submissionsToRemove); |
| submissions.addAll(newSubmissions); |
| } |
| } |
| |
| /** |
| * Notifies this view that the given launches have terminated. When a launch |
| * terminates, remove all context submissions associated with it. |
| * |
| * @param launches the terminated launches |
| */ |
| protected void launchesTerminated(ILaunch[] launches) { |
| List allSubmissions= new ArrayList(); |
| for (int i = 0; i < launches.length; i++) { |
| List submissions= (List) fContextSubmissions.remove(launches[i]); |
| if (submissions != null) { |
| allSubmissions.addAll(submissions); |
| } |
| } |
| PlatformUI.getWorkbench().getContextSupport().removeEnabledSubmissions(allSubmissions); |
| } |
| |
| /** |
| * Returns the view identifier associated with the given extension |
| * element or <code>null</code> if none. |
| * |
| * @param element the contextViewBinding extension element |
| * @return the view identifier associated with the given element or <code>null</code> |
| */ |
| public static String getViewId(IConfigurationElement element) { |
| return element.getAttribute(ATTR_VIEW_ID); |
| } |
| |
| /** |
| * Returns whether the given configuration element is configured |
| * for automatic view opening. The element's view should be automatically |
| * opened if the autoOpen element is specified as true or if the autoOpen |
| * element is unspecified. |
| * |
| * @param element the contextViewBinding extension element |
| * @return whether or not given given configuration element's view |
| * should be automatically opened |
| */ |
| public static boolean isAutoOpen(IConfigurationElement element) { |
| String autoOpen = element.getAttribute(ATTR_AUTO_OPEN); |
| return autoOpen == null || Boolean.valueOf(autoOpen).booleanValue(); |
| } |
| |
| /** |
| * Returns whether the given configuration element is configured |
| * for automatic view closure. The element's view should be automatically |
| * close if the autoClose element is specified as true or if the autoClose |
| * element is unspecified. |
| * |
| * @param element the contextViewBinding extension element |
| * @return whether or not given given configuration element's view |
| * should be automatically closed |
| */ |
| public static boolean isAutoClose(IConfigurationElement element) { |
| String autoClose = element.getAttribute(ATTR_AUTO_CLOSE); |
| return autoClose == null || Boolean.valueOf(autoClose).booleanValue(); |
| } |
| |
| /** |
| * Returns whether this view automatically opens and closes |
| * views based on contexts |
| * @return whether or not this view automatically manages |
| * views based on contexts |
| */ |
| private boolean isAutoManageViews() { |
| IWorkbenchPage page = launchView.getViewSite().getPage(); |
| if (page != null) { |
| IPerspectiveDescriptor descriptor = page.getPerspective(); |
| if (descriptor != null) { |
| return fAutoManagePerspectives.contains(descriptor.getId()); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the workbench page containing the launch view. |
| * |
| * @return the workbench page containing the launch view |
| */ |
| public IWorkbenchPage getPage() { |
| return launchView.getSite().getPage(); |
| } |
| |
| /** |
| * Notifies this listener that the given perspective change |
| * has occurred. |
| * |
| * Don't listen to part open/close notifications during reset. |
| */ |
| public void perspectiveChanged(String changeId) { |
| if (changeId.equals(IWorkbenchPage.CHANGE_RESET)) { |
| fIsTrackingPartChanges= false; |
| } else if (changeId.equals(IWorkbenchPage.CHANGE_RESET_COMPLETE)) { |
| loadTrackViews(); |
| } |
| } |
| |
| /** |
| * Notifies this listener that the given perspective change |
| * has occurred. |
| * |
| * When a part is opened/closed, do not close/open it automatically. |
| */ |
| public void perspectiveChanged(IWorkbenchPartReference ref, String changeId) { |
| if (!fIsTrackingPartChanges) { |
| return; |
| } |
| if (IWorkbenchPage.CHANGE_VIEW_HIDE.equals(changeId) && (ref instanceof IViewReference)) { |
| String id = ((IViewReference) ref).getId(); |
| if (managedViewIds.contains(id)) { |
| viewIdsToNotOpen.add(id); |
| saveViewsToNotOpen(); |
| } |
| |
| removeFromOpenedViews(id); |
| saveOpenedViews(); |
| } else if (IWorkbenchPage.CHANGE_VIEW_SHOW.equals(changeId) && ref instanceof IViewReference) { |
| String id = ((IViewReference) ref).getId(); |
| removeFromOpenedViews(id); |
| saveOpenedViews(); |
| } |
| } |
| |
| /** |
| * Givin a view id, this methods iterates through all the |
| * managed perspective and remove the view from openedViewIds |
| * @param viewId |
| */ |
| private void removeFromOpenedViews(String viewId) { |
| Iterator keys = openedViewIds.keySet().iterator(); |
| while (keys.hasNext()) |
| { |
| String perspId = (String)keys.next(); |
| |
| Set views = (Set)openedViewIds.get(perspId); |
| if (views != null) |
| { |
| views.remove(viewId); |
| } |
| } |
| } |
| |
| /** |
| * Reads the preference specifying whether this view automatically |
| * tracks views being opened and closed for the purpose of not |
| * automatically managing those views once they've been opened/closed |
| * manually. |
| */ |
| public void loadTrackViews() { |
| fIsTrackingPartChanges= DebugUITools.getPreferenceStore().getBoolean(IInternalDebugUIConstants.PREF_TRACK_VIEWS); |
| } |
| |
| /** |
| * Load the collection of perspectives in which view |
| * management will occur from the preference store. |
| */ |
| private void loadAutoManagePerspectives() { |
| String prefString = DebugUIPlugin.getDefault().getPreferenceStore().getString(IDebugUIConstants.PREF_MANAGE_VIEW_PERSPECTIVES); |
| fAutoManagePerspectives= parseList(prefString); |
| } |
| |
| /** |
| * Reloaded the collection of view management perspectives |
| * and updates (potentially opening views) for the given |
| * selection. |
| */ |
| public void reloadAutoManagePerspectives(Object selection) { |
| // Remove the context ids associated with the current selection |
| // so that updateForSelection(...) will open views |
| // as appropriate given the new view management settings. |
| String[] modelIds = getDebugModelIdsForSelection(selection); |
| List contextIds = getContextsForModels(modelIds); |
| lastEnabledIds.removeAll(contextIds); |
| |
| loadAutoManagePerspectives(); |
| updateForSelection(selection); |
| } |
| |
| public void reloadViewsToNotOpen(Object selection) { |
| // Remove the context ids associated with the current selection |
| // so that updateForSelection(...) will open views |
| // as appropriate given the new view management settings. |
| String[] modelIds = getDebugModelIdsForSelection(selection); |
| List contextIds = getContextsForModels(modelIds); |
| lastEnabledIds.removeAll(contextIds); |
| |
| loadViewsToNotOpen(); |
| updateForSelection(selection); |
| } |
| |
| /** |
| * Parses the comma separated string into a list of strings |
| * |
| * @return list |
| */ |
| public static List parseList(String listString) { |
| List list = new ArrayList(10); |
| StringTokenizer tokenizer = new StringTokenizer(listString, ","); //$NON-NLS-1$ |
| while (tokenizer.hasMoreTokens()) { |
| String token = tokenizer.nextToken(); |
| list.add(token); |
| } |
| return list; |
| } |
| |
| /** |
| * The launch view associated with this context listener has |
| * been disposed. Remove as a context listener. |
| * |
| */ |
| public void dispose() { |
| IWorkbench workbench = PlatformUI.getWorkbench(); |
| workbench.getContextSupport().getContextManager().removeContextManagerListener(this); |
| workbench.getActivitySupport().getActivityManager().removeActivityManagerListener(this); |
| } |
| |
| /** |
| * Clears the cache of last enabled contexts. Called by the debug view when the pespective |
| * changes. |
| */ |
| protected void clearLastEnabledContexts() { |
| lastEnabledIds.clear(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.activities.IActivityManagerListener#activityManagerChanged(org.eclipse.ui.activities.ActivityManagerEvent) |
| */ |
| public void activityManagerChanged(ActivityManagerEvent activityManagerEvent) { |
| if (activityManagerEvent.haveEnabledActivityIdsChanged()) { |
| enabledActivities = activityManagerEvent.getActivityManager().getEnabledActivityIds(); |
| } |
| |
| } |
| |
| } |