1 /*
2  * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.awt;
26 
27 import java.awt.peer.FileDialogPeer;
28 import java.io.FilenameFilter;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.File;
32 import sun.awt.AWTAccessor;
33 
34 /**
35  * The {@code FileDialog} class displays a dialog window
36  * from which the user can select a file.
37  * <p>
38  * Since it is a modal dialog, when the application calls
39  * its {@code show} method to display the dialog,
40  * it blocks the rest of the application until the user has
41  * chosen a file.
42  *
43  * @see Window#show
44  *
45  * @author      Sami Shaio
46  * @author      Arthur van Hoff
47  * @since       1.0
48  */
49 public class FileDialog extends Dialog {
50 
51     /**
52      * This constant value indicates that the purpose of the file
53      * dialog window is to locate a file from which to read.
54      */
55     public static final int LOAD = 0;
56 
57     /**
58      * This constant value indicates that the purpose of the file
59      * dialog window is to locate a file to which to write.
60      */
61     public static final int SAVE = 1;
62 
63     /*
64      * There are two {@code FileDialog} modes: {@code LOAD} and
65      * {@code SAVE}.
66      * This integer will represent one or the other.
67      * If the mode is not specified it will default to {@code LOAD}.
68      *
69      * @serial
70      * @see getMode()
71      * @see setMode()
72      * @see java.awt.FileDialog#LOAD
73      * @see java.awt.FileDialog#SAVE
74      */
75     int mode;
76 
77     /*
78      * The string specifying the directory to display
79      * in the file dialog.  This variable may be {@code null}.
80      *
81      * @serial
82      * @see getDirectory()
83      * @see setDirectory()
84      */
85     String dir;
86 
87     /*
88      * The string specifying the initial value of the
89      * filename text field in the file dialog.
90      * This variable may be {@code null}.
91      *
92      * @serial
93      * @see getFile()
94      * @see setFile()
95      */
96     String file;
97 
98     /**
99      * Contains the File instances for all the files that the user selects.
100      *
101      * @serial
102      * @see #getFiles
103      * @since 1.7
104      */
105     private File[] files;
106 
107     /**
108      * Represents whether the file dialog allows the multiple file selection.
109      *
110      * @serial
111      * @see #setMultipleMode
112      * @see #isMultipleMode
113      * @since 1.7
114      */
115     private boolean multipleMode = false;
116 
117     /*
118      * The filter used as the file dialog's filename filter.
119      * The file dialog will only be displaying files whose
120      * names are accepted by this filter.
121      * This variable may be {@code null}.
122      *
123      * @serial
124      * @see #getFilenameFilter()
125      * @see #setFilenameFilter()
126      * @see FileNameFilter
127      */
128     @SuppressWarnings("serial") // Not statically typed as Serializable
129     FilenameFilter filter;
130 
131     private static final String base = "filedlg";
132     private static int nameCounter = 0;
133 
134     /*
135      * JDK 1.1 serialVersionUID
136      */
137      private static final long serialVersionUID = 5035145889651310422L;
138 
139 
140     static {
141         /* ensure that the necessary native libraries are loaded */
Toolkit.loadLibraries()142         Toolkit.loadLibraries();
143         if (!GraphicsEnvironment.isHeadless()) {
initIDs()144             initIDs();
145         }
146     }
147 
148     static {
AWTAccessor.setFileDialogAccessor( new AWTAccessor.FileDialogAccessor() { public void setFiles(FileDialog fileDialog, File[] files) { fileDialog.setFiles(files); } public void setFile(FileDialog fileDialog, String file) { fileDialog.file = (R.equals(file)) ? null : file; } public void setDirectory(FileDialog fileDialog, String directory) { fileDialog.dir = (R.equals(directory)) ? null : directory; } public boolean isMultipleMode(FileDialog fileDialog) { synchronized (fileDialog.getObjectLock()) { return fileDialog.multipleMode; } } })149         AWTAccessor.setFileDialogAccessor(
150             new AWTAccessor.FileDialogAccessor() {
151                 public void setFiles(FileDialog fileDialog, File[] files) {
152                     fileDialog.setFiles(files);
153                 }
154                 public void setFile(FileDialog fileDialog, String file) {
155                     fileDialog.file = ("".equals(file)) ? null : file;
156                 }
157                 public void setDirectory(FileDialog fileDialog, String directory) {
158                     fileDialog.dir = ("".equals(directory)) ? null : directory;
159                 }
160                 public boolean isMultipleMode(FileDialog fileDialog) {
161                     synchronized (fileDialog.getObjectLock()) {
162                         return fileDialog.multipleMode;
163                     }
164                 }
165             });
166     }
167 
168     /**
169      * Initialize JNI field and method IDs for fields that may be
170        accessed from C.
171      */
initIDs()172     private static native void initIDs();
173 
174     /**
175      * Creates a file dialog for loading a file.  The title of the
176      * file dialog is initially empty.  This is a convenience method for
177      * {@code FileDialog(parent, "", LOAD)}.
178      * <p>
179      * <strong>Note:</strong> Some platforms may not support
180      * showing the user-specified title in a file dialog.
181      * In this situation, either no title will be displayed in the file dialog's
182      * title bar or, on some systems, the file dialog's title bar will not be
183      * displayed.
184      *
185      * @param parent the owner of the dialog
186      * @since 1.1
187      */
FileDialog(Frame parent)188     public FileDialog(Frame parent) {
189         this(parent, "", LOAD);
190     }
191 
192     /**
193      * Creates a file dialog window with the specified title for loading
194      * a file. The files shown are those in the current directory.
195      * This is a convenience method for
196      * {@code FileDialog(parent, title, LOAD)}.
197      * <p>
198      * <strong>Note:</strong> Some platforms may not support
199      * showing the user-specified title in a file dialog.
200      * In this situation, either no title will be displayed in the file dialog's
201      * title bar or, on some systems, the file dialog's title bar will not be
202      * displayed.
203      *
204      * @param     parent   the owner of the dialog
205      * @param     title    the title of the dialog
206      */
FileDialog(Frame parent, String title)207     public FileDialog(Frame parent, String title) {
208         this(parent, title, LOAD);
209     }
210 
211     /**
212      * Creates a file dialog window with the specified title for loading
213      * or saving a file.
214      * <p>
215      * If the value of {@code mode} is {@code LOAD}, then the
216      * file dialog is finding a file to read, and the files shown are those
217      * in the current directory.   If the value of
218      * {@code mode} is {@code SAVE}, the file dialog is finding
219      * a place to write a file.
220      * <p>
221      * <strong>Note:</strong> Some platforms may not support
222      * showing the user-specified title in a file dialog.
223      * In this situation, either no title will be displayed in the file dialog's
224      * title bar or, on some systems, the file dialog's title bar will not be
225      * displayed.
226      *
227      * @param     parent   the owner of the dialog
228      * @param     title   the title of the dialog
229      * @param     mode   the mode of the dialog; either
230      *            {@code FileDialog.LOAD} or {@code FileDialog.SAVE}
231      * @exception  IllegalArgumentException if an illegal file
232      *                 dialog mode is supplied
233      * @see       java.awt.FileDialog#LOAD
234      * @see       java.awt.FileDialog#SAVE
235      */
FileDialog(Frame parent, String title, int mode)236     public FileDialog(Frame parent, String title, int mode) {
237         super(parent, title, true);
238         this.setMode(mode);
239         setLayout(null);
240     }
241 
242     /**
243      * Creates a file dialog for loading a file.  The title of the
244      * file dialog is initially empty.  This is a convenience method for
245      * {@code FileDialog(parent, "", LOAD)}.
246      * <p>
247      * <strong>Note:</strong> Some platforms may not support
248      * showing the user-specified title in a file dialog.
249      * In this situation, either no title will be displayed in the file dialog's
250      * title bar or, on some systems, the file dialog's title bar will not be
251      * displayed.
252      *
253      * @param     parent   the owner of the dialog
254      * @exception java.lang.IllegalArgumentException if the {@code parent}'s
255      *            {@code GraphicsConfiguration}
256      *            is not from a screen device;
257      * @exception java.lang.IllegalArgumentException if {@code parent}
258      *            is {@code null}; this exception is always thrown when
259      *            {@code GraphicsEnvironment.isHeadless}
260      *            returns {@code true}
261      * @see java.awt.GraphicsEnvironment#isHeadless
262      * @since 1.5
263      */
FileDialog(Dialog parent)264     public FileDialog(Dialog parent) {
265         this(parent, "", LOAD);
266     }
267 
268     /**
269      * Creates a file dialog window with the specified title for loading
270      * a file. The files shown are those in the current directory.
271      * This is a convenience method for
272      * {@code FileDialog(parent, title, LOAD)}.
273      * <p>
274      * <strong>Note:</strong> Some platforms may not support
275      * showing the user-specified title in a file dialog.
276      * In this situation, either no title will be displayed in the file dialog's
277      * title bar or, on some systems, the file dialog's title bar will not be
278      * displayed.
279      *
280      * @param     parent   the owner of the dialog
281      * @param     title    the title of the dialog; a {@code null} value
282      *                     will be accepted without causing a
283      *                     {@code NullPointerException} to be thrown
284      * @exception java.lang.IllegalArgumentException if the {@code parent}'s
285      *            {@code GraphicsConfiguration}
286      *            is not from a screen device;
287      * @exception java.lang.IllegalArgumentException if {@code parent}
288      *            is {@code null}; this exception is always thrown when
289      *            {@code GraphicsEnvironment.isHeadless}
290      *            returns {@code true}
291      * @see java.awt.GraphicsEnvironment#isHeadless
292      * @since     1.5
293      */
FileDialog(Dialog parent, String title)294     public FileDialog(Dialog parent, String title) {
295         this(parent, title, LOAD);
296     }
297 
298     /**
299      * Creates a file dialog window with the specified title for loading
300      * or saving a file.
301      * <p>
302      * If the value of {@code mode} is {@code LOAD}, then the
303      * file dialog is finding a file to read, and the files shown are those
304      * in the current directory.   If the value of
305      * {@code mode} is {@code SAVE}, the file dialog is finding
306      * a place to write a file.
307      * <p>
308      * <strong>Note:</strong> Some platforms may not support
309      * showing the user-specified title in a file dialog.
310      * In this situation, either no title will be displayed in the file dialog's
311      * title bar or, on some systems, the file dialog's title bar will not be
312      * displayed.
313      *
314      * @param     parent   the owner of the dialog
315      * @param     title    the title of the dialog; a {@code null} value
316      *                     will be accepted without causing a
317      *                     {@code NullPointerException} to be thrown
318      * @param     mode     the mode of the dialog; either
319      *                     {@code FileDialog.LOAD} or {@code FileDialog.SAVE}
320      * @exception java.lang.IllegalArgumentException if an illegal
321      *            file dialog mode is supplied;
322      * @exception java.lang.IllegalArgumentException if the {@code parent}'s
323      *            {@code GraphicsConfiguration}
324      *            is not from a screen device;
325      * @exception java.lang.IllegalArgumentException if {@code parent}
326      *            is {@code null}; this exception is always thrown when
327      *            {@code GraphicsEnvironment.isHeadless}
328      *            returns {@code true}
329      * @see       java.awt.GraphicsEnvironment#isHeadless
330      * @see       java.awt.FileDialog#LOAD
331      * @see       java.awt.FileDialog#SAVE
332      * @since     1.5
333      */
FileDialog(Dialog parent, String title, int mode)334     public FileDialog(Dialog parent, String title, int mode) {
335         super(parent, title, true);
336         this.setMode(mode);
337         setLayout(null);
338     }
339 
340 
341     /**
342      * {@inheritDoc}
343      * <p>
344      * <strong>Note:</strong> Some platforms may not support
345      * showing the user-specified title in a file dialog.
346      * In this situation, either no title will be displayed in the file dialog's
347      * title bar or, on some systems, the file dialog's title bar will not be
348      * displayed.
349      */
350     @Override
setTitle(String title)351     public void setTitle(String title) {
352         super.setTitle(title);
353     }
354 
355 
356     /**
357      * Constructs a name for this component. Called by {@code getName()}
358      * when the name is {@code null}.
359      */
constructComponentName()360     String constructComponentName() {
361         synchronized (FileDialog.class) {
362             return base + nameCounter++;
363         }
364     }
365 
366     /**
367      * Creates the file dialog's peer.  The peer allows us to change the look
368      * of the file dialog without changing its functionality.
369      */
addNotify()370     public void addNotify() {
371         synchronized(getTreeLock()) {
372             if (parent != null && parent.peer == null) {
373                 parent.addNotify();
374             }
375             if (peer == null)
376                 peer = getComponentFactory().createFileDialog(this);
377             super.addNotify();
378         }
379     }
380 
381     /**
382      * Indicates whether this file dialog box is for loading from a file
383      * or for saving to a file.
384      *
385      * @return   the mode of this file dialog window, either
386      *               {@code FileDialog.LOAD} or
387      *               {@code FileDialog.SAVE}
388      * @see      java.awt.FileDialog#LOAD
389      * @see      java.awt.FileDialog#SAVE
390      * @see      java.awt.FileDialog#setMode
391      */
getMode()392     public int getMode() {
393         return mode;
394     }
395 
396     /**
397      * Sets the mode of the file dialog.  If {@code mode} is not
398      * a legal value, an exception will be thrown and {@code mode}
399      * will not be set.
400      *
401      * @param      mode  the mode for this file dialog, either
402      *                 {@code FileDialog.LOAD} or
403      *                 {@code FileDialog.SAVE}
404      * @see        java.awt.FileDialog#LOAD
405      * @see        java.awt.FileDialog#SAVE
406      * @see        java.awt.FileDialog#getMode
407      * @exception  IllegalArgumentException if an illegal file
408      *                 dialog mode is supplied
409      * @since      1.1
410      */
setMode(int mode)411     public void setMode(int mode) {
412         switch (mode) {
413           case LOAD:
414           case SAVE:
415             this.mode = mode;
416             break;
417           default:
418             throw new IllegalArgumentException("illegal file dialog mode");
419         }
420     }
421 
422     /**
423      * Gets the directory of this file dialog.
424      *
425      * @return  the (potentially {@code null} or invalid)
426      *          directory of this {@code FileDialog}
427      * @see       java.awt.FileDialog#setDirectory
428      */
getDirectory()429     public String getDirectory() {
430         return dir;
431     }
432 
433     /**
434      * Sets the directory of this file dialog window to be the
435      * specified directory. Specifying a {@code null} or an
436      * invalid directory implies an implementation-defined default.
437      * This default will not be realized, however, until the user
438      * has selected a file. Until this point, {@code getDirectory()}
439      * will return the value passed into this method.
440      * <p>
441      * Specifying "" as the directory is exactly equivalent to
442      * specifying {@code null} as the directory.
443      *
444      * @param     dir   the specified directory
445      * @see       java.awt.FileDialog#getDirectory
446      */
setDirectory(String dir)447     public void setDirectory(String dir) {
448         this.dir = (dir != null && dir.isEmpty()) ? null : dir;
449         FileDialogPeer peer = (FileDialogPeer)this.peer;
450         if (peer != null) {
451             peer.setDirectory(this.dir);
452         }
453     }
454 
455     /**
456      * Gets the selected file of this file dialog.  If the user
457      * selected {@code CANCEL}, the returned file is {@code null}.
458      *
459      * @return    the currently selected file of this file dialog window,
460      *                or {@code null} if none is selected
461      * @see       java.awt.FileDialog#setFile
462      */
getFile()463     public String getFile() {
464         return file;
465     }
466 
467     /**
468      * Returns files that the user selects.
469      * <p>
470      * If the user cancels the file dialog,
471      * then the method returns an empty array.
472      *
473      * @return    files that the user selects or an empty array
474      *            if the user cancels the file dialog.
475      * @see       #setFile(String)
476      * @see       #getFile
477      * @since 1.7
478      */
getFiles()479     public File[] getFiles() {
480         synchronized (getObjectLock()) {
481             if (files != null) {
482                 return files.clone();
483             } else {
484                 return new File[0];
485             }
486         }
487     }
488 
489     /**
490      * Stores the names of all the files that the user selects.
491      *
492      * Note that the method is private and it's intended to be used
493      * by the peers through the AWTAccessor API.
494      *
495      * @param files     the array that contains the short names of
496      *                  all the files that the user selects.
497      *
498      * @see #getFiles
499      * @since 1.7
500      */
setFiles(File[] files)501     private void setFiles(File[] files) {
502         synchronized (getObjectLock()) {
503             this.files = files;
504         }
505     }
506 
507     /**
508      * Sets the selected file for this file dialog window to be the
509      * specified file. This file becomes the default file if it is set
510      * before the file dialog window is first shown.
511      * <p>
512      * When the dialog is shown, the specified file is selected. The kind of
513      * selection depends on the file existence, the dialog type, and the native
514      * platform. E.g., the file could be highlighted in the file list, or a
515      * file name editbox could be populated with the file name.
516      * <p>
517      * This method accepts either a full file path, or a file name with an
518      * extension if used together with the {@code setDirectory} method.
519      * <p>
520      * Specifying "" as the file is exactly equivalent to specifying
521      * {@code null} as the file.
522      *
523      * @param    file   the file being set
524      * @see      #getFile
525      * @see      #getFiles
526      */
setFile(String file)527     public void setFile(String file) {
528         this.file = (file != null && file.isEmpty()) ? null : file;
529         FileDialogPeer peer = (FileDialogPeer)this.peer;
530         if (peer != null) {
531             peer.setFile(this.file);
532         }
533     }
534 
535     /**
536      * Enables or disables multiple file selection for the file dialog.
537      *
538      * @param enable    if {@code true}, multiple file selection is enabled;
539      *                  {@code false} - disabled.
540      * @see #isMultipleMode
541      * @since 1.7
542      */
setMultipleMode(boolean enable)543     public void setMultipleMode(boolean enable) {
544         synchronized (getObjectLock()) {
545             this.multipleMode = enable;
546         }
547     }
548 
549     /**
550      * Returns whether the file dialog allows the multiple file selection.
551      *
552      * @return          {@code true} if the file dialog allows the multiple
553      *                  file selection; {@code false} otherwise.
554      * @see #setMultipleMode
555      * @since 1.7
556      */
isMultipleMode()557     public boolean isMultipleMode() {
558         synchronized (getObjectLock()) {
559             return multipleMode;
560         }
561     }
562 
563     /**
564      * Determines this file dialog's filename filter. A filename filter
565      * allows the user to specify which files appear in the file dialog
566      * window.  Filename filters do not function in Sun's reference
567      * implementation for Microsoft Windows.
568      *
569      * @return    this file dialog's filename filter
570      * @see       java.io.FilenameFilter
571      * @see       java.awt.FileDialog#setFilenameFilter
572      */
getFilenameFilter()573     public FilenameFilter getFilenameFilter() {
574         return filter;
575     }
576 
577     /**
578      * Sets the filename filter for this file dialog window to the
579      * specified filter.
580      * Filename filters do not function in Sun's reference
581      * implementation for Microsoft Windows.
582      *
583      * @param   filter   the specified filter
584      * @see     java.io.FilenameFilter
585      * @see     java.awt.FileDialog#getFilenameFilter
586      */
setFilenameFilter(FilenameFilter filter)587     public synchronized void setFilenameFilter(FilenameFilter filter) {
588         this.filter = filter;
589         FileDialogPeer peer = (FileDialogPeer)this.peer;
590         if (peer != null) {
591             peer.setFilenameFilter(filter);
592         }
593     }
594 
595     /**
596      * Reads the {@code ObjectInputStream} and performs
597      * a backwards compatibility check by converting
598      * either a {@code dir} or a {@code file}
599      * equal to an empty string to {@code null}.
600      *
601      * @param s the {@code ObjectInputStream} to read
602      */
readObject(ObjectInputStream s)603     private void readObject(ObjectInputStream s)
604         throws ClassNotFoundException, IOException
605     {
606         s.defaultReadObject();
607 
608         // 1.1 Compatibility: "" is not converted to null in 1.1
609         if (dir != null && dir.isEmpty()) {
610             dir = null;
611         }
612         if (file != null && file.isEmpty()) {
613             file = null;
614         }
615     }
616 
617     /**
618      * Returns a string representing the state of this {@code FileDialog}
619      * window. This method is intended to be used only for debugging purposes,
620      * and the content and format of the returned string may vary between
621      * implementations. The returned string may be empty but may not be
622      * {@code null}.
623      *
624      * @return  the parameter string of this file dialog window
625      */
paramString()626     protected String paramString() {
627         String str = super.paramString();
628         str += ",dir= " + dir;
629         str += ",file= " + file;
630         return str + ((mode == LOAD) ? ",load" : ",save");
631     }
632 
postsOldMouseEvents()633     boolean postsOldMouseEvents() {
634         return false;
635     }
636 }
637