Java tutorial
/***************************************************************************** * 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; } }