이너넷을 검색하여
발견한 몇 가지 소스들을 조합하여
Tree Node를 추가, 수정, 삭제하는 편집기능과
Drag & Drop을 통하여 위치 이동 및 복사하는 기능을 맹글었습니다.
다음 화면으로 간단히 확인하시고,
첨부한 소스를 활용하시길...
2011.05.17
발견한 몇 가지 소스들을 조합하여
Tree Node를 추가, 수정, 삭제하는 편집기능과
Drag & Drop을 통하여 위치 이동 및 복사하는 기능을 맹글었습니다.
다음 화면으로 간단히 확인하시고,
첨부한 소스를 활용하시길...
2011.05.17
/**
* @(#) TreeDragAndDrop.java
*
* An example for testing the Drag and Drop with JTree.
*
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any commercial and/or non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it as long as you retain this notice.
*
* @author: Hoyal Kim, hoyal.kim@gmail.com
*/
* @(#) TreeDragAndDrop.java
*
* An example for testing the Drag and Drop with JTree.
*
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any commercial and/or non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it as long as you retain this notice.
*
* @author: Hoyal Kim, hoyal.kim@gmail.com
*/
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* 노드 이동은 Drag&Drop
* 노드 복사는 [Ctrl] + Drag&Drop
* 오른쪽 버튼 팝업메뉴 - Add/Modify/Delete
*/
public class TreeDragAndDrop
{
JTree tree;
boolean DEBUG = true;
* 노드 이동은 Drag&Drop
* 노드 복사는 [Ctrl] + Drag&Drop
* 오른쪽 버튼 팝업메뉴 - Add/Modify/Delete
*/
public class TreeDragAndDrop
{
JTree tree;
boolean DEBUG = true;
public static void main(String[] args)
{
JFrame f = new JFrame("JTree DnD Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
{
JFrame f = new JFrame("JTree DnD Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
private JScrollPane getContent()
{
tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
tree.setTransferHandler(new TreeTransferHandler());
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(tree);
tree.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
// 선택 이벤트 테스트
if(DEBUG && tree.getSelectionCount() > 0) {
DefaultMutableTreeNode selectedNode = getSelectedNode();
Object obj = selectedNode.getUserObject();
Object pobj = null;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();
if(parentNode != null) pobj = parentNode.getUserObject();
System.out.println("Selected: [" + obj + "], isLeaf[" + selectedNode.isLeaf() + "], parent:[" + pobj + "]");
}
if (((event.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
&& (tree.getSelectionCount() > 0)) {
showMenu(event.getX(), event.getY());
}
}
});
return new JScrollPane(tree);
}
protected void showMenu(int x, int y) {
JPopupMenu popup = new JPopupMenu();
JMenuItem mi = new JMenuItem("추가");
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
addNewNodeItem();
}
});
mi = new JMenuItem("수정");
TreePath path = tree.getSelectionPath();
Object node = path.getLastPathComponent();
if (node == tree.getModel().getRoot()) {
mi.setEnabled(false);
}
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
modifySelectedNode();
}
});
mi = new JMenuItem("삭제");
if (node == tree.getModel().getRoot()) {
mi.setEnabled(false);
}
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
deleteSelectedItems();
}
});
popup.show(tree, x, y);
}
{
tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
tree.setTransferHandler(new TreeTransferHandler());
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(tree);
tree.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
// 선택 이벤트 테스트
if(DEBUG && tree.getSelectionCount() > 0) {
DefaultMutableTreeNode selectedNode = getSelectedNode();
Object obj = selectedNode.getUserObject();
Object pobj = null;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();
if(parentNode != null) pobj = parentNode.getUserObject();
System.out.println("Selected: [" + obj + "], isLeaf[" + selectedNode.isLeaf() + "], parent:[" + pobj + "]");
}
if (((event.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
&& (tree.getSelectionCount() > 0)) {
showMenu(event.getX(), event.getY());
}
}
});
return new JScrollPane(tree);
}
protected void showMenu(int x, int y) {
JPopupMenu popup = new JPopupMenu();
JMenuItem mi = new JMenuItem("추가");
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
addNewNodeItem();
}
});
mi = new JMenuItem("수정");
TreePath path = tree.getSelectionPath();
Object node = path.getLastPathComponent();
if (node == tree.getModel().getRoot()) {
mi.setEnabled(false);
}
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
modifySelectedNode();
}
});
mi = new JMenuItem("삭제");
if (node == tree.getModel().getRoot()) {
mi.setEnabled(false);
}
popup.add(mi);
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
deleteSelectedItems();
}
});
popup.show(tree, x, y);
}
protected void deleteSelectedItems() {
DefaultMutableTreeNode node = getSelectedNode();
if(node.getChildCount() > 0) {
JOptionPane.showMessageDialog(null, "하위 노드가 있는 경우 삭제할 수 없습니다.\n필요하다면 하위 노드부터 삭제하고 다시 시도하세요.", "주의", JOptionPane.WARNING_MESSAGE);
}
else {
int res = JOptionPane.showConfirmDialog(null, "삭제하면 다시 복원할 수 없습니다.\n삭제하시겠습니까?", "삭제 확인", JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.OK_OPTION) {
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
TreePath[] paths = tree.getSelectionPaths();
for (int i = 0; i < paths.length; i++) {
node = (DefaultMutableTreeNode) (paths[i].getLastPathComponent());
model.removeNodeFromParent(node);
}
}
}
}
DefaultMutableTreeNode node = getSelectedNode();
if(node.getChildCount() > 0) {
JOptionPane.showMessageDialog(null, "하위 노드가 있는 경우 삭제할 수 없습니다.\n필요하다면 하위 노드부터 삭제하고 다시 시도하세요.", "주의", JOptionPane.WARNING_MESSAGE);
}
else {
int res = JOptionPane.showConfirmDialog(null, "삭제하면 다시 복원할 수 없습니다.\n삭제하시겠습니까?", "삭제 확인", JOptionPane.YES_NO_OPTION);
if(res == JOptionPane.OK_OPTION) {
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
TreePath[] paths = tree.getSelectionPaths();
for (int i = 0; i < paths.length; i++) {
node = (DefaultMutableTreeNode) (paths[i].getLastPathComponent());
model.removeNodeFromParent(node);
}
}
}
}
private void modifySelectedNode() {
DefaultMutableTreeNode node = getSelectedNode();
if (node == null) {
JOptionPane.showMessageDialog(null, "변경할 노드를 선택하세요.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
String name = JOptionPane.showInputDialog(null, "새로운 노드 이름 입력하세요: ");
if(name != null && !"".equals(name)) {
node.setUserObject(name);
}
}
DefaultMutableTreeNode node = getSelectedNode();
if (node == null) {
JOptionPane.showMessageDialog(null, "변경할 노드를 선택하세요.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
String name = JOptionPane.showInputDialog(null, "새로운 노드 이름 입력하세요: ");
if(name != null && !"".equals(name)) {
node.setUserObject(name);
}
}
private void addNewNodeItem() {
DefaultMutableTreeNode parent = getSelectedNode();
if (parent == null) {
JOptionPane.showMessageDialog(null, "추가할 위치의 상위 노드를 선택하세요.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
String name = JOptionPane.showInputDialog(null, "삽입할 노드 이름 입력하세요: ");
if(name != null && !"".equals(name)) {
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
model.insertNodeInto(new DefaultMutableTreeNode(name), parent, parent.getChildCount());
tree.expandRow(tree.getLeadSelectionRow());
}
}
private DefaultMutableTreeNode getSelectedNode() {
return (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
}
DefaultMutableTreeNode parent = getSelectedNode();
if (parent == null) {
JOptionPane.showMessageDialog(null, "추가할 위치의 상위 노드를 선택하세요.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
String name = JOptionPane.showInputDialog(null, "삽입할 노드 이름 입력하세요: ");
if(name != null && !"".equals(name)) {
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
model.insertNodeInto(new DefaultMutableTreeNode(name), parent, parent.getChildCount());
tree.expandRow(tree.getLeadSelectionRow());
}
}
private DefaultMutableTreeNode getSelectedNode() {
return (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
}
private void expandTree(JTree tree)
{
DefaultMutableTreeNode root = (DefaultMutableTreeNode)tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while(e.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
if(node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
}
{
DefaultMutableTreeNode root = (DefaultMutableTreeNode)tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while(e.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
if(node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
}
/**
* TransferHandler Extension Class
*/
class TreeTransferHandler extends TransferHandler
{
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler()
{
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
javax.swing.tree.DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support)
{
if(!support.isDrop()) {
return false;
}
support.setShowDropLocation(true);
if(!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// 드래그한 소스 위에 떨어뜨리는 건 허용하지 않음
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl = (JTree.DropLocation)support.getDropLocation();
JTree tree = (JTree)support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for(int i = 0; i < selRows.length; i++) {
if(selRows[i] == dropRow) {
return false;
}
}
// 넌-리프 노드가 선택되었는데 하위 자식노드들이 모두 선택되지 않았다면
// 이동하여 떨어뜨리는 걸 허용하지 않음
// (즉 넌-리프 노드의 이동은 하위 노드들을 모두 선택해야 이동 가능함)
// Do not allow MOVE-action drops if a non-leaf node is
// selected unless all of its children are also selected.
int action = support.getDropAction();
if(action == MOVE) {
return haveCompleteNode(tree);
}
// 넌-리프 노드는 원래 레벨보다 낮은 레벨에 복사하지 못함
// Do not allow a non-leaf node to be copied to a level
// which is less than its source level.
TreePath dest = dl.getPath();
DefaultMutableTreeNode target = (DefaultMutableTreeNode)dest.getLastPathComponent();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode firstNode = (DefaultMutableTreeNode)path.getLastPathComponent();
if(firstNode.getChildCount() > 0 && target.getLevel() < firstNode.getLevel()) {
return false;
}
return true;
}
private boolean haveCompleteNode(JTree tree)
{
int[] selRows = tree.getSelectionRows();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode first = (DefaultMutableTreeNode)path.getLastPathComponent();
int childCount = first.getChildCount();
// first has children and no children are selected.
if(childCount > 0 && selRows.length == 1)
return false;
// first may have children.
for(int i = 1; i < selRows.length; i++) {
path = tree.getPathForRow(selRows[i]);
DefaultMutableTreeNode next = (DefaultMutableTreeNode)path.getLastPathComponent();
if(first.isNodeChild(next)) {
// Found a child of first.
if(childCount > selRows.length-1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c)
{
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();
if(paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List<DefaultMutableTreeNode> copies = new ArrayList<DefaultMutableTreeNode>();
List<DefaultMutableTreeNode> toRemove = new ArrayList<DefaultMutableTreeNode>();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for(int i = 1; i < paths.length; i++) {
DefaultMutableTreeNode next = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
// Do not allow higher level nodes to be added to list.
if(next.getLevel() < node.getLevel()) {
break;
} else if(next.getLevel() > node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes = copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove = toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node)
{
return new DefaultMutableTreeNode(node);
}
protected void exportDone(JComponent source, Transferable data, int action)
{
if((action & MOVE) == MOVE) {
JTree tree = (JTree)source;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for(int i = 0; i < nodesToRemove.length; i++) {
model.removeNodeFromParent(nodesToRemove[i]);
}
}
}
public int getSourceActions(JComponent c)
{
return COPY_OR_MOVE;
}
public boolean importData(TransferHandler.TransferSupport support)
{
if(!canImport(support)) {
return false;
}
// Extract transfer data.
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[])t.getTransferData(nodesFlavor);
} catch(UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch(java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
// Get drop location info.
JTree.DropLocation dl =
(JTree.DropLocation)support.getDropLocation();
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)dest.getLastPathComponent();
JTree tree = (JTree)support.getComponent();
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Configure for drop mode.
int index = childIndex; // DropMode.INSERT
if(childIndex == -1) { // DropMode.ON
index = parent.getChildCount();
}
// Add data to model.
for(int i = 0; i < nodes.length; i++) {
model.insertNodeInto(nodes[i], parent, index++);
}
return true;
}
public String toString()
{
return getClass().getName();
}
/**
* Transferable Implementation Class
*/
public class NodesTransferable implements Transferable
{
DefaultMutableTreeNode[] nodes;
public NodesTransferable(DefaultMutableTreeNode[] nodes)
{
this.nodes = nodes;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
{
if(!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);
return nodes;
}
public DataFlavor[] getTransferDataFlavors()
{
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return nodesFlavor.equals(flavor);
}
}
}
* TransferHandler Extension Class
*/
class TreeTransferHandler extends TransferHandler
{
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler()
{
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
javax.swing.tree.DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support)
{
if(!support.isDrop()) {
return false;
}
support.setShowDropLocation(true);
if(!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// 드래그한 소스 위에 떨어뜨리는 건 허용하지 않음
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl = (JTree.DropLocation)support.getDropLocation();
JTree tree = (JTree)support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for(int i = 0; i < selRows.length; i++) {
if(selRows[i] == dropRow) {
return false;
}
}
// 넌-리프 노드가 선택되었는데 하위 자식노드들이 모두 선택되지 않았다면
// 이동하여 떨어뜨리는 걸 허용하지 않음
// (즉 넌-리프 노드의 이동은 하위 노드들을 모두 선택해야 이동 가능함)
// Do not allow MOVE-action drops if a non-leaf node is
// selected unless all of its children are also selected.
int action = support.getDropAction();
if(action == MOVE) {
return haveCompleteNode(tree);
}
// 넌-리프 노드는 원래 레벨보다 낮은 레벨에 복사하지 못함
// Do not allow a non-leaf node to be copied to a level
// which is less than its source level.
TreePath dest = dl.getPath();
DefaultMutableTreeNode target = (DefaultMutableTreeNode)dest.getLastPathComponent();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode firstNode = (DefaultMutableTreeNode)path.getLastPathComponent();
if(firstNode.getChildCount() > 0 && target.getLevel() < firstNode.getLevel()) {
return false;
}
return true;
}
private boolean haveCompleteNode(JTree tree)
{
int[] selRows = tree.getSelectionRows();
TreePath path = tree.getPathForRow(selRows[0]);
DefaultMutableTreeNode first = (DefaultMutableTreeNode)path.getLastPathComponent();
int childCount = first.getChildCount();
// first has children and no children are selected.
if(childCount > 0 && selRows.length == 1)
return false;
// first may have children.
for(int i = 1; i < selRows.length; i++) {
path = tree.getPathForRow(selRows[i]);
DefaultMutableTreeNode next = (DefaultMutableTreeNode)path.getLastPathComponent();
if(first.isNodeChild(next)) {
// Found a child of first.
if(childCount > selRows.length-1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c)
{
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();
if(paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List<DefaultMutableTreeNode> copies = new ArrayList<DefaultMutableTreeNode>();
List<DefaultMutableTreeNode> toRemove = new ArrayList<DefaultMutableTreeNode>();
DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for(int i = 1; i < paths.length; i++) {
DefaultMutableTreeNode next = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
// Do not allow higher level nodes to be added to list.
if(next.getLevel() < node.getLevel()) {
break;
} else if(next.getLevel() > node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes = copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove = toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node)
{
return new DefaultMutableTreeNode(node);
}
protected void exportDone(JComponent source, Transferable data, int action)
{
if((action & MOVE) == MOVE) {
JTree tree = (JTree)source;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for(int i = 0; i < nodesToRemove.length; i++) {
model.removeNodeFromParent(nodesToRemove[i]);
}
}
}
public int getSourceActions(JComponent c)
{
return COPY_OR_MOVE;
}
public boolean importData(TransferHandler.TransferSupport support)
{
if(!canImport(support)) {
return false;
}
// Extract transfer data.
DefaultMutableTreeNode[] nodes = null;
try {
Transferable t = support.getTransferable();
nodes = (DefaultMutableTreeNode[])t.getTransferData(nodesFlavor);
} catch(UnsupportedFlavorException ufe) {
System.out.println("UnsupportedFlavor: " + ufe.getMessage());
} catch(java.io.IOException ioe) {
System.out.println("I/O error: " + ioe.getMessage());
}
// Get drop location info.
JTree.DropLocation dl =
(JTree.DropLocation)support.getDropLocation();
int childIndex = dl.getChildIndex();
TreePath dest = dl.getPath();
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)dest.getLastPathComponent();
JTree tree = (JTree)support.getComponent();
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Configure for drop mode.
int index = childIndex; // DropMode.INSERT
if(childIndex == -1) { // DropMode.ON
index = parent.getChildCount();
}
// Add data to model.
for(int i = 0; i < nodes.length; i++) {
model.insertNodeInto(nodes[i], parent, index++);
}
return true;
}
public String toString()
{
return getClass().getName();
}
/**
* Transferable Implementation Class
*/
public class NodesTransferable implements Transferable
{
DefaultMutableTreeNode[] nodes;
public NodesTransferable(DefaultMutableTreeNode[] nodes)
{
this.nodes = nodes;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
{
if(!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);
return nodes;
}
public DataFlavor[] getTransferDataFlavors()
{
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return nodesFlavor.equals(flavor);
}
}
}