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