Java Tips Weblog

  • Blog Stats

    • 1,256,954 hits
  • Categories

  • Archives

Single Root File Chooser

Posted by Rob Camick on January 28, 2009

The JFileChooser component allows a user to select a file from anywhere in the File System. The “Look In” combo box allows you to move around the File System easily to find the file you are looking for. However, there may be times when you want to restrict the user to searching a specific directory tree. Therefore, we need to control the entries displayed in the “Look In” combo box.

As the API says, FileSystemView is JFileChooser’s gateway to the file system. The SingleRootFileSystemView class is a customized view of the file system that lets the file chooser only see the files contained in the specified directory (and its sub directories). The “Look In” combo box will now only display the specifed directory, and its children as you navigate the directory tree. In addition, the “Up One Level” button on the file chooser will be disabled when viewing files at the specified root directory to prevent navigation to the parent of the directory.

To limit the file chooser to search the files in my Java JDK I used:

File root = new File("c:/java/jdk6.7");
FileSystemView fsv = new SingleRootFileSystemView( root );
JFileChooser chooser = new JFileChooser(fsv);

After selecting the “docs” directory, the file chooser would look like:

single-root-file-chooser

This class was designed to be used once. That is, if you ever need to change the root directory of the view you should create a new SingleRootFileSystemView class and a new JFileChooser. I recommend this approach because the setFileSystemView(…) does not work as expected. However, it appears that the following work around will allow you to dynamically change the file system view:


File root2 = new File("c:/java/blog");
FileSystemView fsv2 = new SingleRootFileSystemView( root2 );
chooser.setFileSystemView(fsv2);
chooser.updateUI();
chooser.setCurrentDirectory(root2);

I normally don’t ever recommend using the updateUI() method as this should only be used for a Look and Feel change. Use this approach at your own risk.

Get The Code

SingleRootFileSystemView.java

Related Reading

How to Use File Choosers

About these ads

7 Responses to “Single Root File Chooser”

  1. jon80 said

    Looks fine, however, I get a few squibbly error messages when utilizing the code as follows:

    import java.awt.*;
    import java.awt.event.*;
    import java.beans.*;
    import java.io.*;
    import javax.swing.*;
    import javax.swing.filechooser.*;
    import javax.swing.filechooser.FileFilter;
    
    /**
     * @version 1.23 2007-06-12
     * @author Cay Horstmann
     */
    public class FileChooserTest
    {
       public static void main(String[] args)
       {
          EventQueue.invokeLater(new Runnable()
             {
                public void run()
                {
                   ImageViewerFrame frame = new ImageViewerFrame();
                   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                   frame.setVisible(true);
                }
             });
       }
    }
    
    /**
     * A frame that has a menu for loading an image and a display area for the loaded image.
     */
    class ImageViewerFrame extends JFrame
    {
       public ImageViewerFrame()
       {
          setTitle("FileChooserTest");
          setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
    
          // set up menu bar
          JMenuBar menuBar = new JMenuBar();
          setJMenuBar(menuBar);
    
          JMenu menu = new JMenu("File");
          menuBar.add(menu);
    
          JMenuItem openItem = new JMenuItem("Open");
          menu.add(openItem);
          openItem.addActionListener(new FileOpenListener());
    
          JMenuItem exitItem = new JMenuItem("Exit");
          menu.add(exitItem);
          exitItem.addActionListener(new ActionListener()
             {
                public void actionPerformed(ActionEvent event)
                {
                   System.exit(0);
                }
             });
    
          // use a label to display the images
          label = new JLabel();
          add(label);
    
          // set up file chooser
          File root = new File (".");
          FileSystemView fsv = new SingleRootFileSystemView(root);
          chooser = new JFileChooser(fsv);
    
          // accept all image files ending with .jpg, .jpeg, .gif
          /*
          final ExtensionFileFilter filter = new ExtensionFileFilter();
          filter.addExtension("jpg");
          filter.addExtension("jpeg");
          filter.addExtension("gif");
          filter.setDescription("Image files");
          */
          FileNameExtensionFilter filter = new FileNameExtensionFilter("Image files", "jpg", "jpeg", "gif");
          chooser.setFileFilter(filter);
    
          chooser.setAccessory(new ImagePreviewer(chooser));
    
          chooser.setFileView(new FileIconView(filter, new ImageIcon("palette.gif")));
       }
    
       /**
        * This is the listener for the File->Open menu item.
        */
       private class FileOpenListener implements ActionListener
       {
          public void actionPerformed(ActionEvent event)
          {
             chooser.setCurrentDirectory(new File("."));
    
             // show file chooser dialog
             int result = chooser.showOpenDialog(ImageViewerFrame.this);
    
             // if image file accepted, set it as icon of the label
             if (result == JFileChooser.APPROVE_OPTION)
             {
                String name = chooser.getSelectedFile().getPath();
                label.setIcon(new ImageIcon(name));
             }
          }
       }
    
       public static final int DEFAULT_WIDTH = 300;
       public static final int DEFAULT_HEIGHT = 400;
    
       private JLabel label;
       private JFileChooser chooser;
    }
    
    /**
     * A file view that displays an icon for all files that match a file filter.
     */
    class FileIconView extends FileView
    {
       /**
        * Constructs a FileIconView.
        * @param aFilter a file filter--all files that this filter accepts will be shown with the icon.
        * @param anIcon--the icon shown with all accepted files.
        */
       public FileIconView(FileFilter aFilter, Icon anIcon)
       {
          filter = aFilter;
          icon = anIcon;
       }
    
       public Icon getIcon(File f)
       {
          if (!f.isDirectory() && filter.accept(f)) return icon;
          else return null;
       }
    
       private FileFilter filter;
       private Icon icon;
    }
    
    /**
     * A file chooser accessory that previews images.
     */
    class ImagePreviewer extends JLabel
    {
       /**
        * Constructs an ImagePreviewer.
        * @param chooser the file chooser whose property changes trigger an image change in this
        * previewer
        */
       public ImagePreviewer(JFileChooser chooser)
       {
          setPreferredSize(new Dimension(100, 100));
          setBorder(BorderFactory.createEtchedBorder());
    
          chooser.addPropertyChangeListener(new PropertyChangeListener()
             {
                public void propertyChange(PropertyChangeEvent event)
                {
                   if (event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)
                   {
                      // the user has selected a new file
                      File f = (File) event.getNewValue();
                      if (f == null)
                      {
                         setIcon(null);
                         return;
                      }
    
                      // read the image into an icon
                      ImageIcon icon = new ImageIcon(f.getPath());
    
                      // if the icon is too large to fit, scale it
                      if (icon.getIconWidth() > getWidth()) icon = new ImageIcon(icon.getImage()
                            .getScaledInstance(getWidth(), -1, Image.SCALE_DEFAULT));
    
                      setIcon(icon);
                   }
                }
             });
       }
    }
    Sourced from Core Java Vol 1, Chapter 9.
    
    import java.io.*;
    import javax.swing.filechooser.*;
    
    /**
     *  A FileSystemView class that limits the file selections to a single root.
     *
     *  When used with the JFileChooser component the user will only be able to
     *  traverse the directories contained within the specified root fill.
     *
     *  The "Look In" combo box will only display the specified root.
     *
     *  The "Up One Level" button will be disable when at the root.
     *
     */
    public class SingleRootFileSystemView extends FileSystemView
    {
    	File root;
    	File[] roots = new File[1];
    
    	public SingleRootFileSystemView(File root)
    	{
    		super();
    		this.root = root;
    		roots[0] = root;
    	}
    
    	@Override
    	public File createNewFolder(File containingDir)
    	{
    		File folder = new File(containingDir, "New Folder");
    		folder.mkdir();
    		return folder;
    	}
    
    	@Override
    	public File getDefaultDirectory()
    	{
    		return root;
    	}
    
    	@Override
    	public File getHomeDirectory()
    	{
    		return root;
    	}
    
    	@Override
    	public File[] getRoots()
    	{
    		return roots;
    	}
    }
    

    Error (cannot display it all):
    r2.java:418)
    at sun.awt.shell.Win32ShellFolder2$4.call(Win32ShellFolder2.java:389)
    at sun.awt.shell.Win32ShellFolder2$4.call(Win32ShellFolder2.java:385)
    at sun.awt.shell.Win32ShellFolderManager2$ComInvoker.invoke(Win32ShellFo
    lderManager2.java:523)
    at sun.awt.shell.ShellFolder.invoke(ShellFolder.java:399)
    at sun.awt.shell.ShellFolder.invoke(ShellFolder.java:385)
    at sun.awt.shell.Win32ShellFolder2.getIShellFolder(Win32ShellFolder2.jav
    a:384)
    at sun.awt.shell.Win32ShellFolder2.getParentIShellFolder(Win32ShellFolde
    r2.java:418)
    at sun.awt.shell.Win32ShellFolder2$4.call(Win32ShellFolder2.java:389)
    at sun.awt.shell.Win32ShellFolder2$4.call(Win32ShellFolder2.java:385)
    at sun.awt.shell.Win32ShellFolderManager2$ComInvoker.invoke(Win32ShellFo
    lderManager2.java:523)

    • Rob Camick said

      Code works fine for me. Maybe its a version or platform difference. One thing you can try changing:

      //File root = new File (".");
      File root = new File ("").getAbsoluteFile();

      And when you click the menu item you don’t need to set the current directory:

      //chooser.setCurrentDirectory(new File("."));

    • bonechilla said

      Yeah I had the same problem I found that if you want to start from a directory don’t bother with ./ just start from the path as though your in the base Directory and then use .getAbsoluteFile() and it should work

  2. thnks anyway…. work perfectly…. :)

  3. Jörg said

    Hello Rob,

    I just implemented your code in an existing application. Thank you very much.
    I only wondered why in my case the “Up One Level”-button was always enabled, thus making all the code futile.
    After an hour of testing in shutting down my code line by line,it turned out that it happened due to a “myFileChooser.updateUI()” – and I found no workaround. You may want to mention this fact in your description (and also that it’s no way to specify SingleRootFileSystemView AFTER (a parameter-less) creation of JFileChooser with myFileChooser.setFileSystemView(…)).

    Kind regards

    Jörg

    • Rob Camick said

      Jorg,

      As a general rule updateUI() should not be invoked manually on any component. If you use this method it is usually in indication of improper design. Swing will invoke this method automatically on a LAF change. Thanks for pointing out that the setFileSystemView() method does not work. I added some code for a workaround, although I recommend that this code should not be used. As I say any time you need to invoke updateUI() manually I think there is a problem.

      Rob

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 96 other followers

%d bloggers like this: