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 @SuppressWarnings("deprecation") 761 public int showDialog(Component parent, String approveButtonText) 762 throws HeadlessException { 763 if (dialog != null) { 764 // Prevent to show second instance of dialog if the previous one still exists 765 return JFileChooser.ERROR_OPTION; 766 } 767 768 if(approveButtonText != null) { 769 setApproveButtonText(approveButtonText); 770 setDialogType(CUSTOM_DIALOG); 771 } 772 dialog = createDialog(parent); 773 dialog.addWindowListener(new WindowAdapter() { 774 public void windowClosing(WindowEvent e) { 775 returnValue = CANCEL_OPTION; 776 } 777 }); 778 returnValue = ERROR_OPTION; 779 rescanCurrentDirectory(); 780 781 dialog.show(); 782 firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null); 783 784 // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs) 785 // registers AWT listener for dialogs and produces memory leaks. It happens when 786 // installUI invoked after the showDialog method. 787 dialog.getContentPane().removeAll(); 788 dialog.dispose(); 789 dialog = null; 790 return returnValue; 791 } 792 793 /** 794 * Creates and returns a new <code>JDialog</code> wrapping 795 * <code>this</code> centered on the <code>parent</code> 796 * in the <code>parent</code>'s frame. 797 * This method can be overriden to further manipulate the dialog, 798 * to disable resizing, set the location, etc. Example: 799 * <pre> 800 * class MyFileChooser extends JFileChooser { 801 * protected JDialog createDialog(Component parent) throws HeadlessException { 802 * JDialog dialog = super.createDialog(parent); 803 * dialog.setLocation(300, 200); 804 * dialog.setResizable(false); 805 * return dialog; 806 * } 807 * } 808 * </pre> 809 * 810 * @param parent the parent component of the dialog; 811 * can be <code>null</code> 812 * @return a new <code>JDialog</code> containing this instance 813 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 814 * returns true. 815 * @see java.awt.GraphicsEnvironment#isHeadless 816 * @since 1.4 817 */ 818 protected JDialog createDialog(Component parent) throws HeadlessException { 819 FileChooserUI ui = getUI(); 820 String title = ui.getDialogTitle(this); 821 putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY, 822 title); 823 824 JDialog dialog; 825 Window window = JOptionPane.getWindowForComponent(parent); 826 if (window instanceof Frame) { 827 dialog = new JDialog((Frame)window, title, true); 828 } else { 829 dialog = new JDialog((Dialog)window, title, true); 830 } 831 dialog.setComponentOrientation(this.getComponentOrientation()); 832 833 Container contentPane = dialog.getContentPane(); 834 contentPane.setLayout(new BorderLayout()); 835 contentPane.add(this, BorderLayout.CENTER); 836 837 if (JDialog.isDefaultLookAndFeelDecorated()) { 838 boolean supportsWindowDecorations = 839 UIManager.getLookAndFeel().getSupportsWindowDecorations(); 840 if (supportsWindowDecorations) { 841 dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG); 842 } 843 } 844 dialog.pack(); 845 dialog.setLocationRelativeTo(parent); 846 847 return dialog; 848 } 849 850 // ************************** 851 // ***** Dialog Options ***** 852 // ************************** 853 854 /** 855 * Returns the value of the <code>controlButtonsAreShown</code> 856 * property. 857 * 858 * @return the value of the <code>controlButtonsAreShown</code> 859 * property 860 * 861 * @see #setControlButtonsAreShown 862 * @since 1.3 863 */ 864 public boolean getControlButtonsAreShown() { 865 return controlsShown; 866 } 867 868 869 /** 870 * Sets the property 871 * that indicates whether the <i>approve</i> and <i>cancel</i> 872 * buttons are shown in the file chooser. This property 873 * is <code>true</code> by default. Look and feels 874 * that always show these buttons will ignore the value 875 * of this property. 876 * This method fires a property-changed event, 877 * using the string value of 878 * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code> 879 * as the name of the property. 880 * 881 * @param b <code>false</code> if control buttons should not be 882 * shown; otherwise, <code>true</code> 883 * 884 * @beaninfo 885 * preferred: true 886 * bound: true 887 * description: Sets whether the approve & cancel buttons are shown. 888 * 889 * @see #getControlButtonsAreShown 890 * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY 891 * @since 1.3 892 */ 893 public void setControlButtonsAreShown(boolean b) { 894 if(controlsShown == b) { 895 return; 896 } 897 boolean oldValue = controlsShown; 898 controlsShown = b; 899 firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown); 900 } 901 902 /** 903 * Returns the type of this dialog. The default is 904 * <code>JFileChooser.OPEN_DIALOG</code>. 905 * 906 * @return the type of dialog to be displayed: 907 * <ul> 908 * <li>JFileChooser.OPEN_DIALOG 909 * <li>JFileChooser.SAVE_DIALOG 910 * <li>JFileChooser.CUSTOM_DIALOG 911 * </ul> 912 * 913 * @see #setDialogType 914 */ 915 public int getDialogType() { 916 return dialogType; 917 } 918 919 /** 920 * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you 921 * want to bring up a file chooser that the user can use to open a file. 922 * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose 923 * a file for saving. 924 * Use <code>CUSTOM_DIALOG</code> when you want to use the file 925 * chooser in a context other than "Open" or "Save". 926 * For instance, you might want to bring up a file chooser that allows 927 * the user to choose a file to execute. Note that you normally would not 928 * need to set the <code>JFileChooser</code> to use 929 * <code>CUSTOM_DIALOG</code> 930 * since a call to <code>setApproveButtonText</code> does this for you. 931 * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>. 932 * 933 * @param dialogType the type of dialog to be displayed: 934 * <ul> 935 * <li>JFileChooser.OPEN_DIALOG 936 * <li>JFileChooser.SAVE_DIALOG 937 * <li>JFileChooser.CUSTOM_DIALOG 938 * </ul> 939 * 940 * @exception IllegalArgumentException if <code>dialogType</code> is 941 * not legal 942 * @beaninfo 943 * preferred: true 944 * bound: true 945 * description: The type (open, save, custom) of the JFileChooser. 946 * enum: 947 * OPEN_DIALOG JFileChooser.OPEN_DIALOG 948 * SAVE_DIALOG JFileChooser.SAVE_DIALOG 949 * CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG 950 * 951 * @see #getDialogType 952 * @see #setApproveButtonText 953 */ 954 // PENDING(jeff) - fire button text change property 955 public void setDialogType(int dialogType) { 956 if(this.dialogType == dialogType) { 957 return; 958 } 959 checkDialogType(dialogType); 960 int oldValue = this.dialogType; 961 this.dialogType = dialogType; 962 if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) { 963 setApproveButtonText(null); 964 } 965 firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType); 966 } 967 968 private static void checkDialogType(int dialogType) { 969 if (!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG 970 || dialogType == CUSTOM_DIALOG)) { 971 throw new IllegalArgumentException( 972 "Incorrect Dialog Type: " + dialogType); 973 } 974 } 975 976 /** 977 * Sets the string that goes in the <code>JFileChooser</code> window's 978 * title bar. 979 * 980 * @param dialogTitle the new <code>String</code> for the title bar 981 * 982 * @beaninfo 983 * preferred: true 984 * bound: true 985 * description: The title of the JFileChooser dialog window. 986 * 987 * @see #getDialogTitle 988 * 989 */ 990 public void setDialogTitle(String dialogTitle) { 991 String oldValue = this.dialogTitle; 992 this.dialogTitle = dialogTitle; 993 if(dialog != null) { 994 dialog.setTitle(dialogTitle); 995 } 996 firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle); 997 } 998 999 /** 1000 * Gets the string that goes in the <code>JFileChooser</code>'s titlebar. 1001 * 1002 * @return the string from the {@code JFileChooser} window's title bar 1003 * @see #setDialogTitle 1004 */ 1005 public String getDialogTitle() { 1006 return dialogTitle; 1007 } 1008 1009 // ************************************ 1010 // ***** JFileChooser View Options ***** 1011 // ************************************ 1012 1013 1014 1015 /** 1016 * Sets the tooltip text used in the <code>ApproveButton</code>. 1017 * If <code>null</code>, the UI object will determine the button's text. 1018 * 1019 * @beaninfo 1020 * preferred: true 1021 * bound: true 1022 * description: The tooltip text for the ApproveButton. 1023 * 1024 * @param toolTipText the tooltip text for the approve button 1025 * @see #setApproveButtonText 1026 * @see #setDialogType 1027 * @see #showDialog 1028 */ 1029 public void setApproveButtonToolTipText(String toolTipText) { 1030 if(approveButtonToolTipText == toolTipText) { 1031 return; 1032 } 1033 String oldValue = approveButtonToolTipText; 1034 approveButtonToolTipText = toolTipText; 1035 firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText); 1036 } 1037 1038 1039 /** 1040 * Returns the tooltip text used in the <code>ApproveButton</code>. 1041 * If <code>null</code>, the UI object will determine the button's text. 1042 * 1043 * @return the tooltip text used for the approve button 1044 * 1045 * @see #setApproveButtonText 1046 * @see #setDialogType 1047 * @see #showDialog 1048 */ 1049 public String getApproveButtonToolTipText() { 1050 return approveButtonToolTipText; 1051 } 1052 1053 /** 1054 * Returns the approve button's mnemonic. 1055 * @return an integer value for the mnemonic key 1056 * 1057 * @see #setApproveButtonMnemonic 1058 */ 1059 public int getApproveButtonMnemonic() { 1060 return approveButtonMnemonic; 1061 } 1062 1063 /** 1064 * Sets the approve button's mnemonic using a numeric keycode. 1065 * 1066 * @param mnemonic an integer value for the mnemonic key 1067 * 1068 * @beaninfo 1069 * preferred: true 1070 * bound: true 1071 * description: The mnemonic key accelerator for the ApproveButton. 1072 * 1073 * @see #getApproveButtonMnemonic 1074 */ 1075 public void setApproveButtonMnemonic(int mnemonic) { 1076 if(approveButtonMnemonic == mnemonic) { 1077 return; 1078 } 1079 int oldValue = approveButtonMnemonic; 1080 approveButtonMnemonic = mnemonic; 1081 firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic); 1082 } 1083 1084 /** 1085 * Sets the approve button's mnemonic using a character. 1086 * @param mnemonic a character value for the mnemonic key 1087 * 1088 * @see #getApproveButtonMnemonic 1089 */ 1090 public void setApproveButtonMnemonic(char mnemonic) { 1091 int vk = (int) mnemonic; 1092 if(vk >= 'a' && vk <='z') { 1093 vk -= ('a' - 'A'); 1094 } 1095 setApproveButtonMnemonic(vk); 1096 } 1097 1098 1099 /** 1100 * Sets the text used in the <code>ApproveButton</code> in the 1101 * <code>FileChooserUI</code>. 1102 * 1103 * @beaninfo 1104 * preferred: true 1105 * bound: true 1106 * description: The text that goes in the ApproveButton. 1107 * 1108 * @param approveButtonText the text used in the <code>ApproveButton</code> 1109 * 1110 * @see #getApproveButtonText 1111 * @see #setDialogType 1112 * @see #showDialog 1113 */ 1114 // PENDING(jeff) - have ui set this on dialog type change 1115 public void setApproveButtonText(String approveButtonText) { 1116 if(this.approveButtonText == approveButtonText) { 1117 return; 1118 } 1119 String oldValue = this.approveButtonText; 1120 this.approveButtonText = approveButtonText; 1121 firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText); 1122 } 1123 1124 /** 1125 * Returns the text used in the <code>ApproveButton</code> in the 1126 * <code>FileChooserUI</code>. 1127 * If <code>null</code>, the UI object will determine the button's text. 1128 * 1129 * Typically, this would be "Open" or "Save". 1130 * 1131 * @return the text used in the <code>ApproveButton</code> 1132 * 1133 * @see #setApproveButtonText 1134 * @see #setDialogType 1135 * @see #showDialog 1136 */ 1137 public String getApproveButtonText() { 1138 return approveButtonText; 1139 } 1140 1141 /** 1142 * Gets the list of user choosable file filters. 1143 * 1144 * @return a <code>FileFilter</code> array containing all the choosable 1145 * file filters 1146 * 1147 * @see #addChoosableFileFilter 1148 * @see #removeChoosableFileFilter 1149 * @see #resetChoosableFileFilters 1150 */ 1151 public FileFilter[] getChoosableFileFilters() { 1152 FileFilter[] filterArray = new FileFilter[filters.size()]; 1153 filters.copyInto(filterArray); 1154 return filterArray; 1155 } 1156 1157 /** 1158 * Adds a filter to the list of user choosable file filters. 1159 * For information on setting the file selection mode, see 1160 * {@link #setFileSelectionMode setFileSelectionMode}. 1161 * 1162 * @param filter the <code>FileFilter</code> to add to the choosable file 1163 * filter list 1164 * 1165 * @beaninfo 1166 * preferred: true 1167 * bound: true 1168 * description: Adds a filter to the list of user choosable file filters. 1169 * 1170 * @see #getChoosableFileFilters 1171 * @see #removeChoosableFileFilter 1172 * @see #resetChoosableFileFilters 1173 * @see #setFileSelectionMode 1174 */ 1175 public void addChoosableFileFilter(FileFilter filter) { 1176 if(filter != null && !filters.contains(filter)) { 1177 FileFilter[] oldValue = getChoosableFileFilters(); 1178 filters.addElement(filter); 1179 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1180 if (fileFilter == null && filters.size() == 1) { 1181 setFileFilter(filter); 1182 } 1183 } 1184 } 1185 1186 /** 1187 * Removes a filter from the list of user choosable file filters. Returns 1188 * true if the file filter was removed. 1189 * 1190 * @param f the file filter to be removed 1191 * @return true if the file filter was removed, false otherwise 1192 * @see #addChoosableFileFilter 1193 * @see #getChoosableFileFilters 1194 * @see #resetChoosableFileFilters 1195 */ 1196 public boolean removeChoosableFileFilter(FileFilter f) { 1197 int index = filters.indexOf(f); 1198 if (index >= 0) { 1199 if(getFileFilter() == f) { 1200 FileFilter aaff = getAcceptAllFileFilter(); 1201 if (isAcceptAllFileFilterUsed() && (aaff != f)) { 1202 // choose default filter if it is used 1203 setFileFilter(aaff); 1204 } 1205 else if (index > 0) { 1206 // choose the first filter, because it is not removed 1207 setFileFilter(filters.get(0)); 1208 } 1209 else if (filters.size() > 1) { 1210 // choose the second filter, because the first one is removed 1211 setFileFilter(filters.get(1)); 1212 } 1213 else { 1214 // no more filters 1215 setFileFilter(null); 1216 } 1217 } 1218 FileFilter[] oldValue = getChoosableFileFilters(); 1219 filters.removeElement(f); 1220 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1221 return true; 1222 } else { 1223 return false; 1224 } 1225 } 1226 1227 /** 1228 * Resets the choosable file filter list to its starting state. Normally, 1229 * this removes all added file filters while leaving the 1230 * <code>AcceptAll</code> file filter. 1231 * 1232 * @see #addChoosableFileFilter 1233 * @see #getChoosableFileFilters 1234 * @see #removeChoosableFileFilter 1235 */ 1236 public void resetChoosableFileFilters() { 1237 FileFilter[] oldValue = getChoosableFileFilters(); 1238 setFileFilter(null); 1239 filters.removeAllElements(); 1240 if(isAcceptAllFileFilterUsed()) { 1241 addChoosableFileFilter(getAcceptAllFileFilter()); 1242 } 1243 firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters()); 1244 } 1245 1246 /** 1247 * Returns the <code>AcceptAll</code> file filter. 1248 * For example, on Microsoft Windows this would be All Files (*.*). 1249 * 1250 * @return the {@code AcceptAll} file filter 1251 */ 1252 public FileFilter getAcceptAllFileFilter() { 1253 FileFilter filter = null; 1254 if(getUI() != null) { 1255 filter = getUI().getAcceptAllFileFilter(this); 1256 } 1257 return filter; 1258 } 1259 1260 /** 1261 * Returns whether the <code>AcceptAll FileFilter</code> is used. 1262 * @return true if the <code>AcceptAll FileFilter</code> is used 1263 * @see #setAcceptAllFileFilterUsed 1264 * @since 1.3 1265 */ 1266 public boolean isAcceptAllFileFilterUsed() { 1267 return useAcceptAllFileFilter; 1268 } 1269 1270 /** 1271 * Determines whether the <code>AcceptAll FileFilter</code> is used 1272 * as an available choice in the choosable filter list. 1273 * If false, the <code>AcceptAll</code> file filter is removed from 1274 * the list of available file filters. 1275 * If true, the <code>AcceptAll</code> file filter will become the 1276 * actively used file filter. 1277 * 1278 * @param b a {@code boolean} which determines whether the {@code AcceptAll} 1279 * file filter is an available choice in the choosable filter list 1280 * @beaninfo 1281 * preferred: true 1282 * bound: true 1283 * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list. 1284 * 1285 * @see #isAcceptAllFileFilterUsed 1286 * @see #getAcceptAllFileFilter 1287 * @see #setFileFilter 1288 * @since 1.3 1289 */ 1290 public void setAcceptAllFileFilterUsed(boolean b) { 1291 boolean oldValue = useAcceptAllFileFilter; 1292 useAcceptAllFileFilter = b; 1293 if(!b) { 1294 removeChoosableFileFilter(getAcceptAllFileFilter()); 1295 } else { 1296 removeChoosableFileFilter(getAcceptAllFileFilter()); 1297 addChoosableFileFilter(getAcceptAllFileFilter()); 1298 } 1299 firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter); 1300 } 1301 1302 /** 1303 * Returns the accessory component. 1304 * 1305 * @return this JFileChooser's accessory component, or null 1306 * @see #setAccessory 1307 */ 1308 public JComponent getAccessory() { 1309 return accessory; 1310 } 1311 1312 /** 1313 * Sets the accessory component. An accessory is often used to show a 1314 * preview image of the selected file; however, it can be used for anything 1315 * that the programmer wishes, such as extra custom file chooser controls. 1316 * 1317 * <p> 1318 * Note: if there was a previous accessory, you should unregister 1319 * any listeners that the accessory might have registered with the 1320 * file chooser. 1321 * 1322 * @param newAccessory the accessory component to be set 1323 * @beaninfo 1324 * preferred: true 1325 * bound: true 1326 * description: Sets the accessory component on the JFileChooser. 1327 */ 1328 public void setAccessory(JComponent newAccessory) { 1329 JComponent oldValue = accessory; 1330 accessory = newAccessory; 1331 firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory); 1332 } 1333 1334 /** 1335 * Sets the <code>JFileChooser</code> to allow the user to just 1336 * select files, just select 1337 * directories, or select both files and directories. The default is 1338 * <code>JFilesChooser.FILES_ONLY</code>. 1339 * 1340 * @param mode the type of files to be displayed: 1341 * <ul> 1342 * <li>JFileChooser.FILES_ONLY 1343 * <li>JFileChooser.DIRECTORIES_ONLY 1344 * <li>JFileChooser.FILES_AND_DIRECTORIES 1345 * </ul> 1346 * 1347 * @exception IllegalArgumentException if <code>mode</code> is an 1348 * illegal file selection mode 1349 * @beaninfo 1350 * preferred: true 1351 * bound: true 1352 * description: Sets the types of files that the JFileChooser can choose. 1353 * enum: FILES_ONLY JFileChooser.FILES_ONLY 1354 * DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY 1355 * FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES 1356 * 1357 * 1358 * @see #getFileSelectionMode 1359 */ 1360 public void setFileSelectionMode(int mode) { 1361 if(fileSelectionMode == mode) { 1362 return; 1363 } 1364 1365 checkFileSelectionMode(mode); 1366 int oldValue = fileSelectionMode; 1367 fileSelectionMode = mode; 1368 firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode); 1369 } 1370 1371 private static void checkFileSelectionMode(int mode) { 1372 if ((mode != FILES_ONLY) && (mode != DIRECTORIES_ONLY) 1373 && (mode != FILES_AND_DIRECTORIES)) { 1374 throw new IllegalArgumentException( 1375 "Incorrect Mode for file selection: " + mode); 1376 } 1377 } 1378 1379 /** 1380 * Returns the current file-selection mode. The default is 1381 * <code>JFilesChooser.FILES_ONLY</code>. 1382 * 1383 * @return the type of files to be displayed, one of the following: 1384 * <ul> 1385 * <li>JFileChooser.FILES_ONLY 1386 * <li>JFileChooser.DIRECTORIES_ONLY 1387 * <li>JFileChooser.FILES_AND_DIRECTORIES 1388 * </ul> 1389 * @see #setFileSelectionMode 1390 */ 1391 public int getFileSelectionMode() { 1392 return fileSelectionMode; 1393 } 1394 1395 /** 1396 * Convenience call that determines if files are selectable based on the 1397 * current file selection mode. 1398 * 1399 * @return true if files are selectable, false otherwise 1400 * @see #setFileSelectionMode 1401 * @see #getFileSelectionMode 1402 */ 1403 public boolean isFileSelectionEnabled() { 1404 return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES)); 1405 } 1406 1407 /** 1408 * Convenience call that determines if directories are selectable based 1409 * on the current file selection mode. 1410 * 1411 * @return true if directories are selectable, false otherwise 1412 * @see #setFileSelectionMode 1413 * @see #getFileSelectionMode 1414 */ 1415 public boolean isDirectorySelectionEnabled() { 1416 return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES)); 1417 } 1418 1419 /** 1420 * Sets the file chooser to allow multiple file selections. 1421 * 1422 * @param b true if multiple files may be selected 1423 * @beaninfo 1424 * bound: true 1425 * description: Sets multiple file selection mode. 1426 * 1427 * @see #isMultiSelectionEnabled 1428 */ 1429 public void setMultiSelectionEnabled(boolean b) { 1430 if(multiSelectionEnabled == b) { 1431 return; 1432 } 1433 boolean oldValue = multiSelectionEnabled; 1434 multiSelectionEnabled = b; 1435 firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled); 1436 } 1437 1438 /** 1439 * Returns true if multiple files can be selected. 1440 * @return true if multiple files can be selected 1441 * @see #setMultiSelectionEnabled 1442 */ 1443 public boolean isMultiSelectionEnabled() { 1444 return multiSelectionEnabled; 1445 } 1446 1447 1448 /** 1449 * Returns true if hidden files are not shown in the file chooser; 1450 * otherwise, returns false. 1451 * 1452 * @return the status of the file hiding property 1453 * @see #setFileHidingEnabled 1454 */ 1455 public boolean isFileHidingEnabled() { 1456 return useFileHiding; 1457 } 1458 1459 /** 1460 * Sets file hiding on or off. If true, hidden files are not shown 1461 * in the file chooser. The job of determining which files are 1462 * shown is done by the <code>FileView</code>. 1463 * 1464 * @beaninfo 1465 * preferred: true 1466 * bound: true 1467 * description: Sets file hiding on or off. 1468 * 1469 * @param b the boolean value that determines whether file hiding is 1470 * turned on 1471 * @see #isFileHidingEnabled 1472 */ 1473 public void setFileHidingEnabled(boolean b) { 1474 // Dump showFilesListener since we'll ignore it from now on 1475 if (showFilesListener != null) { 1476 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener); 1477 showFilesListener = null; 1478 } 1479 boolean oldValue = useFileHiding; 1480 useFileHiding = b; 1481 firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding); 1482 } 1483 1484 /** 1485 * Sets the current file filter. The file filter is used by the 1486 * file chooser to filter out files from the user's view. 1487 * 1488 * @beaninfo 1489 * preferred: true 1490 * bound: true 1491 * description: Sets the File Filter used to filter out files of type. 1492 * 1493 * @param filter the new current file filter to use 1494 * @see #getFileFilter 1495 */ 1496 public void setFileFilter(FileFilter filter) { 1497 FileFilter oldValue = fileFilter; 1498 fileFilter = filter; 1499 if (filter != null) { 1500 if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) { 1501 Vector<File> fList = new Vector<File>(); 1502 boolean failed = false; 1503 for (File file : selectedFiles) { 1504 if (filter.accept(file)) { 1505 fList.add(file); 1506 } else { 1507 failed = true; 1508 } 1509 } 1510 if (failed) { 1511 setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()])); 1512 } 1513 } else if (selectedFile != null && !filter.accept(selectedFile)) { 1514 setSelectedFile(null); 1515 } 1516 } 1517 firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter); 1518 } 1519 1520 1521 /** 1522 * Returns the currently selected file filter. 1523 * 1524 * @return the current file filter 1525 * @see #setFileFilter 1526 * @see #addChoosableFileFilter 1527 */ 1528 public FileFilter getFileFilter() { 1529 return fileFilter; 1530 } 1531 1532 /** 1533 * Sets the file view to be used to retrieve UI information, such as 1534 * the icon that represents a file or the type description of a file. 1535 * 1536 * @param fileView a {@code FileView} to be used to retrieve UI information 1537 * @beaninfo 1538 * preferred: true 1539 * bound: true 1540 * description: Sets the File View used to get file type information. 1541 * 1542 * @see #getFileView 1543 */ 1544 public void setFileView(FileView fileView) { 1545 FileView oldValue = this.fileView; 1546 this.fileView = fileView; 1547 firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView); 1548 } 1549 1550 /** 1551 * Returns the current file view. 1552 * 1553 * @return the current file view 1554 * @see #setFileView 1555 */ 1556 public FileView getFileView() { 1557 return fileView; 1558 } 1559 1560 // ****************************** 1561 // *****FileView delegation ***** 1562 // ****************************** 1563 1564 // NOTE: all of the following methods attempt to delegate 1565 // first to the client set fileView, and if <code>null</code> is returned 1566 // (or there is now client defined fileView) then calls the 1567 // UI's default fileView. 1568 1569 /** 1570 * Returns the filename. 1571 * @param f the <code>File</code> 1572 * @return the <code>String</code> containing the filename for 1573 * <code>f</code> 1574 * @see FileView#getName 1575 */ 1576 public String getName(File f) { 1577 String filename = null; 1578 if(f != null) { 1579 if(getFileView() != null) { 1580 filename = getFileView().getName(f); 1581 } 1582 1583 FileView uiFileView = getUI().getFileView(this); 1584 1585 if(filename == null && uiFileView != null) { 1586 filename = uiFileView.getName(f); 1587 } 1588 } 1589 return filename; 1590 } 1591 1592 /** 1593 * Returns the file description. 1594 * @param f the <code>File</code> 1595 * @return the <code>String</code> containing the file description for 1596 * <code>f</code> 1597 * @see FileView#getDescription 1598 */ 1599 public String getDescription(File f) { 1600 String description = null; 1601 if(f != null) { 1602 if(getFileView() != null) { 1603 description = getFileView().getDescription(f); 1604 } 1605 1606 FileView uiFileView = getUI().getFileView(this); 1607 1608 if(description == null && uiFileView != null) { 1609 description = uiFileView.getDescription(f); 1610 } 1611 } 1612 return description; 1613 } 1614 1615 /** 1616 * Returns the file type. 1617 * @param f the <code>File</code> 1618 * @return the <code>String</code> containing the file type description for 1619 * <code>f</code> 1620 * @see FileView#getTypeDescription 1621 */ 1622 public String getTypeDescription(File f) { 1623 String typeDescription = null; 1624 if(f != null) { 1625 if(getFileView() != null) { 1626 typeDescription = getFileView().getTypeDescription(f); 1627 } 1628 1629 FileView uiFileView = getUI().getFileView(this); 1630 1631 if(typeDescription == null && uiFileView != null) { 1632 typeDescription = uiFileView.getTypeDescription(f); 1633 } 1634 } 1635 return typeDescription; 1636 } 1637 1638 /** 1639 * Returns the icon for this file or type of file, depending 1640 * on the system. 1641 * @param f the <code>File</code> 1642 * @return the <code>Icon</code> for this file, or type of file 1643 * @see FileView#getIcon 1644 */ 1645 public Icon getIcon(File f) { 1646 Icon icon = null; 1647 if (f != null) { 1648 if(getFileView() != null) { 1649 icon = getFileView().getIcon(f); 1650 } 1651 1652 FileView uiFileView = getUI().getFileView(this); 1653 1654 if(icon == null && uiFileView != null) { 1655 icon = uiFileView.getIcon(f); 1656 } 1657 } 1658 return icon; 1659 } 1660 1661 /** 1662 * Returns true if the file (directory) can be visited. 1663 * Returns false if the directory cannot be traversed. 1664 * @param f the <code>File</code> 1665 * @return true if the file/directory can be traversed, otherwise false 1666 * @see FileView#isTraversable 1667 */ 1668 public boolean isTraversable(File f) { 1669 Boolean traversable = null; 1670 if (f != null) { 1671 if (getFileView() != null) { 1672 traversable = getFileView().isTraversable(f); 1673 } 1674 1675 FileView uiFileView = getUI().getFileView(this); 1676 1677 if (traversable == null && uiFileView != null) { 1678 traversable = uiFileView.isTraversable(f); 1679 } 1680 if (traversable == null) { 1681 traversable = getFileSystemView().isTraversable(f); 1682 } 1683 } 1684 return (traversable != null && traversable.booleanValue()); 1685 } 1686 1687 /** 1688 * Returns true if the file should be displayed. 1689 * @param f the <code>File</code> 1690 * @return true if the file should be displayed, otherwise false 1691 * @see FileFilter#accept 1692 */ 1693 public boolean accept(File f) { 1694 boolean shown = true; 1695 if(f != null && fileFilter != null) { 1696 shown = fileFilter.accept(f); 1697 } 1698 return shown; 1699 } 1700 1701 /** 1702 * Sets the file system view that the <code>JFileChooser</code> uses for 1703 * accessing and creating file system resources, such as finding 1704 * the floppy drive and getting a list of root drives. 1705 * @param fsv the new <code>FileSystemView</code> 1706 * 1707 * @beaninfo 1708 * expert: true 1709 * bound: true 1710 * description: Sets the FileSytemView used to get filesystem information. 1711 * 1712 * @see FileSystemView 1713 */ 1714 public void setFileSystemView(FileSystemView fsv) { 1715 FileSystemView oldValue = fileSystemView; 1716 fileSystemView = fsv; 1717 firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView); 1718 } 1719 1720 /** 1721 * Returns the file system view. 1722 * @return the <code>FileSystemView</code> object 1723 * @see #setFileSystemView 1724 */ 1725 public FileSystemView getFileSystemView() { 1726 return fileSystemView; 1727 } 1728 1729 // ************************** 1730 // ***** Event Handling ***** 1731 // ************************** 1732 1733 /** 1734 * Called by the UI when the user hits the Approve button 1735 * (labeled "Open" or "Save", by default). This can also be 1736 * called by the programmer. 1737 * This method causes an action event to fire 1738 * with the command string equal to 1739 * <code>APPROVE_SELECTION</code>. 1740 * 1741 * @see #APPROVE_SELECTION 1742 */ 1743 public void approveSelection() { 1744 returnValue = APPROVE_OPTION; 1745 if(dialog != null) { 1746 dialog.setVisible(false); 1747 } 1748 fireActionPerformed(APPROVE_SELECTION); 1749 } 1750 1751 /** 1752 * Called by the UI when the user chooses the Cancel button. 1753 * This can also be called by the programmer. 1754 * This method causes an action event to fire 1755 * with the command string equal to 1756 * <code>CANCEL_SELECTION</code>. 1757 * 1758 * @see #CANCEL_SELECTION 1759 */ 1760 public void cancelSelection() { 1761 returnValue = CANCEL_OPTION; 1762 if(dialog != null) { 1763 dialog.setVisible(false); 1764 } 1765 fireActionPerformed(CANCEL_SELECTION); 1766 } 1767 1768 /** 1769 * Adds an <code>ActionListener</code> to the file chooser. 1770 * 1771 * @param l the listener to be added 1772 * 1773 * @see #approveSelection 1774 * @see #cancelSelection 1775 */ 1776 public void addActionListener(ActionListener l) { 1777 listenerList.add(ActionListener.class, l); 1778 } 1779 1780 /** 1781 * Removes an <code>ActionListener</code> from the file chooser. 1782 * 1783 * @param l the listener to be removed 1784 * 1785 * @see #addActionListener 1786 */ 1787 public void removeActionListener(ActionListener l) { 1788 listenerList.remove(ActionListener.class, l); 1789 } 1790 1791 /** 1792 * Returns an array of all the action listeners 1793 * registered on this file chooser. 1794 * 1795 * @return all of this file chooser's <code>ActionListener</code>s 1796 * or an empty 1797 * array if no action listeners are currently registered 1798 * 1799 * @see #addActionListener 1800 * @see #removeActionListener 1801 * 1802 * @since 1.4 1803 */ 1804 public ActionListener[] getActionListeners() { 1805 return listenerList.getListeners(ActionListener.class); 1806 } 1807 1808 /** 1809 * Notifies all listeners that have registered interest for 1810 * notification on this event type. The event instance 1811 * is lazily created using the <code>command</code> parameter. 1812 * 1813 * @param command a string that may specify a command associated with 1814 * the event 1815 * @see EventListenerList 1816 */ 1817 protected void fireActionPerformed(String command) { 1818 // Guaranteed to return a non-null array 1819 Object[] listeners = listenerList.getListenerList(); 1820 long mostRecentEventTime = EventQueue.getMostRecentEventTime(); 1821 int modifiers = 0; 1822 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 1823 if (currentEvent instanceof InputEvent) { 1824 modifiers = ((InputEvent)currentEvent).getModifiers(); 1825 } else if (currentEvent instanceof ActionEvent) { 1826 modifiers = ((ActionEvent)currentEvent).getModifiers(); 1827 } 1828 ActionEvent e = null; 1829 // Process the listeners last to first, notifying 1830 // those that are interested in this event 1831 for (int i = listeners.length-2; i>=0; i-=2) { 1832 if (listeners[i]==ActionListener.class) { 1833 // Lazily create the event: 1834 if (e == null) { 1835 e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 1836 command, mostRecentEventTime, 1837 modifiers); 1838 } 1839 ((ActionListener)listeners[i+1]).actionPerformed(e); 1840 } 1841 } 1842 } 1843 1844 private static class WeakPCL implements PropertyChangeListener { 1845 WeakReference<JFileChooser> jfcRef; 1846 1847 public WeakPCL(JFileChooser jfc) { 1848 jfcRef = new WeakReference<JFileChooser>(jfc); 1849 } 1850 public void propertyChange(PropertyChangeEvent ev) { 1851 assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP); 1852 JFileChooser jfc = jfcRef.get(); 1853 if (jfc == null) { 1854 // Our JFileChooser is no longer around, so we no longer need to 1855 // listen for PropertyChangeEvents. 1856 Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this); 1857 } 1858 else { 1859 boolean oldValue = jfc.useFileHiding; 1860 jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue(); 1861 jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding); 1862 } 1863 } 1864 } 1865 1866 // ********************************* 1867 // ***** Pluggable L&F methods ***** 1868 // ********************************* 1869 1870 /** 1871 * Resets the UI property to a value from the current look and feel. 1872 * 1873 * @see JComponent#updateUI 1874 */ 1875 public void updateUI() { 1876 if (isAcceptAllFileFilterUsed()) { 1877 removeChoosableFileFilter(getAcceptAllFileFilter()); 1878 } 1879 FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this)); 1880 if (fileSystemView == null) { 1881 // We were probably deserialized 1882 setFileSystemView(FileSystemView.getFileSystemView()); 1883 } 1884 setUI(ui); 1885 1886 if(isAcceptAllFileFilterUsed()) { 1887 addChoosableFileFilter(getAcceptAllFileFilter()); 1888 } 1889 } 1890 1891 /** 1892 * Returns a string that specifies the name of the L&F class 1893 * that renders this component. 1894 * 1895 * @return the string "FileChooserUI" 1896 * @see JComponent#getUIClassID 1897 * @see UIDefaults#getUI 1898 * @beaninfo 1899 * expert: true 1900 * description: A string that specifies the name of the L&F class. 1901 */ 1902 public String getUIClassID() { 1903 return uiClassID; 1904 } 1905 1906 /** 1907 * Gets the UI object which implements the L&F for this component. 1908 * 1909 * @return the FileChooserUI object that implements the FileChooserUI L&F 1910 */ 1911 public FileChooserUI getUI() { 1912 return (FileChooserUI) ui; 1913 } 1914 1915 /** 1916 * See <code>readObject</code> and <code>writeObject</code> in 1917 * <code>JComponent</code> for more 1918 * information about serialization in Swing. 1919 */ 1920 private void readObject(java.io.ObjectInputStream in) 1921 throws IOException, ClassNotFoundException { 1922 ObjectInputStream.GetField f = in.readFields(); 1923 1924 dialogTitle = (String) f.get("dialogTitle", null); 1925 approveButtonText = (String) f.get("approveButtonText", null); 1926 approveButtonToolTipText = 1927 (String) f.get("approveButtonToolTipText", null); 1928 approveButtonMnemonic = f.get("approveButtonMnemonic", 0); 1929 @SuppressWarnings("unchecked") 1930 Vector<FileFilter> newFilters = (Vector<FileFilter>) f.get("filters", null); 1931 if (newFilters == null) { 1932 throw new InvalidObjectException("Null filters"); 1933 } 1934 filters = newFilters; 1935 dialog = (JDialog) f.get("dialog", null); 1936 int newDialogType = f.get("dialogType", OPEN_DIALOG); 1937 checkDialogType(newDialogType); 1938 dialogType = newDialogType; 1939 returnValue = f.get("returnValue", 0); 1940 accessory = (JComponent) f.get("accessory", null); 1941 fileView = (FileView) f.get("fileView", null); 1942 controlsShown = f.get("controlsShown", false); 1943 useFileHiding = f.get("useFileHiding", false); 1944 int newFileSelectionMode = f.get("fileSelectionMode", FILES_ONLY); 1945 checkFileSelectionMode(newFileSelectionMode); 1946 fileSelectionMode = newFileSelectionMode; 1947 multiSelectionEnabled = f.get("multiSelectionEnabled", false); 1948 useAcceptAllFileFilter = f.get("useAcceptAllFileFilter", false); 1949 boolean newDragEnabled = f.get("dragEnabled", false); 1950 checkDragEnabled(newDragEnabled); 1951 dragEnabled = newDragEnabled; 1952 fileFilter = (FileFilter) f.get("fileFilter", null); 1953 fileSystemView = (FileSystemView) f.get("fileSystemView", null); 1954 currentDirectory = (File) f.get("currentDirectory", null); 1955 selectedFile = (File) f.get("selectedFile", null); 1956 selectedFiles = (File[]) f.get("selectedFiles", null); 1957 accessibleContext = (AccessibleContext) f.get("accessibleContext", null); 1958 1959 installShowFilesListener(); 1960 } 1961 1962 /** 1963 * See <code>readObject</code> and <code>writeObject</code> in 1964 * <code>JComponent</code> for more 1965 * information about serialization in Swing. 1966 */ 1967 private void writeObject(ObjectOutputStream s) throws IOException { 1968 FileSystemView fsv = null; 1969 1970 if (isAcceptAllFileFilterUsed()) { 1971 //The AcceptAllFileFilter is UI specific, it will be reset by 1972 //updateUI() after deserialization 1973 removeChoosableFileFilter(getAcceptAllFileFilter()); 1974 } 1975 if (fileSystemView.equals(FileSystemView.getFileSystemView())) { 1976 //The default FileSystemView is platform specific, it will be 1977 //reset by updateUI() after deserialization 1978 fsv = fileSystemView; 1979 fileSystemView = null; 1980 } 1981 s.defaultWriteObject(); 1982 if (fsv != null) { 1983 fileSystemView = fsv; 1984 } 1985 if (isAcceptAllFileFilterUsed()) { 1986 addChoosableFileFilter(getAcceptAllFileFilter()); 1987 } 1988 if (getUIClassID().equals(uiClassID)) { 1989 byte count = JComponent.getWriteObjCounter(this); 1990 JComponent.setWriteObjCounter(this, --count); 1991 if (count == 0 && ui != null) { 1992 ui.installUI(this); 1993 } 1994 } 1995 } 1996 1997 1998 /** 1999 * Returns a string representation of this <code>JFileChooser</code>. 2000 * This method 2001 * is intended to be used only for debugging purposes, and the 2002 * content and format of the returned string may vary between 2003 * implementations. The returned string may be empty but may not 2004 * be <code>null</code>. 2005 * 2006 * @return a string representation of this <code>JFileChooser</code> 2007 */ 2008 protected String paramString() { 2009 String approveButtonTextString = (approveButtonText != null ? 2010 approveButtonText: ""); 2011 String dialogTitleString = (dialogTitle != null ? 2012 dialogTitle: ""); 2013 String dialogTypeString; 2014 if (dialogType == OPEN_DIALOG) { 2015 dialogTypeString = "OPEN_DIALOG"; 2016 } else if (dialogType == SAVE_DIALOG) { 2017 dialogTypeString = "SAVE_DIALOG"; 2018 } else if (dialogType == CUSTOM_DIALOG) { 2019 dialogTypeString = "CUSTOM_DIALOG"; 2020 } else dialogTypeString = ""; 2021 String returnValueString; 2022 if (returnValue == CANCEL_OPTION) { 2023 returnValueString = "CANCEL_OPTION"; 2024 } else if (returnValue == APPROVE_OPTION) { 2025 returnValueString = "APPROVE_OPTION"; 2026 } else if (returnValue == ERROR_OPTION) { 2027 returnValueString = "ERROR_OPTION"; 2028 } else returnValueString = ""; 2029 String useFileHidingString = (useFileHiding ? 2030 "true" : "false"); 2031 String fileSelectionModeString; 2032 if (fileSelectionMode == FILES_ONLY) { 2033 fileSelectionModeString = "FILES_ONLY"; 2034 } else if (fileSelectionMode == DIRECTORIES_ONLY) { 2035 fileSelectionModeString = "DIRECTORIES_ONLY"; 2036 } else if (fileSelectionMode == FILES_AND_DIRECTORIES) { 2037 fileSelectionModeString = "FILES_AND_DIRECTORIES"; 2038 } else fileSelectionModeString = ""; 2039 String currentDirectoryString = (currentDirectory != null ? 2040 currentDirectory.toString() : ""); 2041 String selectedFileString = (selectedFile != null ? 2042 selectedFile.toString() : ""); 2043 2044 return super.paramString() + 2045 ",approveButtonText=" + approveButtonTextString + 2046 ",currentDirectory=" + currentDirectoryString + 2047 ",dialogTitle=" + dialogTitleString + 2048 ",dialogType=" + dialogTypeString + 2049 ",fileSelectionMode=" + fileSelectionModeString + 2050 ",returnValue=" + returnValueString + 2051 ",selectedFile=" + selectedFileString + 2052 ",useFileHiding=" + useFileHidingString; 2053 } 2054 2055 ///////////////// 2056 // Accessibility support 2057 //////////////// 2058 2059 /** 2060 * {@code AccessibleContext} associated with this {@code JFileChooser} 2061 */ 2062 protected AccessibleContext accessibleContext = null; 2063 2064 /** 2065 * Gets the AccessibleContext associated with this JFileChooser. 2066 * For file choosers, the AccessibleContext takes the form of an 2067 * AccessibleJFileChooser. 2068 * A new AccessibleJFileChooser instance is created if necessary. 2069 * 2070 * @return an AccessibleJFileChooser that serves as the 2071 * AccessibleContext of this JFileChooser 2072 */ 2073 public AccessibleContext getAccessibleContext() { 2074 if (accessibleContext == null) { 2075 accessibleContext = new AccessibleJFileChooser(); 2076 } 2077 return accessibleContext; 2078 } 2079 2080 /** 2081 * This class implements accessibility support for the 2082 * <code>JFileChooser</code> class. It provides an implementation of the 2083 * Java Accessibility API appropriate to file chooser user-interface 2084 * elements. 2085 */ 2086 @SuppressWarnings("serial") // Superclass is not serializable across versions 2087 protected class AccessibleJFileChooser extends AccessibleJComponent { 2088 2089 /** 2090 * Gets the role of this object. 2091 * 2092 * @return an instance of AccessibleRole describing the role of the 2093 * object 2094 * @see AccessibleRole 2095 */ 2096 public AccessibleRole getAccessibleRole() { 2097 return AccessibleRole.FILE_CHOOSER; 2098 } 2099 2100 } // inner class AccessibleJFileChooser 2101 2102 }