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