org.eclipse.debug.internal.ui.views.expression.ExpressionDropAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.debug.internal.ui.views.expression.ExpressionDropAdapter.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2010 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;
import org.eclipse.ui.IWorkbenchPartSite;

/**
 * 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 IWorkbenchPartSite fSite;
    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(IWorkbenchPartSite site, TreeModelViewer viewer) {
        super(viewer);
        fSite = site;
        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.getPartDebugContext(fSite);
        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;
    }

}