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