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