Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6315069

The documentation for javax.swing.tree.TreeNode is unclear

XMLWordPrintable

    • b53
    • x86
    • windows_xp

      A DESCRIPTION OF THE PROBLEM :
      The documentation for the TreeNode class doesn't mention that an implementation must override the Object#hashCode() method.
      However, the JTree#setSelectionPath(TreePath) method, and maybe a few others, depend on this being done.

      Attaching the nodes for Document Tree

      /**
       * A TreeNode representing a file in a filesystem.
       * Each instance is associated with a File object, accessed with {@link getFile()},
       * and keeps a reference to the root of the file structure, used to limit paths to
       * @author Olivier Pernet
       */
      public class FileTreeNode
              implements TreeNode {
          
          private final File file;
          private final File root;
          
          public FileTreeNode(File file, File root) {
              if (file == null)
                  throw new IllegalArgumentException("The file represented by this tree node shall not be null.");
              if (root == null)
                  throw new IllegalArgumentException("The root of the tree structure shall not be null.");
              this.file = file;
              this.root = root;
          }
          
          /**
           * @return The children of this node as an Enumeration.
           */
          public Enumeration<FileTreeNode> children() {
              File[] children = file.listFiles();
              if (children != null) {
                  ArrayList<FileTreeNode> list = new ArrayList<FileTreeNode>();
                  for (File f : children)
                      list.add(new FileTreeNode(f, root));
                  return Collections.enumeration(list);
              } else {
                  return Collections.enumeration(new ArrayList<FileTreeNode>());
              }
          }
          
          /**
           * Returns whether this node allows having children.
           * Here, only nodes associated with a directory allow children.
           * Thus, this is equivalent to isLeaf(). But other TreeNode implementations
           * might differ on this point, and the constructor {@link JTree(TreeNode, boolean)}
           * allows to account for this difference.
           */
          public boolean getAllowsChildren() {
              return file.isDirectory();
          }
          
          /**
           * @return The node at the specified index among this node's children.
           */
          public TreeNode getChildAt(int childIndex) {
              return new FileTreeNode(file.listFiles()[childIndex], root);
          }
          
          /**
           * @return The number of nodes under this node.
           */
          public int getChildCount() {
              String[] list = file.list();
              return list == null ? 0 : list.length;
          }
          
          /**
           * Returns the index of one of this node's children.
           * Returns -1 if the node is not found.
           * @return The index of node in this node's children.
           */
          public int getIndex(TreeNode node) {
              if (node instanceof FileTreeNode) {
                  FileTreeNode n = (FileTreeNode) node;
                  File [] children = file.listFiles();
                  int i = 0;
                  while (i < children.length) {
                      if (children[i].equals(n.file))
                          return i;
                      i++;
                  }
              }
              return -1;
          }
          
          /**
           * Returns the parent of this node.
           * @return The parent of this node, or null if this is the root node.
           */
          public TreeNode getParent() {
              if (file.equals(root)) return null;
              else {
                  assert file.getParentFile() != null;
                  return new FileTreeNode(file.getParentFile(), root);
              }
          }
          
          /**
           * Returns whether this node is a leaf node.
           * Here, a node is a leaf node if it is not a directory.
           * @return True if and only if this node is a leaf node.
           */
          public boolean isLeaf() {
              return ! file.isDirectory();
          }
          
          /**
           * Returns a String representation of this node, used as the node's label
           * in JTrees. Here, the label is the associated file's name.
           * @return A String representation of this node.
           */
          public String toString() {
              return file.getName();
          }
          
          /**
           * Returns this node's associated file. This method is not part
           * of the TreeNode interface.
           * @return This node's associated file.
           */
          public File getFile() {
              assert file != null;
              return file;
          }
          
          /**
           * Returns the TreePath used to designate this node in the
           * tree structure.
           */
          public FileTreeNode[] getPath() {
              ArrayList<FileTreeNode> nodes = new ArrayList<FileTreeNode>();
              FileTreeNode node = this;
              while (node != null) {
                  // Adds the new node at the beginning of the list.
                  nodes.add(0, node);
                  node = (FileTreeNode) node.getParent();
              }
              // The "new FileTreeNode[0]" parameter is only used to
              // tell the toArray method which runtime type the returned
              // array should have.
              return nodes.toArray(new FileTreeNode[0]);
          }
          
          public TreePath getTreePath() {
              return new TreePath(getPath());
          }
          
          public boolean equals(Object other) {
              return (other instanceof FileTreeNode
                      && ((FileTreeNode) other).file.equals(file));
          }
      }



      And here is my test method, with the working code using DefaultMutableTreeNodes commented out :

          public static void test1() {
              
              final File rootDir = new File("/Users/taton/Dev-Raffin/CCSL");
              final File subDir = new File("/Users/taton/Dev-Raffin/CCSL/depouil-D3/ARRNGD");
              
              JFrame f = new JFrame();
              
              /*
              DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootDir);
              init(root, rootDir);
               */
              FileTreeNode root = new FileTreeNode(rootDir, rootDir);
              JTree tree = new JTree(root);
              
              JScrollPane scroll = new JScrollPane(tree);
              
              f.getContentPane().add(scroll);
              
              f.setBounds(0, 0, 250, 600);
              f.setVisible(true);
              
              f.addWindowListener(new WindowAdapter() {
                  public void windowClosing(WindowEvent e) {
                      System.exit(0);
                  }
              });
              
              JOptionPane.showMessageDialog(f, "Path will be selected");
              TreePath path = new FileTreeNode(subDir, rootDir).getTreePath();
              /*
               TreePath path = new TreePath(
                      find(root, subDir).getPath()
              );
               */
              tree.setSelectionPath(path);
          }
          
          private static void init(DefaultMutableTreeNode top, File root) {
              if (root.listFiles() != null) {
                  for (File f : root.listFiles()) {
                      DefaultMutableTreeNode node = new DefaultMutableTreeNode(f);
                      top.add(node);
                      if (f.isDirectory()) init(node, f);
                  }
              }
          }
          
          private static DefaultMutableTreeNode find(DefaultMutableTreeNode root, Object object) {
              if (root != null) {
                  if (root.getUserObject().equals(object)) return root;
                  else return find(root.getNextNode(), object);
              } else return null;
          }



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      In the interface description :
      Implementations of this interface should override {@link Object#hashCode} in order for some of the JTree methods to work.

      Or something similar.

      ACTUAL -
      Nothing regarding hashCode().

      URL OF FAULTY DOCUMENTATION :
      http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/tree/TreeNode.html

            svioletsunw Scott Violet (Inactive)
            jssunw Jitender S (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: