Copy Paste from JTree Transferable TransferHandler

2019-04-15 06:26发布

I'm exploring How to do the implementation of the Copy & Paste of JTree.

Because, I want Copy from DefaultMutableTreeNode like toString() to paste in another application like Sublime Text.

I was viewing the code in order to view how copy & paste is implemented and how is used drag and drop in JTree.

My first thougth was, Copy and Paste between DefaultMutableTreeNode of JTree must be tested, later how paste from Clipboard to another application, but my code is not working and Don't know why is failing, and I need to solve.

NOTE: Sorry my code is a bit long, because if I put only a snippet code will be non functional. For me all code here is needed to do tests.

Here my code:

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;

public class JTreeTransferHandler extends JFrame {

  public JTreeTransferHandler() {
    initiate();
  }

  private void initiate() {
    setTitle("Copy from JTree");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(400,400);
    setLocation(200,200);
    setVisible(true);

    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
    DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
    vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
    vegetableNode.add(new DefaultMutableTreeNode("Carrot"));

    DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
    fruitNode.add(new DefaultMutableTreeNode("Mango"));
    fruitNode.add(new DefaultMutableTreeNode("Apple"));
    root.add(vegetableNode);
    root.add(fruitNode);

    JTree tree = new JTree(root);

    TreeTransferHandler treeTransferHandler = new TreeTransferHandler();
    tree.setTransferHandler(treeTransferHandler);

    Clipboard clipboard = this.getToolkit().getSystemClipboard();

    JButton copy = new JButton("Copy");
    copy.addActionListener((ActionEvent e) -> {
      TransferHandler handler = tree.getTransferHandler();
      handler.exportToClipboard(tree, clipboard, TransferHandler.COPY);
    });

    JButton paste = new JButton("Paste");
    paste.addActionListener((ActionEvent e) -> {
      Transferable clipData = clipboard.getContents(clipboard);
      if (clipData != null) {
        if (clipData.isDataFlavorSupported(treeTransferHandler.nodesFlavor)) {
          TransferHandler handler = tree.getTransferHandler();
          handler.importData(tree, clipData);
        }
      }
    });

    JPanel buttonsPanel = new JPanel();
    buttonsPanel.add(copy);
    buttonsPanel.add(paste);

    add(new JScrollPane(tree), BorderLayout.CENTER);
    add(buttonsPanel, BorderLayout.SOUTH);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      JTreeTransferHandler jTreeTransferHandler = new JTreeTransferHandler();
    });
  }     
}

class TreeTransferHandler extends TransferHandler {
  DataFlavor nodesFlavor;
  DataFlavor[] flavors = new DataFlavor[1];
  DefaultMutableTreeNode[] nodesToRemove;

  public TreeTransferHandler() {
    try {
      String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" +
          DefaultMutableTreeNode[].class.getName() + "\"";
      nodesFlavor = new DataFlavor(mimeType);
      flavors[0] = nodesFlavor;
    } catch(ClassNotFoundException e) {
      System.out.println("ClassNotFound: " + e.getMessage());
    }
  }

  //TransferHandler
  @Override public int getSourceActions(JComponent c) {
    return TransferHandler.COPY;
  }

  //TransferHandler
  @Override public boolean canImport(JComponent comp, DataFlavor flavor[]) {
    for (int i = 0, n = flavor.length; i < n; i++) {
      for (int j = 0, m = flavors.length; j < m; j++) {
        if (flavor[i].equals(flavors[j])) {
          return true;
        }
      }
    }
    return false;
  }

  //TransferHandler
  @Override protected Transferable createTransferable(JComponent c) {
    JTree tree = (JTree) c;
    TreePath[] paths = tree.getSelectionPaths();
    if (paths != null) {
      List<DefaultMutableTreeNode> copies = new ArrayList<>();
      List<DefaultMutableTreeNode> toRemove = new ArrayList<>();
      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);
  }

  //TransferHandler
  @Override 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;
  }

  //TransferHandler
  public boolean importData(JComponent comp, Transferable t) {
    // Extract transfer data.
    DefaultMutableTreeNode[] nodes;
    try {
      nodes = (DefaultMutableTreeNode[]) t.getTransferData(nodesFlavor);
      if (comp instanceof JTree) {
        JTree tree = (JTree)comp;
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();

        JTree.DropLocation dl = tree.getDropLocation();
        int childIndex = dl.getChildIndex();
        TreePath dest = dl.getPath();
        DefaultMutableTreeNode parent = 
            (DefaultMutableTreeNode)dest.getLastPathComponent();
        // Configure for drop mode.
        int index = childIndex;    // DropMode.INSERT
        if (childIndex == -1) {     // DropMode.ON
          index = parent.getChildCount();
        }
        // Add data to model.
        for (DefaultMutableTreeNode node : nodes) {
          model.insertNodeInto(node, parent, index++);
        }
        return true;
      }
    } catch (UnsupportedFlavorException ufe) {
      System.out.println("UnsupportedFlavor: " + ufe.getMessage());
    } catch (java.io.IOException ioe) {
      System.out.println("I/O error: " + ioe.getMessage());
    }
    return false;
  }

  public class NodesTransferable implements Transferable {
    DefaultMutableTreeNode[] nodes;

    public NodesTransferable(DefaultMutableTreeNode[] nodes) {
      this.nodes = nodes;
    }

    //Transferable
    @Override public Object getTransferData(DataFlavor flavor)  {
      if(!isDataFlavorSupported(flavor)) {
        return false;
      }
      return nodes;
    }

    //Transferable
    @Override public DataFlavor[] getTransferDataFlavors() {
      return flavors;
    }

    //Transferable
    @Override public boolean isDataFlavorSupported(DataFlavor flavor) {
      return flavor.equals(nodesFlavor);
    }
  }
}

1条回答
乱世女痞
2楼-- · 2019-04-15 06:35

TransferHandler.TransferSupport#isDrop() method returns false in the case of via Clipboard, so switching it here seems to work fine.

// Get drop location info.
int childIndex;
TreePath dest;
if (support.isDrop()) {
  JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation();
  childIndex = dl.getChildIndex();
  dest = dl.getPath();
} else {
  childIndex = -1;
  JTree tree = (JTree) support.getComponent();
  dest = tree.getSelectionPath();
}

JTreeTransferHandler2.java

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;

public class JTreeTransferHandler2 extends JFrame {

  public JTreeTransferHandler2() {
    initiate();
  }

  private void initiate() {
    setTitle("Copy from JTree");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(400,400);
    setLocation(200,200);
    setVisible(true);

    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
    DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
    vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
    vegetableNode.add(new DefaultMutableTreeNode("Carrot"));

    DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
    fruitNode.add(new DefaultMutableTreeNode("Mango"));
    fruitNode.add(new DefaultMutableTreeNode("Apple"));
    root.add(vegetableNode);
    root.add(fruitNode);

    JTree tree = new JTree(root);

    TreeTransferHandler treeTransferHandler = new TreeTransferHandler();
    tree.setTransferHandler(treeTransferHandler);

    Clipboard clipboard = this.getToolkit().getSystemClipboard();

    JButton copy = new JButton("Copy");
    copy.addActionListener((ActionEvent e) -> {
      TransferHandler handler = tree.getTransferHandler();
      handler.exportToClipboard(tree, clipboard, TransferHandler.COPY);
    });

    JButton paste = new JButton("Paste");
    paste.addActionListener((ActionEvent e) -> {
      Transferable clipData = clipboard.getContents(null);
      if (clipData != null) {
        if (clipData.isDataFlavorSupported(treeTransferHandler.nodesFlavor)) {
          TransferHandler handler = tree.getTransferHandler();
          handler.importData(tree, clipData);
        }
      }
    });

    JPanel buttonsPanel = new JPanel();
    buttonsPanel.add(copy);
    buttonsPanel.add(paste);

    add(new JScrollPane(tree), BorderLayout.CENTER);
    add(buttonsPanel, BorderLayout.SOUTH);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      JTreeTransferHandler2 jTreeTransferHandler = new JTreeTransferHandler2();
    });
  }     
}

class TreeTransferHandler extends TransferHandler {
  DataFlavor nodesFlavor;
  DataFlavor[] flavors = new DataFlavor[1];
  DefaultMutableTreeNode[] nodesToRemove;

  public TreeTransferHandler() {
    try {
      String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" +
          DefaultMutableTreeNode[].class.getName() + "\"";
      nodesFlavor = new DataFlavor(mimeType);
      flavors[0] = nodesFlavor;
    } catch(ClassNotFoundException e) {
      System.out.println("ClassNotFound: " + e.getMessage());
    }
  }

  //TransferHandler
  @Override public int getSourceActions(JComponent c) {
    return TransferHandler.COPY;
  }

  //TransferHandler
  @Override public boolean canImport(JComponent comp, DataFlavor flavor[]) {
    for (int i = 0, n = flavor.length; i < n; i++) {
      for (int j = 0, m = flavors.length; j < m; j++) {
        if (flavor[i].equals(flavors[j])) {
          return true;
        }
      }
    }
    return false;
  }

  //TransferHandler
  @Override protected Transferable createTransferable(JComponent c) {
    JTree tree = (JTree) c;
    TreePath[] paths = tree.getSelectionPaths();
    if (paths != null) {
      List<DefaultMutableTreeNode> copies = new ArrayList<>();
      List<DefaultMutableTreeNode> toRemove = new ArrayList<>();
      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);
  }

  //TransferHandler
  @Override 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.
    int childIndex;
    TreePath dest;
    if (support.isDrop()) {
      JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation();
      childIndex = dl.getChildIndex();
      dest = dl.getPath();
    } else {
      childIndex = -1;
      JTree tree = (JTree) support.getComponent();
      dest = tree.getSelectionPath();
    }
    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++) {
      // ArrayIndexOutOfBoundsException
      model.insertNodeInto(nodes[i], parent, index++);
    }
    return true;
  }

  //TransferHandler
  @Override public boolean importData(JComponent comp, Transferable t) {
    return importData(new TransferHandler.TransferSupport(comp, t));
  }

  public class NodesTransferable implements Transferable {
    DefaultMutableTreeNode[] nodes;

    public NodesTransferable(DefaultMutableTreeNode[] nodes) {
      this.nodes = nodes;
    }

    //Transferable
    @Override public Object getTransferData(DataFlavor flavor)  {
      if(!isDataFlavorSupported(flavor)) {
        return false;
      }
      return nodes;
    }

    //Transferable
    @Override public DataFlavor[] getTransferDataFlavors() {
      return flavors;
    }

    //Transferable
    @Override public boolean isDataFlavorSupported(DataFlavor flavor) {
      return flavor.equals(nodesFlavor);
    }
  }
}
查看更多
登录 后发表回答