| /******************************************************************************* |
| * Copyright (c) 2008, 2016 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 |
| * Wind River Systems - adapted to use with IToggleBreakpiontsTargetFactory extension |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.ui.actions; |
| |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| 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.expressions.EvaluationResult; |
| import org.eclipse.core.expressions.Expression; |
| import org.eclipse.core.expressions.ExpressionConverter; |
| import org.eclipse.core.expressions.ExpressionTagNames; |
| import org.eclipse.core.expressions.IEvaluationContext; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IAdapterManager; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
| import org.eclipse.core.runtime.preferences.InstanceScope; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.model.IBreakpoint; |
| import org.eclipse.debug.internal.core.IConfigurationElementConstants; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget; |
| import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetFactory; |
| import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetManager; |
| import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetManagerListener; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.jface.text.source.IVerticalRulerInfo; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.texteditor.IDocumentProvider; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; |
| |
| /** |
| * The concrete implementation of the toggle breakpoints target manager |
| * interface. |
| * |
| * @since 3.5 |
| */ |
| public class ToggleBreakpointsTargetManager implements IToggleBreakpointsTargetManager { |
| |
| /** |
| * Toggle breakpoints target ID which refers to a target contributed |
| * through the legacy adapter mechanism. |
| */ |
| public static String DEFAULT_TOGGLE_TARGET_ID = "default"; //$NON-NLS-1$ |
| |
| private static Set<String> DEFAULT_TOGGLE_TARGET_ID_SET = new TreeSet<String>(); |
| static { |
| DEFAULT_TOGGLE_TARGET_ID_SET.add(DEFAULT_TOGGLE_TARGET_ID); |
| } |
| |
| /** |
| * Acts as a proxy between the toggle breakpoints target manager and the factories |
| * contributed to the extension point. Only loads information from the plug-in XML |
| * and only instantiates the specified factory if required (lazy loading). |
| */ |
| private static class ToggleTargetFactory implements IToggleBreakpointsTargetFactory { |
| |
| private IConfigurationElement fConfigElement; |
| private IToggleBreakpointsTargetFactory fFactory; |
| private Expression fEnablementExpression; |
| |
| public ToggleTargetFactory(IConfigurationElement configElement){ |
| fConfigElement = configElement; |
| } |
| |
| /** |
| * @return Returns the instantiated factory specified by the class property. |
| */ |
| private IToggleBreakpointsTargetFactory getFactory() { |
| if (fFactory != null) { |
| return fFactory; |
| } |
| try{ |
| Object obj = fConfigElement.createExecutableExtension(IConfigurationElementConstants.CLASS); |
| if(obj instanceof IToggleBreakpointsTargetFactory) { |
| fFactory = (IToggleBreakpointsTargetFactory)obj; |
| } else { |
| throw new CoreException(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, "org.eclipse.debug.ui.toggleBreakpointsTargetFactories extension failed to load breakpoint toggle target because the specified class does not implement org.eclipse.debug.ui.actions.IToggleBreakpointsTargetFactory. Class specified was: " + obj, null)); //$NON-NLS-1$ |
| } |
| } catch (CoreException e){ |
| DebugUIPlugin.log(e.getStatus()); |
| fFactory = null; |
| } |
| return fFactory; |
| } |
| |
| /** |
| * Checks if the enablement expression for the factory evaluates to true for the |
| * given part and selection. |
| * @param part The active part. |
| * @param selection The current selection |
| * @return whether the delegated target factory is enabled for given |
| * part and selection. |
| */ |
| public boolean isEnabled(IWorkbenchPart part, ISelection selection) { |
| boolean enabled = false; |
| Expression expression = getEnablementExpression(); |
| if (expression != null) { |
| enabled = evalEnablementExpression(part, selection, expression); |
| } else { |
| enabled = true; |
| } |
| return enabled; |
| } |
| |
| /** |
| * Returns the active debug context given the active part. It is used |
| * in creating the evaluation context for the factories' enablement expression. |
| * @param part active part |
| * @return current active debug context |
| */ |
| private IStructuredSelection getDebugContext(IWorkbenchPart part) { |
| ISelection selection = DebugUITools.getDebugContextManager(). |
| getContextService(part.getSite().getWorkbenchWindow()).getActiveContext(); |
| if (selection instanceof IStructuredSelection) { |
| return (IStructuredSelection)selection; |
| } |
| return StructuredSelection.EMPTY; |
| } |
| |
| /** |
| * Evaluate the given expression within the given context and return |
| * the result. Returns <code>true</code> iff result is either TRUE. |
| * |
| * @param part the {@link IWorkbenchPart} context |
| * @param selection the current selection in the part |
| * @param exp the current expression |
| * @return the result of evaluating the expression |
| */ |
| private boolean evalEnablementExpression(IWorkbenchPart part, ISelection selection, Expression exp) { |
| if (exp != null){ |
| IEvaluationContext context = DebugUIPlugin.createEvaluationContext(part); |
| List<Object> debugContextList = getDebugContext(part).toList(); |
| context.addVariable(IConfigurationElementConstants.DEBUG_CONTEXT, debugContextList); |
| |
| if (selection instanceof IStructuredSelection) { |
| List<Object> selectionList = ((IStructuredSelection) selection).toList(); |
| context.addVariable(IConfigurationElementConstants.SELECTION, selectionList); |
| } |
| |
| if (part instanceof IEditorPart) { |
| context.addVariable(IConfigurationElementConstants.EDITOR_INPUT, ((IEditorPart)part).getEditorInput()); |
| } |
| |
| try{ |
| EvaluationResult result = exp.evaluate(context); |
| if (result == EvaluationResult.TRUE){ |
| return true; |
| } |
| } catch (CoreException e){ |
| // Evaluation failed |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @return Returns an expression that represents the enablement logic |
| * for the breakpoint toggle target. |
| */ |
| private Expression getEnablementExpression(){ |
| if (fEnablementExpression == null) { |
| try{ |
| IConfigurationElement[] elements = fConfigElement.getChildren(ExpressionTagNames.ENABLEMENT); |
| IConfigurationElement enablement = elements.length > 0 ? elements[0] : null; |
| if (enablement != null) { |
| fEnablementExpression = ExpressionConverter.getDefault().perform(enablement); |
| } |
| } catch (CoreException e){ |
| DebugUIPlugin.log(e.getStatus()); |
| fEnablementExpression = null; |
| } |
| } |
| return fEnablementExpression; |
| } |
| |
| /** |
| * Instantiates the factory and asks it to produce the IToggleBreakpointsTarget |
| * for the given ID |
| * @param targetID ID to create toggle target for |
| * @return The created toggle target, or null. |
| */ |
| @Override |
| public IToggleBreakpointsTarget createToggleTarget(String targetID) { |
| IToggleBreakpointsTargetFactory factory = getFactory(); |
| if (factory != null) { |
| return factory.createToggleTarget(targetID); |
| } |
| return null; |
| } |
| |
| /** |
| * Instantiates the factory and asks it for the set of toggle target |
| * IDs that the factory can produce for the given part and selection. |
| * @param part The active part. |
| * @param selection The current selection |
| * @return Set of <code>String</code> IDs for possible toggle breakpoint |
| * targets, possibly empty |
| */ |
| @Override |
| public Set<String> getToggleTargets(IWorkbenchPart part, ISelection selection) { |
| IToggleBreakpointsTargetFactory factory = getFactory(); |
| if (factory != null) { |
| return factory.getToggleTargets(part, selection); |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| /** |
| * Instantiates the factory and asks it to produce the name of the toggle target |
| * for the given ID. |
| * @param targetID toggle breakpoints target identifier |
| * @return toggle target name |
| */ |
| @Override |
| public String getToggleTargetName(String targetID) { |
| IToggleBreakpointsTargetFactory factory = getFactory(); |
| if (factory != null) { |
| return factory.getToggleTargetName(targetID); |
| } |
| return null; |
| } |
| |
| /** |
| * Instantiates the factory and asks it to produce the description of the toggle |
| * target for the given ID. |
| * @param targetID toggle breakpoints target identifier |
| * @return toggle target name or <code>null</code> if none |
| */ |
| @Override |
| public String getToggleTargetDescription(String targetID) { |
| IToggleBreakpointsTargetFactory factory = getFactory(); |
| if (factory != null) { |
| return factory.getToggleTargetDescription(targetID); |
| } |
| return null; |
| } |
| |
| /** |
| * Instantiates the factory and asks it for the toggle tareget ID that |
| * the factory considers the default for the given part and selection. |
| * @param part The active part. |
| * @param selection The current selection |
| * @return a breakpoint toggle target identifier or <code>null</code> |
| */ |
| @Override |
| public String getDefaultToggleTarget(IWorkbenchPart part, ISelection selection) { |
| IToggleBreakpointsTargetFactory factory = getFactory(); |
| if (factory != null) { |
| return factory.getDefaultToggleTarget(part, selection); |
| } |
| return null; |
| } |
| } |
| |
| |
| /** |
| * Factory for toggle breakpoints targets contributed through the |
| * adapter mechanism. |
| */ |
| private static class ToggleBreakpointsTargetAdapterFactory implements IToggleBreakpointsTargetFactory { |
| |
| private Object getSelectionElement(ISelection selection) { |
| if (selection instanceof IStructuredSelection) { |
| IStructuredSelection ss = (IStructuredSelection)selection; |
| return ss.getFirstElement(); |
| } |
| return null; |
| } |
| |
| /** |
| * Checks whether the given element is adaptable to the toggle breakpoints target. |
| * This method does not force loading of the adapter. |
| * @param adaptable Element to adapt. |
| * @return returns true if element can be adapted. |
| */ |
| private boolean canGetToggleBreakpointsTarget(Object adaptable) { |
| if (adaptable != null) { |
| IToggleBreakpointsTarget adapter = null; |
| if (adaptable instanceof IAdaptable) { |
| adapter = ((IAdaptable)adaptable).getAdapter(IToggleBreakpointsTarget.class); |
| } |
| if (adapter == null) { |
| IAdapterManager adapterManager = Platform.getAdapterManager(); |
| if (adapterManager.hasAdapter(adaptable, IToggleBreakpointsTarget.class.getName())) { |
| return true; |
| } |
| } else { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Finds the toggle breakpoints target for the active part and selection. |
| * It first looks for the target using the factories registered using an |
| * extension point. If not found it uses the <code>IAdaptable</code> |
| * mechanism. |
| * @param part The workbench part in which toggle target is to be used |
| * @param element The selection element to retrieve the toggle adapter from |
| * @return The toggle breakpoints target, or <code>null</code> if not found. |
| */ |
| private IToggleBreakpointsTarget getToggleBreakpointsTarget(IWorkbenchPart part, Object element) { |
| IToggleBreakpointsTarget target = null; |
| if (element != null) { |
| target = (IToggleBreakpointsTarget) DebugPlugin.getAdapter(element, IToggleBreakpointsTarget.class); |
| } |
| if (target == null) { |
| target = (IToggleBreakpointsTarget) DebugPlugin.getAdapter(part, IToggleBreakpointsTarget.class); |
| } |
| return target; |
| } |
| |
| /** |
| * Checks if there is an adaptable object for the given part and |
| * selection, and if there is, it checks whether an |
| * <code>IToggleBreakpointsTarget</code> can be obtained as an adapter. |
| * @param part The workbench part in which toggle target is to be used |
| * @param selection The active selection to use with toggle target |
| * @return Whether the adapter (default) toggle target is available. |
| */ |
| public boolean isEnabled(IWorkbenchPart part, ISelection selection) { |
| return canGetToggleBreakpointsTarget(getSelectionElement(selection)) || canGetToggleBreakpointsTarget(part); |
| } |
| |
| /** |
| * Not implemented use {@link #createDefaultToggleTarget(IWorkbenchPart, ISelection)} |
| * instead. |
| * @param targetID not used |
| * @return always returns null |
| */ |
| @Override |
| public IToggleBreakpointsTarget createToggleTarget(String targetID) { |
| return null; |
| } |
| |
| /** |
| * @param part The workbench part in which toggle target is to be used |
| * @param selection The active selection to use with toggle target |
| * @return Returns a toggle target for the given part and selection, obtained |
| * through the adapter mechanism. |
| */ |
| public IToggleBreakpointsTarget createDefaultToggleTarget(IWorkbenchPart part, ISelection selection) { |
| return getToggleBreakpointsTarget(part, getSelectionElement(selection)); |
| } |
| |
| @Override |
| public Set<String> getToggleTargets(IWorkbenchPart part, ISelection selection) { |
| if (isEnabled(part, selection)) { |
| return DEFAULT_TOGGLE_TARGET_ID_SET; |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| @Override |
| public String getToggleTargetName(String targetID) { |
| return ActionMessages.ToggleBreakpointsTargetManager_defaultToggleTarget_name; |
| } |
| |
| @Override |
| public String getToggleTargetDescription(String targetID) { |
| return ActionMessages.ToggleBreakpointsTargetManager_defaultToggleTarget_description; |
| } |
| |
| @Override |
| public String getDefaultToggleTarget(IWorkbenchPart part, ISelection selection) { |
| return DEFAULT_TOGGLE_TARGET_ID; |
| } |
| } |
| |
| |
| /** |
| * Preference key for storing the preferred targets map. |
| * @see #storePreferredTargets() |
| * @see #loadPreferredTargets() |
| */ |
| public static final String PREF_TARGETS = "preferredTargets"; //$NON-NLS-1$ |
| |
| |
| /** |
| * There should only ever be once instance of this manager for the workbench. |
| */ |
| private static ToggleBreakpointsTargetManager fgSingleton; |
| |
| public static ToggleBreakpointsTargetManager getDefault(){ |
| if (fgSingleton == null) { |
| fgSingleton = new ToggleBreakpointsTargetManager(); |
| } |
| return fgSingleton; |
| } |
| |
| /** |
| * Maps the IDs of toggle breakpoint targets to their instances. The target |
| * IDs must be unique. |
| */ |
| private Map<String, IToggleBreakpointsTargetFactory> fKnownFactories; |
| |
| /** |
| * Maps a Set of target id's to the one target id that is preferred. |
| */ |
| private Map<Set<String>, String> fPreferredTargets; |
| |
| /** |
| * Maps the IDs of toggle targets to the factory that can create them. |
| * There can currently only be one factory for a given toggle target. |
| */ |
| private Map<String, IToggleBreakpointsTargetFactory> fFactoriesByTargetID = new HashMap<String, IToggleBreakpointsTargetFactory>(); |
| |
| /** |
| * List of listeners to changes in the preferred toggle targets list. |
| */ |
| private ListenerList<IToggleBreakpointsTargetManagerListener> fChangedListners = new ListenerList<>(); |
| |
| /** |
| * Initializes the collection of known factories from extension point contributions. |
| */ |
| private void initializeFactories() { |
| fKnownFactories = new LinkedHashMap<String, IToggleBreakpointsTargetFactory>(); |
| fKnownFactories.put(DEFAULT_TOGGLE_TARGET_ID, new ToggleBreakpointsTargetAdapterFactory()); |
| IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.EXTENSION_POINT_TOGGLE_BREAKPOINTS_TARGET_FACTORIES); |
| IConfigurationElement[] elements = ep.getConfigurationElements(); |
| for (int i= 0; i < elements.length; i++) { |
| String id = elements[i].getAttribute(IConfigurationElementConstants.ID); |
| if (id != null && id.length() != 0) { |
| if (fKnownFactories.containsKey(id)) { |
| DebugUIPlugin.log(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, "org.eclipse.debug.ui.toggleBreakpointsTargetFactory extension failed to load breakpoint toggle target because the specified id is already registered. Specified ID is: " + id, null)); //$NON-NLS-1$ |
| } else { |
| fKnownFactories.put(id, new ToggleTargetFactory(elements[i])); |
| } |
| } else { |
| DebugUIPlugin.log(new Status(IStatus.ERROR, DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.INTERNAL_ERROR, "org.eclipse.debug.ui.toggleBreakpointsTargetFactory extension failed to load breakpoint toggle target because the specified id is empty.", null)); //$NON-NLS-1$ |
| } |
| } |
| |
| // If there are any factories contributed through the extension point, |
| // set a system property for use in enabling actions. |
| System.setProperty(IDebugUIConstants.SYS_PROP_BREAKPOINT_TOGGLE_FACTORIES_USED, |
| fKnownFactories.size() > 1 ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * Returns the set of IToggleBreakpointsTargetFactory objects (they will be |
| * ToggleTargetFactory) that were contributed to the extension point and |
| * are enabled for the given part and selection (enabled if the factory |
| * does not have an enablement expression or if the enablement expression |
| * evaluates to true). |
| * |
| * @param part active part |
| * @param selection active selection in part |
| * @return The factories enabled for the part and selection or an empty |
| * collection. |
| */ |
| private Set<IToggleBreakpointsTargetFactory> getEnabledFactories(IWorkbenchPart part, ISelection selection) { |
| if (fKnownFactories == null) { |
| initializeFactories(); |
| } |
| Set<IToggleBreakpointsTargetFactory> set = new HashSet<IToggleBreakpointsTargetFactory>(); |
| for (Entry<String, IToggleBreakpointsTargetFactory> entry : fKnownFactories.entrySet()) { |
| IToggleBreakpointsTargetFactory factory = entry.getValue(); |
| if (factory instanceof ToggleTargetFactory && |
| ((ToggleTargetFactory)factory).isEnabled(part, selection)) { |
| set.add(factory); |
| } else if (factory instanceof ToggleBreakpointsTargetAdapterFactory && |
| ((ToggleBreakpointsTargetAdapterFactory)factory).isEnabled(part, selection)) { |
| set.add(factory); |
| } |
| } |
| return set; |
| } |
| |
| /** |
| * Produces the set of IDs for all possible toggle targets that can be used for |
| * the given part and selection. |
| * |
| * @param factoriesToQuery The collection of factories to check |
| * @param part active part |
| * @param selection active selection in part |
| * @return Set of toggle target IDs or an empty set |
| */ |
| private Set<String> getEnabledTargetIDs(Set<IToggleBreakpointsTargetFactory> factoriesToQuery, IWorkbenchPart part, ISelection selection) { |
| Set<String> idsForSelection = new TreeSet<String>(); |
| for (IToggleBreakpointsTargetFactory factory : factoriesToQuery) { |
| for(String targetID : factory.getToggleTargets(part, selection)) { |
| fFactoriesByTargetID.put(targetID, factory); |
| idsForSelection.add(targetID); |
| } |
| } |
| return idsForSelection; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetManager# |
| * getEnabledToggleBreakpointsTargetIDs(org.eclipse.ui.IWorkbenchPart, |
| * org.eclipse.jface.viewers.ISelection) |
| */ |
| @Override |
| public Set<String> getEnabledToggleBreakpointsTargetIDs(IWorkbenchPart part, ISelection selection) { |
| return getEnabledTargetIDs(getEnabledFactories(part, selection), part, selection); |
| } |
| |
| @Override |
| public String getPreferredToggleBreakpointsTargetID(IWorkbenchPart part, ISelection selection) { |
| Set<IToggleBreakpointsTargetFactory> factories = getEnabledFactories(part, selection); |
| Set<String> possibleIDs = getEnabledTargetIDs(factories, part, selection); |
| return chooseToggleTargetIDInSet(possibleIDs, part, selection); |
| } |
| |
| @Override |
| public IToggleBreakpointsTarget getToggleBreakpointsTarget(IWorkbenchPart part, ISelection selection) { |
| String id = getPreferredToggleBreakpointsTargetID(part, selection); |
| IToggleBreakpointsTargetFactory factory = fFactoriesByTargetID.get(id); |
| if (factory != null) { |
| if (DEFAULT_TOGGLE_TARGET_ID.equals(id)) { |
| return ((ToggleBreakpointsTargetAdapterFactory)factory).createDefaultToggleTarget(part, selection); |
| } else { |
| return factory.createToggleTarget(id); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public String getToggleBreakpointsTargetName(String id) { |
| IToggleBreakpointsTargetFactory factory = fFactoriesByTargetID.get(id); |
| if (factory != null) { |
| return factory.getToggleTargetName(id); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getToggleBreakpointsTargetDescription(String id) { |
| IToggleBreakpointsTargetFactory factory = fFactoriesByTargetID.get(id); |
| if (factory != null) { |
| return factory.getToggleTargetDescription(id); |
| } |
| return null; |
| } |
| |
| @Override |
| public void addChangedListener(IToggleBreakpointsTargetManagerListener listener) { |
| fChangedListners.add(listener); |
| } |
| |
| @Override |
| public void removeChangedListener(IToggleBreakpointsTargetManagerListener listener) { |
| fChangedListners.remove(listener); |
| } |
| |
| /** |
| * Stores the map of preferred target IDs to the preference store in the format: |
| * |
| * Key1A,Key1B:Value1|Key2A,Key2B,Key2C:Value2| |
| * |
| * Where the sub keys (Key1A, Key1B, etc.) are the elements of the set used at the |
| * key in the mapping and the values are the associated String value in the mapping. |
| */ |
| private void storePreferredTargets() { |
| StringBuffer buffer= new StringBuffer(); |
| for (Entry<Set<String>, String> entry : fPreferredTargets.entrySet()) { |
| for (String currentID : entry.getKey()) { |
| buffer.append(currentID); |
| buffer.append(','); |
| } |
| buffer.deleteCharAt(buffer.length()-1); |
| buffer.append(':'); |
| buffer.append(entry.getValue()); |
| buffer.append('|'); |
| } |
| IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(DebugUIPlugin.getUniqueIdentifier()); |
| if(prefs != null) { |
| prefs.put(PREF_TARGETS, buffer.toString()); |
| } |
| } |
| |
| /** |
| * Loads the map of preferred target IDs from the preference store. |
| * |
| * @see #storePreferredTargets() |
| */ |
| private void loadPreferredTargets() { |
| fPreferredTargets = new HashMap<Set<String>, String>(); |
| String preferenceValue = Platform.getPreferencesService().getString( |
| DebugUIPlugin.getUniqueIdentifier(), |
| PREF_TARGETS, |
| null, |
| null); |
| if(preferenceValue == null) { |
| return; |
| } |
| StringTokenizer entryTokenizer = new StringTokenizer(preferenceValue,"|"); //$NON-NLS-1$ |
| while (entryTokenizer.hasMoreTokens()){ |
| String token = entryTokenizer.nextToken(); |
| int valueStart = token.indexOf(':'); |
| StringTokenizer keyTokenizer = new StringTokenizer(token.substring(0,valueStart),","); //$NON-NLS-1$ |
| Set<String> keys = new TreeSet<String>(); |
| while (keyTokenizer.hasMoreTokens()){ |
| keys.add(keyTokenizer.nextToken()); |
| } |
| fPreferredTargets.put(keys, token.substring(valueStart+1)); |
| } |
| } |
| |
| /** |
| * Adds or updates the mapping to set which target ID is preferred for a certain |
| * set of possible IDs. |
| * |
| * @param possibleIDs The set of possible IDs |
| * @param preferredID The preferred ID in the set. |
| */ |
| public void setPreferredTarget(Set<String> possibleIDs, String preferredID) { |
| if (possibleIDs == null) { |
| return; |
| } |
| |
| if (fKnownFactories == null) { |
| initializeFactories(); |
| } |
| |
| if (fPreferredTargets == null){ |
| loadPreferredTargets(); |
| } |
| String currentKey = fPreferredTargets.get(possibleIDs); |
| if (currentKey == null || !currentKey.equals(preferredID)){ |
| fPreferredTargets.put(possibleIDs, preferredID); |
| storePreferredTargets(); |
| firePreferredTargetsChanged(); |
| } |
| } |
| |
| /** |
| * Returns the preferred toggle target ID from the given set if the mapping has been set. |
| * |
| * @param possibleTargetIDs The set of possible toggle target IDs |
| * @return The preferred ID or null |
| */ |
| private String getUserPreferredTarget(Set<String> possibleTargetIDs) { |
| if (fPreferredTargets == null){ |
| loadPreferredTargets(); |
| } |
| return fPreferredTargets.get(possibleTargetIDs); |
| } |
| |
| /** |
| * Given a set of possible toggle target IDs, this method will determine which target is |
| * preferred and should be used to toggle breakpoints. This method chooses a toggle target |
| * by storing previous choices and can be set using a context menu. |
| * |
| * @param possibleTargetIDs The set of possible toggle target IDs |
| * @param part The workbench part in which toggle target is to be used |
| * @param selection The active selection to use with toggle target |
| * @return The preferred toggle target ID or null |
| */ |
| private String chooseToggleTargetIDInSet(Set<String> possibleTargetIDs, IWorkbenchPart part, ISelection selection) { |
| if (possibleTargetIDs == null || possibleTargetIDs.isEmpty()){ |
| return null; |
| } |
| |
| String preferredID = getUserPreferredTarget(possibleTargetIDs); |
| |
| if (preferredID == null){ |
| // If there is no preferred pane already set, check the factories to see there is a default target |
| Iterator<String> possibleIDsIterator = possibleTargetIDs.iterator(); |
| while (preferredID == null && possibleIDsIterator.hasNext()) { |
| IToggleBreakpointsTargetFactory factory = fFactoriesByTargetID.get(possibleIDsIterator.next()); |
| if (factory != null) { |
| preferredID = factory.getDefaultToggleTarget(part, selection); |
| } |
| } |
| // If the factories don't have a default, just pick the first one. |
| // Also make sure that the default is among the available toggle target |
| // IDs (bug 352502). |
| if (preferredID == null || !possibleTargetIDs.contains(preferredID)) { |
| preferredID= possibleTargetIDs.iterator().next(); |
| } |
| setPreferredTarget(possibleTargetIDs, preferredID); |
| } |
| |
| return preferredID; |
| } |
| |
| /** |
| * Notifies the change listeners that the preferred targets changed. |
| */ |
| private void firePreferredTargetsChanged() { |
| for (IToggleBreakpointsTargetManagerListener iToggleBreakpointsTargetManagerListener : fChangedListners) { |
| iToggleBreakpointsTargetManagerListener.preferredTargetsChanged(); |
| } |
| } |
| |
| public IBreakpoint getBeakpointFromEditor(ITextEditor editor, IVerticalRulerInfo info) { |
| IDocumentProvider provider = editor.getDocumentProvider(); |
| if(provider == null) { |
| return null; |
| } |
| IEditorInput input = editor.getEditorInput(); |
| IAnnotationModel annotationModel = provider.getAnnotationModel(input); |
| if (annotationModel != null) { |
| IDocument document = provider.getDocument(input); |
| Iterator<Annotation> iterator = annotationModel.getAnnotationIterator(); |
| while (iterator.hasNext()) { |
| Annotation annot = iterator.next(); |
| if (annot instanceof SimpleMarkerAnnotation) { |
| SimpleMarkerAnnotation markerAnnotation = (SimpleMarkerAnnotation) annot; |
| IMarker marker = markerAnnotation.getMarker(); |
| try { |
| if (marker.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) { |
| Position position = annotationModel.getPosition(markerAnnotation); |
| int line = document.getLineOfOffset(position.getOffset()); |
| if (line == info.getLineOfLastMouseButtonActivity()) { |
| IBreakpoint breakpoint = DebugPlugin.getDefault().getBreakpointManager().getBreakpoint(marker); |
| if (breakpoint != null) { |
| return breakpoint; |
| } |
| } |
| } |
| } catch (CoreException e) { |
| } catch (BadLocationException e) { |
| } |
| } |
| } |
| } |
| return null; |
| } |
| } |