package de.uni_passau.fim.infosun.prophet.plugin.plugins.codeViewerPlugin.fileTree; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * A <code>DefaultMutableTreeNode</code> to be used in a <code>JTree</code> that displays a file system directory * structure. */ public class FileTreeNode { private FileTreeNode parent; private File file; private List<FileTreeNode> children; /** * Constructs a new <code>FileTreeNode</code> representing the root node of a directory structure. Calling this * constructor will add <code>FileTreeNode</code> instances for all children of <code>file</code> to this * <code>FileTreeNode</code>. Equivalent to calling {@link #FileTreeNode(java.io.File, FileTreeNode)} with * <code>parent</code> <code>null</code>. * * @param file * the <code>File</code> to create a <code>FileTreeNode</code> structure for * * @throws IllegalArgumentException * if <code>file</code> is <code>null</code> or does not exist according to * {@link java.io.File#exists()} */ public FileTreeNode(File file) { this(file, null); } /** * Constructs a new <code>FileTreeNode</code>. Calling this constructor will add <code>FileTreeNode</code> * instances for all (filesystem) children of <code>file</code> to this <code>FileTreeNode</code>. * * @param file * the <code>File</code> to create a <code>FileTreeNode</code> structure for * @param parent * the parent <code>FileTreeNode</code> for this node, <code>null</code> for the root node of a tree * * @throws IllegalArgumentException * if <code>file</code> is <code>null</code> or does not exist according to * {@link java.io.File#exists()} */ public FileTreeNode(File file, FileTreeNode parent) { List<File> files; List<File> directories; File[] children; if (file == null || !file.exists()) { throw new IllegalArgumentException("Can not construct a FileTreeNode from null or a non-existent File."); } this.parent = parent; this.children = new ArrayList<>(); try { this.file = file.getCanonicalFile(); } catch (IOException e) { System.err.println("Could not convert " + file + " to a canonical file. Using absolute file instead."); this.file = file.getAbsoluteFile(); } if (!file.isFile()) { if ((children = file.listFiles()) != null) { files = new ArrayList<>(children.length); directories = new ArrayList<>(children.length); Arrays.sort(children); // sort by the natural ordering of File instances (this is filesystem dependant) for (File child : children) { if (child.isFile()) { files.add(child); } else { directories.add(child); } } directories.stream().map(f -> new FileTreeNode(f, this)).forEach(this.children::add); files.stream().map(f -> new FileTreeNode(f, this)).forEach(this.children::add); } } } /** * Returns the <code>File</code> this <code>FileTreeNode</code> represents. This <code>File</code> is not * guaranteed to be canonical (though it will be if there is no IOException when trying to canonicalize it) but * it will always be an absolute <code>File</code>. * * @return the canonical <code>File</code> */ public File getFile() { return file; } /** * Returns whether this <code>FileTreeNode</code> represents a files (as opposed to a directory). * * @return true iff this <code>FileTreeNode</code> represents a file */ public boolean isFile() { return file.isFile(); } /** * Returns the index of the given <code>child</code> in this <code>FileTreeNode</code>s children list. * * @param child * the child the get the index for * * @return the index, possibly -1 if <code>child</code> is not a child of this node */ public int getIndexOfChild(FileTreeNode child) { return children.indexOf(child); } /** * Returns the number of children this <code>FileTreeNode</code> has. * * @return the number of children */ public int getChildCount() { return children.size(); } /** * Returns an unmodifiable view of the children of this <code>FileTreeNode</code>. * * @return the children of this node */ public List<FileTreeNode> getChildren() { return Collections.unmodifiableList(children); } /** * Returns the child at the given index or <code>null</code> if the index is invalid. * * @param index * the index of the child * * @return the child <code>FileTreeNode</code> or <code>null</code> */ public FileTreeNode getChild(int index) { if (!(index < 0 || index >= getChildCount())) { return children.get(index); } else { return null; } } /** * Removes all children from this <code>FileTreeNode</code> and sets their parents to <code>null</code>. */ public void removeAllChildren() { children.forEach(child -> child.parent = null); children.clear(); } /** * Returns the parent <code>FileTreeNode</code> of this node. The root node of a tree has parent <code>null</code>. * * @return the parent of this node */ public FileTreeNode getParent() { return parent; } /** * Removes this node from its parent and sets its parent to <code>null</code>. Does nothing for the root node of a * tree. */ public void removeFromParent() { if (parent != null) { parent.children.remove(this); parent = null; } } /** * Returns the sub-tree with this node as root in preorder. * * @return the subtree in preorder */ public List<FileTreeNode> preOrder() { List<FileTreeNode> preOrderNodes = new ArrayList<>(); preOrderNodes.add(this); children.stream().map(FileTreeNode::preOrder).forEach(preOrderNodes::addAll); return preOrderNodes; } @Override public String toString() { return file.getName(); } }