blob: a032a73bc76ff2077fb817d3e3b4aa89e1edd117 [file] [log] [blame]
/*****************************************************************
* Copyright (c) 2009 Texas Instruments 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:
* 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.runtime.IAdaptable;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
import org.eclipse.debug.internal.ui.VariablesViewModelPresentation;
import org.eclipse.debug.internal.ui.actions.breakpointGroups.CopyBreakpointsAction;
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.DefaultBreakpointManagerInput;
import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
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.IBreakpointOrganizerDelegate;
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.PropertyChangeEvent;
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.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.SelectionListenerAction;
import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
/**
* This class implements the breakpoints view.
*/
public class BreakpointsView extends VariablesView implements ISelectionListener {
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_IS_TRACKING_SELECTION = "isTrackingSelection"; //$NON-NLS-1$
private static final String KEY_VALUE = "value"; //$NON-NLS-1$
private boolean fIsTrackingSelection = false;
private Clipboard fClipboard;
private IBreakpointOrganizer[] fOrganizers;
private IStructuredSelection fFilterSelection;
public void dispose() {
if (fClipboard != null)
fClipboard.dispose();
super.dispose();
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getDetailPanePreferenceKey()
*/
protected String getDetailPanePreferenceKey() {
return IDebugPreferenceConstants.BREAKPOINTS_DETAIL_PANE_ORIENTATION;
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getHelpContextId()
*/
protected String getHelpContextId() {
return IDebugHelpContextIds.BREAKPOINT_VIEW;
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getViewerStyle()
*/
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)
*/
public Viewer createViewer(Composite parent) {
TreeModelViewer viewer = (TreeModelViewer) super.createViewer(parent);
initBreakpointOrganizers(getMemento());
initIsTrackingSelection(getMemento());
return viewer;
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getModelPresentation()
*/
protected IDebugModelPresentation getModelPresentation() {
if (fModelPresentation == null) {
fModelPresentation = new VariablesViewModelPresentation() {
/**
* Undo double slashes.
*/
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
*/
public TreeModelViewer getTreeModelViewer() {
return (TreeModelViewer) getViewer();
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#configureToolBar(org.eclipse.jface.action.IToolBarManager)
*/
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)
*/
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(ActionFactory.COPY.getCommandId()));
menu.add(getAction(ActionFactory.PASTE.getCommandId()));
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()
*/
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));
setAction(ACTION_SKIP_BREAKPOINTS, new SkipAllBreakpointsAction(this));
fClipboard = new Clipboard(getSite().getShell().getDisplay());
PasteBreakpointsAction paste = new PasteBreakpointsAction(this);
configure(paste, ActionFactory.PASTE.getCommandId(), ActionFactory.PASTE.getCommandId(), ISharedImages.IMG_TOOL_PASTE);
SelectionListenerAction copy = new CopyBreakpointsAction(this, fClipboard, paste);
configure(copy, ActionFactory.COPY.getCommandId(), ActionFactory.COPY.getCommandId(), ISharedImages.IMG_TOOL_COPY);
SelectionListenerAction remove = new RemoveFromWorkingSetAction(this);
setAction(ACTION_REMOVE_FROM_GROUP, remove);
getViewer().addSelectionChangedListener(remove);
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.debug.internal.ui.views.variables.VariablesView#getToggleActionLabel()
*/
protected String getToggleActionLabel() {
return DebugUIViewsMessages.BreakpointsView_12;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#getPresentationContextId()
*/
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)
*/
protected void contextActivated(ISelection selection) {
if (selection == null || selection.isEmpty()) {
Object input = new DefaultBreakpointManagerInput(getTreeModelViewer().getPresentationContext());
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)
*/
protected void setViewerInput(Object context) {
Object current = getViewer().getInput();
if (current == null && context == null) {
return;
}
if (current != null && current.equals(context)) {
return;
}
final TreeModelViewer viewer = getTreeModelViewer();
final IPresentationContext presentationContext = viewer.getPresentationContext();
// set the view organizer - if there is an organizer override per input, than set the organizer to null
Object organizerInputAdapter = null;
if (context instanceof IAdaptable) {
organizerInputAdapter = ((IAdaptable) context).getAdapter(IBreakpointOrganizerInputProvider.class);
}
presentationContext.setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS, organizerInputAdapter != null ? null : fOrganizers);
// set the view filter selection
presentationContext.setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION, fFilterSelection);
// set the element comparator
presentationContext.setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR, new ElementComparator(presentationContext));
showViewer();
getViewer().setInput(context);
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#viewerInputUpdateComplete(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate)
*/
protected void viewerInputUpdateComplete(IViewerInputUpdate update) {
// handles non-standard debug model
if (update.getElement() != null) {
setViewerInput(update.getInputElement());
} else {
setViewerInput(new DefaultBreakpointManagerInput(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() {
return fIsTrackingSelection;
}
/**
* 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) {
fIsTrackingSelection = trackSelection;
if (trackSelection) {
getSite().getPage().addSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
} else {
getSite().getPage().removeSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, this);
}
// 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, new Boolean(fIsTrackingSelection));
}
}
/**
* Initializes the persisted breakpoints organizers.
*/
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 organziers= new ArrayList();
for (int i = 0; i < ids.length; i++) {
IBreakpointOrganizer organizer = manager.getOrganizer(ids[i]);
if (organizer != null) {
organziers.add(organizer);
}
}
fOrganizers = (IBreakpointOrganizer[]) organziers.toArray(new IBreakpointOrganizer[organziers.size()]);
for (int i = 0; i < fOrganizers.length; i++)
fOrganizers[i].addPropertyChangeListener(this);
}
}
}
}
/**
* Configures the action to override the global action, registers
* the action for selection change notification, and registers
* the action with this view.
*
* @param action selection action
* @param defId action definition id
* @param globalId global action id
* @param imgId image identifier
*/
private void configure(SelectionListenerAction action, String defId, String globalId, String imgId) {
setAction(defId, action);
action.setActionDefinitionId(defId);
getViewSite().getActionBars().setGlobalActionHandler(globalId, action);
getViewer().addSelectionChangedListener(action);
action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(imgId));
}
/**
* Initializes whether this view tracks selection in the debug view from the persisted state.
*/
private void initIsTrackingSelection(IMemento memento) {
if (memento != null) {
IMemento node = memento.getChild(KEY_IS_TRACKING_SELECTION);
if (node != null) {
setTrackSelection(Boolean.valueOf(node.getString(KEY_VALUE)).booleanValue());
return;
}
}
setTrackSelection(false);
}
/**
* Initializes drag and drop for the breakpoints viewer
*/
protected void initDragAndDrop(TreeModelViewer viewer) {
int ops = DND.DROP_MOVE | DND.DROP_COPY;
// drop
viewer.addDropSupport(ops, new Transfer[] {LocalSelectionTransfer.getInstance()}, new BreakpointsDropAdapter(viewer, this));
// Drag
viewer.addDragSupport(ops, new Transfer[] {LocalSelectionTransfer.getInstance()}, new BreakpointsDragAdapter(viewer, this));
// Drag only
// viewer.addDragSupport(DND.DROP_COPY, new Transfer[] {LocalSelectionTransfer.getTransfer()}, new SelectionDragAdapter(viewer));
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#saveViewerState(org.eclipse.ui.IMemento)
*/
public void saveViewerState(IMemento memento) {
IMemento node = memento.createChild(KEY_IS_TRACKING_SELECTION);
node.putString(KEY_VALUE, String.valueOf(fIsTrackingSelection));
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(',');
}
}
node = memento.createChild(IDebugUIConstants.EXTENSION_POINT_BREAKPOINT_ORGANIZERS);
node.putString(KEY_VALUE, buffer.toString());
}
super.saveViewerState(memento);
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IWorkbenchPart part, ISelection sel) {
if (sel.isEmpty() || !isTrackingSelection()) {
return;
}
IStructuredSelection selection = (IStructuredSelection) sel;
Iterator iter = selection.iterator();
Object firstElement = iter.next();
if (firstElement == null || iter.hasNext()) {
return;
}
IThread thread = null;
if (firstElement instanceof IStackFrame) {
thread = ((IStackFrame) firstElement).getThread();
} else if (firstElement instanceof IThread) {
thread = (IThread) firstElement;
} else {
return;
}
IBreakpoint[] breakpoints = thread.getBreakpoints();
Viewer viewer = getViewer();
if (viewer != null)
viewer.setSelection(new StructuredSelection(breakpoints), true);
}
/**
* 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;
if (item != null) {
TreeItem parent = item.getParentItem();
if (parent != null) {
int idx = 0;
if (parent.getItemCount() == 1) {
toselect = parent.getData();
}
idx = parent.indexOf(item);
if (idx == 0) {
if (parent.getItemCount() > 1) {
toselect = parent.getItem(1).getData();
} else {
toselect = parent.getItem(0).getData();
}
}
if (idx > 0) {
toselect = parent.getItem(idx - 1).getData();
}
} else {
Tree tree = item.getParent();
TreeItem[] items = tree.getItems();
if (items.length > 1) {
for (int i = 0; i < items.length; i++) {
if (item.equals(items[i])) {
if (i + 1 >= items.length) {
toselect = items[i - 1].getData();
break;
} else {
toselect = items[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) {
if (fOrganizers != null) {
for (int i = 0; fOrganizers != null && i < fOrganizers.length; i++)
fOrganizers[i].removePropertyChangeListener(this);
}
fOrganizers = organizers;
for (int i = 0; fOrganizers != null && i < fOrganizers.length; i++)
fOrganizers[i].addPropertyChangeListener(this);
TreeModelViewer viewer = getTreeModelViewer();
if (viewer != null) {
// update the presentation context organizer
viewer.getPresentationContext().setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS, fOrganizers);
}
}
/**
* Sets the breakpoint filter for this view.
*
* @param ss the selection, can be <code>null</code>.
*/
public void setFilterSelection(IStructuredSelection ss) {
fFilterSelection = ss;
TreeModelViewer viewer = getTreeModelViewer();
if (viewer != null) {
// update the presentation context filter
viewer.getPresentationContext().setProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION, fFilterSelection);
}
}
/**
* 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 breakpoint the breakpoint to get the container for
* @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 breakpoint the breakpoint 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 heirarchy
* of the tree path for the specified target in the event one of the parent element does not support dropping.
* </p>
* @param target
* @param breakpoint
* @return
*/
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 element the element to test if it 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 selection the selection of breakpoints involved in the drag
* @since 3.3
*/
void performDrag(TreePath[] paths) {
if (paths == null) {
return;
}
Map 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 list = (List) containersToBreakpoints.get(container);
if (list == null) {
list = new ArrayList();
containersToBreakpoints.put(container, list);
}
list.add(breakpoint);
}
}
}
Iterator iterator = containersToBreakpoints.entrySet().iterator();
while (iterator.hasNext()) {
Entry entry = (Entry) iterator.next();
IBreakpointContainer container = (IBreakpointContainer) entry.getKey();
List list = (List) entry.getValue();
IBreakpointOrganizer organizer = container.getOrganizer();
IBreakpoint[] breakpoints = (IBreakpoint[]) 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 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(
(IBreakpoint[])breakpoints.toArray(new IBreakpoint[breakpoints.size()]),
container.getCategory());
} else {
for (int i = 0; i < breakpoints.size(); i++) {
organizer.addBreakpoint((IBreakpoint)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 element the element we want to 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;
}
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.views.variables.VariablesView#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
super.propertyChange(event);
if (event.getProperty().equals(IBreakpointOrganizerDelegate.P_CATEGORY_CHANGED)) {
final TreeModelViewer viewer = getTreeModelViewer();
if (viewer != null) {
setBreakpointOrganizers(fOrganizers);
}
}
}
}