1 /*
   2  * Copyright (c) 1995, 2014, 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</code> 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</code> 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</code> modes: <code>LOAD</code> and
  65      * <code>SAVE</code>.
  66      * This integer will represent one or the other.
  67      * If the mode is not specified it will default to <code>LOAD</code>.
  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</code>.
  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</code>.
  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</code>.
 122      *
 123      * @serial
 124      * @see #getFilenameFilter()
 125      * @see #setFilenameFilter()
 126      * @see FileNameFilter
 127      */
 128     FilenameFilter filter;
 129 
 130     private static final String base = "filedlg";
 131     private static int nameCounter = 0;
 132 
 133     /*
 134      * JDK 1.1 serialVersionUID
 135      */
 136      private static final long serialVersionUID = 5035145889651310422L;
 137 
 138 
 139     static {
 140         /* ensure that the necessary native libraries are loaded */
 141         Toolkit.loadLibraries();
 142         if (!GraphicsEnvironment.isHeadless()) {
 143             initIDs();
 144         }
 145     }
 146 
 147     static {
 148         AWTAccessor.setFileDialogAccessor(
 149             new AWTAccessor.FileDialogAccessor() {
 150                 public void setFiles(FileDialog fileDialog, File files[]) {
 151                     fileDialog.setFiles(files);
 152                 }
 153                 public void setFile(FileDialog fileDialog, String file) {
 154                     fileDialog.file = ("".equals(file)) ? null : file;
 155                 }
 156                 public void setDirectory(FileDialog fileDialog, String directory) {
 157                     fileDialog.dir = ("".equals(directory)) ? null : directory;
 158                 }
 159                 public boolean isMultipleMode(FileDialog fileDialog) {
 160                     synchronized (fileDialog.getObjectLock()) {
 161                         return fileDialog.multipleMode;
 162                     }
 163                 }
 164             });
 165     }
 166 
 167     /**
 168      * Initialize JNI field and method IDs for fields that may be
 169        accessed from C.
 170      */
 171     private static native void initIDs();
 172 
 173     /**
 174      * Creates a file dialog for loading a file.  The title of the
 175      * file dialog is initially empty.  This is a convenience method for
 176      * <code>FileDialog(parent, "", LOAD)</code>.
 177      *
 178      * @param parent the owner of the dialog
 179      * @since 1.1
 180      */
 181     public FileDialog(Frame parent) {
 182         this(parent, "", LOAD);
 183     }
 184 
 185     /**
 186      * Creates a file dialog window with the specified title for loading
 187      * a file. The files shown are those in the current directory.
 188      * This is a convenience method for
 189      * <code>FileDialog(parent, title, LOAD)</code>.
 190      *
 191      * @param     parent   the owner of the dialog
 192      * @param     title    the title of the dialog
 193      */
 194     public FileDialog(Frame parent, String title) {
 195         this(parent, title, LOAD);
 196     }
 197 
 198     /**
 199      * Creates a file dialog window with the specified title for loading
 200      * or saving a file.
 201      * <p>
 202      * If the value of <code>mode</code> is <code>LOAD</code>, then the
 203      * file dialog is finding a file to read, and the files shown are those
 204      * in the current directory.   If the value of
 205      * <code>mode</code> is <code>SAVE</code>, the file dialog is finding
 206      * a place to write a file.
 207      *
 208      * @param     parent   the owner of the dialog
 209      * @param     title   the title of the dialog
 210      * @param     mode   the mode of the dialog; either
 211      *          <code>FileDialog.LOAD</code> or <code>FileDialog.SAVE</code>
 212      * @exception  IllegalArgumentException if an illegal file
 213      *                 dialog mode is supplied
 214      * @see       java.awt.FileDialog#LOAD
 215      * @see       java.awt.FileDialog#SAVE
 216      */
 217     public FileDialog(Frame parent, String title, int mode) {
 218         super(parent, title, true);
 219         this.setMode(mode);
 220         setLayout(null);
 221     }
 222 
 223     /**
 224      * Creates a file dialog for loading a file.  The title of the
 225      * file dialog is initially empty.  This is a convenience method for
 226      * <code>FileDialog(parent, "", LOAD)</code>.
 227      *
 228      * @param     parent   the owner of the dialog
 229      * @exception java.lang.IllegalArgumentException if the <code>parent</code>'s
 230      *            <code>GraphicsConfiguration</code>
 231      *            is not from a screen device;
 232      * @exception java.lang.IllegalArgumentException if <code>parent</code>
 233      *            is <code>null</code>; this exception is always thrown when
 234      *            <code>GraphicsEnvironment.isHeadless</code>
 235      *            returns <code>true</code>
 236      * @see java.awt.GraphicsEnvironment#isHeadless
 237      * @since 1.5
 238      */
 239     public FileDialog(Dialog parent) {
 240         this(parent, "", LOAD);
 241     }
 242 
 243     /**
 244      * Creates a file dialog window with the specified title for loading
 245      * a file. The files shown are those in the current directory.
 246      * This is a convenience method for
 247      * <code>FileDialog(parent, title, LOAD)</code>.
 248      *
 249      * @param     parent   the owner of the dialog
 250      * @param     title    the title of the dialog; a <code>null</code> value
 251      *                     will be accepted without causing a
 252      *                     <code>NullPointerException</code> to be thrown
 253      * @exception java.lang.IllegalArgumentException if the <code>parent</code>'s
 254      *            <code>GraphicsConfiguration</code>
 255      *            is not from a screen device;
 256      * @exception java.lang.IllegalArgumentException if <code>parent</code>
 257      *            is <code>null</code>; this exception is always thrown when
 258      *            <code>GraphicsEnvironment.isHeadless</code>
 259      *            returns <code>true</code>
 260      * @see java.awt.GraphicsEnvironment#isHeadless
 261      * @since     1.5
 262      */
 263     public FileDialog(Dialog parent, String title) {
 264         this(parent, title, LOAD);
 265     }
 266 
 267     /**
 268      * Creates a file dialog window with the specified title for loading
 269      * or saving a file.
 270      * <p>
 271      * If the value of <code>mode</code> is <code>LOAD</code>, then the
 272      * file dialog is finding a file to read, and the files shown are those
 273      * in the current directory.   If the value of
 274      * <code>mode</code> is <code>SAVE</code>, the file dialog is finding
 275      * a place to write a file.
 276      *
 277      * @param     parent   the owner of the dialog
 278      * @param     title    the title of the dialog; a <code>null</code> value
 279      *                     will be accepted without causing a
 280      *                     <code>NullPointerException</code> to be thrown
 281      * @param     mode     the mode of the dialog; either
 282      *                     <code>FileDialog.LOAD</code> or <code>FileDialog.SAVE</code>
 283      * @exception java.lang.IllegalArgumentException if an illegal
 284      *            file dialog mode is supplied;
 285      * @exception java.lang.IllegalArgumentException if the <code>parent</code>'s
 286      *            <code>GraphicsConfiguration</code>
 287      *            is not from a screen device;
 288      * @exception java.lang.IllegalArgumentException if <code>parent</code>
 289      *            is <code>null</code>; this exception is always thrown when
 290      *            <code>GraphicsEnvironment.isHeadless</code>
 291      *            returns <code>true</code>
 292      * @see       java.awt.GraphicsEnvironment#isHeadless
 293      * @see       java.awt.FileDialog#LOAD
 294      * @see       java.awt.FileDialog#SAVE
 295      * @since     1.5
 296      */
 297     public FileDialog(Dialog parent, String title, int mode) {
 298         super(parent, title, true);
 299         this.setMode(mode);
 300         setLayout(null);
 301     }
 302 
 303     /**
 304      * Constructs a name for this component. Called by <code>getName()</code>
 305      * when the name is <code>null</code>.
 306      */
 307     String constructComponentName() {
 308         synchronized (FileDialog.class) {
 309             return base + nameCounter++;
 310         }
 311     }
 312 
 313     /**
 314      * Creates the file dialog's peer.  The peer allows us to change the look
 315      * of the file dialog without changing its functionality.
 316      */
 317     @SuppressWarnings("deprecation")
 318     public void addNotify() {
 319         synchronized(getTreeLock()) {
 320             if (parent != null && parent.getPeer() == null) {
 321                 parent.addNotify();
 322             }
 323             if (peer == null)
 324                 peer = getToolkit().createFileDialog(this);
 325             super.addNotify();
 326         }
 327     }
 328 
 329     /**
 330      * Indicates whether this file dialog box is for loading from a file
 331      * or for saving to a file.
 332      *
 333      * @return   the mode of this file dialog window, either
 334      *               <code>FileDialog.LOAD</code> or
 335      *               <code>FileDialog.SAVE</code>
 336      * @see      java.awt.FileDialog#LOAD
 337      * @see      java.awt.FileDialog#SAVE
 338      * @see      java.awt.FileDialog#setMode
 339      */
 340     public int getMode() {
 341         return mode;
 342     }
 343 
 344     /**
 345      * Sets the mode of the file dialog.  If <code>mode</code> is not
 346      * a legal value, an exception will be thrown and <code>mode</code>
 347      * will not be set.
 348      *
 349      * @param      mode  the mode for this file dialog, either
 350      *                 <code>FileDialog.LOAD</code> or
 351      *                 <code>FileDialog.SAVE</code>
 352      * @see        java.awt.FileDialog#LOAD
 353      * @see        java.awt.FileDialog#SAVE
 354      * @see        java.awt.FileDialog#getMode
 355      * @exception  IllegalArgumentException if an illegal file
 356      *                 dialog mode is supplied
 357      * @since      1.1
 358      */
 359     public void setMode(int mode) {
 360         switch (mode) {
 361           case LOAD:
 362           case SAVE:
 363             this.mode = mode;
 364             break;
 365           default:
 366             throw new IllegalArgumentException("illegal file dialog mode");
 367         }
 368     }
 369 
 370     /**
 371      * Gets the directory of this file dialog.
 372      *
 373      * @return  the (potentially <code>null</code> or invalid)
 374      *          directory of this <code>FileDialog</code>
 375      * @see       java.awt.FileDialog#setDirectory
 376      */
 377     public String getDirectory() {
 378         return dir;
 379     }
 380 
 381     /**
 382      * Sets the directory of this file dialog window to be the
 383      * specified directory. Specifying a <code>null</code> or an
 384      * invalid directory implies an implementation-defined default.
 385      * This default will not be realized, however, until the user
 386      * has selected a file. Until this point, <code>getDirectory()</code>
 387      * will return the value passed into this method.
 388      * <p>
 389      * Specifying "" as the directory is exactly equivalent to
 390      * specifying <code>null</code> as the directory.
 391      *
 392      * @param     dir   the specified directory
 393      * @see       java.awt.FileDialog#getDirectory
 394      */
 395     public void setDirectory(String dir) {
 396         this.dir = (dir != null && dir.equals("")) ? null : dir;
 397         FileDialogPeer peer = (FileDialogPeer)this.peer;
 398         if (peer != null) {
 399             peer.setDirectory(this.dir);
 400         }
 401     }
 402 
 403     /**
 404      * Gets the selected file of this file dialog.  If the user
 405      * selected <code>CANCEL</code>, the returned file is <code>null</code>.
 406      *
 407      * @return    the currently selected file of this file dialog window,
 408      *                or <code>null</code> if none is selected
 409      * @see       java.awt.FileDialog#setFile
 410      */
 411     public String getFile() {
 412         return file;
 413     }
 414 
 415     /**
 416      * Returns files that the user selects.
 417      * <p>
 418      * If the user cancels the file dialog,
 419      * then the method returns an empty array.
 420      *
 421      * @return    files that the user selects or an empty array
 422      *            if the user cancels the file dialog.
 423      * @see       #setFile(String)
 424      * @see       #getFile
 425      * @since 1.7
 426      */
 427     public File[] getFiles() {
 428         synchronized (getObjectLock()) {
 429             if (files != null) {
 430                 return files.clone();
 431             } else {
 432                 return new File[0];
 433             }
 434         }
 435     }
 436 
 437     /**
 438      * Stores the names of all the files that the user selects.
 439      *
 440      * Note that the method is private and it's intended to be used
 441      * by the peers through the AWTAccessor API.
 442      *
 443      * @param files     the array that contains the short names of
 444      *                  all the files that the user selects.
 445      *
 446      * @see #getFiles
 447      * @since 1.7
 448      */
 449     private void setFiles(File files[]) {
 450         synchronized (getObjectLock()) {
 451             this.files = files;
 452         }
 453     }
 454 
 455     /**
 456      * Sets the selected file for this file dialog window to be the
 457      * specified file. This file becomes the default file if it is set
 458      * before the file dialog window is first shown.
 459      * <p>
 460      * When the dialog is shown, the specified file is selected. The kind of
 461      * selection depends on the file existence, the dialog type, and the native
 462      * platform. E.g., the file could be highlighted in the file list, or a
 463      * file name editbox could be populated with the file name.
 464      * <p>
 465      * This method accepts either a full file path, or a file name with an
 466      * extension if used together with the {@code setDirectory} method.
 467      * <p>
 468      * Specifying "" as the file is exactly equivalent to specifying
 469      * {@code null} as the file.
 470      *
 471      * @param    file   the file being set
 472      * @see      #getFile
 473      * @see      #getFiles
 474      */
 475     public void setFile(String file) {
 476         this.file = (file != null && file.equals("")) ? null : file;
 477         FileDialogPeer peer = (FileDialogPeer)this.peer;
 478         if (peer != null) {
 479             peer.setFile(this.file);
 480         }
 481     }
 482 
 483     /**
 484      * Enables or disables multiple file selection for the file dialog.
 485      *
 486      * @param enable    if {@code true}, multiple file selection is enabled;
 487      *                  {@code false} - disabled.
 488      * @see #isMultipleMode
 489      * @since 1.7
 490      */
 491     public void setMultipleMode(boolean enable) {
 492         synchronized (getObjectLock()) {
 493             this.multipleMode = enable;
 494         }
 495     }
 496 
 497     /**
 498      * Returns whether the file dialog allows the multiple file selection.
 499      *
 500      * @return          {@code true} if the file dialog allows the multiple
 501      *                  file selection; {@code false} otherwise.
 502      * @see #setMultipleMode
 503      * @since 1.7
 504      */
 505     public boolean isMultipleMode() {
 506         synchronized (getObjectLock()) {
 507             return multipleMode;
 508         }
 509     }
 510 
 511     /**
 512      * Determines this file dialog's filename filter. A filename filter
 513      * allows the user to specify which files appear in the file dialog
 514      * window.  Filename filters do not function in Sun's reference
 515      * implementation for Microsoft Windows.
 516      *
 517      * @return    this file dialog's filename filter
 518      * @see       java.io.FilenameFilter
 519      * @see       java.awt.FileDialog#setFilenameFilter
 520      */
 521     public FilenameFilter getFilenameFilter() {
 522         return filter;
 523     }
 524 
 525     /**
 526      * Sets the filename filter for this file dialog window to the
 527      * specified filter.
 528      * Filename filters do not function in Sun's reference
 529      * implementation for Microsoft Windows.
 530      *
 531      * @param   filter   the specified filter
 532      * @see     java.io.FilenameFilter
 533      * @see     java.awt.FileDialog#getFilenameFilter
 534      */
 535     public synchronized void setFilenameFilter(FilenameFilter filter) {
 536         this.filter = filter;
 537         FileDialogPeer peer = (FileDialogPeer)this.peer;
 538         if (peer != null) {
 539             peer.setFilenameFilter(filter);
 540         }
 541     }
 542 
 543     /**
 544      * Reads the <code>ObjectInputStream</code> and performs
 545      * a backwards compatibility check by converting
 546      * either a <code>dir</code> or a <code>file</code>
 547      * equal to an empty string to <code>null</code>.
 548      *
 549      * @param s the <code>ObjectInputStream</code> to read
 550      */
 551     private void readObject(ObjectInputStream s)
 552         throws ClassNotFoundException, IOException
 553     {
 554         s.defaultReadObject();
 555 
 556         // 1.1 Compatibility: "" is not converted to null in 1.1
 557         if (dir != null && dir.equals("")) {
 558             dir = null;
 559         }
 560         if (file != null && file.equals("")) {
 561             file = null;
 562         }
 563     }
 564 
 565     /**
 566      * Returns a string representing the state of this <code>FileDialog</code>
 567      * window. This method is intended to be used only for debugging purposes,
 568      * and the content and format of the returned string may vary between
 569      * implementations. The returned string may be empty but may not be
 570      * <code>null</code>.
 571      *
 572      * @return  the parameter string of this file dialog window
 573      */
 574     protected String paramString() {
 575         String str = super.paramString();
 576         str += ",dir= " + dir;
 577         str += ",file= " + file;
 578         return str + ((mode == LOAD) ? ",load" : ",save");
 579     }
 580 
 581     boolean postsOldMouseEvents() {
 582         return false;
 583     }
 584 }