JDK-4322989 : Need Directory Chooser dialog
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.0,1.4.0,1.4.2
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2000-03-17
  • Updated: 2018-09-05
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
There are often cases where users are required to select a directory. Currently this functionality is supported using a customized version of the file chooser dialog. This is problematic because the appearance and behavior of the dialog do not make it clear that the thing to be selected is a directory, not a file.
For example the File Name and File Type fields are still visible. Also if the user double-clicks and opens the directory that they want the dialog will not close - they must move up a level in the hierarchy and select the directory when it is in the list.
This has caused a great deal of confusion in usability tests of the J2EE deploytool.

Comments
WORK AROUND The following class implements a tree based directory chooser. A main() method is provided as an example of usage. import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.File; import java.util.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.filechooser.FileSystemView; import javax.swing.tree.*; public class DirectoryChooser extends JTree implements TreeSelectionListener, MouseListener { private static FileSystemView fsv = FileSystemView.getFileSystemView(); /*--- Begin Public API -----*/ public DirectoryChooser() { this(null); } public DirectoryChooser(File dir) { super(new DirNode(fsv.getRoots()[0])); getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); setSelectedDirectory(dir); addTreeSelectionListener(this); addMouseListener(this); } public void setSelectedDirectory(File dir) { if (dir == null) { dir = fsv.getDefaultDirectory(); } setSelectionPath(mkPath(dir)); } public File getSelectedDirectory() { DirNode node = (DirNode)getLastSelectedPathComponent(); if (node != null) { File dir = node.getDir(); if (fsv.isFileSystem(dir)) { return dir; } } return null; } public void addActionListener(ActionListener l) { listenerList.add(ActionListener.class, l); } public void removeActionListener(ActionListener l) { listenerList.remove(ActionListener.class, l); } public ActionListener[] getActionListeners() { return (ActionListener[])listenerList.getListeners(ActionListener.class); } /*--- End Public API -----*/ /*--- TreeSelectionListener Interface -----*/ public void valueChanged(TreeSelectionEvent ev) { File oldDir = null; TreePath oldPath = ev.getOldLeadSelectionPath(); if (oldPath != null) { oldDir = ((DirNode)oldPath.getLastPathComponent()).getDir(); if (!fsv.isFileSystem(oldDir)) { oldDir = null; } } File newDir = getSelectedDirectory(); firePropertyChange("selectedDirectory", oldDir, newDir); } /*--- MouseListener Interface -----*/ public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { TreePath path = getPathForLocation(e.getX(), e.getY()); if (path != null && path.equals(getSelectionPath()) && getSelectedDirectory() != null) { fireActionPerformed("dirSelected", e); } } } public void mouseReleased(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} /*--- Private Section ------*/ private TreePath mkPath(File dir) { DirNode root = (DirNode)getModel().getRoot(); if (root.getDir().equals(dir)) { return new TreePath(root); } TreePath parentPath = mkPath(fsv.getParentDirectory(dir)); DirNode parentNode = (DirNode)parentPath.getLastPathComponent(); Enumeration enumeration = parentNode.children(); while (enumeration.hasMoreElements()) { DirNode child = (DirNode)enumeration.nextElement(); if (child.getDir().equals(dir)) { return parentPath.pathByAddingChild(child); } } return null; } private void fireActionPerformed(String command, InputEvent evt) { ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, command, evt.getWhen(), evt.getModifiers()); ActionListener[] listeners = getActionListeners(); for (int i = listeners.length - 1; i >= 0; i--) { listeners[i].actionPerformed(e); } } private static class DirNode extends DefaultMutableTreeNode { DirNode(File dir) { super(dir); } public File getDir() { return (File)userObject; } public int getChildCount() { populateChildren(); return super.getChildCount(); } public Enumeration children() { populateChildren(); return super.children(); } public boolean isLeaf() { return false; } private void populateChildren() { if (children == null) { File[] files = fsv.getFiles(getDir(), true); Arrays.sort(files); for (int i = 0; i < files.length; i++) { File f = files[i]; if (fsv.isTraversable(f).booleanValue()) { insert(new DirNode(f), (children == null) ? 0 : children.size()); } } } } public String toString() { return fsv.getSystemDisplayName(getDir()); } public boolean equals(Object o) { return (o instanceof DirNode && userObject.equals(((DirNode)o).userObject)); } } /*--- Main for testing ---*/ public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex) { } final JDialog dialog = new JDialog((JFrame)null, true); final DirectoryChooser dc = new DirectoryChooser(); final JButton okButton = new JButton("OK"); final JButton cancelButton = new JButton("Cancel"); dialog.getContentPane().add(new JScrollPane(dc), BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); buttonPanel.add(okButton); buttonPanel.add(cancelButton); dialog.getContentPane().add(buttonPanel, BorderLayout.SOUTH); ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { Object c = e.getSource(); if (c == okButton || c == dc) { System.out.println("You selected: "+dc.getSelectedDirectory()); } dialog.hide(); } }; dc.addActionListener(actionListener); okButton.addActionListener(actionListener); cancelButton.addActionListener(actionListener); dc.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { if (ev.getPropertyName().equals("selectedDirectory")) { okButton.setEnabled(dc.getSelectedDirectory() != null); } } }); dialog.setBounds(200, 200, 300, 350); dc.scrollRowToVisible(Math.max(0, dc.getMinSelectionRow()-4)); dialog.show(); System.exit(0); } } ###@###.### 2003-10-21
21-10-2003

EVALUATION Changing to rfe. Some of the usability issues have been solved with the fix to bug 4239219. leif.samuelsson@Eng 2000-11-14
14-11-2000