001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Desktop;
007import java.io.IOException;
008import java.net.URI;
009import java.net.URISyntaxException;
010
011import org.openstreetmap.josm.Main;
012
013/**
014 * Helper to open platform web browser on different platforms
015 *
016 * This now delegates the real work to a platform specific class.
017 *
018 * @author Imi
019 */
020public final class OpenBrowser {
021
022    private OpenBrowser() {
023        // Hide default constructor for utils classes
024    }
025
026    private static void displayUrlFallback(URI uri) throws IOException {
027        if (Main.platform == null)
028            throw new IllegalStateException(tr("Failed to open URL. There is currently no platform set. Please set a platform first."));
029        Main.platform.openUrl(uri.toString());
030    }
031
032    /**
033     * Displays an external URI using platform associated software.
034     * A web resource will launch platform's browser, an audio file URI will launch audio player, etc.
035     * @param uri The URI to display
036     * @return <code>null</code> for success or a string in case of an error.
037     * @throws IllegalStateException if no platform is set to which opening the URL can be dispatched,
038     * {@link Main#platform}
039     */
040    public static String displayUrl(URI uri) {
041        CheckParameterUtil.ensureParameterNotNull(uri, "uri");
042
043        Logging.info(tr("Opening URL: {0}", uri));
044
045        if (Desktop.isDesktopSupported()) {
046            try {
047                if (Main.isPlatformWindows()) {
048                    // Desktop API works fine under Windows, so we don't try any fallback in case of I/O exceptions because it's not API's fault
049                    Desktop.getDesktop().browse(uri);
050                } else if (Main.platform instanceof PlatformHookUnixoid || Main.platform instanceof PlatformHookOsx) {
051                    // see #5629 #5108 #9568
052                    Main.platform.openUrl(uri.toString());
053                } else {
054                    // This is not the case with some Linux environments (see below),
055                    // and not sure about Mac OS X, so we need to handle API failure
056                    try {
057                        Desktop.getDesktop().browse(uri);
058                    } catch (IOException e) {
059                        // Workaround for KDE (Desktop API is severely flawed)
060                        // see https://bugs.openjdk.java.net/browse/JDK-6486393
061                        Logging.log(Logging.LEVEL_WARN, "Desktop class failed. Platform dependent fall back for open url in browser.", e);
062                        displayUrlFallback(uri);
063                    }
064                }
065            } catch (IOException e) {
066                Logging.warn(e);
067                return e.getMessage();
068            }
069        } else {
070            try {
071                Logging.warn("Desktop class is not supported. Platform dependent fall back for open url in browser.");
072                displayUrlFallback(uri);
073            } catch (IOException e) {
074                Logging.debug(e);
075                return e.getMessage();
076            }
077        }
078        return null;
079    }
080
081    /**
082     * Displays an external URL using platform associated software.
083     * A web resource will launch platform's browser, an audio file URL will launch audio player, etc.
084     * @param url The URL to display
085     * @return <code>null</code> for success or a string in case of an error.
086     * @throws IllegalStateException if no platform is set to which opening the URL can be dispatched,
087     * {@link Main#platform}
088     */
089    public static String displayUrl(String url) {
090        try {
091            return displayUrl(new URI(url));
092        } catch (URISyntaxException e) {
093            Logging.debug(e);
094            return e.getMessage();
095        }
096    }
097}