Sunday, October 25, 2009

12.2 The File Chooser Package




I l@ve RuBoard










12.2 The File Chooser Package



Under
javax.swing, you'll
find a package of helper classes for the
JFileChooser. The
javax.swing.filechooser package contains several
classes for displaying and filtering files.




12.2.1 The FileFilter Class



The FileFilter class
can be used to create
filters for
JFileChooser dialogs. The class contains only two
abstract methods. It's important to note that
extensions are not the only way to judge a file's
fitness for a particular filter. The Mac filesystem, for example, can
understand the creator of a file regardless of the
file's name. On Unix systems, you might write a
filter to display only files that are readable by the current user.




12.2.1.1 Constructor



public FileFilter( )


The FileFilter class receives this default
constructor at compile time; it is not defined in the class itself.








12.2.1.2 Filter methods


public abstract boolean accept(File f)


Return true if file f matches
this filter. Note that you must explicitly accept directories
(f.isDirectory( ) == true) if you want to allow
the user to navigate into any subfolders.



public abstract String getDescription( )


Return a short description to appear in the filters pulldown on the
chooser. An example would be "Java Source
Code" for any .java files.





Figure 12-5 shows a file chooser with custom filters
for multimedia file types.




Figure 12-5. A custom set of filters for use with JFileChooser



Here's the code for the application. Before we make
this chooser visible, we create and insert the three new filters for
our media types. Other than that, it's pretty much
the same code as our previous applications. The Swing demos included
in the SDK provide access to a similar extension-based file filter
class. However, we use this example anyway, as it illustrates the
inner workings of a filter that should seem familiar to most
programmers.




// MyFilterChooser.java
// Just a simple example to see what it takes to make one of these filters work
//
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class MyFilterChooser extends JFrame {
public MyFilterChooser( ) {
super("Filter Test Frame");
setSize(350, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);

Container c = getContentPane( );
c.setLayout(new FlowLayout( ));

JButton openButton = new JButton("Open");
final JLabel statusbar = new JLabel("Output of your selection will go here");

openButton.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
String[] pics = new String[] {"gif", "jpg", "tif"};
String[] audios = new String[] {"au", "aiff", "wav"};
JFileChooser chooser = new JFileChooser( );
chooser.addChoosableFileFilter(new SimpleFileFilter(pics,
"Images (*.gif, *.jpg, *.tif)"));
chooser.addChoosableFileFilter(new SimpleFileFilter(".MOV"));
chooser.addChoosableFileFilter(new SimpleFileFilter(audios,
"Sounds (*.aiff, *.au, *.wav)"));
int option = chooser.showOpenDialog(MyFilterChooser.this);
if (option == JFileChooser.APPROVE_OPTION) {
if (chooser.getSelectedFile( )!=null)
statusbar.setText("You chose " + chooser.getSelectedFile( ).getName( ));
}
else {
statusbar.setText("You canceled.");
}
}
});

c.add(openButton);
c.add(statusbar);
setVisible(true);
}

public static void main(String args[]) {
MyFilterChooser mfc = new MyFilterChooser( );
}
}


Here's the implementation of the filter class. You
pass in an extension (or list of extensions) and a description of the
extension(s) to the constructor. If you don't supply
a description, the constructor builds a simple one for you based on
the extensions you passed in. The only real work this class does
happens in the accept( ) method, where we look to
see if the file presented matches one of the supplied extensions.



// SimpleFileFilter.java
// A straightforward, extension-based example of a file filter. This should be
// replaced by a "first class" Swing class in a later release of Swing.
//
import javax.swing.filechooser.*;
import java.io.File;

public class SimpleFileFilter extends FileFilter {

String[] extensions;
String description;

public SimpleFileFilter(String ext) {
this (new String[] {ext}, null);
}

public SimpleFileFilter(String[] exts, String descr) {
// Clone and lowercase the extensions
extensions = new String[exts.length];
for (int i = exts.length - 1; i >= 0; i--) {
extensions[i] = exts[i].toLowerCase( );
}
// Make sure we have a valid (if simplistic) description.
description = (descr == null ? exts[0] + " files" : descr);
}

public boolean accept(File f) {
// We always allow directories, regardless of their extensions.
if (f.isDirectory( )) { return true; }

// It's a regular file, so check the extension.
String name = f.getName( ).toLowerCase( );
for (int i = extensions.length - 1; i >= 0; i--) {
if (name.endsWith(extensions[i])) {
return true;
}
}
return false;
}

public String getDescription( ) { return description; }
}





12.2.2 The FileView Class



Another abstract helper class in the
javax.swing.filechooser package is the
FileView class. This class is implemented by the
various L&Fs to supply

icons and descriptions
for the basic file and folder entries in the filesystem. While each
L&F has a default implementation of this class, you can write
your own and attach it to a file chooser to supply custom icons and
descriptions for interesting types of files.




12.2.2.1 Constructor



public FileView( )


The FileView class has only this default
constructor.








12.2.2.2 Methods


All of the methods for the FileView class are
abstract and take one File as an argument. You
fill in these methods to present a clean, consistent view of all
files throughout the file chooser. Most custom views end up making
decisions based on file information, such as the
file's name or extension, before returning a result
from these methods.




public abstract String getName(File f)


Return the name of file f. While
it's quite easy to return f.getName( ), you might want to return an all-uppercase version or a
cross-platform, CD-ROM-compliant (ISO 9660) name, etc.



public abstract String getDescription(File f)


Return a description of the file. The description could be a short
abstract of the file's contents. Your file chooser
might not necessarily display this information.



public abstract String getTypeDescription(File f)


Return a description of the type of the file, such as
"Directory" or
"Bitmap Image."



public abstract Icon getIcon(File f)


Return an icon appropriate for file f. This could
be a folder icon, a file icon, or some specific icon based on other
file information, such as its extension.



public abstract boolean isTraversable(File f)


Answer questions about whether a directory can be opened. For
example, Unix and Windows NT/2000 can prevent users from accessing
directories for which they don't have permission.
You could check permissions and return false if
the user is not allowed to open a given folder. Rather than get an
error when trying to open the folder, the user
doesn't get the chance to try.





Figure 12-6 is an example of a custom
FileView that (slowly!) displays tiny
representations of any .gif or
.jpg files in the directory instead of the
generic icons. Since it loads the real image and scales it, rather
than storing some separate set of real icons, you
shouldn't try this on your collection of 5,000 JPEG
clip-art images. It's great for small directories,
though. This example also relies on the
MetalIconFactory, so it does not run (properly)
under other L&Fs. To avoid this problem, we force the use of the
Metal L&F in the main( ) method by setting the
swing.defaultlaf system property.




Figure 12-6. A custom file view for a file chooser that displays icons of image files



Following is the code for this particular file view. Look at the
getIcon( ) method. That's where
we decide which icon to return for a particular file. In this
implementation, we list all directories as traversable and return a
rather generic type description for our files. Notice that in the
getName( ) method we check for an empty string. On
Windows platforms, this empty string corresponds to one of the drive
letters. The "name" of the file is
empty, but the path contains the appropriate information, so we
return that. If you're curious about the
MetalIconFactory that we use to get the file and
folder icons, check out Chapter 26.



You might notice that we store a Component object
(rather than JComponent) as our image observer.
The reason for this is twofold. First, that's one
class the createImage( ) method is defined in.
Second, one obvious choice for the observer is the frame containing
the application, which is frequently a JFrame, and
JFrame does not descend from
JComponent.




// ThumbNailFileView.java
// A simple implementation of the FileView class that provides a 16 x 16 image of
// each GIF or JPG file for its icon. This could be SLOW for large images, as we
// simply load the real image and then scale it.
//
import java.io.File;
import java.awt.*;
import javax.swing.*;
import javax.swing.filechooser.*;
import javax.swing.plaf.metal.MetalIconFactory;

public class ThumbNailFileView extends FileView {

private Icon fileIcon = MetalIconFactory.getTreeLeafIcon( );
private Icon folderIcon = MetalIconFactory.getTreeFolderIcon( );
private Component observer;

public ThumbNailFileView(Component c) {
// We need a component to create our icon's image.
observer = c;
}

public String getDescription(File f) {
// We won't store individual descriptions, so just return the
// type description.
return getTypeDescription(f);
}

public Icon getIcon(File f) {
// Is it a folder?
if (f.isDirectory( )) { return folderIcon; }

// It's a file, so return a custom icon if it's an image file.
String name = f.getName( ).toLowerCase( );
if (name.endsWith(".jpg") || name.endsWith(".gif")) {
return new Icon16(f.getAbsolutePath( ));
}

// Return the generic file icon if it's not.
return fileIcon;
}

public String getName(File f) {
String name = f.getName( );
return name.equals("") ? f.getPath( ) : name;
}

public String getTypeDescription(File f) {
String name = f.getName( ).toLowerCase( );
if (f.isDirectory( )) { return "Folder"; }
if (name.endsWith(".jpg")) { return "JPEG Image"; }
if (name.endsWith(".gif")) { return "GIF Image"; }
return "Generic File";
}

public Boolean isTraversable(File f) {
// We'll mark all directories as traversable.
return f.isDirectory( ) ? Boolean.TRUE : Boolean.FALSE;
}

public class Icon16 extends ImageIcon {
public Icon16(String f) {
super(f);
Image i = observer.createImage(16, 16);
i.getGraphics( ).drawImage(getImage( ), 0, 0, 16, 16, observer);
setImage(i);
}

public int getIconHeight( ) { return 16; }
public int getIconWidth( ) { return 16; }

public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawImage(getImage( ), x, y, c);
}
}
}


Here's the application that uses this file view
implementation. The only real change from the previous applications
is in the properties we set for the chooser and our forced use of the
Metal L&F.



// MyViewChooser.java
// A simple example to see what it takes to make one of these FileViews work
//
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class MyViewChooser extends JFrame {
JFrame parent;
public MyViewChooser( ) {
super("File View Test Frame");
setSize(350, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
parent = this;

Container c = getContentPane( );
c.setLayout(new FlowLayout( ));

JButton openButton = new JButton("Open");
final JLabel statusbar = new JLabel("Output of your selection will go here");

openButton.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
JFileChooser chooser = new JFileChooser( );

// Set up our own file view for the chooser.
chooser.setFileView(new ThumbNailFileView(MyViewChooser.this));

int option = chooser.showOpenDialog(parent);
if (option == JFileChooser.APPROVE_OPTION) {
statusbar.setText("You chose " + chooser.getSelectedFile( ).getName( ));
}
else {
statusbar.setText("You cancelled.");
}
}
});

c.add(openButton);
c.add(statusbar);
}

public static void main(String args[]) {
System.setProperty("swing.defaultlaf",
"javax.swing.plaf.metal.MetalLookAndFeel");
MyViewChooser vc = new MyViewChooser( );
vc.setVisible(true);
}
}





12.2.3 The FileSystemView Class



Another
detail missing from the normal
FileChooser dialog is a system-independent way of
asking for a look at the entire filesystem. On Windows machines, for
example, there are several "root"
directories�one for each floppy drive, hard drive, CD drive,
etc. On Unix systems (which includes Mac
OS X), there is only one root directory, named
"/". The abstract
FileSystemView class is meant to be a source for
system-independent views that map nicely to the real filesystem
underneath your application. Currently, both Unix and Win32 systems
have real implementations, and others are planned for release. (MacOS
X relies on a Unix view of things.) Systems that do not have a full
implementation use a generic filesystem view, similar to what is
available through the standard java.io.File class.




12.2.3.1 Class instantiation method



public static FileSystemView getFileSystemView( )


The default implementation
checks the file separator character to decide which filesystem view
to return. A / returns a Unix view,
\ returns a Win32 view, and everything else gets
the generic view.








12.2.3.2 File and folder methods


If you
do plan to build your own filesystem view, the following methods are
the key pieces to look at:



public abstract File createNewFolder(File containingDir) throws IOException


Create a new folder with some default name appropriate to the
filesystem.



public File[] getFiles(File dir, boolean useFileHiding)


Return a list of all of the files in dir. If
useFileHiding is true, each
file in dir is checked with isHiddenFile( ) before being added to the list.



public File[] getRoots( )


Return a list of "root"
directories. On Unix or Mac OS X systems, this is the
/ directory. On Windows machines, this is a list
of the active drive letters. In OS X, secondary partitions (including
mounted removable media) are listed in the
/Volumes directory. Users are accustomed to
thinking of these as separate entities, so you might want to add your
own code to include them as separate
"roots."



public boolean isHiddenFile(File f)


Return true if file f is a
hidden file. What makes a file a hidden file differs from system to
system.



public boolean isRoot(File f)


Return true if file f maps
to a root directory.













    I l@ve RuBoard



    No comments:

    Post a Comment