/**
*
*/
package org.korsakow.ide.ui.controller.dnd;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.swing.JComponent;
import javax.swing.TransferHandler;
import org.apache.log4j.Logger;
import org.dsrg.soenea.domain.command.CommandException;
import org.korsakow.domain.CommandExecutor;
import org.korsakow.domain.command.CloneResourceCommand;
import org.korsakow.domain.command.Request;
import org.korsakow.domain.command.Response;
import org.korsakow.domain.interf.IResource;
import org.korsakow.ide.Application;
import org.korsakow.ide.lang.LanguageBundle;
import org.korsakow.ide.ui.components.tree.FolderNode;
import org.korsakow.ide.ui.components.tree.KNode;
import org.korsakow.ide.ui.components.tree.ResourceNode;
import org.korsakow.ide.ui.dnd.DataFlavors;
import org.korsakow.ide.ui.resourceexplorer.ResourceTreeTableModel;
import org.korsakow.ide.util.UIUtil;
public class ResourceTreeNodeTransferHandler extends TransferHandler
{
/**
*
*/
private final ResourceTreeTransferHandler resourceTreeTransferHandler;
/**
* @param resourceTreeTransferHandler
*/
ResourceTreeNodeTransferHandler(
ResourceTreeTransferHandler resourceTreeTransferHandler)
{
this.resourceTreeTransferHandler = resourceTreeTransferHandler;
}
@Override
public int getSourceActions(JComponent comp)
{
return TransferHandler.COPY_OR_MOVE;
}
protected Collection<KNode> getTransferNodes(TransferSupport support)
{
Collection<KNode> transferNodes = new ArrayList<KNode>();
if (support.getTransferable() == null)
return null;
Collection<? extends KNode> nodes = Collections.EMPTY_LIST;
try {
nodes = (Collection<? extends KNode>)support.getTransferable().getTransferData(DataFlavors.TreeTableNodesFlavor);
} catch (UnsupportedFlavorException e) {
Logger.getLogger(ResourceTreeTransferHandler.class).error(e);
return null;
} catch (IOException e) {
Logger.getLogger(ResourceTreeTransferHandler.class).error(e);
return null;
}
for (KNode node : nodes) {
// some wierd serialization (or something) happens in DnD. the node we get somehow doesnt match the old one.
transferNodes.add(resourceTreeTransferHandler.resourceTreeTable.getNodeForPath(node.getNamePath()));
// transferNodes.add(node);
}
return transferNodes;
}
@Override
public boolean canImport(JComponent comp, DataFlavor[] flavours) {
KNode dropPointNode = resourceTreeTransferHandler.getDropPointNode(null);
if (dropPointNode == null) {
dropPointNode = resourceTreeTransferHandler.resourceTreeTable.getRootNode();
resourceTreeTransferHandler.resourceTreeTable.getSelectionModel().setSelectionInterval(0, 0);
// resourceTreeTable.repaint();
}
if (Arrays.asList(flavours).contains(DataFlavors.TreeTableNodesFlavor))
return true;
return false;
}
@Override
public boolean importData(TransferSupport support) {
if (!canImport(support))
return false;
int[] _dropPointIndex = new int[1];
KNode dropPointNode = resourceTreeTransferHandler.getDropPointNode(_dropPointIndex);
int dropPointIndex = _dropPointIndex[0];
if (dropPointNode == null)
return false;
int dropAction;
try {
// Swing really sucks. TransferHandler throws IllegalStateException if we try to call getDropAction when the support was constructed
// using anything other than its private constructor. Also all its innards are private.
dropAction = support.getDropAction();
} catch (IllegalStateException e) {
dropAction = TransferHandler.COPY;;
}
Collection<KNode> transferNodes = getTransferNodes(support);
// error checking pass
for (KNode transferNode : transferNodes) {
if (transferNode.isNodeDescendant(dropPointNode))
return false;
if (dropPointNode!=transferNode.getParent() && dropPointNode.getChild(transferNode.getName()) != null) {
switch (dropAction)
{
case TransferHandler.COPY:
case TransferHandler.COPY_OR_MOVE:
break;
default:
Application.getInstance().showAlertDialog(resourceTreeTransferHandler.resourceTreeTable, LanguageBundle.getString("resourcebrowser.errors.duplicateiteminfolder.title"), LanguageBundle.getString("resourcebrowser.errors.duplicateiteminfolder.message"));
return false;
}
}
}
// insertion pass
for (KNode transferNode : transferNodes) {
KNode loopLocalDropPointNode = dropPointNode;
int loopLocalDropPointIndex = dropPointIndex;
int offset = 0;
// resourceTreeTable.getModel().removeNodeFromParent(transferNode); // do this before the getDropPointNode so the indices work out when transferring to the name parent node
// compensate for re-inserting into same parent
if (loopLocalDropPointNode == transferNode.getParent()) {
// This is not only a NO-OP if MOVING a node. But in some cases such as copy/paste this is not the case and in fact prevents such functionality!
// In any case there is no harm and this was a pointless optimization.
// Leaving the old code with this comment as an advisory, though you could remove the code since the comment is here.
//if (dropPointNode.getIndex(transferNode) == dropPointIndex) // no op
// continue;
if (loopLocalDropPointNode.getIndex(transferNode) < loopLocalDropPointIndex) // compensate for index-shift from remove
offset = -1;
}
if (transferNode == loopLocalDropPointNode) {
if (transferNode instanceof FolderNode) {
loopLocalDropPointIndex = transferNode.getParent().getIndex(transferNode);
loopLocalDropPointNode = transferNode.getParent();
} else
continue; // can this happen if not a folder?
}
try {
switch (dropAction)
{
case TransferHandler.COPY:
// case TransferHandler.COPY_OR_MOVE:
transferNode = cloneNode(resourceTreeTransferHandler.resourceTreeTable.getTreeTableModel(), transferNode, loopLocalDropPointNode, loopLocalDropPointIndex + offset);
break;
default:
break;
}
} catch (CommandException e) {
Application.getInstance().showUnhandledErrorDialog(LanguageBundle.getString("general.errors.uncaughtexception.title"), e);
return false;
} catch (InterruptedException e) {
Logger.getLogger(getClass()).error("", e);
return false;
}
resourceTreeTransferHandler.resourceTreeTable.getTreeTableModel().removeNodeFromParent(transferNode);
resourceTreeTransferHandler.resourceTreeTable.getTreeTableModel().insertNodeInto(transferNode, loopLocalDropPointNode, loopLocalDropPointIndex + offset);
// resourceTreeTable.getTreeTableModel().add(transferNode, dropPointNode, dropPointIndex + offset);
}
return true;
}
private KNode cloneNode(ResourceTreeTableModel model, KNode node, KNode parentNode, int childIndex) throws CommandException, InterruptedException
{
if (node instanceof ResourceNode)
{
ResourceNode resourceNode = (ResourceNode)node;
final String resourceName = resourceNode.getName(); // TODO: get this from the resource
String name = UIUtil.createUniqueName(parentNode, resourceName, "copy of ");
IResource clone;
{
Request request = new Request();
request.set(CloneResourceCommand.ID, resourceNode.getResourceId());
request.set(CloneResourceCommand.NAME, name);
Response response = new Response();
CommandExecutor.executeCommand(CloneResourceCommand.class, request, response);
clone = (IResource)response.get(CloneResourceCommand.RESOURCE);
}
Application.getInstance().notifyResourceAdded( clone );
KNode cloneNode = ResourceNode.create( clone );
model.insertNodeInto( cloneNode, parentNode, childIndex );
return cloneNode;
}
else
if (node instanceof FolderNode)
{
FolderNode clone = new FolderNode(node.getName());
String name = UIUtil.createUniqueName(parentNode, node.getName(), "copy of ");
clone.setName(name);
model.insertNodeInto(clone, parentNode, parentNode.getChildCount());
for (KNode folderChild : node.getChildren())
{
clone.add(cloneNode(model, folderChild, clone, node.getIndex(folderChild)));
}
return clone;
}
throw new IllegalArgumentException("unknown node type");
}
}