package org.bundlemaker.core.ui.projecteditor;
import java.util.Set;
import org.bundlemaker.core.project.IProjectContentProvider;
import org.bundlemaker.core.project.IProjectDescriptionAwareBundleMakerProject;
import org.bundlemaker.core.ui.projecteditor.dnd.DropLocation;
import org.bundlemaker.core.ui.projecteditor.dnd.IProjectEditorDropEvent;
import org.bundlemaker.core.ui.projecteditor.dnd.IProjectEditorDropProvider;
import org.bundlemaker.core.ui.projecteditor.dnd.internal.ProjectEditorDropEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
public class ProjectEditorTreeViewerDropAdapter extends ViewerDropAdapter {
private final IProjectDescriptionAwareBundleMakerProject _bundleMakerProject;
private final Set<IProjectEditorDropProvider> _dndProviders;
/**
* Will be set in validateDrop and invalidated in performDrop
*/
private ProjectEditorDropEvent _currentDropEvent;
private IProjectEditorDropProvider _providerCandidate;
public ProjectEditorTreeViewerDropAdapter(Viewer viewer, IProjectDescriptionAwareBundleMakerProject bundleMakerProject,
Set<IProjectEditorDropProvider> dndProviders) {
super(viewer);
_bundleMakerProject = bundleMakerProject;
_dndProviders = dndProviders;
}
private void resetState() {
_providerCandidate = null;
_currentDropEvent = null;
}
@Override
public boolean validateDrop(Object target, int operation, TransferData transferType) {
// reset the state
resetState();
// create a new drop event
ProjectEditorDropEvent dropEvent = createDropEvent(target);
if (dropEvent == null) {
// drop not possible
return false;
}
// try to find a provider for the drop data
for (IProjectEditorDropProvider dndProvider : _dndProviders) {
if (canHandleTransferType(dndProvider, transferType)) {
if (canDrop(dndProvider, dropEvent)) {
// TODO support multiple providers
_providerCandidate = dndProvider;
break;
}
}
}
// at least one provider found: save event and return
if (_providerCandidate != null) {
// Save drop event for use in performDrop()
_currentDropEvent = dropEvent;
// can drop
return true;
}
// no handler found => drop not possible
return false;
}
protected boolean canDrop(IProjectEditorDropProvider provider, IProjectEditorDropEvent event) {
try {
return provider.canDrop(event);
} catch (Exception ex) {
Activator.logError("canDrop failed: " + ex, ex);
}
return false;
}
@Override
public boolean performDrop(Object data) {
try {
// try to do the actual drop
boolean result = performDropInternal(data);
// reset the state (event and drop provider)
resetState();
// return the result
return result;
} catch (RuntimeException ex) {
// in case of an error at least reset the state
resetState();
// re-throw
throw ex;
}
}
private boolean performDropInternal(Object data) {
if (_providerCandidate == null || _currentDropEvent == null) {
// this really should not happen. anyway: in case it does, do nothing
return false;
}
// update the current event with the data to be dropped
_currentDropEvent.setData(data);
// let the provider do the drop
try {
boolean dropped = _providerCandidate.performDrop(_currentDropEvent);
if (dropped) {
afterDrop(getCurrentTarget());
}
return dropped;
} catch (Exception ex) {
// log exception
Activator.logError("Cannot drop: " + ex, ex);
}
return false;
}
/**
* Will be invoked after the drop has been done.
*
* @TODO replace with listener?!
*/
protected void afterDrop(Object target) {
}
private ProjectEditorDropEvent createDropEvent(Object target) {
Object targetElement = null;
IProjectContentProvider projectContentProvider = null;
if (target != null) {
// can only handle targets of type ProjectEditorTreeViewerElement
if (!(target instanceof ProjectEditorTreeViewerElement)) {
return null;
}
ProjectEditorTreeViewerElement treeViewerElement = ((ProjectEditorTreeViewerElement) target);
targetElement = treeViewerElement.getElement();
projectContentProvider = treeViewerElement.getProjectContentProvider();
}
int location = this.determineLocation(getCurrentEvent());
DropLocation dropLocation = DropLocation.getDropLocation(location);
ProjectEditorDropEvent projectEditorDropEvent = new ProjectEditorDropEvent(getViewer().getControl().getShell(),
_bundleMakerProject,
projectContentProvider,
targetElement, dropLocation, getCurrentEvent().currentDataType);
return projectEditorDropEvent;
}
/**
* Checks whether the given dndprovider can handle the given Transfer type
*
* @param dndProvider
* @param transferType
* @return
*/
private boolean canHandleTransferType(IProjectEditorDropProvider dndProvider, TransferData transferType) {
Transfer[] supportedTypes = dndProvider.getSupportedDropTypes();
for (Transfer transfer : supportedTypes) {
if (transfer.isSupportedType(transferType)) {
return true;
}
}
return false;
}
}