blob: 54e6e9185f2533a9ab37cc443586d3b32b97d11b [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2006 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.common.ui.services.dnd.drag;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.common.ui.services.dnd.core.DragDropListenerService;
import org.eclipse.gmf.runtime.common.ui.services.dnd.core.IListenerContext;
import org.eclipse.gmf.runtime.common.ui.services.dnd.core.TransferAdapterService;
import org.eclipse.gmf.runtime.common.ui.services.dnd.internal.CommonUIServicesDNDDebugOptions;
import org.eclipse.gmf.runtime.common.ui.services.dnd.internal.CommonUIServicesDNDPlugin;
import org.eclipse.gmf.runtime.common.ui.services.dnd.internal.CommonUIServicesDNDStatusCodes;
import org.eclipse.gmf.runtime.common.ui.services.dnd.internal.core.DragListenerContext;
import org.eclipse.gmf.runtime.common.ui.services.dnd.internal.l10n.CommonUIServicesDNDMessages;
/**
* This class delegates all the drag source events to the transfer drag source
* adapters. The transfer adapters delegate to the registered listeners
*
* @author Vishy Ramaswamy
*/
public final class DelegatingDragSourceAdapter
implements DragSourceListener {
/**
* Attribute for the all transfer drag source adapters mapped to their
* transfer id.
*/
private final Hashtable allAdapters;
/**
* Attribute for the current transfer drag source adapters.
*/
private ITransferDragSourceListener[] currentAdapters = null;
/**
* Attribute for the chosen transfer drag source adapter.
*/
private ITransferDragSourceListener chosenAdapter = null;
/**
* Attribute for the drag source context.
*/
private final DragSourceContext context;
/**
* Constructor for DelegatingDragSourceAdapter.
*
* @param aContext
* the drag source context
*/
public DelegatingDragSourceAdapter(DragSourceContext aContext) {
super();
assert null != aContext : "aContext cannot be null"; //$NON-NLS-1$
this.context = aContext;
/* Set the adapters */
allAdapters = getAllTransferAdapters();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.dnd.DragSourceListener#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragStart(DragSourceEvent event) {
try {
if (Trace.shouldTrace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND)) {
Trace.trace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND, "dragStart entered"); //$NON-NLS-1$
}
/* Save the provided event information */
boolean saveDoit = event.doit;
Object saveData = event.data;
/* Clear the previous collection of adapters */
setCurrentAdapters(null);
/* Clear the previous chosen adapter */
setChosenAdapter(null);
/* Set the adapters */
setCurrentAdapters(getAdapters(getListeners()));
/* Iterate through the adapters */
boolean doIt = false;
ArrayList listOfActiveAdapters = new ArrayList();
ArrayList listOfActiveTransferAgents = new ArrayList();
if (getCurrentAdapters() != null && getCurrentAdapters().length > 0) {
for (int i = 0; i < getCurrentAdapters().length; i++) {
/* Set the do it flag */
event.doit = saveDoit;
/* Invoke the drag start */
getCurrentAdapters()[i].dragStart(event);
/* If ok to drag add the transfer to the list */
if (event.doit) {
listOfActiveAdapters.add(getCurrentAdapters()[i]);
listOfActiveTransferAgents.add(getCurrentAdapters()[i]
.getTransferAgent().getTransfer());
}
/* Ok to drag if anyone is ready to handle */
doIt = doIt || event.doit;
}
/* Set the transfers and the updated adapters */
if (doIt) {
/* Set the transfers */
((DragSource) event.widget)
.setTransfer((Transfer[]) listOfActiveTransferAgents
.toArray(new Transfer[listOfActiveTransferAgents
.size()]));
/* Set the adapters */
setCurrentAdapters((org.eclipse.gmf.runtime.common.ui.services.dnd.drag.ITransferDragSourceListener[]) listOfActiveAdapters
.toArray(new ITransferDragSourceListener[listOfActiveAdapters
.size()]));
}
if (Trace.shouldTrace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND)) {
String result = doIt ? "true" : "false"; //$NON-NLS-1$ //$NON-NLS-2$
Trace.trace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND,
"DragStart::Event do it flag is " + result); //$NON-NLS-1$
/* Write the transfer adapters */
for (int i = 0; i < getCurrentAdapters().length; i++) {
Trace
.trace(
CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND,
"DragStart::Transfer Adapter is " + getCurrentAdapters()[i].getClass().getName()); //$NON-NLS-1$
}
}
/* Set the event information */
event.data = saveData;
event.doit = doIt;
} else {
/* Delegate to the drag source */
getContext().dragStart(event);
}
} catch (Throwable e) {
event.doit = false;
handle(e, false);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.dnd.DragSourceListener#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragSetData(DragSourceEvent event) {
try {
/* Get the corresponding chosen adapter */
setChosenAdapter(getAdapter(event.dataType));
if (Trace.shouldTrace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND)) {
String adapterChosen = getChosenAdapter() != null ? getChosenAdapter()
.getClass().getName()
: "No Adapter Chosen"; //$NON-NLS-1$
Trace.trace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND,
"DragSetData::Chosen Adapter is " + adapterChosen); //$NON-NLS-1$
}
if (getChosenAdapter() != null) {
getChosenAdapter().dragSetData(event);
} else {
/* Delegate to the drag source */
getContext().dragSetData(event);
}
} catch (Throwable e) {
event.data = null;
handle(e, false);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.dnd.DragSourceListener#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragFinished(DragSourceEvent event) {
try {
if (Trace.shouldTrace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND)) {
String adapterChosen = getChosenAdapter() != null ? getChosenAdapter()
.getClass().getName()
: "No Adapter Chosen"; //$NON-NLS-1$
Trace.trace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.DND,
"DragFinished::Chosen Adapter is " + adapterChosen); //$NON-NLS-1$
}
/* Get the corresponding chosen adapter */
if (getChosenAdapter() != null) {
getChosenAdapter().dragFinished(event);
} else {
setChosenAdapter(getAdapter(event.dataType));
if (getChosenAdapter() != null) {
getChosenAdapter().dragFinished(event);
} else {
/* Delegate to the drag source */
getContext().dragFinished(event);
}
}
} catch (Throwable e) {
handle(e, false);
} finally {
setChosenAdapter(null);
setCurrentAdapters(null);
}
}
/**
* Returns the current adapters.
*
* @return ITransferDragSourceListener[]
*/
private ITransferDragSourceListener[] getCurrentAdapters() {
return currentAdapters;
}
/**
* Returns the drag source context.
*
* @return DragSourceContext
*/
private DragSourceContext getContext() {
return context;
}
/**
* Returns the set of registered listeners. The listeners are acquired
* through the <code>DragDropListenerService</code>.
*
* @return IDragSourceListener[] an array of listeners
*/
private IDragSourceListener[] getListeners() {
/* Get the structured selection */
ISelection selection = getContext().getSelection();
/* Check the selection */
if (selection == null || selection.isEmpty()
|| !(selection instanceof IStructuredSelection)) {
return null;
}
/* Get the selection as an object array */
Object[] array = ((IStructuredSelection) selection).toArray();
/* Create a unique list of element types */
ArrayList listOfElementTypes = new ArrayList();
for (int i = 0; i < array.length; i++) {
if (!listOfElementTypes.contains(array[i].getClass())) {
listOfElementTypes.add(array[i].getClass());
}
}
/* Get the drag source listeners */
ArrayList listOfListeners = new ArrayList();
Iterator iterator = listOfElementTypes.iterator();
while (iterator.hasNext()) {
/* Get the element type */
Class clazz = (Class) iterator.next();
/* Create a drag listener context */
DragListenerContext aContext = new DragListenerContext(getContext()
.getActivePart(), clazz, IListenerContext.ALL_TRANSFERS, false);
/* Get the drag source listeners */
IDragSourceListener[] listeners = DragDropListenerService
.getInstance().getDragSourceListeners(aContext);
/* Get a compatible one if no listener is found for a direct match */
if (listeners == null || listeners.length == 0) {
/* Create a drag listener context */
aContext = new DragListenerContext(
getContext().getActivePart(), clazz,
IListenerContext.ALL_TRANSFERS, true);
/* Get the drag source listener */
listeners = DragDropListenerService.getInstance()
.getDragSourceListeners(aContext);
}
/* Add to the list */
if (listeners != null && listeners.length != 0) {
for (int i = 0; i < listeners.length; i++) {
if (!listOfListeners.contains(listeners[i])) {
listOfListeners.add(listeners[i]);
}
}
}
}
/* Combine all the listeners into one array */
return !listOfListeners.isEmpty() ? (IDragSourceListener[]) listOfListeners
.toArray(new IDragSourceListener[listOfListeners.size()])
: null;
}
/**
* Returns the set of transfer drag source adapters. The adapters are
* created based on the transfers supported by the listeners
*
* @param listeners
* The registered list of <code>IDragSourceListener</code>
* @return ITransferDragSourceListener[] an array of transfer adapters
*/
private ITransferDragSourceListener[] getAdapters(
IDragSourceListener[] listeners) {
/* Return if no listeners or no selection */
if (listeners == null || listeners.length == 0) {
return null;
}
/* Create placeholder for active listeners */
Hashtable listOfUniqueTransferIds = new Hashtable();
/* Check if the listeners can handle the drag */
for (int i = 0; i < listeners.length; i++) {
/* Check if the selection is draggable */
if (!listeners[i].isDraggable(getContext())) {
continue;
}
/* Get the transfer ids */
String[] transferIds = listeners[i].getSupportingTransferIds();
if (transferIds == null || transferIds.length == 0) {
continue;
}
/* Iterate through the ids */
for (int y = 0; y < transferIds.length; y++) {
/* Placeholder for listeners */
ArrayList listOfListeners = null;
if (!listOfUniqueTransferIds.containsKey(transferIds[y])) {
/* Create a new list */
listOfListeners = new ArrayList();
} else {
/* Get the list of listeners and add to it */
listOfListeners = (ArrayList) listOfUniqueTransferIds
.get(transferIds[y]);
}
/* Update the list */
if (listOfListeners != null) {
listOfListeners.add(listeners[i]);
listOfUniqueTransferIds
.put(transferIds[y], listOfListeners);
}
}
}
/* Return if no active transfer agents */
if (listOfUniqueTransferIds.isEmpty()) {
return null;
}
/* Get the adapters */
ArrayList listOfAdapters = new ArrayList();
Enumeration enumeration = listOfUniqueTransferIds.keys();
while (enumeration.hasMoreElements()) {
/* Get the next id */
String transferId = (String) enumeration.nextElement();
/* Get the listeners */
ArrayList supportingListeners = (ArrayList) listOfUniqueTransferIds
.get(transferId);
/* Get the adapter */
ITransferDragSourceListener adapter = (ITransferDragSourceListener) getAllAdapters()
.get(Integer.valueOf(transferId.hashCode()));
if (adapter != null) {
/* Initialize the adapter */
adapter.init(
(IDragSourceListener[]) supportingListeners
.toArray(new IDragSourceListener[supportingListeners
.size()]), getContext());
/* Add to the list */
listOfAdapters.add(adapter);
}
}
/* Return the list of adapters */
return !listOfAdapters.isEmpty() ? (ITransferDragSourceListener[]) listOfAdapters
.toArray(new ITransferDragSourceListener[listOfAdapters.size()])
: null;
}
/**
* Sets the current adapters.
*
* @param currentAdapterArray
* The adapters to set
*/
private void setCurrentAdapters(
ITransferDragSourceListener[] currentAdapterArray) {
this.currentAdapters = currentAdapterArray;
}
/**
* Returns the chosen adapter
*
* @param type
* The transfer data type
* @return The transfer drag source adapter chosen
*/
private ITransferDragSourceListener getAdapter(TransferData type) {
if (type != null) {
for (int i = 0; i < getCurrentAdapters().length; i++) {
if (getCurrentAdapters()[i].getTransferAgent().getTransfer()
.isSupportedType(type)) {
return getCurrentAdapters()[i];
}
}
}
return null;
}
/**
* Returns the chosenAdapter.
*
* @return ITransferDragSourceListener
*/
private ITransferDragSourceListener getChosenAdapter() {
return chosenAdapter;
}
/**
* Sets the chosenAdapter.
*
* @param aChosenAdapter
* The chosenAdapter to set
*/
private void setChosenAdapter(ITransferDragSourceListener aChosenAdapter) {
this.chosenAdapter = aChosenAdapter;
}
/**
* Returns the set of transfer drag source adapters. The adapters are
* created based on the provided transfer ids determined from the drag and
* drop service.
*
* @return Hashtable a table of transfer adapters
*/
private Hashtable getAllTransferAdapters() {
/* Create placeholder for possible adapters */
Hashtable listOfSupportedAdapters = new Hashtable();
/* Get the ids from the drag and drop service */
String[] transferIds = DragDropListenerService.getInstance()
.getAllTransferIds(getContext().getActivePart().getSite().getId(),
IListenerContext.DRAG);
/* Iterate through the ids */
if (transferIds == null || transferIds.length == 0) {
return null;
}
/* Create the adapters */
for (int i = 0; i < transferIds.length; i++) {
ITransferDragSourceListener adapter = TransferAdapterService
.getInstance().getTransferDragSourceAdapter(transferIds[i]);
if (adapter != null) {
listOfSupportedAdapters.put(Integer.valueOf(transferIds[i]
.hashCode()), adapter);
}
}
/* Return the adapters */
return listOfSupportedAdapters;
}
/**
* Handles the specified exception.
*
* @param exception
* The exception to be handled.
* @param displayDialog
* boolean to indicate whether to display dialog
*/
private void handle(Throwable exception, boolean displayDialog) {
if (Trace.shouldTrace(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.EXCEPTIONS_CATCHING)) {
Trace.catching(CommonUIServicesDNDPlugin.getDefault(),
CommonUIServicesDNDDebugOptions.EXCEPTIONS_CATCHING,
getClass(), "handle", exception); //$NON-NLS-1$
}
IStatus status = new Status(IStatus.ERROR, CommonUIServicesDNDPlugin
.getPluginId(), CommonUIServicesDNDStatusCodes.DRAG_ACTION_FAILURE,
CommonUIServicesDNDMessages.DelegatingDragSourceAdapter__ERROR__errorMessage, exception);
Log.log(CommonUIServicesDNDPlugin.getDefault(), status);
if (displayDialog) {
status = new Status(IStatus.ERROR, CommonUIServicesDNDPlugin
.getPluginId(),
CommonUIServicesDNDStatusCodes.DRAG_ACTION_FAILURE,
CommonUIServicesDNDMessages.DelegatingDragSourceAdapter__ERROR__errorMessage,
exception);
ErrorDialog.openError(getContext().getActivePart().getSite()
.getShell(), null, null, status);
}
}
/**
* Returns the adapters.
*
* @return Hashtable
*/
private Hashtable getAllAdapters() {
return allAdapters;
}
}