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