| /***************************************************************** |
| * Copyright (c) 2009, 2018 Texas Instruments 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: |
| * Patrick Chuong (Texas Instruments) - Initial API and implementation (Bug 238956) |
| * IBM Corporation - ongoing enhancements and bug fixing |
| *****************************************************************/ |
| package org.eclipse.debug.internal.ui.views.breakpoints; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.IBreakpointManagerListener; |
| import org.eclipse.debug.core.model.IBreakpoint; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.internal.ui.IDebugHelpContextIds; |
| import org.eclipse.debug.internal.ui.VariablesViewModelPresentation; |
| import org.eclipse.debug.internal.ui.actions.breakpointGroups.PasteBreakpointsAction; |
| import org.eclipse.debug.internal.ui.actions.breakpointGroups.RemoveFromWorkingSetAction; |
| import org.eclipse.debug.internal.ui.actions.breakpoints.OpenBreakpointMarkerAction; |
| import org.eclipse.debug.internal.ui.actions.breakpoints.ShowTargetBreakpointsAction; |
| import org.eclipse.debug.internal.ui.actions.breakpoints.SkipAllBreakpointsAction; |
| import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointContainer; |
| import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer; |
| import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants; |
| import org.eclipse.debug.internal.ui.elements.adapters.DefaultBreakpointsViewInput; |
| import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants; |
| import org.eclipse.debug.internal.ui.viewers.model.VirtualFindAction; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer; |
| import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages; |
| import org.eclipse.debug.internal.ui.views.variables.VariablesView; |
| import org.eclipse.debug.internal.ui.views.variables.details.AvailableDetailPanesAction; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.IBreakpointOrganizerDelegateExtension; |
| import org.eclipse.debug.ui.IDebugModelPresentation; |
| import org.eclipse.debug.ui.IDebugUIConstants; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.util.LocalSelectionTransfer; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.dnd.Clipboard; |
| import org.eclipse.swt.dnd.DND; |
| import org.eclipse.swt.dnd.Transfer; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.TreeItem; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.IWorkbenchActionConstants; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.actions.SelectionListenerAction; |
| import org.eclipse.ui.operations.RedoActionHandler; |
| import org.eclipse.ui.operations.UndoActionHandler; |
| |
| /** |
| * This class implements the breakpoints view. |
| */ |
| public class BreakpointsView extends VariablesView implements IBreakpointManagerListener { |
| private static final String ACTION_GOTO_MARKER = "GotoMarker"; //$NON-NLS-1$ |
| private static final String ACTION_SKIP_BREAKPOINTS = "SkipBreakpoints"; //$NON-NLS-1$ |
| private static final String ACTION_SHOW_MODEL_BREAKPOINT = "ShowBreakpointsForModel";//$NON-NLS-1$ |
| private static final String ACTION_REMOVE_FROM_GROUP = "RemoveFromGroup"; //$NON-NLS-1$ |
| |
| |
| private static final String KEY_VALUE = "value"; //$NON-NLS-1$ |
| |
| private Clipboard fClipboard; |
| private IBreakpointOrganizer[] fOrganizers; |
| |
| /** |
| * Flag used to determine whether the viewer input is being set for the |
| * fist time. If this is the case the view contents are expanded. |
| * (bug 297762) |
| */ |
| private boolean fFirstInputSet = false; |
| |
| private UndoActionHandler fUndoAction; |
| private RedoActionHandler fRedoAction; |
| |
| |
| @Override |
| public void dispose() { |
| if (fClipboard != null) { |
| fClipboard.dispose(); |
| } |
| DebugPlugin.getDefault().getBreakpointManager().removeBreakpointManagerListener(this); |
| |
| fUndoAction.dispose(); |
| fRedoAction.dispose(); |
| |
| super.dispose(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getDetailPanePreferenceKey() |
| */ |
| @Override |
| protected String getDetailPanePreferenceKey() { |
| return IDebugPreferenceConstants.BREAKPOINTS_DETAIL_PANE_ORIENTATION; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getHelpContextId() |
| */ |
| @Override |
| protected String getHelpContextId() { |
| return IDebugHelpContextIds.BREAKPOINT_VIEW; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getViewerStyle() |
| */ |
| @Override |
| protected int getViewerStyle() { |
| return SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION | SWT.CHECK; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#createViewer(org.eclipse.swt.widgets.Composite) |
| */ |
| @Override |
| public Viewer createViewer(Composite parent) { |
| TreeModelViewer viewer = (TreeModelViewer) super.createViewer(parent); |
| |
| initBreakpointOrganizers(getMemento()); |
| |
| IPresentationContext presentationContext = viewer.getPresentationContext(); |
| presentationContext.setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS, fOrganizers); |
| presentationContext.setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR, new ElementComparator(presentationContext)); |
| |
| return viewer; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getModelPresentation() |
| */ |
| @Override |
| protected IDebugModelPresentation getModelPresentation() { |
| if (fModelPresentation == null) { |
| fModelPresentation = new VariablesViewModelPresentation() { |
| /** |
| * Undo double slashes. |
| */ |
| @Override |
| public String getText(Object element) { |
| IDebugModelPresentation lp= getConfiguredPresentation(element); |
| if (lp != null) { |
| return lp.getText(element); |
| } |
| return getDefaultText(element); |
| } |
| }; |
| } |
| return fModelPresentation; |
| } |
| |
| /** |
| * Returns the tree model viewer. |
| * @return the backin gviewer |
| */ |
| public TreeModelViewer getTreeModelViewer() { |
| return (TreeModelViewer) getViewer(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#configureToolBar(org.eclipse.jface.action.IToolBarManager) |
| */ |
| @Override |
| protected void configureToolBar(IToolBarManager tbm) { |
| tbm.add(new Separator(IDebugUIConstants.BREAKPOINT_GROUP)); |
| tbm.add(getAction(ACTION_SHOW_MODEL_BREAKPOINT)); |
| tbm.add(getAction(ACTION_GOTO_MARKER)); |
| tbm.add(getAction(ACTION_SKIP_BREAKPOINTS)); |
| tbm.add(new Separator(IDebugUIConstants.RENDER_GROUP)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#fillContextMenu(org.eclipse.jface.action.IMenuManager) |
| */ |
| @Override |
| protected void fillContextMenu(IMenuManager menu) { |
| updateObjects(); |
| menu.add(new Separator(IDebugUIConstants.EMPTY_NAVIGATION_GROUP)); |
| menu.add(new Separator(IDebugUIConstants.NAVIGATION_GROUP)); |
| menu.add(getAction(ACTION_GOTO_MARKER)); |
| menu.add(new Separator(IDebugUIConstants.EMPTY_BREAKPOINT_GROUP)); |
| menu.add(new Separator(IDebugUIConstants.BREAKPOINT_GROUP)); |
| menu.add(getAction(PASTE_ACTION)); |
| IAction action = getAction(ACTION_REMOVE_FROM_GROUP); |
| if (action != null && action.isEnabled()) { |
| menu.add(action); |
| } |
| menu.add(new Separator(IDebugUIConstants.EMPTY_RENDER_GROUP)); |
| action = new AvailableDetailPanesAction(this); |
| if (isDetailPaneVisible() && action.isEnabled()) { |
| menu.add(action); |
| } |
| menu.add(new Separator(IDebugUIConstants.BREAKPOINT_GROUP_GROUP)); |
| |
| menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#createActions() |
| */ |
| @Override |
| protected void createActions() { |
| IAction action = new OpenBreakpointMarkerAction(getViewer()); |
| setAction(ACTION_GOTO_MARKER, action); |
| setAction(DOUBLE_CLICK_ACTION, action); |
| setAction(ACTION_SHOW_MODEL_BREAKPOINT, new ShowTargetBreakpointsAction(this)); |
| SkipAllBreakpointsAction skipAll = new SkipAllBreakpointsAction(this); |
| setAction(ACTION_SKIP_BREAKPOINTS, skipAll); |
| skipAll.setActionDefinitionId(SkipAllBreakpointsAction.ACTION_DEFINITION_ID); |
| DebugPlugin.getDefault().getBreakpointManager().addBreakpointManagerListener(this); |
| |
| fClipboard = new Clipboard(getSite().getShell().getDisplay()); |
| |
| PasteBreakpointsAction paste = new PasteBreakpointsAction(this); |
| setAction(PASTE_ACTION, paste); |
| paste.setActionDefinitionId(ActionFactory.PASTE.getCommandId()); |
| //actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), paste); |
| setGlobalAction(PASTE_ACTION, paste); |
| getViewer().addSelectionChangedListener(paste); |
| paste.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_PASTE)); |
| |
| SelectionListenerAction remove = new RemoveFromWorkingSetAction(this); |
| setAction(ACTION_REMOVE_FROM_GROUP, remove); |
| getViewer().addSelectionChangedListener(remove); |
| |
| IUndoContext undoContext= DebugUITools.getBreakpointsUndoContext(); |
| fUndoAction= new UndoActionHandler(getSite(), undoContext); |
| fUndoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); |
| fRedoAction= new RedoActionHandler(getSite(), undoContext); |
| fRedoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); |
| //actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), fUndoAction); |
| //actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), fRedoAction); |
| setGlobalAction(ActionFactory.UNDO.getId(), fUndoAction); |
| setGlobalAction(ActionFactory.REDO.getId(), fRedoAction); |
| setGlobalAction(FIND_ACTION, new VirtualFindAction(getVariablesViewer())); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @seeorg.eclipse.debug.internal.ui.views.variables.VariablesView#getToggleActionLabel() |
| */ |
| @Override |
| protected String getToggleActionLabel() { |
| return DebugUIViewsMessages.BreakpointsView_12; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getPresentationContextId() |
| */ |
| @Override |
| protected String getPresentationContextId() { |
| return IDebugUIConstants.ID_BREAKPOINT_VIEW; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#contextActivated(org.eclipse.jface.viewers.ISelection) |
| */ |
| @Override |
| protected void contextActivated(ISelection selection) { |
| if (!isAvailable() || !isVisible()) { |
| return; |
| } |
| |
| IPresentationContext presentationContext = getTreeModelViewer().getPresentationContext(); |
| |
| if (selection == null || selection.isEmpty()) { |
| Object input = new DefaultBreakpointsViewInput(presentationContext); |
| super.contextActivated(new StructuredSelection(input)); |
| } else { |
| super.contextActivated(selection); |
| } |
| if (isAvailable() && isVisible()) { |
| updateAction("ContentAssist"); //$NON-NLS-1$ |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#setViewerInput(java.lang.Object) |
| */ |
| @Override |
| protected void setViewerInput(Object context) { |
| Object current = getViewer().getInput(); |
| if (current == null && context == null) { |
| return; |
| } |
| |
| if (current != null && current.equals(context)) { |
| return; |
| } |
| |
| showViewer(); |
| getViewer().setInput(context); |
| |
| // Expand all elements when the view is first shown. (bug 297762) |
| if (!fFirstInputSet) { |
| fFirstInputSet = true; |
| expandAllElementsInViewer(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#viewerInputUpdateComplete(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate) |
| */ |
| @Override |
| protected void viewerInputUpdateComplete(IViewerInputUpdate update) { |
| // handles non-standard debug model |
| IStatus status = update.getStatus(); |
| if ( (status == null || status.isOK()) && update.getElement() != null) { |
| setViewerInput(update.getInputElement()); |
| } else { |
| setViewerInput(new DefaultBreakpointsViewInput(getTreeModelViewer().getPresentationContext())); |
| } |
| } |
| |
| |
| /** |
| * Returns whether this view is currently tracking the selection from the debug view. |
| * |
| * @return whether this view is currently tracking the debug view's selection |
| */ |
| public boolean isTrackingSelection() { |
| final TreeModelViewer viewer = getTreeModelViewer(); |
| if (viewer != null) { |
| return Boolean.TRUE.equals( |
| viewer.getPresentationContext().getProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_TRACK_SELECTION) ); |
| } |
| return false; |
| } |
| |
| /** |
| * Sets whether this view should track the selection from the debug view. |
| * |
| * @param trackSelection whether or not this view should track the debug view's selection. |
| */ |
| public void setTrackSelection(boolean trackSelection) { |
| // set the track selection property for non-standard model to track the debug context |
| final TreeModelViewer viewer = getTreeModelViewer(); |
| if (viewer != null) { |
| viewer.getPresentationContext().setProperty( |
| IBreakpointUIConstants.PROP_BREAKPOINTS_TRACK_SELECTION, |
| trackSelection ? Boolean.TRUE : Boolean.FALSE); |
| } |
| } |
| |
| /** |
| * Initializes the persisted breakpoints organizers. |
| * @param memento the memento to read |
| */ |
| private void initBreakpointOrganizers(IMemento memento) { |
| if (memento != null) { |
| IMemento node = memento.getChild(IDebugUIConstants.EXTENSION_POINT_BREAKPOINT_ORGANIZERS); |
| if (node == null) { |
| fOrganizers = null; |
| } else { |
| String value = node.getString(KEY_VALUE); |
| if (value != null) { |
| String[] ids = value.split(","); //$NON-NLS-1$ |
| BreakpointOrganizerManager manager = BreakpointOrganizerManager.getDefault(); |
| List<IBreakpointOrganizer> organziers = new ArrayList<>(); |
| for (int i = 0; i < ids.length; i++) { |
| IBreakpointOrganizer organizer = manager.getOrganizer(ids[i]); |
| if (organizer != null) { |
| organziers.add(organizer); |
| } |
| } |
| fOrganizers = organziers.toArray(new IBreakpointOrganizer[organziers.size()]); |
| |
| for (int i = 0; i < fOrganizers.length; i++) { |
| fOrganizers[i].addPropertyChangeListener(this); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Initializes drag and drop for the breakpoints viewer |
| * @param viewer the viewer to add drag and drop support to |
| */ |
| @Override |
| protected void initDragAndDrop(TreeModelViewer viewer) { |
| int ops = DND.DROP_MOVE | DND.DROP_COPY; |
| // drop |
| viewer.addDropSupport(ops, new Transfer[] {LocalSelectionTransfer.getTransfer()}, new BreakpointsDropAdapter(viewer, this)); |
| // Drag |
| viewer.addDragSupport(ops, new Transfer[] {LocalSelectionTransfer.getTransfer()}, new BreakpointsDragAdapter(viewer, this)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesView#saveViewerState(org.eclipse.ui.IMemento) |
| */ |
| @Override |
| public void saveViewerState(IMemento memento) { |
| StringBuffer buffer = new StringBuffer(); |
| if (fOrganizers != null) { |
| for (int i = 0; i < fOrganizers.length; i++) { |
| IBreakpointOrganizer organizer = fOrganizers[i]; |
| buffer.append(organizer.getIdentifier()); |
| if (i < (fOrganizers.length - 1)) { |
| buffer.append(','); |
| } |
| } |
| IMemento node = memento.createChild(IDebugUIConstants.EXTENSION_POINT_BREAKPOINT_ORGANIZERS); |
| node.putString(KEY_VALUE, buffer.toString()); |
| } |
| super.saveViewerState(memento); |
| } |
| |
| /** |
| * Preserves the selection. |
| * |
| * @param selection the selection |
| */ |
| public void preserveSelection(IStructuredSelection selection) { |
| if (selection instanceof ITreeSelection && !selection.isEmpty()) { |
| TreePath path = ((ITreeSelection) selection).getPaths()[0]; |
| TreeItem item = (TreeItem) ((TreeModelViewer) getViewer()).findItem(path); |
| Object toselect = null; |
| TreeItem[] siblings = null; |
| if (item != null) { |
| TreeItem parent = item.getParentItem(); |
| if (parent != null) { |
| siblings = parent.getItems(); |
| } else { |
| siblings = item.getParent().getItems(); |
| } |
| if (siblings.length > 1) { |
| for (int i = 0; i < siblings.length; i++) { |
| if (item.equals(siblings[i])) { |
| if (i + 1 >= siblings.length) { |
| toselect = siblings[i - 1].getData(); |
| break; |
| } else { |
| toselect = siblings[i + 1].getData(); |
| break; |
| } |
| |
| } |
| } |
| } |
| } |
| if (toselect != null) { |
| getViewer().setSelection(new StructuredSelection(toselect),true); |
| } |
| } |
| } |
| |
| /** |
| * Sets the breakpoint organizers for this view. |
| * |
| * @param organizers the organizers, can be <code>null</code>. |
| */ |
| public void setBreakpointOrganizers(IBreakpointOrganizer[] organizers) { |
| fOrganizers = organizers; |
| |
| TreeModelViewer viewer = getTreeModelViewer(); |
| if (viewer != null) { |
| // update the presentation context organizer |
| viewer.getPresentationContext().setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS, fOrganizers); |
| } |
| System.out.println(); |
| } |
| |
| /** |
| * Sets the breakpoint filter for this view. |
| * @param filter the selection to act as a filter |
| */ |
| public void setFilterSelection(boolean filter) { |
| TreeModelViewer viewer = getTreeModelViewer(); |
| if (viewer != null) { |
| // update the presentation context filter |
| viewer.getPresentationContext().setProperty( |
| IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION, filter ? Boolean.TRUE : Boolean.FALSE); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.IBreakpointManagerListener#breakpointManagerEnablementChanged(boolean) |
| */ |
| @Override |
| public void breakpointManagerEnablementChanged(boolean enabled) { |
| DebugUIPlugin.getStandardDisplay().asyncExec(() -> { |
| IAction action = getAction(ACTION_SKIP_BREAKPOINTS); |
| if (action != null) { |
| ((SkipAllBreakpointsAction) action).updateActionCheckedState(); |
| } |
| }); |
| } |
| |
| /** |
| * Expands all elements in the viewer. |
| */ |
| public void expandAllElementsInViewer() { |
| Display display = getSite().getShell().getDisplay(); |
| |
| final VirtualTreeModelViewer virtualViewer = new VirtualTreeModelViewer( |
| display, 0, ((ITreeModelViewer)getViewer()).getPresentationContext()); |
| |
| virtualViewer.setAutoExpandLevel(-1); |
| virtualViewer.addViewerUpdateListener(new IViewerUpdateListener() { |
| @Override |
| public void viewerUpdatesComplete() { |
| ModelDelta stateDelta = new ModelDelta(virtualViewer.getInput(), IModelDelta.NO_CHANGE); |
| virtualViewer.saveElementState(TreePath.EMPTY, stateDelta, IModelDelta.EXPAND); |
| ITreeModelViewer treeModelViewer = ((ITreeModelViewer) getViewer()); |
| if (treeModelViewer != null) { |
| ((ITreeModelViewer) getViewer()).updateViewer(stateDelta); |
| } |
| virtualViewer.dispose(); |
| } |
| @Override |
| public void viewerUpdatesBegin() {} |
| @Override |
| public void updateStarted(IViewerUpdate update) {} |
| @Override |
| public void updateComplete(IViewerUpdate update) {} |
| }); |
| virtualViewer.setInput(getViewer().getInput()); |
| } |
| |
| |
| /** |
| * Returns the breakpoint organizers for this view. |
| * |
| * @return the breakpoint organizers. |
| */ |
| public IBreakpointOrganizer[] getBreakpointOrganizers() { |
| return fOrganizers; |
| } |
| |
| /** |
| * Returns whether the given selection can be pasted into the given target. |
| * <p> |
| * Scheme: |
| * <ul> |
| * <li>Breakpoints can only be pasted into allowable containers (i..e. like workings sets)</li> |
| * <li>Breakpoints can only be pasted into containers that they do not already reside in</li> |
| * <li>Breakpoints can only be pasted into containers, not other breakpoints</li> |
| * </ul> |
| * </p> |
| * |
| * @param target target of the paste |
| * @param selection the selection to paste |
| * @return whether the given selection can be pasted into the given target |
| * |
| * TODO Remove in favor of using <code>TreeItem</code>s and <code>TreePath</code>s to determine paste targets |
| */ |
| public boolean canPaste(Object target, ISelection selection) { |
| if(!(target instanceof IBreakpointContainer) || !(selection instanceof IStructuredSelection)) { |
| return false; |
| } |
| if(selection == null || selection.isEmpty()) { |
| return false; |
| } |
| IStructuredSelection ss = (IStructuredSelection) selection; |
| IBreakpointContainer container = (IBreakpointContainer) target; |
| for (Iterator<?> iter = ss.iterator(); iter.hasNext();) { |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(iter.next(), IBreakpoint.class); |
| if (breakpoint == null || container.contains(breakpoint) || !container.getOrganizer().canAdd(breakpoint, container.getCategory())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Pastes the selection into the given target |
| * |
| * @param target target of the paste, either a IBreakpointContainer, |
| * or a Breakpoint within a IBreakpointContainer |
| * @param selection breakpoints |
| * @return whether successful |
| * |
| * TODO remove in favor of using <code>TreeItem</code> as paste target |
| */ |
| public boolean performPaste(Object target, ISelection selection) { |
| if (target instanceof IBreakpointContainer && selection instanceof IStructuredSelection) { |
| IBreakpointContainer container = (IBreakpointContainer) target; |
| Object[] objects = ((IStructuredSelection)selection).toArray(); |
| for (int i = 0; i < objects.length; i++) { |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(objects[i], IBreakpoint.class); |
| if (breakpoint != null) { |
| container.getOrganizer().addBreakpoint(breakpoint, container.getCategory()); |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the container from within the specified path that is the container the breakpoint can be removed from |
| * @param path the path to get the container from |
| * @return the first found container that includes the breakpoint that allows removal, or <code>null</code> if none found |
| * @since 3.3 |
| */ |
| public IBreakpointContainer getRemovableContainer(TreePath path) { |
| if (path != null) { |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(path.getLastSegment(), IBreakpoint.class); |
| if (breakpoint != null) { |
| IBreakpointContainer container = null; |
| for(int i = path.getSegmentCount()-2; i > -1; i--) { |
| Object segment = path.getSegment(i); |
| if (segment instanceof IBreakpointContainer) { |
| container = (IBreakpointContainer) segment; |
| if(container.contains(breakpoint) && |
| container.getOrganizer() != null && |
| container.getOrganizer().canRemove(breakpoint, container.getCategory())) { |
| return container; |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the addable breakpoint container of the specified tree path |
| * @param path the path to get the container for |
| * @return the first found addable container for the specified tree path or <code>null</code> if none found |
| * @since 3.3 |
| */ |
| protected IBreakpointContainer getAddableContainer(TreePath path) { |
| if (path != null) { |
| Object element = path.getLastSegment(); |
| if (element instanceof IBreakpointContainer) { |
| return (IBreakpointContainer)element; |
| } |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(element, IBreakpoint.class); |
| if (breakpoint != null) { |
| IBreakpointContainer container = null; |
| for (int i = path.getSegmentCount()-2; i > -1; i--) { |
| Object segment = path.getSegment(i); |
| if (segment instanceof IBreakpointContainer) { |
| container = (IBreakpointContainer) segment; |
| if (container.contains(breakpoint) && container.getOrganizer().canAdd(breakpoint, container.getCategory())) { |
| return container; |
| } |
| } |
| } |
| } |
| } |
| return null; |
| } |
| /** |
| * This method is used to determine if there is an addable parent container available for the specified drop target. |
| * <p> |
| * A drop target can be either a <code>IBreakpointContainer</code> or an <code>IBreakpoint</code>. This method always checks the entire hierarchy |
| * of the tree path for the specified target in the event one of the parent element does not support dropping. |
| * </p> |
| * @param path the path |
| * @param breakpoint the breakpoint |
| * @return <code>true</code> if there is a parent container available for the drop target <code>false</code> otherwise |
| */ |
| private boolean checkAddableParentContainers(TreePath path, IBreakpoint breakpoint) { |
| if (path != null) { |
| Object element = null; |
| for (int i = path.getSegmentCount()-1; i > -1; i--) { |
| element = path.getSegment(i); |
| if (element instanceof IBreakpointContainer) { |
| IBreakpointContainer container = (IBreakpointContainer) element; |
| if (container.contains(breakpoint) || !container.getOrganizer().canAdd(breakpoint, container.getCategory())) { |
| return false; |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns if the selected item in the tree can be dragged |
| * <p> |
| * Scheme: |
| * <ul> |
| * <li>breakpoint containers cannot be dragged</li> |
| * <li>breakpoints can be dragged iff the container they reside in supports the removal of breakpoints</li> |
| * </ul> |
| * </p> |
| * @param items the tree paths to check if they can be dragged |
| * @return true if the selected element can be dragged, false otherwise |
| * @since 3.3 |
| */ |
| boolean canDrag(TreePath[] items) { |
| if(items == null) { |
| return false; |
| } |
| if (items.length == 0) { |
| return false; |
| } |
| for (int i = 0; i < items.length; i++) { |
| if (getRemovableContainer(items[i]) == null) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Performs the actual removal of breakpoints from their respective (removable) containers on a successful drag operation |
| * @param paths the tree paths to drag |
| * @since 3.3 |
| */ |
| void performDrag(TreePath[] paths) { |
| if (paths == null) { |
| return; |
| } |
| Map<IBreakpointContainer, List<IBreakpoint>> containersToBreakpoints = new HashMap<>(); |
| for (int i = 0; i < paths.length; i++) { |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(paths[i].getLastSegment(), IBreakpoint.class); |
| if (breakpoint != null) { |
| IBreakpointContainer container = getRemovableContainer(paths[i]); |
| if(container != null) { |
| List<IBreakpoint> list = containersToBreakpoints.get(container); |
| if (list == null) { |
| list = new ArrayList<>(); |
| containersToBreakpoints.put(container, list); |
| } |
| list.add(breakpoint); |
| } |
| } |
| } |
| for (Entry<IBreakpointContainer, List<IBreakpoint>> entry : containersToBreakpoints.entrySet()) { |
| IBreakpointContainer container = entry.getKey(); |
| List<IBreakpoint> list = entry.getValue(); |
| IBreakpointOrganizer organizer = container.getOrganizer(); |
| IBreakpoint[] breakpoints = list.toArray(new IBreakpoint[list.size()]); |
| if (organizer instanceof IBreakpointOrganizerDelegateExtension) { |
| IBreakpointOrganizerDelegateExtension extension = (IBreakpointOrganizerDelegateExtension) organizer; |
| extension.removeBreakpoints(breakpoints, container.getCategory()); |
| } else { |
| for (int i = 0; i < breakpoints.length; i++) { |
| organizer.removeBreakpoint(breakpoints[i], container.getCategory()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Performs the actual addition of the selected breakpoints to the specified target |
| * @param target the target to add the selection of breakpoints to |
| * @param selection the selection of breakpoints |
| * @return true if the drop occurred, false otherwise |
| * @since 3.3 |
| */ |
| protected boolean performDrop(TreePath target, ITreeSelection selection) { |
| if(target == null || selection == null) { |
| return false; |
| } |
| IBreakpointContainer container = getAddableContainer(target); |
| if (container == null) { |
| return false; |
| } |
| |
| IBreakpointOrganizer organizer = container.getOrganizer(); |
| List<IBreakpoint> breakpoints = new ArrayList<>(selection.size()); |
| for (Iterator<?> iter = selection.iterator(); iter.hasNext();) { |
| IBreakpoint breakpoint = (IBreakpoint) DebugPlugin.getAdapter(iter.next(), IBreakpoint.class); |
| if (breakpoint != null) { |
| breakpoints.add(breakpoint); |
| } |
| } |
| if (organizer instanceof IBreakpointOrganizerDelegateExtension) { |
| IBreakpointOrganizerDelegateExtension extension = (IBreakpointOrganizerDelegateExtension) organizer; |
| extension.addBreakpoints( |
| breakpoints.toArray(new IBreakpoint[breakpoints.size()]), |
| container.getCategory()); |
| } else { |
| for (int i = 0; i < breakpoints.size(); i++) { |
| organizer.addBreakpoint(breakpoints.get(i), container.getCategory()); |
| } |
| } |
| // TODO expandToLevel(target.getData(), ALL_LEVELS); |
| return true; |
| } |
| |
| /** |
| * Determines if the specified element can be dropped into the specified target |
| * <p> |
| * Scheme: |
| * <ul> |
| * <li>Breakpoints can be dropped into working sets</li> |
| * <li>Breakpoints can be dropped into breakpoints, provided there is a drop-able parent of the target breakpoint</li> |
| * </ul> |
| * </p> |
| * @param target the target for the drop |
| * @param selection the selection to see if we can drop |
| * @return true if the specified element can be dropped into the specified target, false otherwise |
| * @since 3.3 |
| */ |
| boolean canDrop(TreePath target, ITreeSelection selection) { |
| if (selection == null || target == null) { |
| return false; |
| } |
| for (Iterator<?> iter = selection.iterator(); iter.hasNext();) { |
| IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(iter.next(), IBreakpoint.class); |
| if (breakpoint == null || !checkAddableParentContainers(target, breakpoint)){ |
| return false; |
| } |
| } |
| return true; |
| } |
| } |