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