Source for javax.swing.JFileChooser

   1: /* JFileChooser.java --
   2:    Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.swing;
  39: 
  40: import java.awt.Component;
  41: import java.awt.Frame;
  42: import java.awt.GraphicsEnvironment;
  43: import java.awt.HeadlessException;
  44: import java.awt.event.ActionEvent;
  45: import java.awt.event.ActionListener;
  46: import java.awt.event.WindowEvent;
  47: import java.awt.event.WindowAdapter;
  48: import java.beans.PropertyChangeEvent;
  49: import java.io.File;
  50: import java.util.ArrayList;
  51: 
  52: import javax.accessibility.Accessible;
  53: import javax.accessibility.AccessibleContext;
  54: import javax.accessibility.AccessibleRole;
  55: import javax.swing.filechooser.FileFilter;
  56: import javax.swing.filechooser.FileSystemView;
  57: import javax.swing.filechooser.FileView;
  58: import javax.swing.plaf.FileChooserUI;
  59: 
  60: 
  61: /**
  62:  * A component that provides the user a dialog box to browse through a
  63:  * filesystem and choose one or more files or directories.
  64:  *
  65:  * A JFileChooser can be configured to filter the displayed file list
  66:  * by adding a {@link FileFilter} instance using
  67:  * {@link #addChoosableFileFilter(FileFilter)}. Additional components can
  68:  * be embedded in the file chooser using {@link #setAccessory(JComponent)}.
  69:  * The JFileChooser properties also provide mechanisms to customize the
  70:  * behaviour of the file chooser.
  71:  *
  72:  * @author Kim Ho (kho@luxsci.net)
  73:  */
  74: public class JFileChooser extends JComponent implements Accessible
  75: {
  76:   private static final long serialVersionUID = 3162921138695327837L;
  77: 
  78:   /** 
  79:    * A dialog type for selecting a file to open. 
  80:    * @see #setDialogType(int)
  81:    */
  82:   public static final int OPEN_DIALOG = 0;
  83: 
  84:   /** 
  85:    * A dialog type for selecting a file to save.  
  86:    * @see #setDialogType(int)
  87:    */
  88:   public static final int SAVE_DIALOG = 1;
  89: 
  90:   /** 
  91:    * A dialog type for some custom purpose.
  92:    * @see #setDialogType(int)
  93:    */
  94:   public static final int CUSTOM_DIALOG = 2;
  95: 
  96:   /** 
  97:    * A return value indicating the file chooser has been closed by cancelling.
  98:    * 
  99:    * @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