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