| /******************************************************************************* |
| * Copyright (c) 2007, 2008 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: |
| * Wind River Systems - Pawel Piech - Initial Implementation - Drag/Drop to Expressions View (Bug 184057), Integration with non-standard debug models (Bug 209883) |
| * IBM Corporation - further implementation and documentation |
| * Wind River Systems - integration with non-standard debug models |
| *******************************************************************************/ |
| package org.eclipse.debug.internal.ui.views.expression; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.IExpressionManager; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.model.IDebugElement; |
| import org.eclipse.debug.core.model.IExpression; |
| import org.eclipse.debug.core.model.IVariable; |
| import org.eclipse.debug.core.model.IWatchExpression; |
| import org.eclipse.debug.internal.core.ExpressionManager; |
| import org.eclipse.debug.internal.ui.DebugUIPlugin; |
| import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; |
| import org.eclipse.debug.internal.ui.views.variables.IndexedVariablePartition; |
| import org.eclipse.debug.ui.DebugUITools; |
| import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter; |
| import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2; |
| import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapterExtension; |
| import org.eclipse.jface.util.LocalSelectionTransfer; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ViewerDropAdapter; |
| import org.eclipse.swt.dnd.DND; |
| import org.eclipse.swt.dnd.DropTargetEvent; |
| import org.eclipse.swt.dnd.TextTransfer; |
| import org.eclipse.swt.dnd.TransferData; |
| |
| /** |
| * Drop Adapter allowing expressions, variables and text to be dropped in the Expression View. |
| * When IVariables or text is dropped new watch expressions are created at the drop location. |
| * When IExpressions are dropped, they are moved to the drop location |
| * |
| * @see org.eclipse.debug.internal.ui.views.variables.VariablesDragAdapter |
| * @see ExpressionManager |
| * @since 3.4 |
| */ |
| public class ExpressionDropAdapter extends ViewerDropAdapter { |
| |
| private TransferData fCurrentTransferType = null; |
| private boolean fInsertBefore; |
| private int fDropType; |
| |
| private static final int DROP_TYPE_DEFAULT = 0; |
| private static final int DROP_TYPE_VARIABLE = 1; |
| private static final int DROP_TYPE_EXPRESSION = 2; |
| private static final int DROP_TYPE_WATCH_ADAPTABLE_ELEMENT = 3; |
| |
| /** |
| * Constructor takes the viewer this drop adapter applies to. |
| * @param viewer the viewer to add drop to |
| */ |
| protected ExpressionDropAdapter(TreeModelViewer viewer) { |
| super(viewer); |
| setFeedbackEnabled(true); |
| setSelectionFeedbackEnabled(false); |
| setScrollExpandEnabled(false); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragEnter(org.eclipse.swt.dnd.DropTargetEvent) |
| */ |
| public void dragEnter(DropTargetEvent event) { |
| fDropType = DROP_TYPE_DEFAULT; |
| event.detail = DND.DROP_NONE; |
| |
| for (int i = 0; i < event.dataTypes.length; i++) { |
| if (LocalSelectionTransfer.getTransfer().isSupportedType(event.dataTypes[i])) { |
| if (isExpressionDrop()){ |
| event.currentDataType = event.dataTypes[i]; |
| event.detail = DND.DROP_MOVE; |
| fDropType = DROP_TYPE_EXPRESSION; |
| break; |
| } else if (isVariableDrop()){ |
| event.currentDataType = event.dataTypes[i]; |
| event.detail = DND.DROP_COPY; |
| fDropType = DROP_TYPE_VARIABLE; |
| break; |
| } else if (isWatchAdaptableElementDrop()){ |
| event.currentDataType = event.dataTypes[i]; |
| event.detail = DND.DROP_COPY; |
| fDropType = DROP_TYPE_WATCH_ADAPTABLE_ELEMENT; |
| break; |
| } |
| } else if (TextTransfer.getInstance().isSupportedType(event.dataTypes[i])) { |
| event.currentDataType = event.dataTypes[i]; |
| event.detail = DND.DROP_COPY; |
| fDropType = DROP_TYPE_DEFAULT; |
| break; |
| } |
| } |
| |
| super.dragEnter(event); |
| } |
| |
| /** |
| * @return whether the selection transfer contains only IExpressions |
| */ |
| private boolean isExpressionDrop() { |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| Iterator iterator = selection.iterator(); |
| while (iterator.hasNext()) { |
| Object element = iterator.next(); |
| if (getTargetExpression(element) == null){ |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * @return whether the selection transfer contains only IVariables |
| */ |
| private boolean isVariableDrop() { |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| Iterator iterator = selection.iterator(); |
| while (iterator.hasNext()) { |
| Object element = iterator.next(); |
| if (!(element instanceof IVariable)){ |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * @return whether the selection transfer contains only objects adaptable |
| * to IWatchExpressionFactoryAdapter2 |
| */ |
| private boolean isWatchAdaptableElementDrop() { |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| Iterator iterator = selection.iterator(); |
| while (iterator.hasNext()) { |
| Object element = iterator.next(); |
| if (!(element instanceof IAdaptable && |
| ((IAdaptable)element).getAdapter(IWatchExpressionFactoryAdapter2.class) != null)) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragOver(org.eclipse.swt.dnd.DropTargetEvent) |
| */ |
| public void dragOver(DropTargetEvent event) { |
| super.dragOver(event); |
| // Allow scrolling (but not expansion) |
| event.feedback |= DND.FEEDBACK_SCROLL; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.ViewerDropAdapter#validateDrop(java.lang.Object, int, org.eclipse.swt.dnd.TransferData) |
| */ |
| public boolean validateDrop(Object target, int operation, TransferData transferType) { |
| if (LocalSelectionTransfer.getTransfer().isSupportedType(transferType)) { |
| if (fDropType == DROP_TYPE_EXPRESSION){ |
| return validateExpressionDrop(target); |
| } else if (fDropType == DROP_TYPE_VARIABLE){ |
| return validateVariableDrop(target); |
| } else if (fDropType == DROP_TYPE_WATCH_ADAPTABLE_ELEMENT){ |
| return validateWatchAdaptableDrop(target); |
| } |
| } else if (TextTransfer.getInstance().isSupportedType(transferType)) { |
| return validateTextDrop(target); |
| } |
| return false; |
| } |
| |
| /** |
| * Validates if an IExpression drop is valid by checking if the target |
| * is an IExpression. |
| * @param target target of the drop |
| * @return whether the drop is valid |
| */ |
| private boolean validateExpressionDrop(Object target){ |
| return target instanceof IExpression || |
| ((target instanceof IAdaptable) && ((IAdaptable)target).getAdapter(IExpression.class) != null); |
| } |
| |
| private IExpression getTargetExpression(Object target) { |
| if (target instanceof IExpression) { |
| return (IExpression)target; |
| } else if (target instanceof IAdaptable) { |
| return (IExpression)((IAdaptable)target).getAdapter(IExpression.class); |
| } |
| return null; |
| } |
| |
| /** |
| * Validates if the drop is valid by validating the local selection transfer |
| * to ensure that a watch expression can be created for each contained IVariable. |
| * @param target target of the drop |
| * @return whether the drop is valid |
| */ |
| private boolean validateVariableDrop(Object target) { |
| // Target must be null or an IExpression, you cannot add a new watch expression inside another |
| if (target != null && getTargetExpression(target) == null) { |
| return false; |
| } |
| |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| int enabled = 0; |
| int size = -1; |
| if (selection != null) { |
| size = selection.size(); |
| IExpressionManager manager = DebugPlugin.getDefault().getExpressionManager(); |
| Iterator iterator = selection.iterator(); |
| while (iterator.hasNext()) { |
| Object element = iterator.next(); |
| if (element instanceof IVariable){ |
| IVariable variable = (IVariable) element; |
| if (variable instanceof IndexedVariablePartition) { |
| break; |
| } else if (manager.hasWatchExpressionDelegate(variable.getModelIdentifier()) && isFactoryEnabled(variable)) { |
| enabled++; |
| } else { |
| break; |
| } |
| } |
| } |
| } |
| return enabled == size; |
| } |
| |
| /** |
| * Validates if the drop is valid by validating the local selection transfer |
| * to ensure that a watch expression can be created for each contained element. |
| * @param target target of the drop |
| * @return whether the drop is valid |
| */ |
| private boolean validateWatchAdaptableDrop(Object target) { |
| // Target must be null or an IExpression, you cannot add a new watch expression inside another |
| if (target != null && getTargetExpression(target) == null) { |
| return false; |
| } |
| |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| int enabled = 0; |
| int size = -1; |
| if (selection != null) { |
| size = selection.size(); |
| Iterator iterator = selection.iterator(); |
| while (iterator.hasNext()) { |
| Object element = iterator.next(); |
| if (isFactory2Enabled(element)) { |
| enabled++; |
| } else { |
| break; |
| } |
| } |
| } |
| return enabled == size; |
| } |
| |
| /** |
| * Validates if the drop is valid by validating the drop location. |
| * Only valid if the target is <code>null</code> or an <code>IExpression</code>. |
| * You cannot add a new watch expression inside another. |
| * @param target target of the drop |
| * @return whether the drop is valid |
| */ |
| private boolean validateTextDrop(Object target){ |
| return target == null || getTargetExpression(target) != null; |
| } |
| |
| /** |
| * Returns whether the factory adapter for the given variable is currently enabled. |
| * |
| * @param variable the variable to ask for the adapter |
| * @return whether the factory is enabled |
| */ |
| private boolean isFactoryEnabled(IVariable variable) { |
| IWatchExpressionFactoryAdapter factory = getFactory(variable); |
| if (factory instanceof IWatchExpressionFactoryAdapterExtension) { |
| IWatchExpressionFactoryAdapterExtension ext = (IWatchExpressionFactoryAdapterExtension) factory; |
| return ext.canCreateWatchExpression(variable); |
| } |
| return true; |
| } |
| |
| /** |
| * Returns whether the factory adapter for the given element is currently enabled. |
| * |
| * @param element the element to ask for the adapter |
| * @return whether the factory is enabled |
| */ |
| private boolean isFactory2Enabled(Object element) { |
| IWatchExpressionFactoryAdapter2 factory = getFactory2(element); |
| if (factory != null) { |
| return factory.canCreateWatchExpression(element); |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.ViewerDropAdapter#drop(org.eclipse.swt.dnd.DropTargetEvent) |
| */ |
| public void drop(DropTargetEvent event) { |
| fCurrentTransferType = event.currentDataType; |
| // Unless insert after is explicitly set, insert before |
| fInsertBefore = getCurrentLocation() != LOCATION_AFTER; |
| super.drop(event); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.ViewerDropAdapter#performDrop(java.lang.Object) |
| */ |
| public boolean performDrop(Object data) { |
| if (LocalSelectionTransfer.getTransfer().isSupportedType(fCurrentTransferType)) { |
| IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection(); |
| if (fDropType == DROP_TYPE_EXPRESSION){ |
| return performExpressionDrop(selection); |
| } else if (fDropType == DROP_TYPE_VARIABLE || fDropType == DROP_TYPE_WATCH_ADAPTABLE_ELEMENT){ |
| return performVariableOrWatchAdaptableDrop(selection); |
| } |
| } else if (TextTransfer.getInstance().isSupportedType(fCurrentTransferType)) { |
| if (data != null) { |
| return performTextDrop((String)data); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Performs the drop when the selection is a collection of IExpressions. |
| * Moves the given expressions from their original locations to the |
| * location of the current target. |
| * @param selection the dragged selection |
| * @return whether the drop could be completed |
| */ |
| private boolean performExpressionDrop(IStructuredSelection selection) { |
| IExpression targetExpression = getTargetExpression(getCurrentTarget()); |
| if (targetExpression != null){ |
| IExpression[] expressions = new IExpression[selection.size()]; |
| Object[] selectionElements = selection.toArray(); |
| for (int i = 0; i < selectionElements.length; i++) { |
| expressions[i] = getTargetExpression(selectionElements[i]); |
| } |
| |
| IExpressionManager manager = DebugPlugin.getDefault().getExpressionManager(); |
| if (manager instanceof ExpressionManager){ |
| ((ExpressionManager)manager).moveExpressions(expressions, targetExpression, fInsertBefore); |
| } |
| return true; |
| } |
| return false; |
| |
| } |
| |
| /** |
| * If the dragged data is a structured selection, get any IVariables in it |
| * and create expressions for each of them. Insert the created expressions |
| * at the currently selected target or add them to the end of the collection |
| * if no target is selected. |
| * |
| * @param selection Structured selection containing IVariables |
| * @return whether the drop was successful |
| */ |
| private boolean performVariableOrWatchAdaptableDrop(IStructuredSelection selection) { |
| List expressions = new ArrayList(selection.size()); |
| for (Iterator itr = selection.iterator(); itr.hasNext(); ) { |
| Object element = itr.next(); |
| String expressionText = createExpressionString(element); |
| if (expressionText != null){ |
| IExpression expression = createExpression(expressionText); |
| if (expression != null){ |
| expressions.add(expression); |
| } else { |
| DebugUIPlugin.log(new Status(IStatus.ERROR,DebugUIPlugin.getUniqueIdentifier(),"Drop failed. Watch expression could not be created for the text " + expressionText)); //$NON-NLS-1$ |
| return false; |
| } |
| } else { |
| return false; |
| } |
| } |
| if (expressions.size() == selection.size()){ |
| IExpressionManager manager = DebugPlugin.getDefault().getExpressionManager(); |
| if (manager instanceof ExpressionManager){ |
| IExpression targetExpression = getTargetExpression(getCurrentTarget()); |
| if (targetExpression != null){ |
| ((ExpressionManager)manager).insertExpressions((IExpression[])expressions.toArray(new IExpression[expressions.size()]), targetExpression, fInsertBefore); |
| } else { |
| ((ExpressionManager)manager).addExpressions((IExpression[])expressions.toArray(new IExpression[expressions.size()])); |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Performs the drop when text was dragged. Creates a new watch expression from |
| * the text. Inserts the expression at the currently selected target or adds it |
| * to the end of the collection if no target is selected. |
| * |
| * @param text string to use to create the expression |
| * @return whether the drop was successful |
| */ |
| private boolean performTextDrop(String text){ |
| IExpression expression = createExpression(text); |
| if (expression != null){ |
| IExpressionManager manager = DebugPlugin.getDefault().getExpressionManager(); |
| if (manager instanceof ExpressionManager){ |
| IExpression targetExpression = getTargetExpression(getCurrentTarget()); |
| if (targetExpression != null){ |
| ((ExpressionManager)manager).insertExpressions(new IExpression[]{expression}, targetExpression, fInsertBefore); |
| } else { |
| ((ExpressionManager)manager).addExpression(expression); |
| } |
| return true; |
| } |
| } |
| DebugUIPlugin.log(new Status(IStatus.ERROR,DebugUIPlugin.getUniqueIdentifier(),"Drop failed. Watch expression could not be created for the text " + text)); //$NON-NLS-1$ |
| return false; |
| } |
| |
| /** |
| * Creates a new watch expression from an IVariable using the watch expression factory |
| * adapter for that variable. |
| * |
| * @param variable the variable to use to create the watch expression |
| * @return the string to be used to create expression, return <code>null</code> |
| * if no expression is to be created |
| */ |
| private String createExpressionString(Object element) { |
| try { |
| if (element instanceof IVariable) { |
| IVariable variable = (IVariable)element; |
| IWatchExpressionFactoryAdapter factory = getFactory(variable); |
| String exp = variable.getName(); |
| if (factory != null) { |
| //if a factory exists, use it to create expression, |
| //otherwise just use variable name |
| exp = factory.createWatchExpression(variable); |
| } |
| return exp; |
| } else { |
| IWatchExpressionFactoryAdapter2 factory2 = getFactory2(element); |
| if (factory2 != null) { |
| return factory2.createWatchExpression(element); |
| } |
| } |
| } catch (CoreException e) { |
| DebugUIPlugin.log(e.getStatus()); |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a new watch expression from a string using the default expression manager. |
| * |
| * @param exp the string to use to create the expression |
| */ |
| private IExpression createExpression(String exp) { |
| IWatchExpression expression = DebugPlugin.getDefault().getExpressionManager().newWatchExpression(exp); |
| IAdaptable object = DebugUITools.getDebugContext(); |
| IDebugElement context = null; |
| if (object instanceof IDebugElement) { |
| context = (IDebugElement) object; |
| } else if (object instanceof ILaunch) { |
| context = ((ILaunch) object).getDebugTarget(); |
| } |
| expression.setExpressionContext(context); |
| return expression; |
| } |
| |
| |
| /** |
| * Returns the factory adapter for the given variable or <code>null</code> if none. |
| * |
| * @param variable |
| * @return factory or <code>null</code> |
| */ |
| private IWatchExpressionFactoryAdapter getFactory(IVariable variable) { |
| return (IWatchExpressionFactoryAdapter) variable.getAdapter(IWatchExpressionFactoryAdapter.class); |
| } |
| |
| /** |
| * Returns the factory adapter for the given element or <code>null</code> if none. |
| * |
| * @param element |
| * @return factory or <code>null</code> |
| */ |
| private IWatchExpressionFactoryAdapter2 getFactory2(Object element) { |
| if (element instanceof IAdaptable) { |
| return (IWatchExpressionFactoryAdapter2)((IAdaptable)element).getAdapter(IWatchExpressionFactoryAdapter2.class); |
| } |
| return null; |
| } |
| |
| } |