blob: d779b026de4776caf2c1c4598697b76ce6c26d12 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2014 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.debug.internal.ui.views;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.commands.contexts.Context;
import org.eclipse.core.commands.contexts.ContextManagerEvent;
import org.eclipse.core.commands.contexts.IContextManagerListener;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.core.runtime.preferences.InstanceScope;
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.internal.core.IInternalDebugCoreConstants;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.contexts.DebugModelContextBindingManager;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.debug.ui.contexts.IDebugContextService;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveListener4;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.IConsoleConstants;
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;
/**
* Performs view management for a window.
*
* @since 3.2
*/
public class ViewContextService implements IDebugContextListener, IPerspectiveListener4, IPreferenceChangeListener, IContextManagerListener {
/**
* Maps the perspectives in this window to its last activated workbench context
*/
private final Map<IPerspectiveDescriptor, String> fPerspectiveToActiveContext = new HashMap<>();
/**
* Map of the perspectives to all workbench contexts activated in that perspective
*/
private final Map<IPerspectiveDescriptor, Set<String>> fPerspectiveToActivatedContexts = new HashMap<>();
/**
* Map of context id's to context view bindings
*/
private Map<String, DebugContextViewBindings> fContextIdsToBindings;
/**
* List of perspectives that debugging is allowed in
*/
private Set<String> fEnabledPerspectives = new HashSet<>();
/**
* Whether to ignore perspective change call backs (set to
* true when this class is modifying views).
*/
private boolean fIgnoreChanges = false;
/**
* The window this service is working for
*/
private IWorkbenchWindow fWindow;
private final IContextService fContextService;
private final IDebugContextService fDebugContextService;
/**
* Perspective that is currently being de-activated. Used to determine
* when to ignore active context changes.
*/
private IPerspectiveDescriptor fActivePerspective;
// base debug context
public static final String DEBUG_CONTEXT= "org.eclipse.debug.ui.debugging"; //$NON-NLS-1$
// extension points
private static final String ID_CONTEXT_VIEW_BINDINGS= "contextViewBindings"; //$NON-NLS-1$
// extension elements
private static final String ELEM_CONTEXT_VIEW_BINDING= "contextViewBinding"; //$NON-NLS-1$
private static final String ELEM_PERSPECTIVE= "perspective"; //$NON-NLS-1$
// extension attributes
private static final String ATTR_CONTEXT_ID= "contextId"; //$NON-NLS-1$
private static final String ATTR_VIEW_ID= "viewId"; //$NON-NLS-1$
private static final String ATTR_AUTO_OPEN= "autoOpen"; //$NON-NLS-1$
private static final String ATTR_AUTO_CLOSE= "autoClose"; //$NON-NLS-1$
private static final String ATTR_PERSPECTIVE_ID= "perspectiveId"; //$NON-NLS-1$
// XML tags
private static final String XML_ELEMENT_VIEW_BINDINGS ="viewBindings"; //$NON-NLS-1$
private static final String XML_ELEMENT_PERSPECTIVE ="perspective"; //$NON-NLS-1$
private static final String XML_ELEMENT_VIEW = "view"; //$NON-NLS-1$
private static final String XML_ATTR_ID = "id"; //$NON-NLS-1$
private static final String XML_ATTR_USER_ACTION = "userAction"; //$NON-NLS-1$
private static final String XML_VALUE_OPENED = "opened"; //$NON-NLS-1$
private static final String XML_VALUE_CLOSED = "closed"; //$NON-NLS-1$
// ids of base debug views in debug perspective that should not be auto-closed
private static Set<String> fgBaseDebugViewIds = null;
static {
fgBaseDebugViewIds = new HashSet<>();
fgBaseDebugViewIds.add(IDebugUIConstants.ID_DEBUG_VIEW);
fgBaseDebugViewIds.add(IDebugUIConstants.ID_VARIABLE_VIEW);
fgBaseDebugViewIds.add(IDebugUIConstants.ID_BREAKPOINT_VIEW);
fgBaseDebugViewIds.add(IConsoleConstants.ID_CONSOLE_VIEW);
}
private static String[] EMPTY_IDS = new String[0];
/**
* View bindings for a debug context
*/
private class DebugContextViewBindings {
// context id
private final String fId;
// list of view bindings id's specific to this context
private String[] fViewBindingIds = EMPTY_IDS;
// all bindings including inherited bindings, top down in activation order
private String[] fAllViewBindingIds = null;
// associated binding to activate
private final Map<String, ViewBinding> fAllViewIdToBindings = new HashMap<>();
// all context id's in this context hierarchy (top down order)
private String[] fAllConetxtIds = null;
// id of parent context
private String fParentId;
/**
* Constructs an empty view binding for the given context.
*
* @param id context id
*/
public DebugContextViewBindings(String id) {
fId = id;
}
/**
* Returns the context id for these view bindings
*
* @return context id
*/
public String getId() {
return fId;
}
/**
* Adds the given view binding to this context
*
* @param binding view binding to add
*/
public void addBinding(ViewBinding binding) {
String[] newBindings = new String[fViewBindingIds.length + 1];
System.arraycopy(fViewBindingIds, 0, newBindings, 0, fViewBindingIds.length);
newBindings[fViewBindingIds.length] = binding.getViewId();
fAllViewIdToBindings.put(binding.getViewId(), binding);
fViewBindingIds = newBindings;
}
/**
* Sets the parent id of this view bindings
*
* @param id parent context id
*/
protected void setParentId(String id) {
fParentId = id;
}
/**
* Returns the id of parent context
*
* @return parent context id
*/
public DebugContextViewBindings getParentContext() {
if (fParentId == null) {
return null;
}
return fContextIdsToBindings.get(fParentId);
}
/**
* Activates the views in this context hierarchy. Views are activated top down, allowing
* sub-contexts to override settings in a parent context.
* @param page the page context
* @param perspective the perspective description
* @param allViewIds that are relevant to the chain activation.
*/
public void activateChain(IWorkbenchPage page, IPerspectiveDescriptor perspective, Set<String> allViewIds) {
initializeChain();
doActivation(page, perspective, allViewIds, fAllConetxtIds);
}
public String[] getAllViewBindingsIds() {
initializeChain();
return fAllViewBindingIds;
}
/**
* Activates the view bindings for the specified views and the
* specified contexts in the given page.
*
* @param page page to activate views in
* @param perspective the perspective description
* @param allViewIds id's of all the views that are relevant in this context activation
* @param contextIds associated contexts that are activated
*/
private void doActivation(IWorkbenchPage page, IPerspectiveDescriptor perspective, Set<String> allViewIds, String[] contextIds) {
// note activation of all the relevant contexts
for (int i = 0; i < contextIds.length; i++) {
addActivated(contextIds[i]);
}
// set the active context to be this
setActive(perspective, getId());
// activate the view bindings and bring most relevant views to top
for (int i = 0; i < fAllViewBindingIds.length; i++) {
String viewId = fAllViewBindingIds[i];
ViewBinding binding = fAllViewIdToBindings.get(viewId);
binding.activated(page, perspective);
binding.checkZOrder(page, allViewIds);
}
}
/**
* Builds the top down ordered list of bindings for this context allowing sub-contexts
* to override parent settings.
*/
private synchronized void initializeChain() {
if (fAllViewBindingIds == null) {
List<String> orderedIds = new ArrayList<>();
List<DebugContextViewBindings> contexts = new ArrayList<>();
DebugContextViewBindings context = this;
while (context != null) {
contexts.add(0, context);
context = context.getParentContext();
}
fAllConetxtIds = new String[contexts.size()];
int pos = 0;
for (DebugContextViewBindings bindings : contexts) {
fAllConetxtIds[pos] = bindings.getId();
pos++;
for (int i = 0; i < bindings.fViewBindingIds.length; i++) {
String viewId = bindings.fViewBindingIds[i];
if (bindings == this) {
orderedIds.add(viewId);
}
if (!fAllViewIdToBindings.containsKey(viewId)) {
orderedIds.add(viewId);
fAllViewIdToBindings.put(viewId, bindings.fAllViewIdToBindings.get(viewId));
}
}
}
fAllViewBindingIds = orderedIds.toArray(new String[orderedIds.size()]);
}
}
/**
* Deactivates this context only (not parents)
*
* @param page workbench page
* @param perspective the perspective description
*/
public void deactivate(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
removeActivated(getId());
if (isActiveContext(getId())) {
setActive(page.getPerspective(), null);
}
for (int i = 0; i < fViewBindingIds.length; i++) {
String viewId = fViewBindingIds[i];
ViewBinding binding = fAllViewIdToBindings.get(viewId);
binding.deactivated(page, perspective);
}
}
/**
* Notes when a view is opened/closed manually.
*
* @param opened opened or closed
* @param viewId the view identifier
*/
public void setViewOpened(boolean opened, String viewId) {
initializeChain();
ViewBinding binding = fAllViewIdToBindings.get(viewId);
if (binding != null) {
if (opened) {
binding.userOpened();
} else {
binding.userClosed();
}
}
}
public void applyUserSettings(String viewId, Element viewElement) {
initializeChain();
ViewBinding binding = fAllViewIdToBindings.get(viewId);
if (binding != null) {
binding.applyUserSettings(viewElement);
}
}
/**
* Save view binding settings into XML document.
*
* @param document the document to save to
* @param root the root XML element
* @param alreadyDone views already done
*/
public void saveBindings(Document document, Element root, Set<String> alreadyDone) {
for (int i = 0; i < fViewBindingIds.length; i++) {
String viewId = fViewBindingIds[i];
if (!alreadyDone.contains(viewId)) {
alreadyDone.add(viewId);
ViewBinding binding = fAllViewIdToBindings.get(viewId);
binding.saveBindings(document, root);
}
}
}
}
/**
* Information for a view
*/
private class ViewBinding {
private final IConfigurationElement fElement;
/**
* Set of perspectives this view was opened in by the user
*/
private final Set<String> fUserOpened = new HashSet<>();
/**
* Set of perspectives this view was closed in by the user
*/
private final Set<String> fUserClosed = new HashSet<>();
/**
* Set of perspectives this view was auto-opened by view management.
*/
private final Set<String> fAutoOpened = new HashSet<>();
public ViewBinding(IConfigurationElement element) {
fElement = element;
}
/**
* Returns the id of the view this binding pertains to.
*
* @return the id of the view
*/
public String getViewId() {
return fElement.getAttribute(ATTR_VIEW_ID);
}
/**
* Returns whether this view binding is set for auto-open.
*
* @return if the view is set to auto-open
*/
public boolean isAutoOpen() {
String autoopen = fElement.getAttribute(ATTR_AUTO_OPEN);
return autoopen == null || "true".equals(autoopen); //$NON-NLS-1$
}
/**
* Returns whether this view binding is set for auto-close.
*
* @return if the view is set to auto-close
*/
public boolean isAutoClose() {
String autoclose = fElement.getAttribute(ATTR_AUTO_CLOSE);
return autoclose == null || "true".equals(autoclose); //$NON-NLS-1$
}
/**
* Returns whether this view was opened by the user in the active perspective.
* @param perspective the perspective description
* @return if this view was opened by the user
*/
public boolean isUserOpened(IPerspectiveDescriptor perspective) {
return fUserOpened.contains(perspective.getId());
}
/**
* Returns whether this view was closed by the user in the active perspective
* @param perspective the description of the perspective
* @return if this view was closed by the user in the active perspective
*/
public boolean isUserClosed(IPerspectiveDescriptor perspective) {
return fUserClosed.contains(getActivePerspective().getId());
}
/**
* Returns whether this view is part of the active perspective by default
*
* TODO: we really need an API to determine which views are
* in a perspective by default, but it does not seem to exist.
* @param perspective the description of the perspective
* @return if this view is part of the active perspective by default
*/
public boolean isDefault(IPerspectiveDescriptor perspective) {
String id = perspective.getId();
if (IDebugUIConstants.ID_DEBUG_PERSPECTIVE.equals(id)) {
return fgBaseDebugViewIds.contains(getViewId());
}
return false;
}
protected void userOpened() {
if (isTrackingViews()) {
String id = getActivePerspective().getId();
fAutoOpened.remove(id);
fUserOpened.add(id);
fUserClosed.remove(id);
saveViewBindings();
}
}
protected void userClosed() {
if (isTrackingViews()) {
String id = getActivePerspective().getId();
fAutoOpened.remove(id);
fUserClosed.add(id);
fUserOpened.remove(id);
saveViewBindings();
}
}
/**
* Returns whether the preference is set to track user view open/close.
*
* @return if the service is set to track user view open/close
*/
protected boolean isTrackingViews() {
return DebugUITools.getPreferenceStore().getBoolean(IInternalDebugUIConstants.PREF_TRACK_VIEWS);
}
/**
* Context has been activated, open/show as required.
*
* @param page the workbench page
* @param perspective the perspective description
*/
public void activated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
if (!isUserClosed(perspective)) {
if (isAutoOpen()) {
try {
fIgnoreChanges = true;
// Remember whether the view was opened by view management.
// (Bug 128065)
if (page.findViewReference(getViewId()) == null) {
fAutoOpened.add(perspective.getId());
}
page.showView(getViewId(), null, IWorkbenchPage.VIEW_CREATE);
} catch (PartInitException e) {
DebugUIPlugin.log(e);
} finally {
fIgnoreChanges = false;
}
}
}
}
/**
* Context has been activated. Check the view stack to see if this view
* should be made visible.
*
* @param page the page to check
* @param relevantViews the array of view identifiers
*/
public void checkZOrder(IWorkbenchPage page, Set<String> relevantViews) {
// see if view is open already
String viewId = getViewId();
IViewPart part = page.findView(viewId);
if (part != null) {
IViewPart[] viewStack = page.getViewStack(part);
if (viewStack != null && viewStack.length > 0) {
String top = viewStack[0].getSite().getId();
if (relevantViews.contains(top)) {
return;
}
// Don't bring a minimized or fast view to front
IViewReference partRef = page.findViewReference(viewId);
if (partRef != null && (partRef.isFastView() || IWorkbenchPage.STATE_MINIMIZED == page.getPartState(partRef))) {
return;
}
// an irrelevant view is visible
try {
fIgnoreChanges = true;
page.bringToTop(part);
} finally {
fIgnoreChanges = false;
}
}
}
}
/**
* Context has been deactivated, close as required.
*
* @param page the workbench page
* @param perspective the perspective description
*/
public void deactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
if (!isUserOpened(perspective)) {
if (fAutoOpened.remove(perspective.getId()) && isAutoClose() && !isDefault(perspective)) {
IViewReference reference = page.findViewReference(getViewId());
if (reference != null) {
try {
fIgnoreChanges = true;
page.hideView(reference);
} finally {
fIgnoreChanges = false;
}
}
}
}
}
/**
* Save view binding settings into XML document.
*
* @param document the document to save to
* @param root the root XML element
*/
public void saveBindings(Document document, Element root) {
Element viewElement = document.createElement(XML_ELEMENT_VIEW);
viewElement.setAttribute(XML_ATTR_ID, getViewId());
appendPerspectives(document, viewElement, fUserOpened, XML_VALUE_OPENED);
appendPerspectives(document, viewElement, fUserClosed, XML_VALUE_CLOSED);
if (viewElement.hasChildNodes()) {
root.appendChild(viewElement);
}
}
private void appendPerspectives(Document document, Element parent, Set<String> perpectives, String xmlValue) {
String[] ids = perpectives.toArray(new String[perpectives.size()]);
for (int i = 0; i < ids.length; i++) {
String id = ids[i];
Element element = document.createElement(XML_ELEMENT_PERSPECTIVE);
element.setAttribute(XML_ATTR_ID, id);
element.setAttribute(XML_ATTR_USER_ACTION, xmlValue);
parent.appendChild(element);
}
}
public void applyUserSettings(Element viewElement) {
NodeList list = viewElement.getChildNodes();
int length = list.getLength();
for (int i = 0; i < length; ++i) {
Node node = list.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element entry = (Element) node;
if(entry.getNodeName().equalsIgnoreCase(XML_ELEMENT_PERSPECTIVE)){
String id = entry.getAttribute(XML_ATTR_ID);
String setting = entry.getAttribute(XML_ATTR_USER_ACTION);
if (id != null) {
if (XML_VALUE_CLOSED.equals(setting)) {
fUserClosed.add(id);
} else if (XML_VALUE_OPENED.equals(setting)) {
fUserOpened.add(id);
}
}
}
}
}
}
}
private IDebugContextService getDebugContextService() {
return fDebugContextService;
}
/**
* Creates a service for the given window
*
* @param window the window to attach this service to
*/
ViewContextService(IWorkbenchWindow window) {
fWindow = window;
fContextService = PlatformUI.getWorkbench().getAdapter(IContextService.class);
fDebugContextService = DebugUITools.getDebugContextManager().getContextService(fWindow);
loadContextToViewExtensions();
applyUserViewBindings();
loadPerspectives();
window.addPerspectiveListener(this);
getDebugContextService().addDebugContextListener(this);
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(DebugUIPlugin.getUniqueIdentifier());
if (node != null) {
node.addPreferenceChangeListener(this);
}
fContextService.addContextManagerListener(this);
if (fWindow != null) {
IWorkbenchPage page = fWindow.getActivePage();
if (page != null) {
fActivePerspective = page.getPerspective();
}
}
}
public void dispose() {
fWindow.removePerspectiveListener(this);
fWindow = null; // avoid leaking a window reference (bug 321658).
getDebugContextService().removeDebugContextListener(this);
IEclipsePreferences node = InstanceScope.INSTANCE.getNode(DebugUIPlugin.getUniqueIdentifier());
if (node != null) {
node.removePreferenceChangeListener(this);
}
fContextService.removeContextManagerListener(this);
fActivePerspective = null;
}
/**
* Loads extensions which map context id's to view bindings.
*/
private void loadContextToViewExtensions() {
fContextIdsToBindings = new HashMap<>();
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];
if ( ELEM_CONTEXT_VIEW_BINDING.equals(element.getName()) ) {
String viewId = element.getAttribute(ATTR_VIEW_ID);
String contextId = element.getAttribute(ATTR_CONTEXT_ID);
if (contextId == null || viewId == null) {
continue;
}
ViewBinding info = new ViewBinding(element);
DebugContextViewBindings bindings = fContextIdsToBindings.get(contextId);
if (bindings == null) {
bindings = new DebugContextViewBindings(contextId);
fContextIdsToBindings.put(contextId, bindings);
}
bindings.addBinding(info);
}
}
linkParentContexts();
}
/**
* Applies user settings that modify view binding extensions.
*/
private void applyUserViewBindings() {
String xml = DebugUITools.getPreferenceStore().getString(IInternalDebugUIConstants.PREF_USER_VIEW_BINDINGS);
if (xml.length() > 0) {
try {
Element root = DebugPlugin.parseDocument(xml);
NodeList list = root.getChildNodes();
int length = list.getLength();
for (int i = 0; i < length; ++i) {
Node node = list.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element entry = (Element) node;
if(entry.getNodeName().equalsIgnoreCase(XML_ELEMENT_VIEW)){
String id = entry.getAttribute(XML_ATTR_ID);
for (DebugContextViewBindings binding : fContextIdsToBindings.values()) {
binding.applyUserSettings(id, entry);
}
}
}
}
} catch (CoreException e) {
DebugUIPlugin.log(e);
}
}
}
/**
* Load the collection of perspectives in which view management will occur from the preference store.
*/
private void loadPerspectives() {
String preference = DebugUIPlugin.getDefault().getPreferenceStore().getString(
IDebugUIConstants.PREF_MANAGE_VIEW_PERSPECTIVES);
if (IDebugUIConstants.PREF_MANAGE_VIEW_PERSPECTIVES_DEFAULT.equals(preference)) {
fEnabledPerspectives = getDefaultEnabledPerspectives();
} else {
fEnabledPerspectives = parseList(preference);
}
}
/**
* Returns whether this service's window's active perspective supports view management.
*
* @return whether this service's window's active perspective supports view management
*/
private boolean isEnabledPerspective() {
IPerspectiveDescriptor perspective = getActivePerspective();
if (perspective != null) {
return fEnabledPerspectives.contains(perspective.getId());
}
return false;
}
/**
* Returns the active perspective in this service's window, or <code>null</code>
*
* @return active perspective or <code>null</code>
*/
private IPerspectiveDescriptor getActivePerspective() {
if (fWindow == null) {
return null;
}
return fActivePerspective;
}
/**
* Parses the comma separated string into a list of strings
* @param listString the comma separated string to parse into a list object
*
* @return list
*/
public static Set<String> parseList(String listString) {
Set<String> list = new HashSet<>(10);
StringTokenizer tokenizer = new StringTokenizer(listString, ","); //$NON-NLS-1$
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
list.add(token);
}
return list;
}
/**
* Calculates the default set of perspectives enabled for view management
* based on the contextViewBindings extension point.
*
* @return set of enabled perspectives.
*
* @since 3.5
*/
public static Set<String> getDefaultEnabledPerspectives() {
Set<String> perspectives = new HashSet<>(4);
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];
if ( ELEM_PERSPECTIVE.equals(element.getName()) ) {
String perspectiveId = element.getAttribute(ATTR_PERSPECTIVE_ID);
if (perspectiveId != null) {
perspectives.add(perspectiveId);
}
}
}
return perspectives;
}
public void contextActivated(ISelection selection) {
if (isEnabledPerspective()) {
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
IStructuredSelection ss = (IStructuredSelection) selection;
Iterator<?> iterator = ss.iterator();
while (iterator.hasNext()) {
Object target = iterator.next();
ILaunch launch = DebugModelContextBindingManager.getLaunch(target);
if (launch != null && !launch.isTerminated()) {
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
if (launchConfiguration != null) {
try {
ILaunchConfigurationType type = launchConfiguration.getType();
// check if this perspective is enabled for the launch type
// Include the word '.internal.' so the context is filtered from the key binding pref page (Bug 144019) also see PerspectiveManager.handleBreakpointHit()
if (fContextService.getActiveContextIds().contains(type.getIdentifier() + ".internal." + getActivePerspective().getId())) { //$NON-NLS-1$
// get the leaf contexts to be activated
List<String> workbenchContexts = DebugModelContextBindingManager.getDefault().getWorkbenchContextsForDebugContext(target);
// TODO: do we need to check if contexts are actually enabled in workbench first?
if (!workbenchContexts.isEmpty()) {
// Quickly check if any contexts need activating
boolean needToActivate = false;
for (int i = 0; i < workbenchContexts.size(); i++) {
if (!isActivated(workbenchContexts.get(i))) {
needToActivate = true;
break;
}
}
if (needToActivate) {
Set<String> allViewIds = getAllContextsViewIDs(workbenchContexts);
// if all contexts already activate and last context is already active context == done
for (int i = 0; i < workbenchContexts.size(); i++) {
String contextId = workbenchContexts.get(i);
if (!isActivated(contextId)) {
activateChain(contextId, getActivePerspective(), allViewIds);
}
}
}
}
}
} catch (CoreException e) {
DebugUIPlugin.log(e);
}
}
}
}
}
}
}
/**
* Returns whether the given context is the active context in the active perspective.
*
* @param contextId the id of the context
* @return if the given id is the id for the currently active context
*/
private boolean isActiveContext(String contextId) {
IPerspectiveDescriptor activePerspective = getActivePerspective();
if (activePerspective != null) {
String activeId = fPerspectiveToActiveContext.get(activePerspective);
return contextId.equals(activeId);
}
return false;
}
/**
* Returns whether the given context is activated in the active perspective.
*
* @param contextId the context id
* @return if the given context is activated in the active perspective
*/
private boolean isActivated(String contextId) {
IPerspectiveDescriptor activePerspective = getActivePerspective();
if (activePerspective != null) {
Set<String> contexts = fPerspectiveToActivatedContexts.get(activePerspective);
if (contexts != null) {
return contexts.contains(contextId);
}
}
return false;
}
private void addActivated(String contextId) {
IPerspectiveDescriptor activePerspective = getActivePerspective();
if (activePerspective != null) {
Set<String> contexts = fPerspectiveToActivatedContexts.get(activePerspective);
if (contexts == null) {
contexts = new HashSet<>();
fPerspectiveToActivatedContexts.put(activePerspective, contexts);
}
contexts.add(contextId);
}
}
private void removeActivated(String contextId) {
IPerspectiveDescriptor activePerspective = getActivePerspective();
if (activePerspective != null) {
Set<String> contexts = fPerspectiveToActivatedContexts.get(activePerspective);
if (contexts != null) {
contexts.remove(contextId);
}
}
}
@Override
public void debugContextChanged(DebugContextEvent event) {
if ((event.getFlags() & DebugContextEvent.ACTIVATED) > 0) {
contextActivated(event.getContext());
}
}
@Override
public void perspectiveOpened(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
}
@Override
public void perspectiveClosed(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
}
@Override
public void perspectiveDeactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
}
/**
* Closes all auto-opened views.
*
* @param perspective the perspective descriptor
*/
private void clean(IPerspectiveDescriptor perspective) {
Set<String> contexts = fPerspectiveToActivatedContexts.remove(perspective);
fPerspectiveToActiveContext.remove(perspective);
if (contexts != null) {
for (String id : contexts) {
deactivate(id, perspective);
}
}
}
@Override
public void perspectiveSavedAs(IWorkbenchPage page, IPerspectiveDescriptor oldPerspective, IPerspectiveDescriptor newPerspective) {
}
@Override
public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, IWorkbenchPartReference partRef, String changeId) {
if (!fIgnoreChanges && page.getWorkbenchWindow().equals(fWindow)) {
if(partRef != null) {
if (IWorkbenchPage.CHANGE_VIEW_SHOW == changeId || IWorkbenchPage.CHANGE_VIEW_HIDE == changeId) {
// Update only the contexts which are currently active (Bug 128065)
Set<String> activatedContexts = fPerspectiveToActivatedContexts.get(perspective);
if (activatedContexts != null) {
for (String id : activatedContexts) {
DebugContextViewBindings bindings = fContextIdsToBindings.get(id);
if (bindings != null) {
bindings.setViewOpened(IWorkbenchPage.CHANGE_VIEW_SHOW == changeId, partRef.getId());
}
}
}
}
}
}
}
@Override
public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
if (page.getWorkbenchWindow().equals(fWindow)) {
fActivePerspective = perspective;
ISelection activeContext = getDebugContextService().getActiveContext();
if (activeContext != null) {
contextActivated(activeContext);
}
}
}
@Override
public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {
}
/**
* Activates all parent contexts of the given context, top down.
*
* @param contextId the identifier of the {@link DebugContextViewBindings} to activate
* @param perspective the perspective description
*/
private void activateChain(String contextId, IPerspectiveDescriptor perspective, Set<String> allViewIds) {
if (fWindow == null) {
return; // disposed
}
IWorkbenchPage page = fWindow.getActivePage();
if (page != null) {
DebugContextViewBindings bindings= fContextIdsToBindings.get(contextId);
if (bindings != null) {
bindings.activateChain(page, perspective, allViewIds);
}
}
}
private Set<String> getAllContextsViewIDs(List<String> contextsIds) {
if (fWindow == null) {
return Collections.EMPTY_SET; // disposed
}
TreeSet<String> viewIds = new TreeSet<>();
for (int i = 0; i < contextsIds.size(); i++) {
DebugContextViewBindings bindings= fContextIdsToBindings.get(contextsIds.get(i));
if (bindings != null) {
String[] bindingViewIds = bindings.getAllViewBindingsIds();
for (int j = 0; j < bindingViewIds.length; j++) {
viewIds.add(bindingViewIds[j]);
}
}
}
return viewIds;
}
/**
* Links each debug context view bindings with its parent context bindings
*/
private void linkParentContexts() {
for (Entry<String, DebugContextViewBindings> entry : fContextIdsToBindings.entrySet()) {
DebugContextViewBindings bindings = entry.getValue();
if (!bindings.getId().equals(DEBUG_CONTEXT)) {
Context context = fContextService.getContext(entry.getKey());
try {
bindings.setParentId(context.getParentId());
} catch (NotDefinedException e) {
DebugUIPlugin.log(e);
}
}
}
}
/**
* Sets the active context in the given perspective, or removes
* when <code>null</code>.
*
* @param perspective the perspective descriptor
* @param contextId the context identifier
*/
private void setActive(IPerspectiveDescriptor perspective, String contextId) {
if (contextId == null) {
fPerspectiveToActiveContext.remove(perspective);
} else {
fPerspectiveToActiveContext.put(perspective, contextId);
}
}
@Override
public void contextManagerChanged(ContextManagerEvent event) {
if (event.isActiveContextsChanged() && getActivePerspective() != null) {
Set<String> disabledContexts = getDisabledContexts(event);
if (!disabledContexts.isEmpty()) {
for (String contextId : disabledContexts) {
if (isViewContext(contextId)) {
if (isActivated(contextId)) {
deactivate(contextId, getActivePerspective());
}
}
}
}
// Ensure that the views are activated for the new contexts if needed.
contextActivated(DebugUITools.getDebugContextManager().getContextService(fWindow).getActiveContext());
}
}
private void deactivate(String contextId, IPerspectiveDescriptor perspective) {
if (fWindow == null)
{
return; // disposed
}
IWorkbenchPage page = fWindow.getActivePage();
if (page != null) {
DebugContextViewBindings bindings = fContextIdsToBindings.get(contextId);
if (bindings != null) {
bindings.deactivate(page, perspective);
}
}
}
/**
* Returns a set of contexts disabled in the given event, possibly empty.
*
* @param event the event
* @return disabled context id's
*/
private Set<String> getDisabledContexts(ContextManagerEvent event) {
Set<String> prev = new HashSet<String>(event.getPreviouslyActiveContextIds());
Set<String> activeContextIds = event.getContextManager().getActiveContextIds();
if (activeContextIds != null) {
prev.removeAll(activeContextIds);
}
return prev;
}
/**
* Returns whether the given context has view bindings.
*
* @param id the context id
* @return whether the given context has view bindings
*/
private boolean isViewContext(String id) {
return fContextIdsToBindings.containsKey(id);
}
/**
* Save view binding settings that differ from extension settings
*/
private void saveViewBindings() {
try {
Document document = DebugPlugin.newDocument();
Element root = document.createElement(XML_ELEMENT_VIEW_BINDINGS);
document.appendChild(root);
Set<String> done = new HashSet<>();
for (DebugContextViewBindings binding : fContextIdsToBindings.values()) {
binding.saveBindings(document, root, done);
}
String prefValue = IInternalDebugCoreConstants.EMPTY_STRING;
if (root.hasChildNodes()) {
prefValue = DebugPlugin.serializeDocument(document);
}
fIgnoreChanges = true;
DebugUITools.getPreferenceStore().setValue(IInternalDebugUIConstants.PREF_USER_VIEW_BINDINGS, prefValue);
} catch (CoreException e) {
DebugUIPlugin.log(e);
} finally {
fIgnoreChanges = false;
}
}
/**
* Returns the perspectives in which debugging is enabled.
*
* @return the array of perspective identifiers in which debugging is enabled
*/
public String[] getEnabledPerspectives() {
return fEnabledPerspectives.toArray(new String[fEnabledPerspectives.size()]);
}
/**
* Show the view without effecting user preferences
*
* @param viewId the id of the view to show
*/
public void showViewQuiet(String viewId) {
if (fWindow == null)
{
return; // disposed;
}
IWorkbenchPage page = fWindow.getActivePage();
if (page != null) {
try {
fIgnoreChanges = true;
IViewPart part = page.showView(viewId, null, IWorkbenchPage.VIEW_VISIBLE);
if (!page.isPartVisible(part)) {
page.bringToTop(part);
}
} catch (PartInitException e) {
DebugUIPlugin.log(e);
} finally {
fIgnoreChanges = false;
}
}
}
@Override
public void perspectivePreDeactivate(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
if (page.getWorkbenchWindow().equals(fWindow)) {
fActivePerspective = null;
clean(perspective);
}
}
@Override
public void preferenceChange(PreferenceChangeEvent event) {
if (!fIgnoreChanges) {
if (IDebugUIConstants.PREF_MANAGE_VIEW_PERSPECTIVES.equals(event.getKey())) {
loadPerspectives();
} else if (IInternalDebugUIConstants.PREF_USER_VIEW_BINDINGS.equals(event.getKey())) {
loadContextToViewExtensions();
applyUserViewBindings();
// clear activations to re-enable activation based on new
// settings
fPerspectiveToActivatedContexts.clear();
ISelection selection = getDebugContextService().getActiveContext();
contextActivated(selection);
}
}
}
}