1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing; 27 28 import javax.swing.event.*; 29 import javax.swing.filechooser.*; 30 import javax.swing.plaf.FileChooserUI; 31 32 import javax.accessibility.*; 33 34 import java.io.File; 35 import java.io.ObjectOutputStream; 36 import java.io.IOException; 37 38 import java.util.Vector; 39 import java.awt.AWTEvent; 40 import java.awt.Component; 41 import java.awt.Container; 42 import java.awt.BorderLayout; 43 import java.awt.Window; 44 import java.awt.Dialog; 45 import java.awt.Frame; 46 import java.awt.GraphicsEnvironment; 47 import java.awt.HeadlessException; 48 import java.awt.EventQueue; 49 import java.awt.Toolkit; 50 import java.awt.event.*; 51 import java.beans.PropertyChangeListener; 52 import java.beans.PropertyChangeEvent; 53 import java.io.InvalidObjectException; 54 import java.io.ObjectInputStream; 55 import java.lang.ref.WeakReference; 56 57 /** 58 * <code>JFileChooser</code> provides a simple mechanism for the user to 59 * choose a file. 60 * For information about using <code>JFileChooser</code>, see 61 * <a 62 href="http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html">How to Use File Choosers</a>, 63 * a section in <em>The Java Tutorial</em>. 64 * 65 * <p> 66 * 67 * The following code pops up a file chooser for the user's home directory that 68 * sees only .jpg and .gif images: 69 * <pre> 70 * JFileChooser chooser = new JFileChooser(); 71 * FileNameExtensionFilter filter = new FileNameExtensionFilter( 72 * "JPG & GIF Images", "jpg", "gif"); 73 * chooser.setFileFilter(filter); 74 * int returnVal = chooser.showOpenDialog(parent); 75 * if(returnVal == JFileChooser.APPROVE_OPTION) { 76 * System.out.println("You chose to open this file: " + 77 * chooser.getSelectedFile().getName()); 78 * } 79 * </pre> 80 * <p> 81 * <strong>Warning:</strong> Swing is not thread safe. For more 82 * information see <a 83 * href="package-summary.html#threading">Swing's Threading 84 * Policy</a>. 85 * 86 * @beaninfo 87 * attribute: isContainer false 88 * description: A component which allows for the interactive selection of a file. 89 * 90 * @author Jeff Dinkins 91 * @since 1.2 92 */ 93 @SuppressWarnings("serial") // Superclass is not serializable across versions 94 public class JFileChooser extends JComponent implements Accessible { 95 96 /** 97 * @see #getUIClassID 98 * @see #readObject 99 */ 100 private static final String uiClassID = "FileChooserUI"; 101 102 // ************************ 103 // ***** Dialog Types ***** 104 // ************************ 105 106 /** 107 * Type value indicating that the <code>JFileChooser</code> supports an 108 * "Open" file operation. 109 */ 110 public static final int OPEN_DIALOG = 0; 111 112 /** 113 * Type value indicating that the <code>JFileChooser</code> supports a 114 * "Save" file operation. 115 */ 116 public static final int SAVE_DIALOG = 1; 117 118 /** 119 * Type value indicating that the <code>JFileChooser</code> supports a 120 * developer-specified file operation. 121 */ 122 public static final int CUSTOM_DIALOG = 2; 123 124 125 // ******************************** 126 // ***** Dialog Return Values ***** 127 // ******************************** 128 129 /** 130 * Return value if cancel is chosen. 131 */ 132 public static final int CANCEL_OPTION = 1; 133 134 /** 135 * Return value if approve (yes, ok) is chosen. 136 */ 137 public static final int APPROVE_OPTION = 0; 138 139 /** 140 * Return value if an error occurred. 141 */ 142 public static final int ERROR_OPTION = -1; 143 144 145 // ********************************** 146 // ***** JFileChooser properties ***** 147 // ********************************** 148 149 150 /** Instruction to display only files. */ 151 public static final int FILES_ONLY = 0; 152 153 /** Instruction to display only directories. */ 154 public static final int DIRECTORIES_ONLY = 1; 155 156 /** Instruction to display both files and directories. */ 157 public static final int FILES_AND_DIRECTORIES = 2; 158 159 /** Instruction to cancel the current selection. */ 160 public static final String CANCEL_SELECTION = "CancelSelection"; 161 162 /** 163 * Instruction to approve the current selection 164 * (same as pressing yes or ok). 165 */ 166 public static final String APPROVE_SELECTION = "ApproveSelection"; 167 168 /** Identifies change in the text on the approve (yes, ok) button. */ 169 public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = "ApproveButtonTextChangedProperty"; 170 171 /** 172 * Identifies change in the tooltip text for the approve (yes, ok) 173 * button. 174 */ 175 public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = "ApproveButtonToolTipTextChangedProperty"; 176 177 /** Identifies change in the mnemonic for the approve (yes, ok) button. */ 178 public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = "ApproveButtonMnemonicChangedProperty"; 179 180 /** Instruction to display the control buttons. */ 181 public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = "ControlButtonsAreShownChangedProperty"; 182 183 /** Identifies user's directory change. */ 184 public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged"; 185 186 /** Identifies change in user's single-file selection. */ 187 public static final String SELECTED_FILE_CHANGED_PROPERTY = "SelectedFileChangedProperty"; 188 189 /** Identifies change in user's multiple-file selection. */ 190 public static final String SELECTED_FILES_CHANGED_PROPERTY = "SelectedFilesChangedProperty"; 191 192 /** Enables multiple-file selections. */ 193 public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty"; 194 195 /** 196 * Says that a different object is being used to find available drives 197 * on the system. 198 */ 199 public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = "FileSystemViewChanged"; 200 201 /** 202 * Says that a different object is being used to retrieve file 203 * information. 204 */ 205 public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged"; 206 207 /** Identifies a change in the display-hidden-files property. */ 208 public static final String FILE_HIDING_CHANGED_PROPERTY = "FileHidingChanged"; 209 210 /** User changed the kind of files to display. */ 211 public static final String FILE_FILTER_CHANGED_PROPERTY = "fileFilterChanged"; 212 213 /** 214 * Identifies a change in the kind of selection (single, 215 * multiple, etc.). 216 */ 217 public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = "fileSelectionChanged"; 218 219 /** 220 * Says that a different accessory component is in use 221 * (for example, to preview files). 222 */ 223 public static final String ACCESSORY_CHANGED_PROPERTY = "AccessoryChangedProperty"; 224 225 /** 226 * Identifies whether a the AcceptAllFileFilter is used or not. 227 */ 228 public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = "acceptAllFileFilterUsedChanged"; 229 230 /** Identifies a change in the dialog title. */ 231 public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty"; 232 233 /** 234 * Identifies a change in the type of files displayed (files only, 235 * directories only, or both files and directories). 236 */ 237 public static final String DIALOG_TYPE_CHANGED_PROPERTY = "DialogTypeChangedProperty"; 238 239 /** 240 * Identifies a change in the list of predefined file filters 241 * the user can choose from. 242 */ 243 public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = "ChoosableFileFilterChangedProperty"; 244 245 // ****************************** 246 // ***** instance variables ***** 247 // ****************************** 248 249 private String dialogTitle = null; 250 private String approveButtonText = null; 251 private String approveButtonToolTipText = null; 252 private int approveButtonMnemonic = 0; 253 254 private Vector<FileFilter> filters = new Vector<FileFilter>(5); 255 private JDialog dialog = null; 256 private int dialogType = OPEN_DIALOG; 257 private int returnValue = ERROR_OPTION; 258 private JComponent accessory = null; 259 260 private FileView fileView = null; 261 262 private boolean controlsShown = true; 263 264 private boolean useFileHiding = true; 265 private static final String SHOW_HIDDEN_PROP = "awt.file.showHiddenFiles"; 266 267 // Listens to changes in the native setting for showing hidden files. 268 // The Listener is removed and the native setting is ignored if 269 // setFileHidingEnabled() is ever called. 270 private transient PropertyChangeListener showFilesListener = null; 271 272 private int fileSelectionMode = FILES_ONLY; 273 274 private boolean multiSelectionEnabled = false; 275 276 private boolean useAcceptAllFileFilter = true; 277 278 private boolean dragEnabled = false; 279 280 private FileFilter fileFilter = null; 281 282 private FileSystemView fileSystemView = null; 283 284 private File currentDirectory = null; 285 private File selectedFile = null; 286 private File[] selectedFiles; 287 288 // ************************************* 289 // ***** JFileChooser Constructors ***** 290 // ************************************* 291 292 /** 293 * Constructs a <code>JFileChooser</code> pointing to the user's 294 * default directory. This default depends on the operating system. 295 * It is typically the "My Documents" folder on Windows, and the 296 * user's home directory on Unix. 297 */ 298 public JFileChooser() { 299 this((File) null, (FileSystemView) null); 300 } 301 302 /** 303 * Constructs a <code>JFileChooser</code> using the given path. 304 * Passing in a <code>null</code> 305 * string causes the file chooser to point to the user's default directory. 306 * This default depends on the operating system. It is 307 * typically the "My Documents" folder on Windows, and the user's 308 * home directory on Unix. 309 * 310 * @param currentDirectoryPath a <code>String</code> giving the path 311 * to a file or directory 312 */ 313 public JFileChooser(String currentDirectoryPath) { 314 this(currentDirectoryPath, (FileSystemView) null); 315 } 316 317 /** 318 * Constructs a <code>JFileChooser</code> using the given <code>File</code> 319 * as the path. Passing in a <code>null</code> file 320 * causes the file chooser to point to the user's default directory. 321 * This default depends on the operating system. It is 322 * typically the "My Documents" folder on Windows, and the user's 323 * home directory on Unix. 324 * 325 * @param currentDirectory a <code>File</code> object specifying 326 * the path to a file or directory 327 */ 328 public JFileChooser(File currentDirectory) { 329 this(currentDirectory, (FileSystemView) null); 330 } 331 332 /** 333 * Constructs a <code>JFileChooser</code> using the given 334 * <code>FileSystemView</code>. 335 * 336 * @param fsv a {@code FileSystemView} 337 */ 338 public JFileChooser(FileSystemView fsv) { 339 this((File) null, fsv); 340 } 341 342 343 /** 344 * Constructs a <code>JFileChooser</code> using the given current directory 345 * and <code>FileSystemView</code>. 346 * 347 * @param currentDirectory a {@code File} object specifying the path to a 348 * file or directory 349 * @param fsv a {@code FileSystemView} 350 */ 351 public JFileChooser(File currentDirectory, FileSystemView fsv) { 352 setup(fsv); 353 setCurrentDirectory(currentDirectory); 354 } 355 356 /** 357 * Constructs a <code>JFileChooser</code> using the given current directory 358 * path and <code>FileSystemView</code>. 359 * 360 * @param currentDirectoryPath a {@code String} specifying the path to a file 361 * or directory 362 * @param fsv a {@code FileSystemView} 363 */ 364 public JFileChooser(String currentDirectoryPath, FileSystemView fsv) { 365 setup(fsv); 366 if(currentDirectoryPath == null) { 367 setCurrentDirectory(null); 368 } else { 369 setCurrentDirectory(fileSystemView.createFileObject(currentDirectoryPath)); 370 } 371 } 372 373 /** 374 * Performs common constructor initialization and setup. 375 * 376 * @param view the {@code FileSystemView} used for setup 377 */ 378 protected void setup(FileSystemView view) { 379 installShowFilesListener(); 380 installHierarchyListener(); 381 382 if(view == null) { 383 view = FileSystemView.getFileSystemView(); 384 } 385 setFileSystemView(view); 386 updateUI(); 387 if(isAcceptAllFileFilterUsed()) { 388 setFileFilter(getAcceptAllFileFilter()); 389 } 390 enableEvents(AWTEvent.MOUSE_EVENT_MASK); 391 } 392 393 private void installHierarchyListener() { 394 addHierarchyListener(new HierarchyListener() { 395 @Override 396 public void hierarchyChanged(HierarchyEvent e) { 397 if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) 398 == HierarchyEvent.PARENT_CHANGED) { 399 JFileChooser fc = JFileChooser.this; 400 JRootPane rootPane = SwingUtilities.getRootPane(fc); 401 if (rootPane != null) { 402 rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc)); 403 } 404 } 405 } 406 }); 407 } 408 409 private void installShowFilesListener() { 410 // Track native setting for showing hidden files 411 Toolkit tk = Toolkit.getDefaultToolkit(); 412 Object showHiddenProperty = tk.getDesktopProperty(SHOW_HIDDEN_PROP); 413 if (showHiddenProperty instanceof Boolean) { 414 useFileHiding = !((Boolean)showHiddenProperty).booleanValue(); 415 showFilesListener = new WeakPCL(this); 416 tk.addPropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener); 417 } 418 } 419 420 /** 421 * Sets the <code>dragEnabled</code> property, 422 * which must be <code>true</code> to enable 423 * automatic drag handling (the first part of drag and drop) 424 * on this component. 425 * The <code>transferHandler</code> property needs to be set 426 * to a non-<code>null</code> value for the drag to do 427 * anything. The default value of the <code>dragEnabled</code> 428 * property 429 * is <code>false</code>. 430 * 431 * <p> 432 * 433 * When automatic drag handling is enabled, 434 * most look and feels begin a drag-and-drop operation 435 * whenever the user presses the mouse button over an item 436 * and then moves the mouse a few pixels. 437 * Setting this property to <code>true</code> 438 * can therefore have a subtle effect on 439 * how selections behave. 440 * 441 * <p> 442 * 443 * Some look and feels might not support automatic drag and drop; 444 * they will ignore this property. You can work around such 445 * look and feels by modifying the component 446 * to directly call the <code>exportAsDrag</code> method of a 447 * <code>TransferHandler</code>. 448 * 449 * @param b the value to set the <code>dragEnabled</code> property to 450 * @exception HeadlessException if 451 * <code>b</code> is <code>true</code> and 452 * <code>GraphicsEnvironment.isHeadless()</code> 453 * returns <code>true</code> 454 * @see java.awt.GraphicsEnvironment#isHeadless 455 * @see #getDragEnabled 456 * @see #setTransferHandler 457 * @see TransferHandler 458 * @since 1.4 459 * 460 * @beaninfo 461 * description: determines whether automatic drag handling is enabled 462 * bound: false 463 */ 464 public void setDragEnabled(boolean b) { 465 checkDragEnabled(b); 466 dragEnabled = b; 467 } 468 469 private static void checkDragEnabled(boolean b) { 470 if (b && GraphicsEnvironment.isHeadless()) { 471 throw new HeadlessException(); 472 } 473 } 474 475 /** 476 * Gets the value of the <code>dragEnabled</code> property. 477 * 478 * @return the value of the <code>dragEnabled</code> property 479 * @see #setDragEnabled 480 * @since 1.4 481 */ 482 public boolean getDragEnabled() { 483 return dragEnabled; 484 } 485 486 // ***************************** 487 // ****** File Operations ****** 488 // ***************************** 489 490 /** 491 * Returns the selected file. This can be set either by the 492 * programmer via <code>setSelectedFile</code> or by a user action, such as 493 * either typing the filename into the UI or selecting the 494 * file from a list in the UI. 495 * 496 * @see #setSelectedFile 497 * @return the selected file 498 */ 499 public File getSelectedFile() { 500 return selectedFile; 501 } 502 503 /** 504 * Sets the selected file. If the file's parent directory is 505 * not the current directory, changes the current directory 506 * to be the file's parent directory. 507 * 508 * @beaninfo 509 * preferred: true 510 * bound: true 511 * 512 * @see #getSelectedFile 513 * 514 * @param file the selected file 515 */ 516 public void setSelectedFile(File file) { 517 File oldValue = selectedFile; 518 selectedFile = file; 519 if(selectedFile != null) { 520 if (file.isAbsolute() && !getFileSystemView().isParent(getCurrentDirectory(), selectedFile)) { 521 setCurrentDirectory(selectedFile.getParentFile()); 522 } 523 if (!isMultiSelectionEnabled() || selectedFiles == null || selectedFiles.length == 1) { 524 ensureFileIsVisible(selectedFile); 525 } 526 } 527 firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, oldValue, selectedFile); 528 } 529 530 /** 531 * Returns a list of selected files if the file chooser is 532 * set to allow multiple selection. 533 * 534 * @return an array of selected {@code File}s 535 */ 536 public File[] getSelectedFiles() { 537 if(selectedFiles == null) { 538 return new File[0]; 539 } else { 540 return selectedFiles.clone(); 541 } 542 } 543 544 /** 545 * Sets the list of selected files if the file chooser is 546 * set to allow multiple selection. 547 * 548 * @param selectedFiles an array {@code File}s to be selected 549 * @beaninfo 550 * bound: true 551 * description: The list of selected files if the chooser is in multiple selection mode. 552 */ 553 public void setSelectedFiles(File[] selectedFiles) { 554 File[] oldValue = this.selectedFiles; 555 if (selectedFiles == null || selectedFiles.length == 0) { 556 selectedFiles = null; 557 this.selectedFiles = null; 558 setSelectedFile(null); 559 } else { 560 this.selectedFiles = selectedFiles.clone(); 561 setSelectedFile(this.selectedFiles[0]); 562 } 563 firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, oldValue, selectedFiles); 564 } 565 566 /** 567 * Returns the current directory. 568 * 569 * @return the current directory 570 * @see #setCurrentDirectory 571 */ 572 public File getCurrentDirectory() { 573 return currentDirectory; 574 } 575 576 /** 577 * Sets the current directory. Passing in <code>null</code> sets the 578 * file chooser to point to the user's default directory. 579 * This default depends on the operating system. It is 580 * typically the "My Documents" folder on Windows, and the user's 581 * home directory on Unix. 582 * 583 * If the file passed in as <code>currentDirectory</code> is not a 584 * directory, the parent of the file will be used as the currentDirectory. 585 * If the parent is not traversable, then it will walk up the parent tree 586 * until it finds a traversable directory, or hits the root of the 587 * file system. 588 * 589 * @beaninfo 590 * preferred: true 591 * bound: true 592 * description: The directory that the JFileChooser is showing files of. 593 * 594 * @param dir the current directory to point to 595 * @see #getCurrentDirectory 596 */ 597 public void setCurrentDirectory(File dir) { 598 File oldValue = currentDirectory; 599 600 if (dir != null && !dir.exists()) { 601 dir = currentDirectory; 602 } 603 if (dir == null) { 604 dir = getFileSystemView().getDefaultDirectory(); 605 } 606 if (currentDirectory != null) { 607 /* Verify the toString of object */ 608 if (this.currentDirectory.equals(dir)) { 609 return; 610 } 611 } 612 613 File prev = null; 614 while (!isTraversable(dir) && prev != dir) { 615 prev = dir; 616 dir = getFileSystemView().getParentDirectory(dir); 617 } 618 currentDirectory = dir; 619 620 firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentDirectory); 621 } 622 623 /** 624 * Changes the directory to be set to the parent of the 625 * current directory. 626 * 627 * @see #getCurrentDirectory 628 */ 629 public void changeToParentDirectory() { 630 selectedFile = null; 631 File oldValue = getCurrentDirectory(); 632 setCurrentDirectory(getFileSystemView().getParentDirectory(oldValue)); 633 } 634 635 /** 636 * Tells the UI to rescan its files list from the current directory. 637 */ 638 public void rescanCurrentDirectory() { 639 getUI().rescanCurrentDirectory(this); 640 } 641 642 /** 643 * Makes sure that the specified file is viewable, and 644 * not hidden. 645 * 646 * @param f a File object 647 */ 648 public void ensureFileIsVisible(File f) { 649 getUI().ensureFileIsVisible(this, f); 650 } 651 652 // ************************************** 653 // ***** JFileChooser Dialog methods ***** 654 // ************************************** 655 656 /** 657 * Pops up an "Open File" file chooser dialog. Note that the 658 * text that appears in the approve button is determined by 659 * the L&F. 660 * 661 * @param parent the parent component of the dialog, 662 * can be <code>null</code>; 663 * see <code>showDialog</code> for details 664 * @return the return state of the file chooser on popdown: 665 * <ul> 666 * <li>JFileChooser.CANCEL_OPTION 667 * <li>JFileChooser.APPROVE_OPTION 668 * <li>JFileChooser.ERROR_OPTION if an error occurs or the 669 * dialog is dismissed 670 * </ul> 671 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 672 * returns true. 673 * @see java.awt.GraphicsEnvironment#isHeadless 674 * @see #showDialog 675 */ 676 public int showOpenDialog(Component parent) throws HeadlessException { 677 setDialogType(OPEN_DIALOG); 678 return showDialog(parent, null); 679 } 680 681 /** 682 * Pops up a "Save File" file chooser dialog. Note that the 683 * text that appears in the approve button is determined by 684 * the L&F. 685 * 686 * @param parent the parent component of the dialog, 687 * can be <code>null</code>; 688 * see <code>showDialog</code> for details 689 * @return the return state of the file chooser on popdown: 690 * <ul> 691 * <li>JFileChooser.CANCEL_OPTION 692 * <li>JFileChooser.APPROVE_OPTION 693 * <li>JFileChooser.ERROR_OPTION if an error occurs or the 694 * dialog is dismissed 695 * </ul> 696 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 697 * returns true. 698 * @see java.awt.GraphicsEnvironment#isHeadless 699 * @see #showDialog 700 */ 701 public int showSaveDialog(Component parent) throws HeadlessException { 702 setDialogType(SAVE_DIALOG); 703 return showDialog(parent, null); 704 } 705 706 /** 707 * Pops a custom file chooser dialog with a custom approve button. 708 * For example, the following code 709 * pops up a file chooser with a "Run Application" button 710 * (instead of the normal "Save" or "Open" button): 711 * <pre> 712 * filechooser.showDialog(parentFrame, "Run Application"); 713 * </pre> 714 * 715 * Alternatively, the following code does the same thing: 716 * <pre> 717 * JFileChooser chooser = new JFileChooser(null); 718 * chooser.setApproveButtonText("Run Application"); 719 * chooser.showDialog(parentFrame, null); 720 * </pre> 721 * 722 * <!--PENDING(jeff) - the following method should be added to the api: 723 * showDialog(Component parent);--> 724 * <!--PENDING(kwalrath) - should specify modality and what 725 * "depends" means.--> 726 * 727 * <p> 728 * 729 * The <code>parent</code> argument determines two things: 730 * the frame on which the open dialog depends and 731 * the component whose position the look and feel 732 * should consider when placing the dialog. If the parent 733 * is a <code>Frame</code> object (such as a <code>JFrame</code>) 734 * then the dialog depends on the frame and 735 * the look and feel positions the dialog 736 * relative to the frame (for example, centered over the frame). 737 * If the parent is a component, then the dialog 738 * depends on the frame containing the component, 739 * and is positioned relative to the component 740 * (for example, centered over the component). 741 * If the parent is <code>null</code>, then the dialog depends on 742 * no visible window, and it's placed in a 743 * look-and-feel-dependent position 744 * such as the center of the screen. 745 * 746 * @param parent the parent component of the dialog; 747 * can be <code>null</code> 748 * @param approveButtonText the text of the <code>ApproveButton</code> 749 * @return the return state of the file chooser on popdown: 750 * <ul> 751 * <li>JFileChooser.CANCEL_OPTION 752 * <li>JFileChooser.APPROVE_OPTION 753 * <li>JFileChooser.ERROR_OPTION if an error occurs or the 754 * dialog is dismissed 755 * </ul> 756 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 757 * returns true. 758 * @see java.awt.GraphicsEnvironment#isHeadless 759 */ 760 public int showDialog(Component parent, String approveButtonText) 761 throws HeadlessException { 762 if (dialog != null) { 763 // Prevent to show second instance of dialog if the previous one still exists 764 return JFileChooser.ERROR_OPTION; 765 } 766 767 if(approveButtonText != null) { 768 setApproveButtonText(approveButtonText); 769 setDialogType(CUSTOM_DIALOG); 770 } 771 dialog = createDialog(parent); 772 dialog.addWindowListener(new WindowAdapter() { 773 public void windowClosing(WindowEvent e) { 774 returnValue = CANCEL_OPTION; 775 } 776 }); 777 returnValue = ERROR_OPTION; 778 rescanCurrentDirectory(); 779 780 dialog.show(); 781 firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null); 782 783 // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs) 784 // registers AWT listener for dialogs and produces memory leaks. It happens when 785 // installUI invoked after the showDialog method. 786 dialog.getContentPane().removeAll(); 787 dialog.dispose(); 788 dialog = null; 789 return returnValue; 790 } 791 792 /** 793 * Creates and returns a new <code>JDialog</code> wrapping 794 * <code>this</code> centered on the <code>parent</code> 795 * in the <code>parent</code>'s frame. 796 * This method can be overriden to further manipulate the dialog, 797 * to disable resizing, set the location, etc. Example: 798 * <pre> 799 * class MyFileChooser extends JFileChooser { 800 * protected JDialog createDialog(Component parent) throws HeadlessException { 801 * JDialog dialog = super.createDialog(parent); 802 * dialog.setLocation(300, 200); 803 * dialog.setResizable(false); 804 * return dialog; 805 * } 806 * } 807 * </pre> 808 * 809 * @param parent the parent component of the dialog; 810 * can be <code>null</code> 811 * @return a new <code>JDialog</code> containing this instance 812 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 813 * returns true. 814 * @see java.awt.GraphicsEnvironment#isHeadless 815 * @since 1.4 816 */ 817 protected JDialog createDialog(Component parent) throws HeadlessException { 818 FileChooserUI ui = getUI(); 819 String title = ui.getDialogTitle(this); 820 putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY, 821 title); 822 823 JDialog dialog; 824 Window window = JOptionPane.getWindowForComponent(parent); 825 if (window instanceof Frame) { 826 dialog = new JDialog((Frame)window, title, true); 827 } else { 828 dialog = new JDialog((Dialog)window, title, true); 829 } 830 dialog.setComponentOrientation(this.getComponentOrientation()); 831 832 Container contentPane = dialog.getContentPane(); 833 contentPane.setLayout(new BorderLayout()); 834 contentPane.add(this, BorderLayout.CENTER); 835 836 if (JDialog.isDefaultLookAndFeelDecorated()) { 837 boolean supportsWindowDecorations = 838 UIManager.getLookAndFeel().getSupportsWindowDecorations(); 839 if (supportsWindowDecorations) { 840 dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG); 841 } 842 } 843 dialog.pack(); 844 dialog.setLocationRelativeTo(parent); 845 846 return dialog; 847 } 848 849 // ************************** 850 // ***** Dialog Options ***** 851 // ************************** 852 853 /** 854 * Returns the value of the <code>controlButtonsAreShown</code> 855 * property. 856 * 857 * @return the value of the <code>controlButtonsAreShown</code> 858 * property 859 * 860 * @see #setControlButtonsAreShown 861 * @since 1.3 862 */ 863 public boolean getControlButtonsAreShown() { 864 return controlsShown; 865 } 866 867 868 /** 869 * Sets the property 870 * that indicates whether the <i>approve</i> and <i>cancel</i> 871 * buttons are shown in the file chooser. This property 872 * is <code>true</code> by default. Look and feels 873 * that always show these buttons will ignore the value 874 * of this property. 875 * This method fires a property-changed event, 876 * using the string value of 877 * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code> 878 * as the name of the property. 879 * 880 * @param b <code>false</code> if control buttons should not be 881 * shown; otherwise, <code>true</code> 882 * 883 * @beaninfo 884 * preferred: true 885 * bound: true 886 * description: Sets whether the approve & cancel buttons are shown. 887 * 888 * @see #getControlButtonsAreShown 889 * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY 890 * @since 1.3 891 */ 892 public void setControlButtonsAreShown(boolean b) { 893 if(controlsShown == b) { 894 return; 895 } 896 boolean oldValue = controlsShown; 897 controlsShown = b; 898 firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown); 899 } 900 901 /** 902 * Returns the type of this dialog. The default is 903 * <code>JFileChooser.OPEN_DIALOG</code>. 904 * 905 * @return the type of dialog to be displayed: 906 * <ul> 907 * <li>JFileChooser.OPEN_DIALOG 908 * <li>JFileChooser.SAVE_DIALOG 909 * <li>JFileChooser.CUSTOM_DIALOG 910 * </ul> 911 * 912 * @see #setDialogType 913 */ 914 public int getDialogType() { 915 return dialogType; 916 } 917 918 /** 919 * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you 920 * want to bring up a file chooser that the user can use to open a file. 921 * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose 922 * a file for saving. 923 * Use <code>CUSTOM_DIALOG</code> when you want to use the file 924 * chooser in a context other than "Open" or "Save". 925 * For instance, you might want to bring up a file chooser that allows 926 * the user to choose a file to execute. Note that you normally would not 927 * need to set the <code>JFileChooser</code> to use 928 * <code>CUSTOM_DIALOG</code> 929 * since a call to <code>setApproveButtonText</code> does this for you. 930 * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>. 931 * 932 * @param dialogType the type of dialog to be displayed: 933 * <ul> 934 * <li>JFileChooser.OPEN_DIALOG 935 * <li>JFileChooser.SAVE_DIALOG 936 * <li>JFileChooser.CUSTOM_DIALOG 937 * </ul> 938 * 939 * @exception IllegalArgumentException if <code>dialogType</code> is 940 * not legal 941 * @beaninfo 942 * preferred: true 943 * bound: true 944 * description: The type (open, save, custom) of the JFileChooser. 945 * enum: 946 * OPEN_DIALOG JFileChooser.OPEN_DIALOG 947 * SAVE_DIALOG JFileChooser.SAVE_DIALOG 948 * CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG 949 * 950 * @see #getDialogType 951 * @see #setApproveButtonText 952 */ 953 // PENDING(jeff) - fire button text change property 954 public void setDialogType(int dialogType) { 955 if(this.dialogType == dialogType) { 956 return; 957 } 958 checkDialogType(dialogType); 959 int oldValue = this.dialogType; 960 this.dialogType = dialogType; 961 if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) { 962 setApproveButtonText(null); 963 } 964 firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType); 965 } 966 967 private static void checkDialogType(int dialogType) { 968 if (!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG 969 || dialogType == CUSTOM_DIALOG)) { 970 throw new IllegalArgumentException( 971 "Incorrect Dialog Type: " + dialogType); 972 } 973 } 974 975 /** 976 * Sets the string that goes in the <code>JFileChooser</code> window's 977 * title bar. 978 * 979 * @param dialogTitle the new <code>String</code> for the title bar 980 * 981 * @beaninfo 982 * preferred: true 983 * bound: true 984 * description: The title of the JFileChooser dialog window. 985 * 986 * @see #getDialogTitle 987 * 988 */ 989 public void setDialogTitle(String dialogTitle) { 990 String oldValue = this.dialogTitle; 991 this.dialogTitle = dialogTitle; 992 if(dialog != null) { 993 dialog.setTitle(dialogTitle); 994 } 995 firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle); 996 } 997 998 /** 999 * Gets the string that goes in the <code>JFileChooser</code>'s titlebar. 1000 * 1001 * @return the string from the {@code JFileChooser} window's title bar 1002 * @see #setDialogTitle 1003 */ 1004 public String getDialogTitle() { 1005 return dialogTitle; 1006 } 1007 1008 // ************************************ 1009 // ***** JFileChooser View Options ***** 1010 // ************************************ 1011 1012 1013 1014 /** 1015 * Sets the tooltip text used in the <code>ApproveButton</code>. 1016 * If <code>null</code>, the UI object will determine the button's text. 1017 * 1018 * @beaninfo 1019 * preferred: true 1020 * bound: true 1021 * description: The tooltip text for the ApproveButton. 1022 * 1023 * @param toolTipText the tooltip text for the approve button 1024 * @see #setApproveButtonText 1025 * @see #setDialogType 1026 * @see #showDialog 1027 */ 1028 public void setApproveButtonToolTipText(String toolTipText) { 1029 if(approveButtonToolTipText == toolTipText) { 1030 return; 1031 } 1032 String oldValue = approveButtonToolTipText; 1033 approveButtonToolTipText = toolTipText; 1034 firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText); 1035 } 1036 1037 1038 /** 1039 * Returns the tooltip text used in the <code>ApproveButton</code>. 1040 * If <code>null</code>, the UI object will determine the button's text. 1041 * 1042 * @return the tooltip text used for the approve button 1043 * 1044 * @see #setApproveButtonText 1045 * @see #setDialogType 1046 * @see #showDialog 1047 */ 1048 public String getApproveButtonToolTipText() { 1049 return approveButtonToolTipText; 1050 } 1051 1052 /** 1053 * Returns the approve button's mnemonic. 1054 * @return an integer value for the mnemonic key 1055 * 1056 * @see #setApproveButtonMnemonic 1057 */ 1058 public int getApproveButtonMnemonic() { 1059 return approveButtonMnemonic; 1060 } 1061 1062 /** 1063 * Sets the approve button's mnemonic using a numeric keycode. 1064 * 1065 * @param mnemonic an integer value for the mnemonic key 1066 * 1067 * @beaninfo 1068 * preferred: true 1069 * bound: true 1070 * description: The mnemonic key accelerator for the ApproveButton. 1071 * 1072 * @see #getApproveButtonMnemonic 1073 */ 1074 public void setApproveButtonMnemonic(int mnemonic) { 1075 if(approveButtonMnemonic == mnemonic) { 1076 return; 1077 } 1078 int oldValue = approveButtonMnemonic; 1079 approveButtonMnemonic = mnemonic; 1080 firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic); 1081 } 1082 1083 /** 1084 * Sets the approve button's mnemonic using a character. 1085 * @param mnemonic a character value for the mnemonic key 1086 * 1087 * @see #getApproveButtonMnemonic 1088 */ 1089 public void setApproveButtonMnemonic(char mnemonic) { 1090 int vk = (int) mnemonic; 1091 if(vk >= 'a' && vk <='z') { 1092 vk -= ('a' - 'A'); 1093 } 1094 setApproveButtonMnemonic(vk); 1095 } 1096 1097 1098 /** 1099 * Sets the text used in the <code>ApproveButton</code> in the 1100 * <code>FileChooserUI</code>. 1101 * 1102 * @beaninfo 1103 * preferred: true 1104 * bound: true 1105 * description: The text that goes in the ApproveButton. 1106 * 1107 * @param approveButtonText the text used in the <code>ApproveButton</code> 1108 * 1109 * @see #getApproveButtonText 1110 * @see #setDialogType 1111 * @see #showDialog 1112 */ 1113 // PENDING(jeff) - have ui set this on dialog type change 1114 public void setApproveButtonText(String approveButtonText) { 1115 if(this.approveButtonText == approveButtonText) { 1116 return; 1117 } 1118 String oldValue = this.approveButtonText; 1119 this.approveButtonText = approveButtonText; 1120 firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText); 1121 } 1122 1123 /** 1124 * Returns the text used in the <code>ApproveButton</code> in the 1125 * <code>FileChooserUI</code>. 1126 * If <code>null</code>, the UI object will determine the button's text. 1127 * 1128 * Typically, this would be "Open" or "Save". 1129 * 1130 * @return the text used in the <code>ApproveButton</code> 1131 * 1132 * @see #setApproveButtonText 1133 * @see #setDialogType 1134 * @see #showDialog 1135 */ 1136 public String getApproveButtonText() { 1137 return approveButtonText; 1138 } 1139 1140 /** 1141 * Gets the list of user choosable file filters. 1142 * 1143 * @return a <code>FileFilter</code> array containing all the choosable 1144 * file filters 1145 * 1146 * @see #addChoosableFileFilter 1147 * @see #removeChoosableFileFilter 1148 * @see #resetChoosableFileFilters 1149 */ 1150 public FileFilter[] getChoosableFileFilters() { 1151 FileFilter[] filterArray = new FileFilter[filters.size()]; 1152 filters.copyInto(filterArray); 1153 return filterArray; 1154 } 1155 1156 /** 1157 * Adds a filter to the list of user choosable file filters. 1158 * For information on setting the file selection mode, see 1159 * {@link #setFileSelectionMode setFileSelectionMode}. 1160 * 1161 * @param filter the <code>FileFilter</code> to add to the choosable file 1162 * filter list 1163 * 1164 * @beaninfo 1165 * preferred: true 1166 * bound: true 1167 * description: Adds a filter to the list of user choosable file filters. 1168 * 1169 * @see #getChoosableFileFilters 1170 * @see #removeChoosableFileFilter 1171 * @see #resetChoosableFileFilters 1172 * @see #setFileSelectionMode 1173 */ 1174 public void addChoosableFileFilter(FileFilter filter) { 1175 if(filter != null && !filters.contains(filter)) { 1176 FileFilter[] oldValue = getChoosableFileFilters(); 1177 filters.addElement(filter); 1178 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1179 if (fileFilter == null && filters.size() == 1) { 1180 setFileFilter(filter); 1181 } 1182 } 1183 } 1184 1185 /** 1186 * Removes a filter from the list of user choosable file filters. Returns 1187 * true if the file filter was removed. 1188 * 1189 * @param f the file filter to be removed 1190 * @return true if the file filter was removed, false otherwise 1191 * @see #addChoosableFileFilter 1192 * @see #getChoosableFileFilters 1193 * @see #resetChoosableFileFilters 1194 */ 1195 public boolean removeChoosableFileFilter(FileFilter f) { 1196 int index = filters.indexOf(f); 1197 if (index >= 0) { 1198 if(getFileFilter() == f) { 1199 FileFilter aaff = getAcceptAllFileFilter(); 1200 if (isAcceptAllFileFilterUsed() && (aaff != f)) { 1201 // choose default filter if it is used 1202 setFileFilter(aaff); 1203 } 1204 else if (index > 0) { 1205 // choose the first filter, because it is not removed 1206 setFileFilter(filters.get(0)); 1207 } 1208 else if (filters.size() > 1) { 1209 // choose the second filter, because the first one is removed 1210 setFileFilter(filters.get(1)); 1211 } 1212 else { 1213 // no more filters 1214 setFileFilter(null); 1215 } 1216 } 1217 FileFilter[] oldValue = getChoosableFileFilters(); 1218 filters.removeElement(f); 1219 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1220 return true; 1221 } else { 1222 return false; 1223 } 1224 } 1225 1226 /** 1227 * Resets the choosable file filter list to its starting state. Normally, 1228 * this removes all added file filters while leaving the 1229 * <code>AcceptAll</code> file filter. 1230 * 1231 * @see #addChoosableFileFilter 1232 * @see #getChoosableFileFilters 1233 * @see #removeChoosableFileFilter 1234 */ 1235 public void resetChoosableFileFilters() { 1236 FileFilter[] oldValue = getChoosableFileFilters(); 1237 setFileFilter(null); 1238 filters.removeAllElements(); 1239 if(isAcceptAllFileFilterUsed()) { 1240 addChoosableFileFilter(getAcceptAllFileFilter()); 1241 } 1242 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1243 } 1244 1245 /** 1246 * Returns the <code>AcceptAll</code> file filter. 1247 * For example, on Microsoft Windows this would be All Files (*.*). 1248 * 1249 * @return the {@code AcceptAll} file filter 1250 */ 1251 public FileFilter getAcceptAllFileFilter() { 1252 FileFilter filter = null; 1253 if(getUI() != null) { 1254 filter = getUI().getAcceptAllFileFilter(this); 1255 } 1256 return filter; 1257 } 1258 1259 /** 1260 * Returns whether the <code>AcceptAll FileFilter</code> is used. 1261 * @return true if the <code>AcceptAll FileFilter</code> is used 1262 * @see #setAcceptAllFileFilterUsed 1263 * @since 1.3 1264 */ 1265 public boolean isAcceptAllFileFilterUsed() { 1266 return useAcceptAllFileFilter; 1267 } 1268 1269 /** 1270 * Determines whether the <code>AcceptAll FileFilter</code> is used 1271 * as an available choice in the choosable filter list. 1272 * If false, the <code>AcceptAll</code> file filter is removed from 1273 * the list of available file filters. 1274 * If true, the <code>AcceptAll</code> file filter will become the 1275 * actively used file filter. 1276 * 1277 * @param b a {@code boolean} which determines whether the {@code AcceptAll} 1278 * file filter is an available choice in the choosable filter list 1279 * @beaninfo 1280 * preferred: true 1281 * bound: true 1282 * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list. 1283 * 1284 * @see #isAcceptAllFileFilterUsed 1285 * @see #getAcceptAllFileFilter 1286 * @see #setFileFilter 1287 * @since 1.3 1288 */ 1289 public void setAcceptAllFileFilterUsed(boolean b) { 1290 boolean oldValue = useAcceptAllFileFilter; 1291 useAcceptAllFileFilter = b; 1292 if(!b) { 1293 removeChoosableFileFilter(getAcceptAllFileFilter()); 1294 } else { 1295 removeChoosableFileFilter(getAcceptAllFileFilter()); 1296 addChoosableFileFilter(getAcceptAllFileFilter()); 1297 } 1298 firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter); 1299 } 1300 1301 /** 1302 * Returns the accessory component. 1303 * 1304 * @return this JFileChooser's accessory component, or null 1305 * @see #setAccessory 1306 */ 1307 public JComponent getAccessory() { 1308 return accessory; 1309 } 1310 1311 /** 1312 * Sets the accessory component. An accessory is often used to show a 1313 * preview image of the selected file; however, it can be used for anything 1314 * that the programmer wishes, such as extra custom file chooser controls. 1315 * 1316 * <p> 1317 * Note: if there was a previous accessory, you should unregister 1318 * any listeners that the accessory might have registered with the 1319 * file chooser. 1320 * 1321 * @param newAccessory the accessory component to be set 1322 * @beaninfo 1323 * preferred: true 1324 * bound: true 1325 * description: Sets the accessory component on the JFileChooser. 1326 */ 1327 public void setAccessory(JComponent newAccessory) { 1328 JComponent oldValue = accessory; 1329 accessory = newAccessory; 1330 firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory); 1331 } 1332 1333 /** 1334 * Sets the <code>JFileChooser</code> to allow the user to just 1335 * select files, just select 1336 * directories, or select both files and directories. The default is 1337 * <code>JFilesChooser.FILES_ONLY</code>. 1338 * 1339 * @param mode the type of files to be displayed: 1340 * <ul> 1341 * <li>JFileChooser.FILES_ONLY 1342 * <li>JFileChooser.DIRECTORIES_ONLY 1343 * <li>JFileChooser.FILES_AND_DIRECTORIES 1344 * </ul> 1345 * 1346 * @exception IllegalArgumentException if <code>mode</code> is an 1347 * illegal file selection mode 1348 * @beaninfo 1349 * preferred: true 1350 * bound: true 1351 * description: Sets the types of files that the JFileChooser can choose. 1352 * enum: FILES_ONLY JFileChooser.FILES_ONLY 1353 * DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY 1354 * FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES 1355 * 1356 * 1357 * @see #getFileSelectionMode 1358 */ 1359 public void setFileSelectionMode(int mode) { 1360 if(fileSelectionMode == mode) { 1361 return; 1362 } 1363 1364 checkFileSelectionMode(mode); 1365 int oldValue = fileSelectionMode; 1366 fileSelectionMode = mode; 1367 firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode); 1368 } 1369 1370 private static void checkFileSelectionMode(int mode) { 1371 if ((mode != FILES_ONLY) && (mode != DIRECTORIES_ONLY) 1372 && (mode != FILES_AND_DIRECTORIES)) { 1373 throw new IllegalArgumentException( 1374 "Incorrect Mode for file selection: " + mode); 1375 } 1376 } 1377 1378 /** 1379 * Returns the current file-selection mode. The default is 1380 * <code>JFilesChooser.FILES_ONLY</code>. 1381 * 1382 * @return the type of files to be displayed, one of the following: 1383 * <ul> 1384 * <li>JFileChooser.FILES_ONLY 1385 * <li>JFileChooser.DIRECTORIES_ONLY 1386 * <li>JFileChooser.FILES_AND_DIRECTORIES 1387 * </ul> 1388 * @see #setFileSelectionMode 1389 */ 1390 public int getFileSelectionMode() { 1391 return fileSelectionMode; 1392 } 1393 1394 /** 1395 * Convenience call that determines if files are selectable based on the 1396 * current file selection mode. 1397 * 1398 * @return true if files are selectable, false otherwise 1399 * @see #setFileSelectionMode 1400 * @see #getFileSelectionMode 1401 */ 1402 public boolean isFileSelectionEnabled() { 1403 return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES)); 1404 } 1405 1406 /** 1407 * Convenience call that determines if directories are selectable based 1408 * on the current file selection mode. 1409 * 1410 * @return true if directories are selectable, false otherwise 1411 * @see #setFileSelectionMode 1412 * @see #getFileSelectionMode 1413 */ 1414 public boolean isDirectorySelectionEnabled() { 1415 return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES)); 1416 } 1417 1418 /** 1419 * Sets the file chooser to allow multiple file selections. 1420 * 1421 * @param b true if multiple files may be selected 1422 * @beaninfo 1423 * bound: true 1424 * description: Sets multiple file selection mode. 1425 * 1426 * @see #isMultiSelectionEnabled 1427 */ 1428 public void setMultiSelectionEnabled(boolean b) { 1429 if(multiSelectionEnabled == b) { 1430 return; 1431 } 1432 boolean oldValue = multiSelectionEnabled; 1433 multiSelectionEnabled = b; 1434 firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled); 1435 } 1436 1437 /** 1438 * Returns true if multiple files can be selected. 1439 * @return true if multiple files can be selected 1440 * @see #setMultiSelectionEnabled 1441 */ 1442 public boolean isMultiSelectionEnabled() { 1443 return multiSelectionEnabled; 1444 } 1445 1446 1447 /** 1448 * Returns true if hidden files are not shown in the file chooser; 1449 * otherwise, returns false. 1450 * 1451 * @return the status of the file hiding property 1452 * @see #setFileHidingEnabled 1453 */ 1454 public boolean isFileHidingEnabled() { 1455 return useFileHiding; 1456 } 1457 1458 /** 1459 * Sets file hiding on or off. If true, hidden files are not shown 1460 * in the file chooser. The job of determining which files are 1461 * shown is done by the <code>FileView</code>. 1462 * 1463 * @beaninfo 1464 * preferred: true 1465 * bound: true 1466 * description: Sets file hiding on or off. 1467 * 1468 * @param b the boolean value that determines whether file hiding is 1469 * turned on 1470 * @see #isFileHidingEnabled 1471 */ 1472 public void setFileHidingEnabled(boolean b) { 1473 // Dump showFilesListener since we'll ignore it from now on 1474 if (showFilesListener != null) { 1475 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener); 1476 showFilesListener = null; 1477 } 1478 boolean oldValue = useFileHiding; 1479 useFileHiding = b; 1480 firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding); 1481 } 1482 1483 /** 1484 * Sets the current file filter. The file filter is used by the 1485 * file chooser to filter out files from the user's view. 1486 * 1487 * @beaninfo 1488 * preferred: true 1489 * bound: true 1490 * description: Sets the File Filter used to filter out files of type. 1491 * 1492 * @param filter the new current file filter to use 1493 * @see #getFileFilter 1494 */ 1495 public void setFileFilter(FileFilter filter) { 1496 FileFilter oldValue = fileFilter; 1497 fileFilter = filter; 1498 if (filter != null) { 1499 if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) { 1500 Vector<File> fList = new Vector<File>(); 1501 boolean failed = false; 1502 for (File file : selectedFiles) { 1503 if (filter.accept(file)) { 1504 fList.add(file); 1505 } else { 1506 failed = true; 1507 } 1508 } 1509 if (failed) { 1510 setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()])); 1511 } 1512 } else if (selectedFile != null && !filter.accept(selectedFile)) { 1513 setSelectedFile(null); 1514 } 1515 } 1516 firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter); 1517 } 1518 1519 1520 /** 1521 * Returns the currently selected file filter. 1522 * 1523 * @return the current file filter 1524 * @see #setFileFilter 1525 * @see #addChoosableFileFilter 1526 */ 1527 public FileFilter getFileFilter() { 1528 return fileFilter; 1529 } 1530 1531 /** 1532 * Sets the file view to be used to retrieve UI information, such as 1533 * the icon that represents a file or the type description of a file. 1534 * 1535 * @param fileView a {@code FileView} to be used to retrieve UI information 1536 * @beaninfo 1537 * preferred: true 1538 * bound: true 1539 * description: Sets the File View used to get file type information. 1540 * 1541 * @see #getFileView 1542 */ 1543 public void setFileView(FileView fileView) { 1544 FileView oldValue = this.fileView; 1545 this.fileView = fileView; 1546 firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView); 1547 } 1548 1549 /** 1550 * Returns the current file view. 1551 * 1552 * @return the current file view 1553 * @see #setFileView 1554 */ 1555 public FileView getFileView() { 1556 return fileView; 1557 } 1558 1559 // ****************************** 1560 // *****FileView delegation ***** 1561 // ****************************** 1562 1563 // NOTE: all of the following methods attempt to delegate 1564 // first to the client set fileView, and if <code>null</code> is returned 1565 // (or there is now client defined fileView) then calls the 1566 // UI's default fileView. 1567 1568 /** 1569 * Returns the filename. 1570 * @param f the <code>File</code> 1571 * @return the <code>String</code> containing the filename for 1572 * <code>f</code> 1573 * @see FileView#getName 1574 */ 1575 public String getName(File f) { 1576 String filename = null; 1577 if(f != null) { 1578 if(getFileView() != null) { 1579 filename = getFileView().getName(f); 1580 } 1581 1582 FileView uiFileView = getUI().getFileView(this); 1583 1584 if(filename == null && uiFileView != null) { 1585 filename = uiFileView.getName(f); 1586 } 1587 } 1588 return filename; 1589 } 1590 1591 /** 1592 * Returns the file description. 1593 * @param f the <code>File</code> 1594 * @return the <code>String</code> containing the file description for 1595 * <code>f</code> 1596 * @see FileView#getDescription 1597 */ 1598 public String getDescription(File f) { 1599 String description = null; 1600 if(f != null) { 1601 if(getFileView() != null) { 1602 description = getFileView().getDescription(f); 1603 } 1604 1605 FileView uiFileView = getUI().getFileView(this); 1606 1607 if(description == null && uiFileView != null) { 1608 description = uiFileView.getDescription(f); 1609 } 1610 } 1611 return description; 1612 } 1613 1614 /** 1615 * Returns the file type. 1616 * @param f the <code>File</code> 1617 * @return the <code>String</code> containing the file type description for 1618 * <code>f</code> 1619 * @see FileView#getTypeDescription 1620 */ 1621 public String getTypeDescription(File f) { 1622 String typeDescription = null; 1623 if(f != null) { 1624 if(getFileView() != null) { 1625 typeDescription = getFileView().getTypeDescription(f); 1626 } 1627 1628 FileView uiFileView = getUI().getFileView(this); 1629 1630 if(typeDescription == null && uiFileView != null) { 1631 typeDescription = uiFileView.getTypeDescription(f); 1632 } 1633 } 1634 return typeDescription; 1635 } 1636 1637 /** 1638 * Returns the icon for this file or type of file, depending 1639 * on the system. 1640 * @param f the <code>File</code> 1641 * @return the <code>Icon</code> for this file, or type of file 1642 * @see FileView#getIcon 1643 */ 1644 public Icon getIcon(File f) { 1645 Icon icon = null; 1646 if (f != null) { 1647 if(getFileView() != null) { 1648 icon = getFileView().getIcon(f); 1649 } 1650 1651 FileView uiFileView = getUI().getFileView(this); 1652 1653 if(icon == null && uiFileView != null) { 1654 icon = uiFileView.getIcon(f); 1655 } 1656 } 1657 return icon; 1658 } 1659 1660 /** 1661 * Returns true if the file (directory) can be visited. 1662 * Returns false if the directory cannot be traversed. 1663 * @param f the <code>File</code> 1664 * @return true if the file/directory can be traversed, otherwise false 1665 * @see FileView#isTraversable 1666 */ 1667 public boolean isTraversable(File f) { 1668 Boolean traversable = null; 1669 if (f != null) { 1670 if (getFileView() != null) { 1671 traversable = getFileView().isTraversable(f); 1672 } 1673 1674 FileView uiFileView = getUI().getFileView(this); 1675 1676 if (traversable == null && uiFileView != null) { 1677 traversable = uiFileView.isTraversable(f); 1678 } 1679 if (traversable == null) { 1680 traversable = getFileSystemView().isTraversable(f); 1681 } 1682 } 1683 return (traversable != null && traversable.booleanValue()); 1684 } 1685 1686 /** 1687 * Returns true if the file should be displayed. 1688 * @param f the <code>File</code> 1689 * @return true if the file should be displayed, otherwise false 1690 * @see FileFilter#accept 1691 */ 1692 public boolean accept(File f) { 1693 boolean shown = true; 1694 if(f != null && fileFilter != null) { 1695 shown = fileFilter.accept(f); 1696 } 1697 return shown; 1698 } 1699 1700 /** 1701 * Sets the file system view that the <code>JFileChooser</code> uses for 1702 * accessing and creating file system resources, such as finding 1703 * the floppy drive and getting a list of root drives. 1704 * @param fsv the new <code>FileSystemView</code> 1705 * 1706 * @beaninfo 1707 * expert: true 1708 * bound: true 1709 * description: Sets the FileSytemView used to get filesystem information. 1710 * 1711 * @see FileSystemView 1712 */ 1713 public void setFileSystemView(FileSystemView fsv) { 1714 FileSystemView oldValue = fileSystemView; 1715 fileSystemView = fsv; 1716 firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView); 1717 } 1718 1719 /** 1720 * Returns the file system view. 1721 * @return the <code>FileSystemView</code> object 1722 * @see #setFileSystemView 1723 */ 1724 public FileSystemView getFileSystemView() { 1725 return fileSystemView; 1726 } 1727 1728 // ************************** 1729 // ***** Event Handling ***** 1730 // ************************** 1731 1732 /** 1733 * Called by the UI when the user hits the Approve button 1734 * (labeled "Open" or "Save", by default). This can also be 1735 * called by the programmer. 1736 * This method causes an action event to fire 1737 * with the command string equal to 1738 * <code>APPROVE_SELECTION</code>. 1739 * 1740 * @see #APPROVE_SELECTION 1741 */ 1742 public void approveSelection() { 1743 returnValue = APPROVE_OPTION; 1744 if(dialog != null) { 1745 dialog.setVisible(false); 1746 } 1747 fireActionPerformed(APPROVE_SELECTION); 1748 } 1749 1750 /** 1751 * Called by the UI when the user chooses the Cancel button. 1752 * This can also be called by the programmer. 1753 * This method causes an action event to fire 1754 * with the command string equal to 1755 * <code>CANCEL_SELECTION</code>. 1756 * 1757 * @see #CANCEL_SELECTION 1758 */ 1759 public void cancelSelection() { 1760 returnValue = CANCEL_OPTION; 1761 if(dialog != null) { 1762 dialog.setVisible(false); 1763 } 1764 fireActionPerformed(CANCEL_SELECTION); 1765 } 1766 1767 /** 1768 * Adds an <code>ActionListener</code> to the file chooser. 1769 * 1770 * @param l the listener to be added 1771 * 1772 * @see #approveSelection 1773 * @see #cancelSelection 1774 */ 1775 public void addActionListener(ActionListener l) { 1776 listenerList.add(ActionListener.class, l); 1777 } 1778 1779 /** 1780 * Removes an <code>ActionListener</code> from the file chooser. 1781 * 1782 * @param l the listener to be removed 1783 * 1784 * @see #addActionListener 1785 */ 1786 public void removeActionListener(ActionListener l) { 1787 listenerList.remove(ActionListener.class, l); 1788 } 1789 1790 /** 1791 * Returns an array of all the action listeners 1792 * registered on this file chooser. 1793 * 1794 * @return all of this file chooser's <code>ActionListener</code>s 1795 * or an empty 1796 * array if no action listeners are currently registered 1797 * 1798 * @see #addActionListener 1799 * @see #removeActionListener 1800 * 1801 * @since 1.4 1802 */ 1803 public ActionListener[] getActionListeners() { 1804 return listenerList.getListeners(ActionListener.class); 1805 } 1806 1807 /** 1808 * Notifies all listeners that have registered interest for 1809 * notification on this event type. The event instance 1810 * is lazily created using the <code>command</code> parameter. 1811 * 1812 * @param command a string that may specify a command associated with 1813 * the event 1814 * @see EventListenerList 1815 */ 1816 protected void fireActionPerformed(String command) { 1817 // Guaranteed to return a non-null array 1818 Object[] listeners = listenerList.getListenerList(); 1819 long mostRecentEventTime = EventQueue.getMostRecentEventTime(); 1820 int modifiers = 0; 1821 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 1822 if (currentEvent instanceof InputEvent) { 1823 modifiers = ((InputEvent)currentEvent).getModifiers(); 1824 } else if (currentEvent instanceof ActionEvent) { 1825 modifiers = ((ActionEvent)currentEvent).getModifiers(); 1826 } 1827 ActionEvent e = null; 1828 // Process the listeners last to first, notifying 1829 // those that are interested in this event 1830 for (int i = listeners.length-2; i>=0; i-=2) { 1831 if (listeners[i]==ActionListener.class) { 1832 // Lazily create the event: 1833 if (e == null) { 1834 e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 1835 command, mostRecentEventTime, 1836 modifiers); 1837 } 1838 ((ActionListener)listeners[i+1]).actionPerformed(e); 1839 } 1840 } 1841 } 1842 1843 private static class WeakPCL implements PropertyChangeListener { 1844 WeakReference<JFileChooser> jfcRef; 1845 1846 public WeakPCL(JFileChooser jfc) { 1847 jfcRef = new WeakReference<JFileChooser>(jfc); 1848 } 1849 public void propertyChange(PropertyChangeEvent ev) { 1850 assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP); 1851 JFileChooser jfc = jfcRef.get(); 1852 if (jfc == null) { 1853 // Our JFileChooser is no longer around, so we no longer need to 1854 // listen for PropertyChangeEvents. 1855 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this); 1856 } 1857 else { 1858 boolean oldValue = jfc.useFileHiding; 1859 jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue(); 1860 jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding); 1861 } 1862 } 1863 } 1864 1865 // ********************************* 1866 // ***** Pluggable L&F methods ***** 1867 // ********************************* 1868 1869 /** 1870 * Resets the UI property to a value from the current look and feel. 1871 * 1872 * @see JComponent#updateUI 1873 */ 1874 public void updateUI() { 1875 if (isAcceptAllFileFilterUsed()) { 1876 removeChoosableFileFilter(getAcceptAllFileFilter()); 1877 } 1878 FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this)); 1879 if (fileSystemView == null) { 1880 // We were probably deserialized 1881 setFileSystemView(FileSystemView.getFileSystemView()); 1882 } 1883 setUI(ui); 1884 1885 if(isAcceptAllFileFilterUsed()) { 1886 addChoosableFileFilter(getAcceptAllFileFilter()); 1887 } 1888 } 1889 1890 /** 1891 * Returns a string that specifies the name of the L&F class 1892 * that renders this component. 1893 * 1894 * @return the string "FileChooserUI" 1895 * @see JComponent#getUIClassID 1896 * @see UIDefaults#getUI 1897 * @beaninfo 1898 * expert: true 1899 * description: A string that specifies the name of the L&F class. 1900 */ 1901 public String getUIClassID() { 1902 return uiClassID; 1903 } 1904 1905 /** 1906 * Gets the UI object which implements the L&F for this component. 1907 * 1908 * @return the FileChooserUI object that implements the FileChooserUI L&F 1909 */ 1910 public FileChooserUI getUI() { 1911 return (FileChooserUI) ui; 1912 } 1913 1914 /** 1915 * See <code>readObject</code> and <code>writeObject</code> in 1916 * <code>JComponent</code> for more 1917 * information about serialization in Swing. 1918 */ 1919 private void readObject(java.io.ObjectInputStream in) 1920 throws IOException, ClassNotFoundException { 1921 ObjectInputStream.GetField f = in.readFields(); 1922 1923 dialogTitle = (String) f.get("dialogTitle", null); 1924 approveButtonText = (String) f.get("approveButtonText", null); 1925 approveButtonToolTipText = 1926 (String) f.get("approveButtonToolTipText", null); 1927 approveButtonMnemonic = f.get("approveButtonMnemonic", 0); 1928 @SuppressWarnings("unchecked") 1929 Vector<FileFilter> newFilters = (Vector<FileFilter>) f.get("filters", null); 1930 if (newFilters == null) { 1931 throw new InvalidObjectException("Null filters"); 1932 } 1933 filters = newFilters; 1934 dialog = (JDialog) f.get("dialog", null); 1935 int newDialogType = f.get("dialogType", OPEN_DIALOG); 1936 checkDialogType(newDialogType); 1937 dialogType = newDialogType; 1938 returnValue = f.get("returnValue", 0); 1939 accessory = (JComponent) f.get("accessory", null); 1940 fileView = (FileView) f.get("fileView", null); 1941 controlsShown = f.get("controlsShown", false); 1942 useFileHiding = f.get("useFileHiding", false); 1943 int newFileSelectionMode = f.get("fileSelectionMode", FILES_ONLY); 1944 checkFileSelectionMode(newFileSelectionMode); 1945 fileSelectionMode = newFileSelectionMode; 1946 multiSelectionEnabled = f.get("multiSelectionEnabled", false); 1947 useAcceptAllFileFilter = f.get("useAcceptAllFileFilter", false); 1948 boolean newDragEnabled = f.get("dragEnabled", false); 1949 checkDragEnabled(newDragEnabled); 1950 dragEnabled = newDragEnabled; 1951 fileFilter = (FileFilter) f.get("fileFilter", null); 1952 fileSystemView = (FileSystemView) f.get("fileSystemView", null); 1953 currentDirectory = (File) f.get("currentDirectory", null); 1954 selectedFile = (File) f.get("selectedFile", null); 1955 selectedFiles = (File[]) f.get("selectedFiles", null); 1956 accessibleContext = (AccessibleContext) f.get("accessibleContext", null); 1957 1958 installShowFilesListener(); 1959 } 1960 1961 /** 1962 * See <code>readObject</code> and <code>writeObject</code> in 1963 * <code>JComponent</code> for more 1964 * information about serialization in Swing. 1965 */ 1966 private void writeObject(ObjectOutputStream s) throws IOException { 1967 FileSystemView fsv = null; 1968 1969 if (isAcceptAllFileFilterUsed()) { 1970 //The AcceptAllFileFilter is UI specific, it will be reset by 1971 //updateUI() after deserialization 1972 removeChoosableFileFilter(getAcceptAllFileFilter()); 1973 } 1974 if (fileSystemView.equals(FileSystemView.getFileSystemView())) { 1975 //The default FileSystemView is platform specific, it will be 1976 //reset by updateUI() after deserialization 1977 fsv = fileSystemView; 1978 fileSystemView = null; 1979 } 1980 s.defaultWriteObject(); 1981 if (fsv != null) { 1982 fileSystemView = fsv; 1983 } 1984 if (isAcceptAllFileFilterUsed()) { 1985 addChoosableFileFilter(getAcceptAllFileFilter()); 1986 } 1987 if (getUIClassID().equals(uiClassID)) { 1988 byte count = JComponent.getWriteObjCounter(this); 1989 JComponent.setWriteObjCounter(this, --count); 1990 if (count == 0 && ui != null) { 1991 ui.installUI(this); 1992 } 1993 } 1994 } 1995 1996 1997 /** 1998 * Returns a string representation of this <code>JFileChooser</code>. 1999 * This method 2000 * is intended to be used only for debugging purposes, and the 2001 * content and format of the returned string may vary between 2002 * implementations. The returned string may be empty but may not 2003 * be <code>null</code>. 2004 * 2005 * @return a string representation of this <code>JFileChooser</code> 2006 */ 2007 protected String paramString() { 2008 String approveButtonTextString = (approveButtonText != null ? 2009 approveButtonText: ""); 2010 String dialogTitleString = (dialogTitle != null ? 2011 dialogTitle: ""); 2012 String dialogTypeString; 2013 if (dialogType == OPEN_DIALOG) { 2014 dialogTypeString = "OPEN_DIALOG"; 2015 } else if (dialogType == SAVE_DIALOG) { 2016 dialogTypeString = "SAVE_DIALOG"; 2017 } else if (dialogType == CUSTOM_DIALOG) { 2018 dialogTypeString = "CUSTOM_DIALOG"; 2019 } else dialogTypeString = ""; 2020 String returnValueString; 2021 if (returnValue == CANCEL_OPTION) { 2022 returnValueString = "CANCEL_OPTION"; 2023 } else if (returnValue == APPROVE_OPTION) { 2024 returnValueString = "APPROVE_OPTION"; 2025 } else if (returnValue == ERROR_OPTION) { 2026 returnValueString = "ERROR_OPTION"; 2027 } else returnValueString = ""; 2028 String useFileHidingString = (useFileHiding ? 2029 "true" : "false"); 2030 String fileSelectionModeString; 2031 if (fileSelectionMode == FILES_ONLY) { 2032 fileSelectionModeString = "FILES_ONLY"; 2033 } else if (fileSelectionMode == DIRECTORIES_ONLY) { 2034 fileSelectionModeString = "DIRECTORIES_ONLY"; 2035 } else if (fileSelectionMode == FILES_AND_DIRECTORIES) { 2036 fileSelectionModeString = "FILES_AND_DIRECTORIES"; 2037 } else fileSelectionModeString = ""; 2038 String currentDirectoryString = (currentDirectory != null ? 2039 currentDirectory.toString() : ""); 2040 String selectedFileString = (selectedFile != null ? 2041 selectedFile.toString() : ""); 2042 2043 return super.paramString() + 2044 ",approveButtonText=" + approveButtonTextString + 2045 ",currentDirectory=" + currentDirectoryString + 2046 ",dialogTitle=" + dialogTitleString + 2047 ",dialogType=" + dialogTypeString + 2048 ",fileSelectionMode=" + fileSelectionModeString + 2049 ",returnValue=" + returnValueString + 2050 ",selectedFile=" + selectedFileString + 2051 ",useFileHiding=" + useFileHidingString; 2052 } 2053 2054 ///////////////// 2055 // Accessibility support 2056 //////////////// 2057 2058 /** 2059 * {@code AccessibleContext} associated with this {@code JFileChooser} 2060 */ 2061 protected AccessibleContext accessibleContext = null; 2062 2063 /** 2064 * Gets the AccessibleContext associated with this JFileChooser. 2065 * For file choosers, the AccessibleContext takes the form of an 2066 * AccessibleJFileChooser. 2067 * A new AccessibleJFileChooser instance is created if necessary. 2068 * 2069 * @return an AccessibleJFileChooser that serves as the 2070 * AccessibleContext of this JFileChooser 2071 */ 2072 public AccessibleContext getAccessibleContext() { 2073 if (accessibleContext == null) { 2074 accessibleContext = new AccessibleJFileChooser(); 2075 } 2076 return accessibleContext; 2077 } 2078 2079 /** 2080 * This class implements accessibility support for the 2081 * <code>JFileChooser</code> class. It provides an implementation of the 2082 * Java Accessibility API appropriate to file chooser user-interface 2083 * elements. 2084 */ 2085 @SuppressWarnings("serial") // Superclass is not serializable across versions 2086 protected class AccessibleJFileChooser extends AccessibleJComponent { 2087 2088 /** 2089 * Gets the role of this object. 2090 * 2091 * @return an instance of AccessibleRole describing the role of the 2092 * object 2093 * @see AccessibleRole 2094 */ 2095 public AccessibleRole getAccessibleRole() { 2096 return AccessibleRole.FILE_CHOOSER; 2097 } 2098 2099 } // inner class AccessibleJFileChooser 2100 2101 }