001    /* JFileChooser.java --
002       Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.swing;
039    
040    import java.awt.Component;
041    import java.awt.Frame;
042    import java.awt.GraphicsEnvironment;
043    import java.awt.HeadlessException;
044    import java.awt.event.ActionEvent;
045    import java.awt.event.ActionListener;
046    import java.awt.event.WindowEvent;
047    import java.awt.event.WindowAdapter;
048    import java.beans.PropertyChangeEvent;
049    import java.io.File;
050    import java.util.ArrayList;
051    
052    import javax.accessibility.Accessible;
053    import javax.accessibility.AccessibleContext;
054    import javax.accessibility.AccessibleRole;
055    import javax.swing.filechooser.FileFilter;
056    import javax.swing.filechooser.FileSystemView;
057    import javax.swing.filechooser.FileView;
058    import javax.swing.plaf.FileChooserUI;
059    
060    
061    /**
062     * A component that provides the user a dialog box to browse through a
063     * filesystem and choose one or more files or directories.
064     *
065     * A JFileChooser can be configured to filter the displayed file list
066     * by adding a {@link FileFilter} instance using
067     * {@link #addChoosableFileFilter(FileFilter)}. Additional components can
068     * be embedded in the file chooser using {@link #setAccessory(JComponent)}.
069     * The JFileChooser properties also provide mechanisms to customize the
070     * behaviour of the file chooser.
071     *
072     * @author Kim Ho (kho@luxsci.net)
073     */
074    public class JFileChooser extends JComponent implements Accessible
075    {
076      private static final long serialVersionUID = 3162921138695327837L;
077    
078      /** 
079       * A dialog type for selecting a file to open. 
080       * @see #setDialogType(int)
081       */
082      public static final int OPEN_DIALOG = 0;
083    
084      /** 
085       * A dialog type for selecting a file to save.  
086       * @see #setDialogType(int)
087       */
088      public static final int SAVE_DIALOG = 1;
089    
090      /** 
091       * A dialog type for some custom purpose.
092       * @see #setDialogType(int)
093       */
094      public static final int CUSTOM_DIALOG = 2;
095    
096      /** 
097       * A return value indicating the file chooser has been closed by cancelling.
098       * 
099       * @see #showOpenDialog(Component)
100       * @see #showSaveDialog(Component) 
101       */
102      public static final int CANCEL_OPTION = 1;
103    
104      /** 
105       * A return value indicating the file chooser has been closed by approving
106       * the selection.
107       * @see #showOpenDialog(Component)
108       * @see #showSaveDialog(Component) 
109       */
110      public static final int APPROVE_OPTION = 0;
111    
112      /** 
113       * A return value indicating the file chooser has been closed by some error.
114       * @see #showOpenDialog(Component)
115       * @see #showSaveDialog(Component) 
116       */
117      public static final int ERROR_OPTION = -1;
118    
119      /** 
120       * A selection mode constant indicating acceptance of files only.
121       * @see #setFileSelectionMode(int)
122       */
123      public static final int FILES_ONLY = 0;
124    
125      /** 
126       * A selection mode constant indicating acceptance of directories only. 
127       * @see #setFileSelectionMode(int)
128       */
129      public static final int DIRECTORIES_ONLY = 1;
130    
131      /** 
132       * A selection mode constant indicating acceptance of files and directories.
133       * @see #setFileSelectionMode(int)
134       */
135      public static final int FILES_AND_DIRECTORIES = 2;
136    
137      /** 
138       * Action command string for cancelling the current selection.
139       * @see #cancelSelection()
140       */
141      public static final String CANCEL_SELECTION = "CancelSelection";
142    
143      /** 
144       * Action command string for approving the current selection.
145       * @see #cancelSelection()
146       */
147      public static final String APPROVE_SELECTION = "ApproveSelection";
148    
149      /**
150       * The name of the property for the approve button text.
151       * @see #setApproveButtonText(String) 
152       */
153      public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY =
154        "ApproveButtonTextChangedProperty";
155    
156      /**
157       * The name of the property for the approve button tool tip text.
158       * @see #setApproveButtonToolTipText(String)
159       */
160      public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY =
161        "ApproveButtonToolTipTextChangedProperty";
162    
163      /**
164       * The name of the property for the approve button mnemonic.
165       * @see #setApproveButtonMnemonic(int)
166       */
167      public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY =
168        "ApproveButtonMnemonicChangedProperty";
169    
170      /**
171       * The name of the property for control button visibility.
172       * @see #setControlButtonsAreShown(boolean)
173       */
174      public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY =
175        "ControlButtonsAreShownChangedProperty";
176    
177      /**
178       * The name of the property for the current directory.
179       * @see #setCurrentDirectory(File)  
180       */
181      public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";
182    
183      /**
184       * The name of the property for the selected file.
185       * @see #setSelectedFile(File)
186       */
187      public static final String SELECTED_FILE_CHANGED_PROPERTY =
188        "SelectedFileChangedProperty";
189    
190      /**
191       * The name of the property for the selected files.
192       * @see #setSelectedFiles(File[])
193       */
194      public static final String SELECTED_FILES_CHANGED_PROPERTY =
195        "SelectedFilesChangedProperty";
196    
197      /** 
198       * The name of the property for multi-selection.
199       * @see #setMultiSelectionEnabled(boolean) 
200       */
201      public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY =
202        "MultiSelectionEnabledChangedProperty";
203    
204      /**
205       * The name of the 'file system view' property.
206       * @see #setFileSystemView(FileSystemView) 
207       */
208      public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY =
209        "FileSystemViewChanged";
210    
211      /**
212       * The name of the 'file view' property.
213       * @see #setFileView(FileView) 
214       */
215      public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";
216    
217      /**
218       * The name of the 'file hiding enabled' property.
219       * @see #setFileHidingEnabled(boolean)
220       */
221      public static final String FILE_HIDING_CHANGED_PROPERTY =
222        "FileHidingChanged";
223    
224      /**
225       * The name of the 'file filter' property.
226       * @see #setFileFilter(FileFilter)
227       */
228      public static final String FILE_FILTER_CHANGED_PROPERTY =
229        "fileFilterChanged";
230    
231      /**
232       * The name of the 'file selection mode' property.
233       * @see #setFileSelectionMode(int)
234       */
235      public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY =
236        "fileSelectionChanged";
237    
238      /**
239       * The name of the 'accessory' property.
240       * @see #setAccessory(JComponent)
241       */
242      public static final String ACCESSORY_CHANGED_PROPERTY =
243        "AccessoryChangedProperty";
244    
245      /**
246       * The name of the 'accept all file filter used' property.
247       * @see #setAcceptAllFileFilterUsed(boolean)
248       */
249      public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY =
250        "acceptAllFileFilterUsedChanged";
251    
252      /**
253       * The name of the 'dialog title' property.
254       * @see #setDialogTitle(String)
255       */
256      public static final String DIALOG_TITLE_CHANGED_PROPERTY =
257        "DialogTitleChangedProperty";
258    
259      /**
260       * The name of the 'dialog type' property.
261       * @see #setDialogType(int)
262       */
263      public static final String DIALOG_TYPE_CHANGED_PROPERTY =
264        "DialogTypeChangedProperty";
265    
266      /**
267       * The name of the 'choosable file filters' property.
268       * @see #addChoosableFileFilter(FileFilter)
269       */
270      public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY =
271        "ChoosableFileFilterChangedProperty";
272    
273      /** 
274       * The accessible context. 
275       * @see #getAccessibleContext()
276       */
277      protected AccessibleContext accessibleContext;
278    
279      /** 
280       * The file system view.
281       * @see #setFileSystemView(FileSystemView)
282       */
283      private FileSystemView fsv;
284    
285      /**
286       * The accessory component.
287       * @see #setAccessory(JComponent)
288       */
289      private JComponent accessory;
290    
291      /**
292       * The approve button mnemonic.
293       * @see #setApproveButtonMnemonic(int)
294       */
295      private int approveButtonMnemonic = 0;
296    
297      /**
298       * The approve button text.
299       * @see #setApproveButtonText(String)
300       */
301      private String approveButtonText;
302    
303      /**
304       * The approve button tool tip text.
305       * @see #setApproveButtonToolTipText(String)
306       */
307      private String approveButtonToolTipText;
308    
309      /**
310       * The choosable file filters.
311       * @see #addChoosableFileFilter(FileFilter)
312       */
313      private ArrayList choosableFilters = new ArrayList();
314    
315      /**
316       * A flag controlling whether the accept all file filter is used.
317       * @see #setAcceptAllFileFilterUsed(boolean)
318       */
319      private boolean isAcceptAll = true;
320    
321      /**
322       * The dialog title.
323       * @see #setDialogTitle(String)
324       */
325      private String dialogTitle;
326    
327      /**
328       * The dialog type.
329       * @see #setDialogType(int)
330       */
331      private int dialogType = OPEN_DIALOG;
332    
333      /**
334       * The return value for the dialog.
335       * @see #showOpenDialog(Component)
336       * @see #showSaveDialog(Component)
337       */
338      private int retval = ERROR_OPTION;
339    
340      /**
341       * A flag indicating whether the file chooser allows multiple selection.
342       * @see #isMultiSelectionEnabled()
343       */
344      private boolean multiSelection = false;
345    
346      /**
347       * A flag indicating whether file hiding is enabled.
348       * @see #isFileHidingEnabled()
349       */
350      private boolean fileHiding = true;
351    
352      /**
353       * The file selection mode.
354       * @see #setFileSelectionMode(int) 
355       */
356      private int fileSelectionMode = FILES_ONLY;
357    
358      /** 
359       * The file view.
360       * @see #setFileView(FileView)
361       */
362      private FileView fv = null;
363    
364      /** 
365       * A flag controlling whether or not the control buttons are visible. 
366       * @see #setControlButtonsAreShown(boolean) 
367       */
368      private boolean controlButtonsShown = true;
369    
370      /** 
371       * The current directory. 
372       * @see #setCurrentDirectory(File)
373       */
374      private File currentDir = null;
375    
376      /** 
377       * The current file filter.
378       * @see #setFileFilter(FileFilter)
379       */
380      private FileFilter currentFilter = null;
381    
382      /** 
383       * An array of selected files.
384       * @see #setSelectedFiles(File[]) 
385       */
386      private File[] selectedFiles;
387    
388      /** 
389       * The selected file. 
390       * @see #setSelectedFile(File)
391       */
392      private File selectedFile;
393      
394      /**
395       * The drag enabled property.
396       * @see #setDragEnabled(boolean)
397       * @see #getDragEnabled()
398       */
399      private boolean dragEnabled;
400    
401      /**
402       * Creates a new <code>JFileChooser</code> object.
403       */
404      public JFileChooser()
405      {
406        setup(null);
407        setCurrentDirectory(null);
408      }
409    
410      /**
411       * Creates a new <code>JFileChooser</code> object.
412       *
413       * @param currentDirectoryPath the directory that should initially be
414       *        shown in the filechooser (if <code>null</code>, the user's home 
415       *        directory is used).
416       */
417      public JFileChooser(String currentDirectoryPath)
418      {
419        this(currentDirectoryPath, null);
420      }
421    
422      /**
423       * Creates a new <code>JFileChooser</code> object with the specified 
424       * directory and {@link FileSystemView}.
425       *
426       * @param currentDirectoryPath  the directory that should initially be
427       *        shown in the filechooser (if <code>null</code>, the user's home 
428       *        directory is used).
429       * @param fsv  the file system view (if <code>null</code>, the default file
430       *             system view is used).
431       */
432      public JFileChooser(String currentDirectoryPath, FileSystemView fsv)
433      {
434        setup(fsv);
435        File dir = null;
436        if (currentDirectoryPath != null)
437          dir = getFileSystemView().createFileObject(currentDirectoryPath);
438        setCurrentDirectory(dir);
439      }
440    
441      /**
442       * Creates a new <code>JFileChooser</code> object.
443       *
444       * @param currentDirectory  the directory that should initially be
445       *        shown in the filechooser (if <code>null</code>, the user's home 
446       *        directory is used).
447       */
448      public JFileChooser(File currentDirectory)
449      {
450        setup(null);
451        setCurrentDirectory(currentDirectory);
452      }
453    
454      /**
455       * Creates a new <code>JFileChooser</code> object.
456       *
457       * @param fsv  the file system view (if <code>null</code>, the default file
458       *             system view is used).
459       */
460      public JFileChooser(FileSystemView fsv)
461      {
462        setup(fsv);
463        setCurrentDirectory(null);
464      }
465    
466      /**
467       * Creates a new <code>JFileChooser</code> object.
468       *
469       * @param currentDirectory  the directory that should initially be
470       *        shown in the filechooser (if <code>null</code>, the user's home 
471       *        directory is used).
472       * @param fsv  the file system view (if <code>null</code>, the default file
473       *             system view is used).
474       */
475      public JFileChooser(File currentDirectory, FileSystemView fsv)
476      {
477        setup(fsv);
478        setCurrentDirectory(currentDirectory);
479      }
480    
481      /**
482       * Sets up the file chooser.  This method is called by all the constructors.
483       *
484       * @param view  the file system view (if <code>null</code>, the default file
485       *              system view is used).
486       * 
487       * @see FileSystemView#getFileSystemView()
488       */
489      protected void setup(FileSystemView view)
490      {
491        if (view == null)
492          view = FileSystemView.getFileSystemView();
493        setFileSystemView(view);
494        updateUI();
495      }
496    
497      /**
498       * Sets the dragEnabled property, this disables/enables automatic drag
499       * handling (drag and drop) on this component. The default value of the
500       * dragEnabled property is false. 
501       * 
502       * Some look and feels might not support automatic drag and drop; they
503       * will ignore this property.
504       * 
505       * @param b - the new dragEnabled value
506       */
507      public void setDragEnabled(boolean b)
508      {
509        if (b && GraphicsEnvironment.isHeadless())
510          throw new HeadlessException();
511        
512        dragEnabled = b;
513      }
514    
515      /**
516       * Returns true if dragging is enabled.
517       *
518       * @return true if dragging is enabled.
519       */
520      public boolean getDragEnabled()
521      {
522        return dragEnabled;
523      }
524    
525      /**
526       * Returns the selected file, if there is one.
527       *
528       * @return The selected file (possibly <code>null</code>).
529       * 
530       * @see #setSelectedFile(File)
531       */
532      public File getSelectedFile()
533      {
534        return selectedFile;
535      }
536    
537      /**
538       * Sets the selected file and sends a {@link PropertyChangeEvent} to all
539       * registered listeners.  The property name is 
540       * {@link #SELECTED_FILE_CHANGED_PROPERTY}.
541       *
542       * @param file  the file (<code>null</code> permitted).
543       */
544      public void setSelectedFile(File file)
545      {
546        if (selectedFile == null || !selectedFile.equals(file))
547          {
548            File old = selectedFile;
549            selectedFile = file;
550            firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, old, selectedFile);
551          }
552      }
553    
554      /**
555       * Returns the selected file or files in an array.  If no files are selected,
556       * an empty array is returned.
557       *
558       * @return An array of the selected files (possibly empty).
559       */
560      public File[] getSelectedFiles()
561      {
562        if (selectedFiles != null)
563          return selectedFiles;
564        if (selectedFile != null)
565          return new File[] { selectedFile };
566        return new File[0];
567      }
568    
569      /**
570       * Sets the selected files and sends a {@link PropertyChangeEvent} (with the 
571       * name {@link #SELECTED_FILES_CHANGED_PROPERTY}) to all registered 
572       * listeners.  
573       *
574       * @param selectedFiles  the selected files (<code>null</code> permitted).
575       */
576      public void setSelectedFiles(File[] selectedFiles)
577      {
578        if (selectedFiles == null)
579          selectedFiles = new File[0];
580        if (selectedFiles.length > 0)
581          setSelectedFile(selectedFiles[0]);
582        else
583          setSelectedFile(null);
584        if (this.selectedFiles != selectedFiles)
585          {
586            File[] old = this.selectedFiles;
587            this.selectedFiles = selectedFiles;
588            firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, old, selectedFiles);
589          }
590    
591      }
592    
593      /**
594       * Returns the current directory.
595       *
596       * @return The current directory.
597       */
598      public File getCurrentDirectory()
599      {
600        return currentDir;
601      }
602    
603      /**
604       * Sets the current directory and fires a {@link PropertyChangeEvent} (with 
605       * the property name {@link #DIRECTORY_CHANGED_PROPERTY}) to all registered 
606       * listeners.  If <code>dir</code> is <code>null</code>, the current 
607       * directory is set to the default directory returned by the file system
608       * view.
609       *
610       * @param dir  the new directory (<code>null</code> permitted).
611       * 
612       * @see FileSystemView#getDefaultDirectory()
613       */
614      public void setCurrentDirectory(File dir)
615      {
616        if (currentDir != dir || dir == null)
617          {
618            if (dir == null)
619              dir = fsv.getDefaultDirectory();
620    
621            File old = currentDir;
622            currentDir = dir;
623            firePropertyChange(DIRECTORY_CHANGED_PROPERTY, old, currentDir);
624          }
625      }
626    
627      /**
628       * Called by the UI delegate when the parent directory is changed.
629       */
630      public void changeToParentDirectory()
631      {
632        setCurrentDirectory(fsv.getParentDirectory(currentDir));
633      }
634    
635      /**
636       * Rescans the current directory (this is handled by the UI delegate).
637       */
638      public void rescanCurrentDirectory()
639      {
640        getUI().rescanCurrentDirectory(this);
641      }
642    
643      /**
644       * Ensures the the specified file is visible (this is handled by the 
645       * UI delegate).
646       *
647       * @param f  the file.
648       */
649      public void ensureFileIsVisible(File f)
650      {
651        getUI().ensureFileIsVisible(this, f);
652      }
653    
654      /**
655       * Displays the file chooser in a modal dialog using the 
656       * {@link #OPEN_DIALOG} type.
657       *
658       * @param parent  the parent component.
659       *
660       * @return A return value indicating how the dialog was closed (one of 
661       *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
662       *         {@link #ERROR_OPTION}).
663       *
664       * @throws HeadlessException DOCUMENT ME!
665       */
666      public int showOpenDialog(Component parent) throws HeadlessException
667      {
668        JDialog d = createDialog(parent);
669    
670        // FIXME: Remove when we get ancestor property
671        d.setTitle("Open");
672        setDialogType(OPEN_DIALOG);
673    
674        retval = ERROR_OPTION;
675    
676        d.pack();
677        d.show();
678        return retval;
679      }
680    
681      /**
682       * Displays the file chooser in a modal dialog using the 
683       * {@link #SAVE_DIALOG} type.
684       *
685       * @param parent  the parent component.
686       *
687       * @return A return value indicating how the dialog was closed (one of 
688       *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
689       *         {@link #ERROR_OPTION}).
690       *
691       * @throws HeadlessException DOCUMENT ME!
692       */
693      public int showSaveDialog(Component parent) throws HeadlessException
694      {
695        JDialog d = createDialog(parent);
696        setDialogType(SAVE_DIALOG);
697    
698        retval = ERROR_OPTION;
699    
700        d.pack();
701        d.show();
702        return retval;
703      }
704    
705      /**
706       * Displays the file chooser in a modal dialog using the 
707       * {@link #CUSTOM_DIALOG} type.
708       *
709       * @param parent  the parent component.
710       *
711       * @return A return value indicating how the dialog was closed (one of 
712       *         {@link #APPROVE_OPTION}, {@link #CANCEL_OPTION} and 
713       *         {@link #ERROR_OPTION}).
714       *
715       * @throws HeadlessException DOCUMENT ME!
716       */
717      public int showDialog(Component parent, String approveButtonText)
718                     throws HeadlessException
719      {
720        JDialog d = createDialog(parent);
721        setApproveButtonText(approveButtonText);
722        setDialogType(CUSTOM_DIALOG);
723    
724        retval = ERROR_OPTION;
725    
726        d.pack();
727        d.show();
728        return retval;
729      }
730    
731      /**
732       * Creates a modal dialog in which to display the file chooser.
733       *
734       * @param parent  the parent component.
735       *
736       * @return The dialog.
737       *
738       * @throws HeadlessException DOCUMENT ME!
739       */
740      protected JDialog createDialog(Component parent) throws HeadlessException
741      {
742        Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent);
743        if (toUse == null)
744          toUse = (Frame) SwingUtilities.getOwnerFrame(null);
745    
746        JDialog dialog = new JDialog(toUse);
747        setSelectedFile(null);
748        dialog.getContentPane().add(this);
749        dialog.addWindowListener( new WindowAdapter()
750          {
751            public void windowClosing(WindowEvent e)
752            {
753              cancelSelection();
754            }
755          });
756        dialog.setModal(true);
757        dialog.invalidate();
758        dialog.repaint();
759        return dialog;
760      }
761    
762      /**
763       * Returns the flag that controls whether or not the control buttons are
764       * shown on the file chooser.
765       *
766       * @return A boolean.
767       * 
768       * @see #setControlButtonsAreShown(boolean)
769       */
770      public boolean getControlButtonsAreShown()
771      {
772        return controlButtonsShown;
773      }
774    
775      /**
776       * Sets the flag that controls whether or not the control buttons are
777       * shown and, if it changes, sends a {@link PropertyChangeEvent} (with the
778       * property name {@link #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY}) to
779       * all registered listeners.
780       *
781       * @param b  the new value for the flag.
782       */
783      public void setControlButtonsAreShown(boolean b)
784      {
785        if (controlButtonsShown != b)
786          {
787            controlButtonsShown = b;
788            firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY,
789                               ! controlButtonsShown, controlButtonsShown);
790          }
791      }
792    
793      /**
794       * Returns the type of file chooser.
795       *
796       * @return {@link #OPEN_DIALOG}, {@link #SAVE_DIALOG} or 
797       * {@link #CUSTOM_DIALOG}.
798       * 
799       * @see #setDialogType(int)
800       */
801      public int getDialogType()
802      {
803        return dialogType;
804      }
805    
806      /**
807       * Sets the dialog type and fires a {@link PropertyChangeEvent} (with the
808       * property name {@link #DIALOG_TYPE_CHANGED_PROPERTY}) to all 
809       * registered listeners.
810       *
811       * @param dialogType  the dialog type (one of: {@link #OPEN_DIALOG},
812       * {@link #SAVE_DIALOG}, {@link #CUSTOM_DIALOG}).
813       * 
814       * @throws IllegalArgumentException if <code>dialogType</code> is not valid.
815       */
816      public void setDialogType(int dialogType)
817      {
818        if (dialogType != OPEN_DIALOG && dialogType != SAVE_DIALOG
819            && dialogType != CUSTOM_DIALOG)
820          throw new IllegalArgumentException("Choose allowable dialogType.");
821    
822        if (this.dialogType != dialogType)
823          {
824            int old = this.dialogType;
825            this.dialogType = dialogType;
826            firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, old, this.dialogType);
827          }
828      }
829    
830      /**
831       * Sets the dialog title and sends a {@link PropertyChangeEvent} (with the 
832       * property name {@link #DIALOG_TITLE_CHANGED_PROPERTY}) to all 
833       * registered listeners.
834       *
835       * @param dialogTitle  the dialog title (<code>null</code> permitted).
836       * 
837       * @see #getDialogTitle()
838       */
839      public void setDialogTitle(String dialogTitle)
840      {
841        if (this.dialogTitle != dialogTitle)
842          {
843            String old = this.dialogTitle;
844            this.dialogTitle = dialogTitle;
845            firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, old, this.dialogTitle);
846          }
847      }
848    
849      /**
850       * Returns the dialog title.
851       *
852       * @return The dialog title (possibly <code>null</code>).
853       * 
854       * @see #setDialogTitle(String)
855       */
856      public String getDialogTitle()
857      {
858        return dialogTitle;
859      }
860    
861      /**
862       * Sets the tool tip text for the approve button and sends a 
863       * {@link PropertyChangeEvent} (with the property name
864       * {@link #APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY}) to all 
865       * registered listeners.
866       *
867       * @param toolTipText  the text.
868       */
869      public void setApproveButtonToolTipText(String toolTipText)
870      {
871        if (approveButtonToolTipText != toolTipText)
872          {
873            String oldText = approveButtonToolTipText;
874            approveButtonToolTipText = toolTipText;
875            firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY,
876                               oldText, approveButtonToolTipText);
877          }
878      }
879    
880      /**
881       * Returns the tool tip text for the approve button.
882       *
883       * @return The tool tip text for the approve button.
884       * 
885       * @see #setApproveButtonToolTipText(String)
886       */
887      public String getApproveButtonToolTipText()
888      {
889        return approveButtonToolTipText;
890      }
891    
892      /**
893       * Returns the approve button mnemonic, or zero if no mnemonic has been set.
894       *
895       * @return The approve button mnemonic.
896       * 
897       * @see #setApproveButtonMnemonic(int)
898       */
899      public int getApproveButtonMnemonic()
900      {
901        return approveButtonMnemonic;
902      }
903    
904      /**
905       * Sets the mnemonic for the approve button and sends a 
906       * {@link PropertyChangeEvent} (with the property name 
907       * {@link #APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY}) to all registered 
908       * listeners.
909       *
910       * @param mnemonic  the mnemonic.
911       * 
912       * @see #setApproveButtonMnemonic(char)
913       */
914      public void setApproveButtonMnemonic(int mnemonic)
915      {
916        if (approveButtonMnemonic != mnemonic)
917          {
918            int oldMnemonic = approveButtonMnemonic;
919            approveButtonMnemonic = mnemonic;
920            firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY,
921                               oldMnemonic, approveButtonMnemonic);
922          }
923      }
924    
925      /**
926       * Sets the mnemonic for the approve button and sends a 
927       * {@link PropertyChangeEvent} (with the property name 
928       * {@link #APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY}) to all registered 
929       * listeners.
930       *
931       * @param mnemonic  the mnemonic.
932       * 
933       * @see #setApproveButtonMnemonic(int)
934       */
935      public void setApproveButtonMnemonic(char mnemonic)
936      {
937        setApproveButtonMnemonic((int) Character.toUpperCase(mnemonic));
938      }
939    
940      /**
941       * Sets the approve button text and fires a {@link PropertyChangeEvent} 
942       * (with the property name {@link #APPROVE_BUTTON_TEXT_CHANGED_PROPERTY}) to 
943       * all registered listeners.
944       *
945       * @param approveButtonText  the text (<code>null</code> permitted).
946       * 
947       * @see #getApproveButtonText()
948       */
949      public void setApproveButtonText(String approveButtonText)
950      {
951        if (this.approveButtonText != approveButtonText)
952          {
953            String oldText = this.approveButtonText;
954            this.approveButtonText = approveButtonText;
955            firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldText,
956                               this.approveButtonText);
957          }
958      }
959    
960      /**
961       * Returns the approve button text.
962       *
963       * @return The approve button text (possibly <code>null</code>).
964       * 
965       * @see #setApproveButtonText(String)
966       */
967      public String getApproveButtonText()
968      {
969        return approveButtonText;
970      }
971    
972      /**
973       * Returns the available file filters for this file chooser.
974       *
975       * @return The available file filters.
976       */
977      public FileFilter[] getChoosableFileFilters()
978      {
979        return (FileFilter[]) choosableFilters.toArray(new FileFilter[choosableFilters.size()]);
980      }
981    
982      /**
983       * Adds a file filter to the list of available filters and sends a 
984       * {@link PropertyChangeEvent} (with the property name 
985       * {@link #CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY}) to all registered 
986       * listeners.
987       *
988       * @param filter  the filter (<code>null</code> permitted).
989       */
990      public void addChoosableFileFilter(FileFilter filter)
991      {
992        if (filter != null)
993          {
994            FileFilter[] old = getChoosableFileFilters();
995            choosableFilters.add(filter);
996            FileFilter[] newFilters = getChoosableFileFilters();
997            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, 
998                  newFilters);
999          }
1000        setFileFilter(filter);
1001      }
1002    
1003      /**
1004       * Removes a file filter from the list of available filters and sends a 
1005       * {@link PropertyChangeEvent} (with the property name 
1006       * {@link #CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY}) to all registered 
1007       * listeners.
1008       *
1009       * @param f  the file filter.
1010       *
1011       * @return <code>true</code> if the filter was removed and 
1012       *         <code>false</code> otherwise.
1013       */
1014      public boolean removeChoosableFileFilter(FileFilter f)
1015      {
1016        if (f == currentFilter)
1017          setFileFilter(null);
1018        FileFilter[] old = getChoosableFileFilters();
1019        if (! choosableFilters.remove(f))
1020          return false;
1021        FileFilter[] newFilters = getChoosableFileFilters();
1022        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, newFilters);
1023        return true;
1024      }
1025    
1026      /**
1027       * Clears the list of choosable file filters and installs the 'accept all'
1028       * filter from the UI delegate.
1029       */
1030      public void resetChoosableFileFilters()
1031      {
1032        choosableFilters.clear();
1033        choosableFilters.add(getUI().getAcceptAllFileFilter(this));
1034        setFileFilter((FileFilter) choosableFilters.get(0));
1035      }
1036    
1037      /**
1038       * Returns the 'accept all' file filter from the UI delegate.
1039       *
1040       * @return The 'accept all' file filter.
1041       */
1042      public FileFilter getAcceptAllFileFilter()
1043      {
1044        return getUI().getAcceptAllFileFilter(this);
1045      }
1046    
1047      /**
1048       * Returns the flag that controls whether or not the 'accept all' file 
1049       * filter is included in the list of filters.
1050       *
1051       * @return A boolean.
1052       * 
1053       * @see #setAcceptAllFileFilterUsed(boolean)
1054       */
1055      public boolean isAcceptAllFileFilterUsed()
1056      {
1057        return isAcceptAll;
1058      }
1059    
1060      /**
1061       * Sets the flag that controls whether or not the 'accept all' file filter
1062       * is included in the list of filters, and sends a 
1063       * {@link PropertyChangeEvent} (with the property name 
1064       * {@link #ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY}) to all registered 
1065       * listeners.
1066       *
1067       * @param b  the new value of the flag.
1068       */
1069      public void setAcceptAllFileFilterUsed(boolean b)
1070      {
1071        if (isAcceptAll != b)
1072          {
1073            isAcceptAll = b;
1074            if (b)
1075              addChoosableFileFilter(getAcceptAllFileFilter());
1076            else 
1077              removeChoosableFileFilter(getAcceptAllFileFilter());
1078            firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY,
1079                               ! isAcceptAll, isAcceptAll);
1080          }
1081      }
1082    
1083      /**
1084       * Returns the accessory component for the file chooser.  The default
1085       * value is <code>null</code>.
1086       *
1087       * @return The accessory component (possibly <code>null</code>).
1088       * 
1089       * @see #setAccessory(JComponent)
1090       */
1091      public JComponent getAccessory()
1092      {
1093        return accessory;
1094      }
1095    
1096      /**
1097       * Sets the accessory component for the file chooser and sends a 
1098       * {@link PropertyChangeEvent} to all registered listeners.  The property
1099       * name is {@link #ACCESSORY_CHANGED_PROPERTY}.
1100       *
1101       * @param newAccessory  the accessory component.
1102       */
1103      public void setAccessory(JComponent newAccessory)
1104      {
1105        if (accessory != newAccessory)
1106          {
1107            JComponent old = accessory;
1108            accessory = newAccessory;
1109            firePropertyChange(ACCESSORY_CHANGED_PROPERTY, old, accessory);
1110          }
1111      }
1112    
1113      /**
1114       * Sets the file selection mode and sends a {@link PropertyChangeEvent}
1115       * to all registered listeners.  The property name is 
1116       * {@link #FILE_SELECTION_MODE_CHANGED_PROPERTY}.
1117       *
1118       * @param mode  the mode ({@link #FILES_ONLY}, {@link #DIRECTORIES_ONLY} or
1119       *              {@link #FILES_AND_DIRECTORIES}).
1120       * 
1121       * @throws IllegalArgumentException if the mode is invalid.
1122       */
1123      public void setFileSelectionMode(int mode)
1124      {
1125        if (mode != FILES_ONLY && mode != DIRECTORIES_ONLY
1126            && mode != FILES_AND_DIRECTORIES)
1127          throw new IllegalArgumentException("Choose a correct file selection mode.");
1128        if (fileSelectionMode != mode)
1129          {
1130            int old = fileSelectionMode;
1131            fileSelectionMode = mode;
1132            firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, old,
1133                               fileSelectionMode);
1134          }
1135      }
1136    
1137      /**
1138       * Returns the file selection mode, one of: {@link #FILES_ONLY}, 
1139       * {@link #DIRECTORIES_ONLY} or {@link #FILES_AND_DIRECTORIES}.  The
1140       * default is {@link #FILES_ONLY}.
1141       *
1142       * @return The file selection mode.
1143       * 
1144       * @see #setFileSelectionMode(int)
1145       */
1146      public int getFileSelectionMode()
1147      {
1148        return fileSelectionMode;
1149      }
1150    
1151      /**
1152       * Returns <code>true</code> if file selection is enabled, and 
1153       * <code>false</code> otherwise.  File selection is enabled when the
1154       * file selection mode is {@link #FILES_ONLY} or 
1155       * {@link #FILES_AND_DIRECTORIES}.
1156       *
1157       * @return <code>true</code> if file selection is enabled.
1158       * 
1159       * @see #getFileSelectionMode()
1160       */
1161      public boolean isFileSelectionEnabled()
1162      {
1163        return (fileSelectionMode == FILES_ONLY
1164               || fileSelectionMode == FILES_AND_DIRECTORIES);
1165      }
1166    
1167      /**
1168       * Returns <code>true</code> if directory selection is enabled, and 
1169       * <code>false</code> otherwise.  Directory selection is enabled when the
1170       * file selection mode is {@link #DIRECTORIES_ONLY} or 
1171       * {@link #FILES_AND_DIRECTORIES}.
1172       *
1173       * @return <code>true</code> if file selection is enabled.
1174       * 
1175       * @see #getFileSelectionMode()
1176       */
1177      public boolean isDirectorySelectionEnabled()
1178      {
1179        return (fileSelectionMode == DIRECTORIES_ONLY
1180               || fileSelectionMode == FILES_AND_DIRECTORIES);
1181      }
1182    
1183      /**
1184       * Sets the flag that controls whether multiple selections are allowed in 
1185       * this filechooser and sends a {@link PropertyChangeEvent} (with the 
1186       * property name {@link #MULTI_SELECTION_ENABLED_CHANGED_PROPERTY}) to all 
1187       * registered listeners.
1188       *
1189       * @param b  the new value of the flag.
1190       */
1191      public void setMultiSelectionEnabled(boolean b)
1192      {
1193        if (multiSelection != b)
1194          {
1195            multiSelection = b;
1196            firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY,
1197                               ! multiSelection, multiSelection);
1198          }
1199      }
1200    
1201      /**
1202       * Returns <code>true</code> if multiple selections are allowed within this
1203       * file chooser, and <code>false</code> otherwise.
1204       *
1205       * @return A boolean.
1206       * 
1207       * @see #setMultiSelectionEnabled(boolean)
1208       */
1209      public boolean isMultiSelectionEnabled()
1210      {
1211        return multiSelection;
1212      }
1213    
1214      /**
1215       * Returns <code>true</code> if hidden files are to be hidden, and 
1216       * <code>false</code> otherwise.
1217       *
1218       * @return A boolean.
1219       * 
1220       * @see #setFileHidingEnabled(boolean)
1221       */
1222      public boolean isFileHidingEnabled()
1223      {
1224        return fileHiding;
1225      }
1226    
1227      /**
1228       * Sets the flag that controls whether or not hidden files are displayed,
1229       * and sends a {@link PropertyChangeEvent} (with the property name
1230       * {@link #FILE_HIDING_CHANGED_PROPERTY}) to all registered listeners.
1231       *
1232       * @param b  the new value of the flag.
1233       */
1234      public void setFileHidingEnabled(boolean b)
1235      {
1236        if (fileHiding != b)
1237          {
1238            fileHiding = b;
1239            firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, ! fileHiding,
1240                               fileHiding);
1241          }
1242      }
1243    
1244      /**
1245       * Sets the file filter and sends a {@link PropertyChangeEvent} (with the
1246       * property name {@link #FILE_FILTER_CHANGED_PROPERTY}) to all registered 
1247       * listeners.
1248       *
1249       * @param filter  the filter (<code>null</code> permitted).
1250       */
1251      public void setFileFilter(FileFilter filter)
1252      {
1253        if (currentFilter != filter)
1254          {
1255            if (filter != null && !choosableFilters.contains(filter))
1256              addChoosableFileFilter(filter);
1257            FileFilter old = currentFilter;
1258            currentFilter = filter;
1259            firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, old, currentFilter);
1260          }
1261      }
1262    
1263      /**
1264       * Returns the file filter.
1265       *
1266       * @return The file filter.
1267       * 
1268       * @see #setFileFilter(FileFilter)
1269       */
1270      public FileFilter getFileFilter()
1271      {
1272        return currentFilter;
1273      }
1274    
1275      /**
1276       * Sets a custom {@link FileView} for the file chooser and sends a 
1277       * {@link PropertyChangeEvent} to all registered listeners.  The property
1278       * name is {@link #FILE_VIEW_CHANGED_PROPERTY}.
1279       *
1280       * @param fileView  the file view (<code>null</code> permitted).
1281       *
1282       * @see #getFileView()
1283       */
1284      public void setFileView(FileView fileView)
1285      {
1286        if (fv != fileView)
1287          {
1288            FileView old = fv;
1289            fv = fileView;
1290            firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, old, fv);
1291          }
1292      }
1293    
1294      /**
1295       * Returns the custom {@link FileView} for the file chooser.
1296       *
1297       * @return The file view (possibly <code>null</code>).
1298       */
1299      public FileView getFileView()
1300      {
1301        return fv;
1302      }
1303    
1304      /**
1305       * Returns the name of the file, generated by the current (or default)
1306       * {@link FileView}.
1307       *
1308       * @param f  the file.
1309       *
1310       * @return The file name.
1311       */
1312      public String getName(File f)
1313      {
1314        String name = null;
1315        if (fv != null)
1316          name = fv.getName(f);
1317        if (name == null)
1318          name = getUI().getFileView(this).getName(f);
1319        return name;
1320      }
1321    
1322      /**
1323       * Returns the description of the file, generated by the current (or default)
1324       * {@link FileView}.
1325       *
1326       * @param f  the file.
1327       *
1328       * @return The file description.
1329       */
1330      public String getDescription(File f)
1331      {
1332        String result = null;
1333        if (fv != null)
1334          result = fv.getDescription(f);
1335        if (result == null)
1336          result = getUI().getFileView(this).getDescription(f);
1337        return result;
1338      }
1339    
1340      /**
1341       * Returns the type description for the file, generated by the current (or 
1342       * default) {@link FileView}.
1343       *
1344       * @param f  the file.
1345       *
1346       * @return The file type description.
1347       */
1348      public String getTypeDescription(File f)
1349      {
1350        String result = null;
1351        if (fv != null)
1352          result = getFileView().getTypeDescription(f);
1353        if (result == null)
1354          result = getUI().getFileView(this).getTypeDescription(f);
1355        return result;
1356      }
1357    
1358      /**
1359       * Returns the icon provided by the current (or default) {@link FileView}.
1360       *
1361       * @param f  the file.
1362       *
1363       * @return An icon representing the file.
1364       */
1365      public Icon getIcon(File f)
1366      {
1367        Icon result = null;
1368        if (fv != null)
1369          result = fv.getIcon(f);
1370        if (result == null)
1371          result = getUI().getFileView(this).getIcon(f);
1372        return result;
1373      }
1374    
1375      /**
1376       * Returns <code>true</code> if the file is traversable, and 
1377       * <code>false</code> otherwise.
1378       *
1379       * @param f  the file or directory.
1380       *
1381       * @return A boolean.
1382       */
1383      public boolean isTraversable(File f)
1384      {
1385        return getFileSystemView().isTraversable(f).booleanValue();
1386      }
1387    
1388      /**
1389       * Returns <code>true</code> if the file is accepted by the current
1390       * file filter.
1391       *
1392       * @param f  the file.
1393       *
1394       * @return A boolean.
1395       */
1396      public boolean accept(File f)
1397      {
1398        if (f == null)
1399          return true;
1400        FileFilter ff = getFileFilter();
1401        if (ff != null) 
1402          return ff.accept(f);
1403        else
1404          return true;
1405      }
1406    
1407      /**
1408       * Sets the file system view for the file chooser and sends a 
1409       * {@link PropertyChangeEvent} to all registered listeners.
1410       *
1411       * @param fsv  the file system view.
1412       */
1413      public void setFileSystemView(FileSystemView fsv)
1414      {
1415        if (this.fsv != fsv)
1416          {
1417            FileSystemView old = this.fsv;
1418            this.fsv = fsv;
1419            firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, old, this.fsv);
1420          }
1421      }
1422    
1423      /**
1424       * Returns the file system view being used by this file chooser.
1425       *
1426       * @return The file system view.
1427       * 
1428       * @see #setFileSystemView(FileSystemView)
1429       */
1430      public FileSystemView getFileSystemView()
1431      {
1432        return fsv;
1433      }
1434    
1435      /**
1436       * Approves the selection.  An {@link ActionEvent} is sent to all registered
1437       * listeners.
1438       */
1439      public void approveSelection()
1440      {
1441        retval = APPROVE_OPTION;
1442        fireActionPerformed(APPROVE_SELECTION);
1443      }
1444    
1445      /**
1446       * Cancels the selection. An {@link ActionEvent} is sent to all registered
1447       * listeners.
1448       */
1449      public void cancelSelection()
1450      {
1451        retval = CANCEL_OPTION;
1452        fireActionPerformed(CANCEL_SELECTION);
1453      }
1454    
1455      /**
1456       * Adds an {@link ActionListener} to the file chooser.
1457       *
1458       * @param l  the listener.
1459       */
1460      public void addActionListener(ActionListener l)
1461      {
1462        listenerList.add(ActionListener.class, l);
1463      }
1464    
1465      /**
1466       * Removes an {@link ActionListener} from this file chooser.
1467       *
1468       * @param l  the listener.
1469       */
1470      public void removeActionListener(ActionListener l)
1471      {
1472        try
1473          {
1474            listenerList.remove(ActionListener.class, l);
1475          }
1476        catch (IllegalArgumentException e)
1477          {
1478            e.printStackTrace();
1479          }
1480      }
1481    
1482      /**
1483       * Returns the action listeners registered with this file chooser.
1484       *
1485       * @return An array of listeners.
1486       */
1487      public ActionListener[] getActionListeners()
1488      {
1489        return (ActionListener[]) getListeners(ActionListener.class);
1490      }
1491    
1492      /**
1493       * Sends an @link {ActionEvent} to all registered listeners.
1494       *
1495       * @param command  the action command.
1496       */
1497      protected void fireActionPerformed(String command)
1498      {
1499        ActionListener[] list = getActionListeners();
1500        ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1501                                            command);
1502    
1503        for (int i = 0; i < list.length; i++)
1504          list[i].actionPerformed(event);
1505      }
1506    
1507      /**
1508       * Installs the UI delegate for the current look and feel.
1509       */
1510      public void updateUI()
1511      {
1512        setUI((FileChooserUI) UIManager.getUI(this));
1513      }
1514    
1515      /**
1516       * Returns the UI delegate class identifier.
1517       *
1518       * @return <code>FileChooserUI</code>.
1519       */
1520      public String getUIClassID()
1521      {
1522        return "FileChooserUI";
1523      }
1524    
1525      /**
1526       * Returns the UI delegate for the component.
1527       *
1528       * @return The UI delegate.
1529       */
1530      public FileChooserUI getUI()
1531      {
1532        return (FileChooserUI) ui;
1533      }
1534    
1535      /**
1536       * Returns a string describing the attributes for the 
1537       * <code>JFileChooser</code> component, for use in debugging.  The return 
1538       * value is guaranteed to be non-<code>null</code>, but the format of the 
1539       * string may vary between implementations.
1540       *
1541       * @return A string describing the attributes of the 
1542       *     <code>JFileChooser</code>.
1543       */
1544      protected String paramString()
1545      {
1546        StringBuffer sb = new StringBuffer(super.paramString());
1547        sb.append(",approveButtonText=");
1548        if (approveButtonText != null)
1549          sb.append(approveButtonText);
1550        sb.append(",currentDirectory=");
1551        if (currentDir != null)
1552          sb.append(currentDir);
1553        sb.append(",dialogTitle=");
1554        if (dialogTitle != null)
1555          sb.append(dialogTitle);
1556        sb.append(",dialogType=");
1557        if (dialogType == OPEN_DIALOG)
1558          sb.append("OPEN_DIALOG");
1559        if (dialogType == SAVE_DIALOG)
1560          sb.append("SAVE_DIALOG");
1561        if (dialogType == CUSTOM_DIALOG)
1562          sb.append("CUSTOM_DIALOG");
1563        sb.append(",fileSelectionMode=");
1564        if (fileSelectionMode == FILES_ONLY)
1565          sb.append("FILES_ONLY");
1566        if (fileSelectionMode == DIRECTORIES_ONLY)
1567          sb.append("DIRECTORIES_ONLY");
1568        if (fileSelectionMode == FILES_AND_DIRECTORIES)
1569          sb.append("FILES_AND_DIRECTORIES");
1570        sb.append(",returnValue=");
1571        if (retval == APPROVE_OPTION)
1572          sb.append("APPROVE_OPTION");
1573        if (retval == CANCEL_OPTION)
1574          sb.append("CANCEL_OPTION");
1575        if (retval == ERROR_OPTION)
1576          sb.append("ERROR_OPTION");
1577        sb.append(",selectedFile=");
1578        if (selectedFile != null)
1579          sb.append(selectedFile);
1580        sb.append(",useFileHiding=").append(fileHiding);
1581        return sb.toString();
1582      }
1583    
1584      /**
1585       * Returns the object that provides accessibility features for this
1586       * <code>JFileChooser</code> component.
1587       *
1588       * @return The accessible context (an instance of 
1589       *     {@link AccessibleJFileChooser}).
1590       */
1591      public AccessibleContext getAccessibleContext()
1592      {
1593        if (accessibleContext == null)
1594          accessibleContext = new AccessibleJFileChooser();
1595        return accessibleContext;
1596      }
1597    
1598      /**
1599       * Provides the accessibility features for the <code>JFileChooser</code>
1600       * component.
1601       */
1602      protected class AccessibleJFileChooser 
1603        extends JComponent.AccessibleJComponent
1604      {
1605        /**
1606         * Creates a new instance of <code>AccessibleJFileChooser</code>.
1607         */
1608        protected AccessibleJFileChooser()
1609        {
1610          // Nothing to do here.
1611        }
1612        
1613        /**
1614         * Returns the accessible role for the <code>JFileChooser</code> 
1615         * component.
1616         *
1617         * @return {@link AccessibleRole#FILE_CHOOSER}.
1618         */
1619        public AccessibleRole getAccessibleRole()
1620        {
1621          return AccessibleRole.FILE_CHOOSER;
1622        }
1623      }
1624    }