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