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