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