patternjavaMajor
File Browser GUI
Viewed 0 times
guifilebrowser
Problem
FileBro is a basic GUI based File Browser.
FileBro Functionality
Does the current functionality work as per above description?
FileBrowser.java
```
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Container;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.table.*;
import javax.swing.filechooser.FileSystemView;
import javax.imageio.ImageIO;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.nio.channels.FileChannel;
import java.net.URL;
/**
A basic File Browser. Requires 1.6+ for the Desktop & SwingWorker
classes, amongst other minor things.
Includes support classes FileTableModel & FileTreeCellRenderer.
@TODO Bugs
Fix keyboard focus issues - especially when functions like
rename/delete etc. are called that update nodes & file lists.
Needs more t
FileBro Functionality
- Directory tree - shows the file system roots at start-up, but is otherwise built lazily as the user browses around the file system. FileBro displays a progress bar as it is loading new entries.
- The file list (a table) displays a list of the directories and files in the current directory tree selection. Sort by clicking on the column header.
- Buttons - all use the
Desktopclass for their functionality. If the action cannot be completed, a meaningful reason should by displayed in aJEditorPaneerror message.
Locate- opens the parent directory of the currently selected file.
Open- launches whatever application is the default consumer for that file type.
Edit- opens the file for edit in the default consumer.
Print- prints the file using the default consumer.
- Details on the selected file are displayed below the buttons.
Does the current functionality work as per above description?
FileBrowser.java
```
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Container;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.table.*;
import javax.swing.filechooser.FileSystemView;
import javax.imageio.ImageIO;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.nio.channels.FileChannel;
import java.net.URL;
/**
A basic File Browser. Requires 1.6+ for the Desktop & SwingWorker
classes, amongst other minor things.
Includes support classes FileTableModel & FileTreeCellRenderer.
@TODO Bugs
Fix keyboard focus issues - especially when functions like
rename/delete etc. are called that update nodes & file lists.
Needs more t
Solution
This code concerns me:
as you're making Swing calls to a JProgressBar off of the EDT. Best to start the progress bar before the SwingWorker and end it in the done method. Either that or add a PropertyChangeListener to the SwingWorker and end the progress bar when the worker's state property is StateValue.DONE.
Another issue is that you're using a DefaultMutableTreeNode, and per the API, concurrency care must be taken when using this since you do appear to be using this in more than one thread:
This is not a thread safe class.If you intend to use a DefaultMutableTreeNode (or a tree of TreeNodes) in more than one thread, you need to do your own synchronizing. A good convention to adopt is synchronizing on the root node of a tree.
EDIT
One way to possibly get DefaultMutableTreeNode at least out of the equation is to add nodes to it in one thread only, the EDT, by using SwingWorker's publish/process. For example:
SwingWorker worker = new SwingWorker() {
@Override
public String doInBackground() {
tree.setEnabled(false);
progressBar.setVisible(true);
progressBar.setIndeterminate(true);
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true);
if (node.isLeaf()) {
for (File child : files) {
if (child.isDirectory()) {
node.add(new DefaultMutableTreeNode(child));
}
}
}
setTableData(files);
}
progressBar.setIndeterminate(false);
progressBar.setVisible(false);
tree.setEnabled(true);
return "done";
}
};
worker.execute();as you're making Swing calls to a JProgressBar off of the EDT. Best to start the progress bar before the SwingWorker and end it in the done method. Either that or add a PropertyChangeListener to the SwingWorker and end the progress bar when the worker's state property is StateValue.DONE.
Another issue is that you're using a DefaultMutableTreeNode, and per the API, concurrency care must be taken when using this since you do appear to be using this in more than one thread:
This is not a thread safe class.If you intend to use a DefaultMutableTreeNode (or a tree of TreeNodes) in more than one thread, you need to do your own synchronizing. A good convention to adopt is synchronizing on the root node of a tree.
EDIT
One way to possibly get DefaultMutableTreeNode at least out of the equation is to add nodes to it in one thread only, the EDT, by using SwingWorker's publish/process. For example:
private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
progressBar.setVisible(true);
progressBar.setIndeterminate(true);
SwingWorker worker = new SwingWorker() {
@Override
public Void doInBackground() {
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true); //!!
if (node.isLeaf()) {
for (File child : files) {
if (child.isDirectory()) {
publish(child);
}
}
}
setTableData(files);
}
return null;
}
@Override
protected void process(List chunks) {
for (File child : chunks) {
node.add(new DefaultMutableTreeNode(child));
}
}
@Override
protected void done() {
progressBar.setIndeterminate(false);
progressBar.setVisible(false);
tree.setEnabled(true);
}
};
worker.execute();
}Code Snippets
SwingWorker worker = new SwingWorker() {
@Override
public String doInBackground() {
tree.setEnabled(false);
progressBar.setVisible(true);
progressBar.setIndeterminate(true);
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true);
if (node.isLeaf()) {
for (File child : files) {
if (child.isDirectory()) {
node.add(new DefaultMutableTreeNode(child));
}
}
}
setTableData(files);
}
progressBar.setIndeterminate(false);
progressBar.setVisible(false);
tree.setEnabled(true);
return "done";
}
};
worker.execute();private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
progressBar.setVisible(true);
progressBar.setIndeterminate(true);
SwingWorker<Void, File> worker = new SwingWorker<Void, File>() {
@Override
public Void doInBackground() {
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true); //!!
if (node.isLeaf()) {
for (File child : files) {
if (child.isDirectory()) {
publish(child);
}
}
}
setTableData(files);
}
return null;
}
@Override
protected void process(List<File> chunks) {
for (File child : chunks) {
node.add(new DefaultMutableTreeNode(child));
}
}
@Override
protected void done() {
progressBar.setIndeterminate(false);
progressBar.setVisible(false);
tree.setEnabled(true);
}
};
worker.execute();
}Context
StackExchange Code Review Q#4446, answer score: 42
Revisions (0)
No revisions yet.