Search code examples
javaswingfilesystemsjtree

Hiding files and hidden directories in a Swing JTree


I've used this code from the Java2s.com to display a file tree of my home directory. I'd like to have the user select directories that are going to contain information that my program will use. I've made numerous attempts (too many to list here) to get the tree to display only non-hidden directories. Files and hidden directories are not to be shown on the tree.

Is there a way to do this? I've spent quite a lot of time on this but have not succeeded. Is there a way to intercept what the final display will look like? Maybe the a renderer could interrogate the tree and remove nodes that fall under isHidden()?

public class FileTreeDemo {

    static File root;
    static FileTreeModel model;

    public static void main(String[] args) {
        // Figure out where in the filesystem to start displaying

        if (args.length > 0) {
            root = new File(args[0]);
        } else {
            root = new File(System.getProperty("user.home"));
        }

        // Create a TreeModel object to represent our tree of files
        model = new FileTreeModel(root);

        // Create a JTree and tell it to display our model
        JTree tree = new JTree();
        tree.setModel(model);

        // The JTree can get big, so allow it to scroll
        JScrollPane scrollpane = new JScrollPane(tree);

        // Display it all in a window and make the window appear
        JFrame frame = new JFrame("FileTreeDemo");
        frame.getContentPane().add(scrollpane, "Center");
        frame.setSize(400, 600);
        frame.setVisible(true);
    }

    /**
     * The methods in this class allow the JTree component to traverse the file
     * system tree and display the files and directories.
     *
     */
    static class FileTreeModel implements TreeModel {

        // We specify the root directory when we create the model.
        protected File root;

        public FileTreeModel(File root) {
            this.root = root;
        }

        // The model knows how to return the root object of the tree
        public Object getRoot() {
            return root;
        }

        // Tell JTree whether an object in the tree is a leaf
        @Override
      public boolean isLeaf(Object node) { 

          return ((File)node).isFile(); 
      }            
        // Tell JTree how many children a node has
        public int getChildCount(Object parent) {
            String[] children = ((File) parent).list();
            if (children == null) {
                return 0;
            }
            return children.length;
        }

        // Fetch any numbered child of a node for the JTree.
        // Our model returns File objects for all nodes in the tree.  The
        // JTree displays these by calling the File.toString() method.
        public Object getChild(Object parent, int index) {               

            String[] children = ((File) parent).list();


            if ((children == null) || (index >= children.length)) {
                return null;
            }
            return new File((File) parent, children[index]);
        }
        // Figure out a child's position in its parent node.
        @Override
        public int getIndexOfChild(Object parent, Object child) {

            String[] children = ((File) parent).list();
            if (children == null) {
                return -1;
            }
            String childname = ((File) child).getName();
            for (int i = 0; i < children.length; i++) {
                if (childname.equals(children[i])) {
                    return i;
                }
            }
            return -1;
        }

        // This method is invoked by the JTree only for editable trees.  
        // This TreeModel does not allow editing, so we do not implement 
        // this method.  The JTree editable property is false by default.
        public void valueForPathChanged(TreePath path, Object newvalue) {
        }

        // Since this is not an editable tree model, we never fire any events,
        // so we don't actually have to keep track of interested listeners
        public void addTreeModelListener(TreeModelListener l) {
        }

        public void removeTreeModelListener(TreeModelListener l) {
        }
    }
}

Solution

  • It is up to the model to ignore hidden files. Renderer's job is display only, it should not interfere with data selection and filtering. For example you can use File.listFiles(FileFilter filter) in the model:

    private static final File[] EMPTY_LIST = {};
    
    private File[] getFiles(File parent) {
        File[] files = parent.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return !file.isHidden();
            }
        });
        return files != null ? files : EMPTY_LIST;
    }
    
    @Override
    public int getChildCount(Object parent) {
        return getFiles((File) parent).length;
    }
    
    @Override
    public Object getChild(Object parent, int index) {
        return getFiles((File) parent)[index];
    }
    
    @Override
    public int getIndexOfChild(Object parent, Object child) {
        File[] files = getFiles((File) parent);
        for (int idx = 0; idx < files.length; idx++) {
            if (files[idx].equals(child))
                return idx;
        }
        return -1;
    }