package chatty.gui; import chatty.util.MiscUtil; import chatty.util.ProcessManager; import java.awt.Component; import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.swing.JOptionPane; /** * Opens the given URL in the default browser, with or without prompt. * * @author tduva */ public class UrlOpener { private static final Logger LOGGER = Logger.getLogger(UrlOpener.class.getName()); /** * The maximum number of chars before an url is split up into several lines * when displaying it in a prompt. */ private final static int MAX_URL_LENGTH = 80; /** * Save whether to currently use a prompt by default. */ private static boolean prompt = true; /** * Changes whether to use a prompt by default. * * @param usePrompt */ public static void setPrompt(boolean usePrompt) { prompt = usePrompt; } private static boolean customCommandEnabled; private static String customCommand; public static void setCustomCommandEnabled(boolean enabled) { customCommandEnabled = enabled; } public static void setCustomCommand(String command) { customCommand = command; } /** * Open a single URL with a prompt if enabled. * * @param parent The Component that will be used as parent for the prompt. * @param url The URL as a String. * @return true if the given url was opened successfully, false otherwise */ public static boolean openUrlPrompt(Component parent, String url) { return openUrlPrompt(parent, url, false); } /** * Open a single URL with a prompt if enabled or if the prompt is forced * by the parameter. * * @param parent The Component that will be used as parent for the prompt. * @param url The URL as a String. * @param forcePrompt Whether to force a prompt or use the default setting. * @return true if the given url was opened successfully, false otherwise */ public static boolean openUrlPrompt(Component parent, String url, boolean forcePrompt) { if (url == null) { return false; } List<String> list = new ArrayList<>(); list.add(url); return openUrlsPrompt(parent, list, forcePrompt); } /** * Directly open the given URL in the default browser. * * @param url The URL as a String. * @return true if the url was opened successfully, false if an error * occured, e.g. if the url was empty or invalid */ public static boolean openUrl(String url) { if (url == null) { return false; } URI parsed; try { parsed = new URI(url); } catch (URISyntaxException ex) { LOGGER.warning("Invalid URI format: " + ex); return false; } if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE) && !customCommandEnabled) { try { Desktop.getDesktop().browse(parsed); return true; } catch (IOException ex) { LOGGER.warning("Error opening URL: "+ex); } } else { return openUrlNative(url); } return false; } private static boolean openUrlNative(String url) { String command = null; if (customCommandEnabled && customCommand != null && !customCommand.isEmpty()) { command = customCommand+" "+url; } else if (MiscUtil.OS_WINDOWS) { command = "explorer "+url; } else if (MiscUtil.OS_LINUX) { command = "xdg-open "+url; } else if (MiscUtil.OS_MAC) { command = "open "+url; } if (command != null) { ProcessManager.execute(command, "URL"); return true; } return false; } /** * Open several URLs by using a prompt if it's enabled. * * @param parent The Component that will be used as parent for the prompt. * @param urls The list of URLs as Strings. */ public static void openUrlsPrompt(Component parent, List<String> urls) { openUrlsPrompt(parent, urls, false); } /** * Opens several URLs by using a prompt if it's enabled or if a prompt is * forced by the parameter. * * @param parent The Component that should be the parent of a prompt * @param urls The list of URLs as Strings * @param forcePrompt Always show a prompt, even if it's not the default * setting * @return true if at least one of the given URLs was opened successfully */ public static boolean openUrlsPrompt(Component parent, List<String> urls, boolean forcePrompt) { if (urls.isEmpty()) { return false; } if (!forcePrompt && !prompt) { return openUrls(urls); } switch (showUrlsPrompt(parent, urls)) { case 0: return openUrls(urls); case 1: MiscUtil.copyToClipboard(urls.get(0)); } return true; } /** * Opens one or more URLs specified in the given list in the default * browser. * * @param urls The list of URLs to open * @return true if all of the given URLs were opened successfully, false * otherwise */ public static boolean openUrls(List<String> urls) { boolean result = true; for (String url : urls) { if (!openUrl(url)) { result = false; } } return result; } /** * Actually show the dialog that contain the given URLs and give the user * the option to open the URL, copy it or cancel the dialog. * * @param parent The Component that will be used as parent for the prompt. * @param urls The list of URLs as Strings * @return 0 if the URL should be opened, 1 if it should be copied, 2 if * nothing should be done */ private static int showUrlsPrompt(Component parent, List<String> urls) { // Make text String text = "<html><body style='width: 100px;'>"; for (String url : urls) { url = splitUrl(url); text += url + "<br />"; } // Make options String okOption = "Open URL"; if (urls.size() > 1) { okOption = "Open "+urls.size()+" URLs"; } String[] options = {okOption, "Cancel"}; if (urls.size() == 1) { options = new String[]{okOption, "Copy URL", "Cancel"}; } // Show dialog int chosenOption = JOptionPane.showOptionDialog(parent, text, "Open in default browser?", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 1); return chosenOption; } /** * Split up the given url if it is longer than the max length, by adding a * space in between, so it can be linebroken at that point. * * @param url The url to split up * @return The url with added spaces if it exceeded max length */ private static String splitUrl(String url) { if (url.length() > MAX_URL_LENGTH) { return url.substring(0, MAX_URL_LENGTH)+" "+splitUrl(url.substring(MAX_URL_LENGTH)); } return url; } }