JTree - home-Verzeichnis des Benutzers aufklappen

Hm. Falls ich das richtig verstanden habe, existiert der Teil des JTrees ja noch gar nicht, in dem Moment, wo es ausgeklappt werden soll. (Also, dieser Teil wird ja erst durch den SelectionListener erstellt …).

(Ich würde da eher einen TreeWillExpandListener verwenden, aber … vielleicht gibt es für den SelectionListener ja einen Grund…)

Zugegeben, mit dem FileSystemView hatte ich bisher noch nicht wirklich was gemacht. Ich war dann etwas irritiert, zu sehen, dass er bei mir „Desktop“ als Root zurückgegeben hat, aber auch als Home-Directory - das macht irgendwie keinen Sinn… :confused:

Wie auch immer, es gibt bei der genauen Umsetztung sicher einige Freiheitsgrade, aber ich hab’ mal was gebastelt, was „bei mir funktioniert“ :wink: - vielleicht ist doch der eine oder andere hilfreiche Schnipsel drin…

package bytewelt;

import java.awt.BorderLayout;
import java.io.File;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class FileTreeExpandTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultTreeModel fileTreeModel = createFileTreeModel();
        JTree tree = new JTree(fileTreeModel);
        JScrollPane scrollPane = new JScrollPane(tree);
        
        tree.addTreeWillExpandListener(new TreeWillExpandListener()
        {
            @Override
            public void treeWillExpand(TreeExpansionEvent event)
                throws ExpandVetoException
            {
                TreePath path = event.getPath();
                DefaultMutableTreeNode lastNode = 
                    (DefaultMutableTreeNode)path.getLastPathComponent();
                Object userObject = lastNode.getUserObject();
                File file = (File)userObject;
                List<File> subdirectories = getSubdirectories(file);
                System.out.println("treeWillExpand at " + lastNode
                    + ", validating children for " + subdirectories);
                validateChildren(lastNode, subdirectories);
            }
            @Override
            public void treeWillCollapse(TreeExpansionEvent event)
                throws ExpandVetoException
            {
                // Not used
            }
        });

        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
        
        JButton expandButton = new JButton("Expand Home");
        expandButton.addActionListener(e -> expandHome(tree));
        frame.getContentPane().add(expandButton, BorderLayout.SOUTH);
        
        frame.setSize(600, 600);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);    
    }

    private static void expandHome(JTree fileTree)
    {
        File homePath = new File("C:/Users/User/");
        List<File> pathObjects = createPathFromRoot(homePath);
        
        System.out.println("Expanding "+pathObjects);
        
        TreeModel treeModel = fileTree.getModel();
        DefaultTreeModel defaultTreeModel = (DefaultTreeModel) treeModel;
        TreePath treePath = validateTreePath(defaultTreeModel, pathObjects);
        
        fileTree.expandPath(treePath);
        fileTree.setSelectionPath(treePath);
    }
    
    
    
    // Create a list containing the Files from the root of the
    // file system, up to the given file
    private static List<File> createPathFromRoot(File file)
    {
        Deque<File> list = new LinkedList<File>();
        File current = file;
        while (current != null)
        {
            list.addFirst(current);
            current = FILE_SYSTEM_VIEW.getParentDirectory(current);
        }
        return new ArrayList<File>(list);
    }
    
    // Make sure that the given tree model contains a path with
    // the given user objects, creating the nodes if necessary,
    // and return this path
    private static TreePath validateTreePath(
        DefaultTreeModel treeModel, List<?> objects)
    {
        DefaultMutableTreeNode rootNode = 
            (DefaultMutableTreeNode)treeModel.getRoot();
        DefaultMutableTreeNode currentNode = rootNode;
        TreePath treePath = new TreePath(currentNode);
        for (int i=0; i<objects.size(); i++)
        {
            Object object = objects.get(i);
            DefaultMutableTreeNode nextNode = 
                validateChild(currentNode, object);
            currentNode = nextNode;
            treePath = treePath.pathByAddingChild(currentNode);
        }
        return treePath;
    }
    
    // Make sure that the given node has a child with the given
    // user object, creating it if necessary, and return the child
    private static DefaultMutableTreeNode validateChild(
        DefaultMutableTreeNode node, Object userObject)
    {
        int n = node.getChildCount();
        for (int i = 0; i < n; i++)
        {
            DefaultMutableTreeNode child = 
                (DefaultMutableTreeNode)node.getChildAt(i);
            Object childUserObject = child.getUserObject();
            if (Objects.equals(childUserObject, userObject))
            {
                return child;
            }
        }
        DefaultMutableTreeNode newChild = 
            new DefaultMutableTreeNode(userObject);
        node.add(newChild);
        return newChild;
    }
    
    
    
    private static FileSystemView FILE_SYSTEM_VIEW =
        FileSystemView.getFileSystemView();

    private static DefaultTreeModel createFileTreeModel()
    {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode();

        File[] fileSystemRoots = FILE_SYSTEM_VIEW.getRoots();
        for (File rootPath : fileSystemRoots)
        {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(rootPath);
            root.add(node);
            List<File> subdirectories = getSubdirectories(rootPath);
            validateChildren(node, subdirectories);
        }
        return new DefaultTreeModel(root, true);
    }
    
    
    // If the given file is a directory, return a list of all subdirectories
    private static List<File> getSubdirectories(File file)
    {
        List<File> subdirectories = new ArrayList<File>();
        if (file.isDirectory())
        {
            File[] subDirs = FILE_SYSTEM_VIEW.getFiles(file, true);
            for (File subDir : subDirs)
            {
                if (subDir.isDirectory())
                {
                    subdirectories.add(subDir);
                }
            }
        }
        return subdirectories;
    }
    
    // Make sure that the given node has children 
    // with all the given user objects
    private static boolean validateChildren(
        DefaultMutableTreeNode node, Iterable<?> childUserObjects)
    {
        boolean changed = false;
        Set<Object> existing = getChildUserObjects(node);
        for (Object childUserObject : childUserObjects)
        {
            if (!existing.contains(childUserObject))
            {
                node.add(new DefaultMutableTreeNode(childUserObject));
                changed = true;
            }
        }
        return changed;
    }
    
    // Returns a set of the user objects of all children of the given node
    private static Set<Object> getChildUserObjects(Object nodeObject)
    {
        Set<Object> childUserObjects = new LinkedHashSet<Object>();
        if (!(nodeObject instanceof DefaultMutableTreeNode))
        {
            // Warning here
            return childUserObjects;
        }
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)nodeObject;
        int n = node.getChildCount();
        for (int i = 0; i < n; i++)
        {
            DefaultMutableTreeNode child = 
                (DefaultMutableTreeNode)node.getChildAt(i);
            Object childUserObject = child.getUserObject();
            childUserObjects.add(childUserObject);
        }
        return childUserObjects;
    }
    
}
1 „Gefällt mir“