I am trying to build JTree based file browser and trying to navigate to particular path using setSelectionPath
with DefaultMutableTreeNode
.
I have taken the reference of the code from here
import java.io.File;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import static javax.management.Query.value;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileSysBrowser extends JFrame {
public JTree fileTree;
private FileSystemModel fileSystemModel;
static String REPO = "repo/dinesh/trunk";
static String[] REPO_PATH = REPO.split("/", -1);
static int repoPathIdx = 0;
private JTextArea fileDetailsTextArea = new JTextArea();
public FileSysBrowser(String directory) {
System.out.println(Arrays.toString(REPO_PATH));
setTitle("FileSysBrowser");
fileDetailsTextArea.setEditable(false);
fileSystemModel = new FileSystemModel(new File(directory));
fileTree = new JTree(fileSystemModel);
fileTree.setEditable(true);
fileTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent event) {
// System.out.println(fileTree.getLastSelectedPathComponent());
// File file = (File) fileTree.getLastSelectedPathComponent();
// fileDetailsTextArea.setText(getFileDetails(file));
}
});
getContentPane().add(new JScrollPane(fileTree));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setVisible(true);
}
private DefaultMutableTreeNode buildNodeFromString(String path) {
String[] s = path.split("/");
File myFilePath = new File(path);
DefaultMutableTreeNode node, lastNode = null, root = null;
for (String str : s) {
if (str.indexOf(":") != -1) {
str = str.substring(0, str.indexOf(":"));
}
node = new DefaultMutableTreeNode(str);
if (root == null) {
root = node;
}
if (lastNode != null) {
lastNode.add(node);
}
lastNode = node;
}
return root;
}
public static void main(String args[]) {
FileSysBrowser fileSysBrowser = new FileSysBrowser("/");
JTree jt = fileSysBrowser.fileTree;
// jt.expandRow(21);
// jt.expandRow(32);
// TreePath pathForRow = jt.getPathForRow(4);
// System.out.println(pathForRow);
DefaultMutableTreeNode node = fileSysBrowser.buildNodeFromString("repo/dinesh/trunk");
TreePath pathForRow = new TreePath(node.getLastLeaf().getPath());
System.out.println("pathForRow : " + pathForRow);
jt.setSelectionPath(pathForRow);
}
}
class FileSystemModel implements TreeModel {
private File root;
private final Vector listeners = new Vector();
public FileSystemModel(File rootDirectory) {
root = rootDirectory;
}
@Override
public Object getRoot() {
return root;
}
@Override
public Object getChild(Object parent, int index) {
File directory = (File) parent;
String[] children = directory.list();
Arrays.sort(children);
String currentChild = children[index];
return new TreeFile(directory, currentChild);
}
@Override
public int getChildCount(Object parent) {
File file = (File) parent;
if (file.isDirectory()) {
String[] fileList = file.list();
if (fileList != null) {
return file.list().length;
}
}
return 0;
}
@Override
public boolean isLeaf(Object node) {
if (node.getClass() == DefaultMutableTreeNode.class) {
DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) node;
System.out.println("chidcount ->" + dmtn.getChildCount());
System.out.println(dmtn.getChildCount()==0);
return dmtn.getChildCount() == 0;
} else {
File file = (File) node;
return file.isFile();
}
}
@Override
public int getIndexOfChild(Object parent, Object child) {
File directory = (File) parent;
File file = (File) child;
String[] children = directory.list();
for (int i = 0; i < children.length; i++) {
if (file.getName().equals(children[i])) {
return i;
}
}
return -1;
}
@Override
public void valueForPathChanged(TreePath path, Object value) {
File oldFile = (File) path.getLastPathComponent();
String fileParentPath = oldFile.getParent();
String newFileName = (String) value;
File targetFile = new File(fileParentPath, newFileName);
oldFile.renameTo(targetFile);
File parent = new File(fileParentPath);
int[] changedChildrenIndices = {getIndexOfChild(parent, targetFile)};
Object[] changedChildren = {targetFile};
fireTreeNodesChanged(path.getParentPath(), changedChildrenIndices, changedChildren);
}
private void fireTreeNodesChanged(TreePath parentPath, int[] indices, Object[] children) {
TreeModelEvent event = new TreeModelEvent(this, parentPath, indices, children);
Iterator iterator = listeners.iterator();
TreeModelListener listener = null;
while (iterator.hasNext()) {
listener = (TreeModelListener) iterator.next();
listener.treeNodesChanged(event);
}
}
@Override
public void addTreeModelListener(TreeModelListener listener) {
listeners.add(listener);
}
@Override
public void removeTreeModelListener(TreeModelListener listener) {
listeners.remove(listener);
}
private class TreeFile extends File {
public TreeFile(File parent, String child) {
super(parent, child);
}
@Override
public String toString() {
return getName();
}
}
}
I have just included check in the isLeaf
alone. As of now, it is not expanding the path.
With expandRow
only, I am able to achieve the node expansion.
What should I do to make it work with setSelectionPath
?
After exploring about TreeModel
, I found a solution. I have extended the DefaultMutableTreeNode
as FileMutuableTreeNode
and wherever DefaultMutableTreeNode
is used with TreeModel
, I have replaced it with FileMutuableTreeNode
. Hope it is useful for those who are reading this in near future.
The actual question is based on the below reference link.
FileSysBrowser.java
//Reference : http://www.javaprogrammingforums.com/java-swing-tutorials/7944-how-use-jtree-create-file-system-viewer-tree.html
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class FileSysBrowser extends JFrame {
public JTree fileTree;
private FileSystemModel fileSystemModel;
public FileSysBrowser(String directory) {
// System.out.println("REPO : " + Arrays.toString(REPO_PATH));
setTitle("FileSysBrowser");
fileSystemModel = new FileSystemModel(new FileMutableTreeNode(new File(directory)));
fileTree = new JTree(fileSystemModel);
fileTree.setEditable(false);
JPanel pnlMain = new JPanel(new BorderLayout(5, 5));
pnlMain.add(new JScrollPane(fileTree), BorderLayout.CENTER);
final JButton btn = new JButton("click");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Thread() {
@Override
public void run() {
btn.setEnabled(false);
expandNodePath("/repo/dinesh/trunk/Design/");
btn.setEnabled(true);
}
}.start();
}
});
pnlMain.add(btn, BorderLayout.PAGE_END);
getContentPane().add(pnlMain);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setVisible(true);
}
//Reference : https://stackoverflow.com/questions/8210630/how-to-search-a-particular-node-in-jtree-and-make-that-node-expanded
//Thanks to 'trashgod' for the answer
private FileMutableTreeNode findNode(FileMutableTreeNode root, String s) {
@SuppressWarnings("unchecked")
Enumeration<FileMutableTreeNode> e = root.depthFirstEnumeration();
while (e.hasMoreElements()) {
FileMutableTreeNode node = e.nextElement();
if (node.toString().equals(s)) {
// return new TreePath(node.getPath());
return node;
}
}
return null;
}
private void expandNodePath(String filePath) {
if(filePath.startsWith("/")) {
filePath = filePath.replaceFirst("/", "");
}
String[] files = filePath.split("/");
//Initializing the parent node as 'root'
FileMutableTreeNode parentNode = fileSystemModel.getRoot();
for (String file : files) {
FileMutableTreeNode childNode = findNode(parentNode, file);
fileTree.expandPath(new TreePath(childNode.getPath()));
// Then setting the current 'child' node as parent node
// for the next iteration
parentNode = childNode;
}
// The below code is what the expansion of above for loop code.
// For ease of understanding, I have kept it for others.
// FileMutableTreeNode repoNode = findNode(fileSystemModel.getRoot(), "repo");
// fileTree.expandPath(new TreePath(repoNode.getPath()));
// FileMutableTreeNode dineshNode = findNode(repoNode, "dinesh");
// fileTree.expandPath(new TreePath(dineshNode.getPath()));
}
public static void main(String args[]) {
// System.out.println(new File("/").getName());
FileSysBrowser fileSysBrowser = new FileSysBrowser("/");
JTree jt = fileSysBrowser.fileTree;
jt.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath tp = e.getNewLeadSelectionPath();
if (tp != null) {
System.out.println(tp);
// System.out.println(tp.getLastPathComponent());
}
}
});
}
}
class FileSystemModel implements TreeModel {
// private File root;
private FileMutableTreeNode root;
private final Vector listeners = new Vector();
public FileSystemModel(FileMutableTreeNode rootDirectory) {
root = rootDirectory;
}
@Override
public FileMutableTreeNode getRoot() {
return root;
}
@Override
public Object getChild(Object parent, int index) {
FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
File directory = parentNode.getFileNode();
String[] children = directory.list();
Arrays.sort(children);
String currentChild = children[index];
FileMutableTreeNode childNode = new FileMutableTreeNode(new File(directory, currentChild));
if (parentNode.toString().equals("/")) {
root.add(childNode);
} else {
parentNode.add(childNode);
}
return childNode;
}
@Override
public int getChildCount(Object parent) {
FileMutableTreeNode fileNode = (FileMutableTreeNode) parent;
File file = fileNode.getFileNode();
if (file.isDirectory()) {
String[] fileList = file.list();
if (fileList != null) {
return file.list().length;
}
}
return 0;
}
@Override
public boolean isLeaf(Object node) {
FileMutableTreeNode fileNode = (FileMutableTreeNode) node;
File file = fileNode.getFileNode();
return file.isFile();
}
@Override
public int getIndexOfChild(Object parent, Object child) {
FileMutableTreeNode parentNode = (FileMutableTreeNode) parent;
File directory = parentNode.getFileNode();
FileMutableTreeNode childNode = (FileMutableTreeNode) child;
File file = childNode.getFileNode();
String[] children = directory.list();
for (int i = 0; i < children.length; i++) {
if (file.getName().equals(children[i])) {
return i;
}
}
return -1;
}
@Override
public void valueForPathChanged(TreePath path, Object value) {
System.out.println("valueForPathChanged -> path : " + path + ", value : " + value);
}
@Override
public void addTreeModelListener(TreeModelListener listener) {
listeners.add(listener);
}
@Override
public void removeTreeModelListener(TreeModelListener listener) {
listeners.remove(listener);
}
}
FileMutableTreeNode .java
import java.io.File;
import javax.swing.tree.DefaultMutableTreeNode;
class FileMutableTreeNode extends DefaultMutableTreeNode {
private File fileNode = null;
public FileMutableTreeNode(File fileNode) {
this.fileNode = fileNode;
}
public File getFileNode() {
return fileNode;
}
@Override
public String toString() {
//For root, returning the name as '/'
if (fileNode.getAbsolutePath().equals("/")) {
return "/";
} else {
return fileNode.getName();
}
}
}