eu.geclipse.ui.internal.transfer.SelectionTransferDropAdapter.java Source code

Java tutorial

Introduction

Here is the source code for eu.geclipse.ui.internal.transfer.SelectionTransferDropAdapter.java

Source

/*****************************************************************************
 * Copyright (c) 2006, 2007 g-Eclipse Consortium 
 * 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
 *
 * Initial development of the original code was made for the
 * g-Eclipse project founded by European Union
 * project number: FP6-IST-034327  http://www.geclipse.eu/
 *
 * Contributors:
 *    Mathias Stuempert - initial API and implementation
 *****************************************************************************/

package eu.geclipse.ui.internal.transfer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.views.navigator.LocalSelectionTransfer;

import eu.geclipse.core.model.IGridConnection;
import eu.geclipse.core.model.IGridContainer;
import eu.geclipse.core.model.IGridElement;
import eu.geclipse.core.model.IGridJob;

/**
 * Transfer drop adapter for selections specialised for the transfer of
 * Grid elements.
 */
public class SelectionTransferDropAdapter implements TransferDropTargetListener {

    /**
     * The current target of the DND-operation.
     */
    private IGridContainer lastTarget;

    /**
     * The last detail of the transfer.
     */
    private int lastDetail;

    /* (non-Javadoc)
     * @see org.eclipse.jface.util.TransferDropTargetListener#getTransfer()
     */
    public Transfer getTransfer() {
        return LocalSelectionTransfer.getInstance();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.util.TransferDropTargetListener#isEnabled(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public boolean isEnabled(final DropTargetEvent event) {
        IGridContainer target = getTarget(event);
        return target != null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void dragEnter(final DropTargetEvent event) {
        this.lastTarget = getTarget(event);
        this.lastDetail = event.detail;
        validateDrop(event);
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void dragLeave(final DropTargetEvent event) {
        this.lastTarget = null;
        this.lastDetail = DND.DROP_NONE;
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#dragOperationChanged(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void dragOperationChanged(final DropTargetEvent event) {
        this.lastDetail = event.detail;
        validateDrop(event);
        computeFeedback(event);
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void dragOver(final DropTargetEvent event) {
        IGridContainer newTarget = getTarget(event);
        if (newTarget != this.lastTarget) {
            this.lastTarget = newTarget;
            validateDrop(event);
        }
        computeFeedback(event);
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void drop(final DropTargetEvent event) {

        IGridContainer target = getTarget(event);

        IGridElement[] elements = getElements();
        GridElementTransferOperation op = null;

        switch (event.detail) {
        case DND.DROP_COPY:
            op = new GridElementTransferOperation(elements, target, false);
            break;
        case DND.DROP_MOVE:
            op = new GridElementTransferOperation(elements, target, true);
            break;
        }

        if (op != null) {
            op.setUser(true);
            op.setPriority(Job.LONG);
            op.schedule();
        } else {
            event.detail = DND.DROP_NONE;
        }

    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.dnd.DropTargetListener#dropAccept(org.eclipse.swt.dnd.DropTargetEvent)
     */
    public void dropAccept(final DropTargetEvent event) {
        this.lastTarget = getTarget(event);
        validateDrop(event);
        this.lastDetail = event.detail;
    }

    /**
     * Compute the drag over effect feedback for the specified
     * {@link DropTargetEvent}.
     * 
     * @param event The event to apply the computed feedback.
     */
    protected void computeFeedback(final DropTargetEvent event) {
        event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL | DND.FEEDBACK_SELECT;
    }

    /**
     * Get the Grid elements that are contained in the specified
     * {@link DropTargetEvent}. This methods returns <code>null</code>
     * if not all dragged elements are {@link IGridElement}s.
     * 
     * @param event The event from which to get the elements.
     * @return All Grid element that are contained in the specified
     * event.
     */
    protected IGridElement[] getElements() {
        IGridElement[] result = null;
        ISelection selection = LocalSelectionTransfer.getInstance().getSelection();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection sSelection = (IStructuredSelection) selection;
            Iterator<?> iter = sSelection.iterator();
            List<IGridElement> elements = new ArrayList<IGridElement>();
            while (iter.hasNext()) {
                Object obj = iter.next();
                if (obj instanceof IGridElement) {
                    elements.add((IGridElement) obj);
                }
            }
            if (elements.size() == sSelection.size()) {
                result = elements.toArray(new IGridElement[elements.size()]);
            }
        }
        return result;
    }

    /**
     * Get the target that is contained in the specified event. If the
     * target is not present or the target is not an {@link IGridContainer}
     * this method returns <code>null</code>.
     * 
     * @param event The event from which the retrieve the target.
     * @return The current target of the DND-operation. 
     */
    protected IGridContainer getTarget(final DropTargetEvent event) {
        IGridContainer result = null;
        Widget item = event.item;
        if (item != null) {
            Object data = item.getData();
            if ((data != null) && (data instanceof IGridContainer)) {
                result = (IGridContainer) data;
            }
        }
        return result;
    }

    /**
     * Validate the drop, i.e. set the detail field of the specified
     * {@link DropTargetEvent} according to the policies of the
     * Grid model.
     * 
     * @param event The event to be modified.
     */
    protected void validateDrop(final DropTargetEvent event) {
        int ops = computeDropOperations(event);
        //if ( ( ops & event.detail ) == 0 ) {
        if ((ops & this.lastDetail) != 0) {
            event.detail = this.lastDetail;
        } else {
            if ((ops & DND.DROP_DEFAULT) != 0) {
                event.detail = DND.DROP_DEFAULT;
            } else if ((ops & DND.DROP_MOVE) != 0) {
                event.detail = DND.DROP_MOVE;
            } else if ((ops & DND.DROP_COPY) != 0) {
                event.detail = DND.DROP_COPY;
            } else {
                event.detail = DND.DROP_NONE;
            }
        }
    }

    /**
     * Compute the drop operation for the dragged elements.
     * 
     * @param event The drop target event.
     * @return The new drop operations.
     */
    protected int computeDropOperations(final DropTargetEvent event) {
        int ops = DND.DROP_NONE;
        if (this.lastTarget != null) {
            IGridElement[] elements = getElements();
            if ((elements != null) && (elements.length > 0)) {
                ops = event.operations;
                for (IGridElement element : elements) {
                    ops &= computeDropOperations(this.lastTarget, element);
                    if (ops == DND.DROP_NONE) {
                        break;
                    }
                }
            }
        }
        return ops;
    }

    /**
     * Compute the drop operations that are allowed for the specified
     * combination of target and element.
     * 
     * @param target The target of the drop operation.
     * @param element The element beeing dragged.
     * @return A bitwise combination of {@link DND.DROP_COPY} and
     * {@link DND.DROP_MOVE} or simply {@link DND.DROP_NONE}.
     */
    protected int computeDropOperations(final IGridContainer target, final IGridElement element) {

        int result = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_DEFAULT;

        if ((target == element) || (target == element.getParent()) || !target.canContain(element)
                || isGridJob(target)) {
            result = DND.DROP_NONE;
        }

        else {

            boolean tLocal = isLocal(target);
            boolean eLocal = isLocal(element);

            if (!tLocal || !eLocal) { // remote -> local || local -> remote || remote -> remote 

                if (!tLocal && !eLocal) { // remote -> remote
                    IGridElement tParent = findLastRemoteElement(target);
                    IGridElement eParent = findLastRemoteElement(element);
                    if (tParent != eParent) { // different connections
                        result = DND.DROP_COPY;
                    } // else result = default
                }

                else { // remote -> local || local -> remote
                    if (!eLocal) { // remote -> local
                        IGridElement eParent = findLastRemoteElement(element);
                        if (eParent != element) { // not a connection root
                            result = DND.DROP_COPY;
                        } // else result = default
                    } else { // local -> remote
                        result = DND.DROP_COPY;
                    }
                }

            }

        }

        return result;

    }

    /**
     * Find the last remote parent in the list of parents of the specified
     * element. This method walks down the list of parents of the element and
     * returns the first element whose {@link IGridElement#isLocal()} method
     * returns false.
     * 
     * @param element The element to be queried.
     * @return The last parent of the specified element that is not local.
     */
    private IGridElement findLastRemoteElement(final IGridElement element) {
        IGridElement result = element;
        IGridElement parent = element.getParent();
        while ((parent != null) && !parent.isLocal()) {
            result = parent;
            parent = parent.getParent();
        }
        return result;
    }

    private boolean isLocal(final IGridElement element) {
        boolean local = false;

        if (element.isLocal()) {
            local = true;
        } else {
            if (element instanceof IGridConnection) {
                IGridConnection connection = (IGridConnection) element;
                try {
                    IFileStore fileStore = connection.getConnectionFileStore();
                    if (fileStore != null) {
                        local = EFS.SCHEME_FILE.equals(fileStore.getFileSystem().getScheme());
                    }
                } catch (CoreException exception) {
                    // ignore exceptions
                }

            }
        }

        return local;
    }

    private boolean isGridJob(final IGridContainer element) {
        boolean isGridJob = false;
        IGridContainer currentElement = element;

        while (currentElement != null && !isGridJob) {
            isGridJob = (currentElement instanceof IGridJob);
            currentElement = currentElement.getParent();
        }

        return isGridJob;
    }

}