1 /* 2 * Copyright (c) 2005, 2015, 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 26 package java.awt; 27 28 import java.awt.desktop.*; 29 import java.awt.peer.DesktopPeer; 30 import java.io.File; 31 import java.io.FilePermission; 32 import java.io.IOException; 33 import java.lang.annotation.Native; 34 import java.net.MalformedURLException; 35 import java.net.URI; 36 import java.net.URISyntaxException; 37 import java.net.URL; 38 39 import sun.awt.SunToolkit; 40 import javax.swing.JMenuBar; 41 import sun.security.util.SecurityConstants; 42 43 /** 44 * The {@code Desktop} class allows interact with various desktop capabilities. 45 * 46 * <p> Supported operations include: 47 * <ul> 48 * <li>launching the user-default browser to show a specified 49 * URI;</li> 50 * <li>launching the user-default mail client with an optional 51 * {@code mailto} URI;</li> 52 * <li>launching a registered application to open, edit or print a 53 * specified file.</li> 54 * </ul> 55 * 56 * <p> This class provides methods corresponding to these 57 * operations. The methods look for the associated application 58 * registered on the current platform, and launch it to handle a URI 59 * or file. If there is no associated application or the associated 60 * application fails to be launched, an exception is thrown. 61 * 62 * Please see {@link Desktop.Action} for the full list of supported operations 63 * and capabilities. 64 * 65 * <p> An application is registered to a URI or file type; for 66 * example, the {@code "sxi"} file extension is typically registered 67 * to StarOffice. The mechanism of registering, accessing, and 68 * launching the associated application is platform-dependent. 69 * 70 * <p> Each operation is an action type represented by the {@link 71 * Desktop.Action} class. 72 * 73 * <p> Note: when some action is invoked and the associated 74 * application is executed, it will be executed on the same system as 75 * the one on which the Java application was launched. 76 * 77 * @see Action 78 * 79 * @since 1.6 80 * @author Armin Chen 81 * @author George Zhang 82 */ 83 public class Desktop { 84 85 /** 86 * Represents an action type. Each platform supports a different 87 * set of actions. You may use the {@link Desktop#isSupported} 88 * method to determine if the given action is supported by the 89 * current platform. 90 * @see java.awt.Desktop#isSupported(java.awt.Desktop.Action) 91 * @since 1.6 92 */ 93 public static enum Action { 94 /** 95 * Represents an "open" action. 96 * @see Desktop#open(java.io.File) 97 */ 98 OPEN, 99 /** 100 * Represents an "edit" action. 101 * @see Desktop#edit(java.io.File) 102 */ 103 EDIT, 104 /** 105 * Represents a "print" action. 106 * @see Desktop#print(java.io.File) 107 */ 108 PRINT, 109 /** 110 * Represents a "mail" action. 111 * @see Desktop#mail() 112 * @see Desktop#mail(java.net.URI) 113 */ 114 MAIL, 115 116 /** 117 * Represents a "browse" action. 118 * @see Desktop#browse(java.net.URI) 119 */ 120 BROWSE, 121 122 /** 123 * Represents an AppForegroundListener 124 * @see java.awt.desktop.AppForegroundListener 125 * @since 1.9 126 */ 127 APP_EVENT_FOREGROUND, 128 129 /** 130 * Represents an AppHiddenListener 131 * @see java.awt.desktop.AppHiddenListener 132 * @since 1.9 133 */ 134 APP_EVENT_HIDDEN, 135 136 /** 137 * Represents an AppReopenedListener 138 * @see java.awt.desktop.AppReopenedListener 139 * @since 1.9 140 */ 141 APP_EVENT_REOPENED, 142 143 /** 144 * Represents a ScreenSleepListener 145 * @see java.awt.desktop.ScreenSleepListener 146 * @since 1.9 147 */ 148 APP_EVENT_SCREEN_SLEEP, 149 150 /** 151 * Represents a SystemSleepListener 152 * @see java.awt.desktop.SystemSleepListener 153 * @since 1.9 154 */ 155 APP_EVENT_SYSTEM_SLEEP, 156 157 /** 158 * Represents a UserSessionListener 159 * @see java.awt.desktop.UserSessionListener 160 * @since 1.9 161 */ 162 APP_EVENT_USER_SESSION, 163 164 /** 165 * Represents an AboutHandler 166 * @see #setAboutHandler(java.awt.desktop.AboutHandler) 167 * @since 1.9 168 */ 169 APP_ABOUT, 170 171 /** 172 * Represents a PreferencesHandler 173 * @see #setPreferencesHandler(java.awt.desktop.PreferencesHandler) 174 * @since 1.9 175 */ 176 APP_PREFERENCES, 177 178 /** 179 * Represents an OpenFilesHandler 180 * @see #setOpenFileHandler(java.awt.desktop.OpenFilesHandler) 181 * @since 1.9 182 */ 183 APP_OPEN_FILE, 184 185 /** 186 * Represents a PrintFilesHandler 187 * @see #setPrintFileHandler(java.awt.desktop.PrintFilesHandler) 188 * @since 1.9 189 */ 190 APP_PRINT_FILE, 191 192 /** 193 * Represents an OpenURIHandler 194 * @see #setOpenURIHandler(java.awt.desktop.OpenURIHandler) 195 * @since 1.9 196 */ 197 APP_OPEN_URI, 198 199 /** 200 * Represents a QuitHandler 201 * @see #setQuitHandler(java.awt.desktop.QuitHandler) 202 * @since 1.9 203 */ 204 APP_QUIT_HANDLER, 205 206 /** 207 * Represents a QuitStrategy 208 * @see #setQuitStrategy(java.awt.desktop.QuitStrategy) 209 * @since 1.9 210 */ 211 APP_QUIT_STRATEGY, 212 213 /** 214 * Represents a SuddenTermination 215 * @see #enableSuddenTermination() 216 * @since 1.9 217 */ 218 APP_SUDDEN_TERMINATION, 219 220 /** 221 * Represents a requestForeground 222 * @see #requestForeground(boolean) 223 * @since 1.9 224 */ 225 APP_REQUEST_FOREGROUND, 226 227 /** 228 * Represents a HelpViewer 229 * @see #openHelpViewer() 230 * @since 1.9 231 */ 232 APP_HELP_VIEWER, 233 234 /** 235 * Represents a menu bar 236 * @see #setDefaultMenuBar(javax.swing.JMenuBar) 237 * @since 1.9 238 */ 239 APP_MENU_BAR, 240 241 /** 242 * Represents a browse file directory 243 * @see #browseFileDirectory(java.io.File) 244 * @since 1.9 245 */ 246 BROWSE_FILE_DIR, 247 248 /** 249 * Represents a move to trash 250 * @see #moveToTrash(java.io.File) 251 * @since 1.9 252 */ 253 MOVE_TO_TRASH 254 }; 255 256 private DesktopPeer peer; 257 258 /** 259 * Suppresses default constructor for noninstantiability. 260 */ 261 private Desktop() { 262 Toolkit defaultToolkit = Toolkit.getDefaultToolkit(); 263 // same cast as in isDesktopSupported() 264 if (defaultToolkit instanceof SunToolkit) { 265 peer = ((SunToolkit) defaultToolkit).createDesktopPeer(this); 266 } 267 } 268 269 /** 270 * Returns the <code>Desktop</code> instance of the current 271 * desktop context. On some platforms the Desktop API may not be 272 * supported; use the {@link #isDesktopSupported} method to 273 * determine if the current desktop is supported. 274 * @return the Desktop instance 275 * @throws HeadlessException if {@link 276 * GraphicsEnvironment#isHeadless()} returns {@code true} 277 * @throws UnsupportedOperationException if this class is not 278 * supported on the current platform 279 * @see #isDesktopSupported() 280 * @see java.awt.GraphicsEnvironment#isHeadless 281 */ 282 public static synchronized Desktop getDesktop(){ 283 if (GraphicsEnvironment.isHeadless()) throw new HeadlessException(); 284 if (!Desktop.isDesktopSupported()) { 285 throw new UnsupportedOperationException("Desktop API is not " + 286 "supported on the current platform"); 287 } 288 289 sun.awt.AppContext context = sun.awt.AppContext.getAppContext(); 290 Desktop desktop = (Desktop)context.get(Desktop.class); 291 292 if (desktop == null) { 293 desktop = new Desktop(); 294 context.put(Desktop.class, desktop); 295 } 296 297 return desktop; 298 } 299 300 /** 301 * Tests whether this class is supported on the current platform. 302 * If it's supported, use {@link #getDesktop()} to retrieve an 303 * instance. 304 * 305 * @return <code>true</code> if this class is supported on the 306 * current platform; <code>false</code> otherwise 307 * @see #getDesktop() 308 */ 309 public static boolean isDesktopSupported(){ 310 Toolkit defaultToolkit = Toolkit.getDefaultToolkit(); 311 if (defaultToolkit instanceof SunToolkit) { 312 return ((SunToolkit)defaultToolkit).isDesktopSupported(); 313 } 314 return false; 315 } 316 317 /** 318 * Tests whether an action is supported on the current platform. 319 * 320 * <p>Even when the platform supports an action, a file or URI may 321 * not have a registered application for the action. For example, 322 * most of the platforms support the {@link Desktop.Action#OPEN} 323 * action. But for a specific file, there may not be an 324 * application registered to open it. In this case, {@link 325 * #isSupported} may return {@code true}, but the corresponding 326 * action method will throw an {@link IOException}. 327 * 328 * @param action the specified {@link Action} 329 * @return <code>true</code> if the specified action is supported on 330 * the current platform; <code>false</code> otherwise 331 * @see Desktop.Action 332 */ 333 public boolean isSupported(Action action) { 334 return peer.isSupported(action); 335 } 336 337 /** 338 * Checks if the file is a valid file and readable. 339 * 340 * @throws SecurityException If a security manager exists and its 341 * {@link SecurityManager#checkRead(java.lang.String)} method 342 * denies read access to the file 343 * @throws NullPointerException if file is null 344 * @throws IllegalArgumentException if file doesn't exist 345 */ 346 private static void checkFileValidation(File file){ 347 if (file == null) throw new NullPointerException("File must not be null"); 348 349 if (!file.exists()) { 350 throw new IllegalArgumentException("The file: " 351 + file.getPath() + " doesn't exist."); 352 } 353 354 file.canRead(); 355 } 356 357 /** 358 * Checks if the action type is supported. 359 * 360 * @param actionType the action type in question 361 * @throws UnsupportedOperationException if the specified action type is not 362 * supported on the current platform 363 */ 364 private void checkActionSupport(Action actionType){ 365 if (!isSupported(actionType)) { 366 throw new UnsupportedOperationException("The " + actionType.name() 367 + " action is not supported on the current platform!"); 368 } 369 } 370 371 372 /** 373 * Calls to the security manager's <code>checkPermission</code> method with 374 * an <code>AWTPermission("showWindowWithoutWarningBanner")</code> 375 * permission. 376 */ 377 private void checkAWTPermission(){ 378 SecurityManager sm = System.getSecurityManager(); 379 if (sm != null) { 380 sm.checkPermission(new AWTPermission( 381 "showWindowWithoutWarningBanner")); 382 } 383 } 384 385 /** 386 * Launches the associated application to open the file. 387 * 388 * <p> If the specified file is a directory, the file manager of 389 * the current platform is launched to open it. 390 * 391 * @param file the file to be opened with the associated application 392 * @throws NullPointerException if {@code file} is {@code null} 393 * @throws IllegalArgumentException if the specified file doesn't 394 * exist 395 * @throws UnsupportedOperationException if the current platform 396 * does not support the {@link Desktop.Action#OPEN} action 397 * @throws IOException if the specified file has no associated 398 * application or the associated application fails to be launched 399 * @throws SecurityException if a security manager exists and its 400 * {@link java.lang.SecurityManager#checkRead(java.lang.String)} 401 * method denies read access to the file, or it denies the 402 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> 403 * permission, or the calling thread is not allowed to create a 404 * subprocess 405 * @see java.awt.AWTPermission 406 */ 407 public void open(File file) throws IOException { 408 checkAWTPermission(); 409 checkExec(); 410 checkActionSupport(Action.OPEN); 411 checkFileValidation(file); 412 413 peer.open(file); 414 } 415 416 /** 417 * Launches the associated editor application and opens a file for 418 * editing. 419 * 420 * @param file the file to be opened for editing 421 * @throws NullPointerException if the specified file is {@code null} 422 * @throws IllegalArgumentException if the specified file doesn't 423 * exist 424 * @throws UnsupportedOperationException if the current platform 425 * does not support the {@link Desktop.Action#EDIT} action 426 * @throws IOException if the specified file has no associated 427 * editor, or the associated application fails to be launched 428 * @throws SecurityException if a security manager exists and its 429 * {@link java.lang.SecurityManager#checkRead(java.lang.String)} 430 * method denies read access to the file, or {@link 431 * java.lang.SecurityManager#checkWrite(java.lang.String)} method 432 * denies write access to the file, or it denies the 433 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> 434 * permission, or the calling thread is not allowed to create a 435 * subprocess 436 * @see java.awt.AWTPermission 437 */ 438 public void edit(File file) throws IOException { 439 checkAWTPermission(); 440 checkExec(); 441 checkActionSupport(Action.EDIT); 442 file.canWrite(); 443 checkFileValidation(file); 444 445 peer.edit(file); 446 } 447 448 /** 449 * Prints a file with the native desktop printing facility, using 450 * the associated application's print command. 451 * 452 * @param file the file to be printed 453 * @throws NullPointerException if the specified file is {@code 454 * null} 455 * @throws IllegalArgumentException if the specified file doesn't 456 * exist 457 * @throws UnsupportedOperationException if the current platform 458 * does not support the {@link Desktop.Action#PRINT} action 459 * @throws IOException if the specified file has no associated 460 * application that can be used to print it 461 * @throws SecurityException if a security manager exists and its 462 * {@link java.lang.SecurityManager#checkRead(java.lang.String)} 463 * method denies read access to the file, or its {@link 464 * java.lang.SecurityManager#checkPrintJobAccess()} method denies 465 * the permission to print the file, or the calling thread is not 466 * allowed to create a subprocess 467 */ 468 public void print(File file) throws IOException { 469 checkExec(); 470 SecurityManager sm = System.getSecurityManager(); 471 if (sm != null) { 472 sm.checkPrintJobAccess(); 473 } 474 checkActionSupport(Action.PRINT); 475 checkFileValidation(file); 476 477 peer.print(file); 478 } 479 480 /** 481 * Launches the default browser to display a {@code URI}. 482 * If the default browser is not able to handle the specified 483 * {@code URI}, the application registered for handling 484 * {@code URIs} of the specified type is invoked. The application 485 * is determined from the protocol and path of the {@code URI}, as 486 * defined by the {@code URI} class. 487 * <p> 488 * If the calling thread does not have the necessary permissions, 489 * and this is invoked from within an applet, 490 * {@code AppletContext.showDocument()} is used. Similarly, if the calling 491 * does not have the necessary permissions, and this is invoked from within 492 * a Java Web Started application, {@code BasicService.showDocument()} 493 * is used. 494 * 495 * @param uri the URI to be displayed in the user default browser 496 * @throws NullPointerException if {@code uri} is {@code null} 497 * @throws UnsupportedOperationException if the current platform 498 * does not support the {@link Desktop.Action#BROWSE} action 499 * @throws IOException if the user default browser is not found, 500 * or it fails to be launched, or the default handler application 501 * failed to be launched 502 * @throws SecurityException if a security manager exists and it 503 * denies the 504 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> 505 * permission, or the calling thread is not allowed to create a 506 * subprocess; and not invoked from within an applet or Java Web Started 507 * application 508 * @throws IllegalArgumentException if the necessary permissions 509 * are not available and the URI can not be converted to a {@code URL} 510 * @see java.net.URI 511 * @see java.awt.AWTPermission 512 * @see java.applet.AppletContext 513 */ 514 public void browse(URI uri) throws IOException { 515 SecurityException securityException = null; 516 try { 517 checkAWTPermission(); 518 checkExec(); 519 } catch (SecurityException e) { 520 securityException = e; 521 } 522 checkActionSupport(Action.BROWSE); 523 if (uri == null) { 524 throw new NullPointerException(); 525 } 526 if (securityException == null) { 527 peer.browse(uri); 528 return; 529 } 530 531 // Calling thread doesn't have necessary privileges. 532 // Delegate to DesktopBrowse so that it can work in 533 // applet/webstart. 534 URL url = null; 535 try { 536 url = uri.toURL(); 537 } catch (MalformedURLException e) { 538 throw new IllegalArgumentException("Unable to convert URI to URL", e); 539 } 540 sun.awt.DesktopBrowse db = sun.awt.DesktopBrowse.getInstance(); 541 if (db == null) { 542 // Not in webstart/applet, throw the exception. 543 throw securityException; 544 } 545 db.browse(url); 546 } 547 548 /** 549 * Launches the mail composing window of the user default mail 550 * client. 551 * 552 * @throws UnsupportedOperationException if the current platform 553 * does not support the {@link Desktop.Action#MAIL} action 554 * @throws IOException if the user default mail client is not 555 * found, or it fails to be launched 556 * @throws SecurityException if a security manager exists and it 557 * denies the 558 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> 559 * permission, or the calling thread is not allowed to create a 560 * subprocess 561 * @see java.awt.AWTPermission 562 */ 563 public void mail() throws IOException { 564 checkAWTPermission(); 565 checkExec(); 566 checkActionSupport(Action.MAIL); 567 URI mailtoURI = null; 568 try{ 569 mailtoURI = new URI("mailto:?"); 570 peer.mail(mailtoURI); 571 } catch (URISyntaxException e){ 572 // won't reach here. 573 } 574 } 575 576 /** 577 * Launches the mail composing window of the user default mail 578 * client, filling the message fields specified by a {@code 579 * mailto:} URI. 580 * 581 * <p> A <code>mailto:</code> URI can specify message fields 582 * including <i>"to"</i>, <i>"cc"</i>, <i>"subject"</i>, 583 * <i>"body"</i>, etc. See <a 584 * href="http://www.ietf.org/rfc/rfc2368.txt">The mailto URL 585 * scheme (RFC 2368)</a> for the {@code mailto:} URI specification 586 * details. 587 * 588 * @param mailtoURI the specified {@code mailto:} URI 589 * @throws NullPointerException if the specified URI is {@code 590 * null} 591 * @throws IllegalArgumentException if the URI scheme is not 592 * <code>"mailto"</code> 593 * @throws UnsupportedOperationException if the current platform 594 * does not support the {@link Desktop.Action#MAIL} action 595 * @throws IOException if the user default mail client is not 596 * found or fails to be launched 597 * @throws SecurityException if a security manager exists and it 598 * denies the 599 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> 600 * permission, or the calling thread is not allowed to create a 601 * subprocess 602 * @see java.net.URI 603 * @see java.awt.AWTPermission 604 */ 605 public void mail(URI mailtoURI) throws IOException { 606 checkAWTPermission(); 607 checkExec(); 608 checkActionSupport(Action.MAIL); 609 if (mailtoURI == null) throw new NullPointerException(); 610 611 if (!"mailto".equalsIgnoreCase(mailtoURI.getScheme())) { 612 throw new IllegalArgumentException("URI scheme is not \"mailto\""); 613 } 614 615 peer.mail(mailtoURI); 616 } 617 618 private void checkExec() throws SecurityException { 619 SecurityManager sm = System.getSecurityManager(); 620 if (sm != null) { 621 sm.checkPermission(new FilePermission("<<ALL FILES>>", 622 SecurityConstants.FILE_EXECUTE_ACTION)); 623 } 624 } 625 626 private void checkRead() throws SecurityException { 627 SecurityManager sm = System.getSecurityManager(); 628 if (sm != null) { 629 sm.checkPermission(new FilePermission("<<ALL FILES>>", 630 SecurityConstants.FILE_READ_ACTION)); 631 } 632 } 633 634 private void checkWrite() throws SecurityException { 635 SecurityManager sm = System.getSecurityManager(); 636 if (sm != null) { 637 sm.checkPermission(new FilePermission("<<ALL FILES>>", 638 SecurityConstants.FILE_WRITE_ACTION)); 639 } 640 } 641 642 /** 643 * Adds sub-types of {@link SystemEventListener} to listen for notifications 644 * from the native system. 645 * 646 * Has no effect if SystemEventListener's sub-type is unsupported on the current 647 * platform. 648 * 649 * @param listener listener 650 * @see AppForegroundListener 651 * @see AppHiddenListener 652 * @see AppReopenedListener 653 * @see ScreenSleepListener 654 * @see SystemSleepListener 655 * @see UserSessionListener 656 * @since 1.9 657 */ 658 public void addAppEventListener(final SystemEventListener listener) { 659 peer.addAppEventListener(listener); 660 } 661 662 /** 663 * Removes sub-types of {@link SystemEventListener} to listen for notifications 664 * from the native system. 665 * 666 * Has no effect if SystemEventListener's sub-type is unsupported on the current 667 * platform. 668 * 669 * @param listener listener 670 * @see AppForegroundListener 671 * @see AppHiddenListener 672 * @see AppReopenedListener 673 * @see ScreenSleepListener 674 * @see SystemSleepListener 675 * @see UserSessionListener 676 * @since 1.9 677 */ 678 public void removeAppEventListener(final SystemEventListener listener) { 679 peer.removeAppEventListener(listener); 680 } 681 682 /** 683 * Installs a handler to show a custom About window for your application. 684 * <p> 685 * Setting the {@link AboutHandler} to <code>null</code> reverts it to the 686 * default behavior. 687 * 688 * @param aboutHandler the handler to respond to the 689 * @throws UnsupportedOperationException if the current platform 690 * does not support the {@link Desktop.Action#APP_ABOUT} action 691 * {@link AboutHandler#handleAbout} )} message 692 * @since 1.9 693 */ 694 public void setAboutHandler(final AboutHandler aboutHandler) { 695 checkActionSupport(Action.APP_ABOUT); 696 peer.setAboutHandler(aboutHandler); 697 } 698 699 /** 700 * Installs a handler to show a custom Preferences window for your 701 * application. 702 * <p> 703 * Setting the {@link PreferencesHandler} to <code>null</code> reverts it to 704 * the default behavior 705 * 706 * @param preferencesHandler the handler to respond to the 707 * @throws UnsupportedOperationException if the current platform 708 * does not support the {@link Desktop.Action#APP_PREFERENCES} action 709 * {@link PreferencesHandler#handlePreferences(PreferencesEvent)} 710 * @since 1.9 711 */ 712 public void setPreferencesHandler(final PreferencesHandler preferencesHandler) { 713 checkActionSupport(Action.APP_PREFERENCES); 714 peer.setPreferencesHandler(preferencesHandler); 715 } 716 717 /** 718 * Installs the handler which is notified when the application is asked to 719 * open a list of files. 720 * 721 * @implNote Please note that for Mac OS, notifications 722 * are only sent if the Java app is a bundled application, 723 * with a {@code CFBundleDocumentTypes} array present in its 724 * Info.plist. See the 725 * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference"> 726 * Info.plist Key Reference</a> for more information about adding a 727 * {@code CFBundleDocumentTypes} key to your app's Info.plist. 728 * 729 * @param openFileHandler handler 730 * @throws UnsupportedOperationException if the current platform 731 * does not support the {@link Desktop.Action#APP_OPEN_FILE} action 732 * @since 1.9 733 */ 734 public void setOpenFileHandler(final OpenFilesHandler openFileHandler) { 735 checkActionSupport(Action.APP_OPEN_FILE); 736 peer.setOpenFileHandler(openFileHandler); 737 } 738 739 /** 740 * Installs the handler which is notified when the application is asked to 741 * print a list of files. 742 * 743 * @implNote Please note that for Mac OS, notifications 744 * are only sent if the Java app is a bundled application, 745 * with a {@code CFBundleDocumentTypes} array present in its 746 * Info.plist. See the 747 * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference"> 748 * Info.plist Key Reference</a> for more information about adding a 749 * {@code CFBundleDocumentTypes} key to your app's Info.plist. 750 * 751 * @param printFileHandler handler 752 * @throws UnsupportedOperationException if the current platform 753 * does not support the {@link Desktop.Action#APP_PRINT_FILE} action 754 * @since 1.9 755 */ 756 public void setPrintFileHandler(final PrintFilesHandler printFileHandler) { 757 checkActionSupport(Action.APP_PRINT_FILE); 758 peer.setPrintFileHandler(printFileHandler); 759 } 760 761 /** 762 * Installs the handler which is notified when the application is asked to 763 * open a URL. 764 * 765 * Setting the handler to <code>null</code> causes all 766 * {@link OpenURIHandler#openURI(AppEvent.OpenURIEvent)} requests to be 767 * enqueued until another handler is set. 768 * 769 * @implNote Please note that for Mac OS, notifications 770 * are only sent if the Java app is a bundled application, 771 * with a {@code CFBundleDocumentTypes} array present in its 772 * Info.plist. See the 773 * <a href="http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference"> 774 * Info.plist Key Reference</a> for more information about adding a 775 * {@code CFBundleDocumentTypes} key to your app's Info.plist. 776 * 777 * @param openURIHandler handler 778 * @throws UnsupportedOperationException if the current platform 779 * does not support the {@link Desktop.Action#APP_OPEN_URI} action 780 * @since 1.9 781 */ 782 public void setOpenURIHandler(final OpenURIHandler openURIHandler) { 783 checkActionSupport(Action.APP_OPEN_URI); 784 peer.setOpenURIHandler(openURIHandler); 785 } 786 787 /** 788 * Installs the handler which determines if the application should quit. The 789 * handler is passed a one-shot {@link QuitResponse} which can cancel or 790 * proceed with the quit. Setting the handler to <code>null</code> causes 791 * all quit requests to directly perform the default {@link QuitStrategy}. 792 * 793 * @param quitHandler the handler that is called when the application is 794 * asked to quit 795 * @throws UnsupportedOperationException if the current platform 796 * does not support the {@link Desktop.Action#APP_QUIT_HANDLER} action 797 * @since 1.9 798 */ 799 public void setQuitHandler(final QuitHandler quitHandler) { 800 checkActionSupport(Action.APP_QUIT_HANDLER); 801 peer.setQuitHandler(quitHandler); 802 } 803 804 /** 805 * Sets the default strategy used to quit this application. The default is 806 * calling SYSTEM_EXIT_0. 807 * 808 * @param strategy the way this application should be shutdown 809 * @throws UnsupportedOperationException if the current platform 810 * does not support the {@link Desktop.Action#APP_QUIT_STRATEGY} action 811 * @see QuitStrategy 812 * @since 1.9 813 */ 814 public void setQuitStrategy(final QuitStrategy strategy) { 815 checkActionSupport(Action.APP_QUIT_STRATEGY); 816 peer.setQuitStrategy(strategy); 817 } 818 819 /** 820 * Enables this application to be suddenly terminated. 821 * 822 * Call this method to indicate your application's state is saved, and 823 * requires no notification to be terminated. Letting your application 824 * remain terminatable improves the user experience by avoiding re-paging in 825 * your application when it's asked to quit. 826 * 827 * <b>Note: enabling sudden termination will allow your application to be 828 * quit without notifying your QuitHandler, or running any shutdown 829 * hooks.</b> 830 * E.g. user-initiated Cmd-Q, logout, restart, or shutdown requests will 831 * effectively "kill -KILL" your application. 832 * 833 * @throws UnsupportedOperationException if the current platform 834 * does not support the {@link Desktop.Action#APP_SUDDEN_TERMINATION} action 835 * @see #disableSuddenTermination() 836 * @since 1.9 837 */ 838 public void enableSuddenTermination() { 839 checkActionSupport(Action.APP_SUDDEN_TERMINATION); 840 peer.enableSuddenTermination(); 841 } 842 843 /** 844 * Prevents this application from being suddenly terminated. 845 * 846 * Call this method to indicate that your application has unsaved state, and 847 * may not be terminated without notification. 848 * 849 * @throws UnsupportedOperationException if the current platform 850 * does not support the {@link Desktop.Action#APP_SUDDEN_TERMINATION} action 851 * @see #enableSuddenTermination() 852 * @since 1.9 853 */ 854 public void disableSuddenTermination() { 855 checkActionSupport(Action.APP_SUDDEN_TERMINATION); 856 peer.disableSuddenTermination(); 857 } 858 859 /** 860 * Requests this application to move to the foreground. 861 * 862 * @param allWindows if all windows of this application should be moved to 863 * the foreground, or only the foremost one 864 * @throws SecurityException if a security manager exists and it denies the 865 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> permission. 866 * @throws UnsupportedOperationException if the current platform 867 * does not support the {@link Desktop.Action#APP_REQUEST_FOREGROUND} action 868 * @since 1.9 869 */ 870 public void requestForeground(final boolean allWindows) { 871 checkAWTPermission(); 872 checkActionSupport(Action.APP_REQUEST_FOREGROUND); 873 peer.requestForeground(allWindows); 874 } 875 876 /** 877 * Opens the native help viewer application. 878 * 879 * @throws SecurityException if a security manager exists and it denies the 880 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> permission. 881 * @throws UnsupportedOperationException if the current platform 882 * does not support the {@link Desktop.Action#APP_HELP_VIEWER} action 883 * @since 1.9 884 */ 885 public void openHelpViewer() { 886 checkAWTPermission(); 887 checkActionSupport(Action.APP_HELP_VIEWER); 888 peer.openHelpViewer(); 889 } 890 891 /** 892 * Sets the default menu bar to use when there are no active frames. 893 * 894 * @implNote Aqua Look and Feel should be active to support this on Mac OS. 895 * 896 * @param menuBar to use when no other frames are active 897 * @throws SecurityException if a security manager exists and it denies the 898 * <code>AWTPermission("showWindowWithoutWarningBanner")</code> permission. 899 * @throws UnsupportedOperationException if the current platform 900 * does not support the {@link Desktop.Action#APP_MENU_BAR} action 901 * @since 1.9 902 */ 903 public void setDefaultMenuBar(final JMenuBar menuBar) { 904 checkAWTPermission(); 905 checkActionSupport(Action.APP_MENU_BAR); 906 peer.setDefaultMenuBar(menuBar); 907 } 908 909 /** 910 * Opens a folder containing the {@code file} and selects it 911 * in a default system file manager. 912 * @param file the file 913 * @throws SecurityException If a security manager exists and its 914 * {@link SecurityManager#checkRead(java.lang.String)} method 915 * denies read access to the file 916 * @throws UnsupportedOperationException if the current platform 917 * does not support the {@link Desktop.Action#BROWSE_FILE_DIR} action 918 * @throws NullPointerException if {@code file} is {@code null} 919 * @throws IllegalArgumentException if the specified file doesn't 920 * exist 921 * @since 1.9 922 */ 923 public void browseFileDirectory(File file) { 924 checkRead(); 925 checkActionSupport(Action.BROWSE_FILE_DIR); 926 checkFileValidation(file); 927 peer.browseFileDirectory(file); 928 } 929 930 /** 931 * Moves the specified file to the trash. 932 * 933 * @param file the file 934 * @return returns true if successfully moved the file to the trash. 935 * @throws SecurityException If a security manager exists and its 936 * {@link SecurityManager#checkWrite(java.lang.String)} method 937 * denies write access to the file 938 * @throws UnsupportedOperationException if the current platform 939 * does not support the {@link Desktop.Action#MOVE_TO_TRASH} action 940 * @throws NullPointerException if {@code file} is {@code null} 941 * @throws IllegalArgumentException if the specified file doesn't 942 * exist 943 * 944 * @since 1.9 945 */ 946 public boolean moveToTrash(final File file) { 947 checkWrite(); 948 checkActionSupport(Action.MOVE_TO_TRASH); 949 checkFileValidation(file); 950 return peer.moveToTrash(file); 951 } 952 }