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