BrowserUtil.browse can open url with fragments

Now you can just pass File, VirtualFile, URL or URI instead of String — don't use file.toURI or url.toString or virtualFile.getUrl
This commit is contained in:
Vladimir Krivosheev
2012-12-27 16:27:13 +04:00
parent 89c3c2931a
commit ff28f8c757
17 changed files with 228 additions and 94 deletions
@@ -104,10 +104,10 @@ public class ProjectNameWithTypeStep extends ProjectNameStep {
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
try {
BrowserUtil.launchBrowser(e.getURL().toString());
BrowserUtil.browse(e.getURL());
}
catch (IllegalThreadStateException ex) {
// it's nnot a problem
// it's not a problem
}
}
}
@@ -314,7 +314,7 @@ public class JavadocConfiguration implements ModuleRunProfile, JDOMExternalizabl
if (OPEN_IN_BROWSER) {
File url = new File(OUTPUT_DIRECTORY, INDEX_HTML);
if (url.exists() && event.getExitCode() == 0) {
BrowserUtil.launchBrowser(url.getPath());
BrowserUtil.browse(url);
}
}
}
@@ -136,7 +136,7 @@ public class ExportHTMLAction extends AnAction implements DumbAware {
}
if (exportToHTML && exportToHTMLSettings.OPEN_IN_BROWSER) {
BrowserUtil.launchBrowser(exportToHTMLSettings.OUTPUT_DIRECTORY + File.separator + "index.html");
BrowserUtil.browse(new File(exportToHTMLSettings.OUTPUT_DIRECTORY, "index.html"));
}
}
});
@@ -316,7 +316,7 @@ public class RegExHelpPopup extends JPanel {
myEditorPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (HyperlinkEvent.EventType.ACTIVATED == e.getEventType()) BrowserUtil.launchBrowser(e.getURL().toString());
if (HyperlinkEvent.EventType.ACTIVATED == e.getEventType()) BrowserUtil.browse(e.getURL());
}
});
@@ -48,6 +48,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
@@ -62,7 +64,7 @@ import static com.intellij.util.containers.ContainerUtil.newSmartList;
import static com.intellij.util.containers.ContainerUtilRt.newArrayList;
public class BrowserUtil {
private static final Logger LOG = Logger.getInstance("#" + BrowserUtil.class.getName());
private static final Logger LOG = Logger.getInstance(BrowserUtil.class);
private static final boolean TRIM_URLS = !"false".equalsIgnoreCase(System.getProperty("idea.browse.trim.urls"));
@@ -93,43 +95,123 @@ public class BrowserUtil {
@Nullable
public static URL getURL(String url) throws MalformedURLException {
if (!isAbsoluteURL(url)) {
return new URL("file", "", url);
}
return VfsUtil.convertToURL(url);
return isAbsoluteURL(url) ? VfsUtil.convertToURL(url) : new URL("file", "", url);
}
/**
* Main method: tries to launch a browser using every possible way.
*
* @param url an URL to open.
*/
public static void launchBrowser(@NotNull @NonNls String url) {
LOG.debug("Launch browser: [" + url + "]");
public static void browse(@NotNull VirtualFile file) {
browse(VfsUtil.toUri(file));
}
public static boolean browse(@NotNull File file) {
try {
browse(new URI(StandardFileSystems.FILE_PROTOCOL, "", file.getAbsolutePath(), null));
return true;
}
catch (URISyntaxException e) {
LOG.debug(e);
return false;
}
}
public static void browse(@NotNull URL url) {
launchBrowser(url.toExternalForm());
}
public static void launchBrowser(@NotNull @NonNls String url) {
browse(url);
}
public static void browse(@NotNull @NonNls String url) {
openOrBrowse(url, true);
}
public static void open(@NotNull @NonNls String url) {
openOrBrowse(url, false);
}
private static void openOrBrowse(@NotNull @NonNls String url, boolean browse) {
if (TRIM_URLS) {
url = url.trim();
}
if (url.startsWith("jar:")) {
String files = extractFiles(url);
if (files == null) return;
if (files == null) {
return;
}
url = files;
}
if (getGeneralSettingsInstance().isUseDefaultBrowser() && canStartDefaultBrowser()) {
final List<String> command = getDefaultBrowserCommand();
if (command != null) {
launchBrowserByCommand(url, command);
}
else {
launchBrowserUsingDesktopApi(url);
}
URI uri;
if (isAbsoluteURL(url)) {
uri = VfsUtil.toUri(url);
}
else {
launchBrowserUsingStandardWay(url);
File file = new File(url);
if (!browse && isDesktopActionSupported(Desktop.Action.OPEN)) {
try {
Desktop.getDesktop().open(file);
return;
}
catch (IOException e) {
LOG.debug(e);
}
}
if (browse(file)) {
return;
}
uri = null;
}
if (uri == null) {
showErrorMessage(IdeBundle.message("error.malformed.url", url), CommonBundle.getErrorTitle());
}
else {
browse(uri);
}
}
/**
* Main method: tries to launch a browser using every possible way
*/
public static void browse(@NotNull URI uri) {
LOG.debug("Launch browser: [" + uri + "]");
if (getGeneralSettingsInstance().isUseDefaultBrowser()) {
if (isDesktopActionSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(uri);
LOG.debug("Browser launched using JDK 1.6 API");
}
catch (Exception e) {
LOG.error(e);
}
return;
}
else {
List<String> command = getDefaultBrowserCommand();
if (command != null) {
launchBrowserByCommand(uri, command);
return;
}
}
}
String browserPath = getGeneralSettingsInstance().getBrowserPath();
if (StringUtil.isEmptyOrSpaces(browserPath)) {
showErrorMessage(IdeBundle.message("error.please.specify.path.to.web.browser"), IdeBundle.message("title.browser.not.found"));
return;
}
launchBrowserByCommand(uri, getOpenBrowserCommand(browserPath));
}
private static boolean isDesktopActionSupported(Desktop.Action action) {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(action)) {
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6457572
return !SystemInfo.isWindows || SystemInfo.isJavaVersionAtLeast("1.7");
}
return false;
}
private static GeneralSettings getGeneralSettingsInstance() {
@@ -167,22 +249,10 @@ public class BrowserUtil {
return null;
}
private static void launchBrowserByCommand(final String url, @NotNull final List<String> command) {
URL curl;
try {
curl = getURL(url);
}
catch (MalformedURLException ignored) {
curl = null;
}
if (curl == null) {
showErrorMessage(IdeBundle.message("error.malformed.url", url), CommonBundle.getErrorTitle());
return;
}
private static void launchBrowserByCommand(@NotNull final URI uri, @NotNull final List<String> command) {
try {
final GeneralCommandLine commandLine = new GeneralCommandLine(command);
commandLine.addParameter(escapeUrl(curl.toString()));
commandLine.addParameter(escapeUrl(uri.toString()));
if (SystemInfo.isWindows) {
commandLine.putUserData(GeneralCommandLine.DO_NOT_ESCAPE_QUOTES, true);
}
@@ -199,31 +269,7 @@ public class BrowserUtil {
@NotNull
public static String escapeUrl(@NotNull @NonNls String url) {
return SystemInfo.isWindows ? "\"" + url + "\""
: url;
}
private static boolean launchBrowserUsingDesktopApi(final String sUrl) {
try {
URL url = getURL(sUrl);
if (url == null) return false;
Desktop.getDesktop().browse(url.toURI());
LOG.debug("Browser launched using JDK 1.6 API");
return true;
}
catch (Exception e) {
return false;
}
}
private static void launchBrowserUsingStandardWay(final String url) {
final String browserPath = getGeneralSettingsInstance().getBrowserPath();
if (StringUtil.isEmptyOrSpaces(browserPath)) {
showErrorMessage(IdeBundle.message("error.please.specify.path.to.web.browser"), IdeBundle.message("title.browser.not.found"));
return;
}
launchBrowserByCommand(url, getOpenBrowserCommand(browserPath));
return SystemInfo.isWindows ? '"' + url + '"' : url;
}
@NotNull
@@ -281,6 +327,7 @@ public class BrowserUtil {
String targetFilePath = file.getPath();
String targetFileRelativePath = StringUtil.substringAfter(targetFilePath, JarFileSystem.JAR_SEPARATOR);
LOG.assertTrue(targetFileRelativePath != null);
String jarVirtualFileLocationHash = jarVirtualFile.getName() + Integer.toHexString(jarVirtualFile.getUrl().hashCode());
final File outputDir = new File(getExtractedFilesDir(), jarVirtualFileLocationHash);
@@ -31,7 +31,7 @@ public interface NotificationListener {
@Override
public void hyperlinkUpdate(@NotNull final Notification notification, @NotNull final HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
BrowserUtil.launchBrowser(event.getURL().toExternalForm());
BrowserUtil.browse(event.getURL());
}
}
};
@@ -320,8 +320,6 @@ public class VfsUtil extends VfsUtilCore {
return file;
}
@NonNls private static final String FILE = "file";
@NonNls private static final String JAR = "jar";
@NonNls private static final String MAILTO = "mailto";
private static final String PROTOCOL_DELIMITER = ":";
@@ -361,7 +359,7 @@ public class VfsUtil extends VfsUtilCore {
@Nullable
public static URL convertToURL(@NotNull String vfsUrl) {
if (vfsUrl.startsWith(JAR)) {
if (vfsUrl.startsWith(StandardFileSystems.JAR_PROTOCOL)) {
LOG.error("jar: protocol not supported.");
return null;
}
@@ -387,7 +385,7 @@ public class VfsUtil extends VfsUtilCore {
String path = split[1];
try {
if (protocol.equals(FILE)) {
if (protocol.equals(StandardFileSystems.FILE_PROTOCOL)) {
return new URL(protocol, "", path);
}
else {
@@ -404,8 +402,8 @@ public class VfsUtil extends VfsUtilCore {
public static String convertFromUrl(@NotNull URL url) {
String protocol = url.getProtocol();
String path = url.getPath();
if (protocol.equals(JAR)) {
if (StringUtil.startsWithConcatenationOf(path, FILE, PROTOCOL_DELIMITER)) {
if (protocol.equals(StandardFileSystems.JAR_PROTOCOL)) {
if (StringUtil.startsWithConcatenationOf(path, StandardFileSystems.FILE_PROTOCOL, PROTOCOL_DELIMITER)) {
try {
URL subURL = new URL(path);
path = subURL.getPath();
@@ -519,6 +517,51 @@ public class VfsUtil extends VfsUtilCore {
}
}
/**
* uri - may be incorrect (escaping or missed "/" before disk name under windows), may be not fully encoded,
* may contains query and fragment
* @return correct URI, must be used only for external communication
*/
@Nullable
public static URI toUri(@NotNull String uri) {
int index = uri.indexOf("://");
if (index < 0) {
// true URI, like mailto:
try {
return new URI(uri);
}
catch (URISyntaxException e) {
LOG.debug(e);
return null;
}
}
if (SystemInfo.isWindows && uri.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) {
int firstSlashIndex = index + "://".length();
if (uri.charAt(firstSlashIndex) != '/') {
uri = LocalFileSystem.PROTOCOL_PREFIX + '/' + uri.substring(firstSlashIndex);
}
}
try {
return new URI(uri);
}
catch (URISyntaxException e) {
LOG.debug("uri is not fully encoded", e);
// so, uri is not fully encoded (space)
try {
int fragmentIndex = uri.lastIndexOf('#');
String path = uri.substring(index + 1, fragmentIndex > 0 ? fragmentIndex : uri.length());
String fragment = fragmentIndex > 0 ? uri.substring(fragmentIndex + 1) : null;
return new URI(uri.substring(0, index), path, fragment);
}
catch (URISyntaxException e1) {
LOG.debug(e1);
return null;
}
}
}
/**
* Returns the relative path from one virtual file to another.
*
@@ -138,7 +138,7 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
final URL url = e.getURL();
if (url != null) {
BrowserUtil.launchBrowser(url.toString());
BrowserUtil.browse(url);
hint.hide();
return;
}
@@ -36,8 +36,9 @@ public class RefCardAction extends AnAction implements DumbAware {
public void actionPerformed(AnActionEvent e) {
final String url = KEYMAP_URL;
if (new File(url).isFile()) {
BrowserUtil.launchBrowser(url);
File file = new File(url);
if (file.isFile()) {
BrowserUtil.browse(file);
}
else {
final ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx();
@@ -432,7 +432,7 @@ public abstract class PluginManagerMain implements Disposable {
else {
URL url = e.getURL();
if (url != null) {
BrowserUtil.launchBrowser(url.toString());
BrowserUtil.browse(url);
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.testFramework.PlatformLangTestCase;
import com.intellij.testFramework.PlatformTestUtil;
@@ -32,6 +33,7 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -293,4 +295,52 @@ public class VfsUtilTest extends PlatformLangTestCase {
assertNotNull(vFile2);
assertTrue(vFile2.isDirectory());
}
public void testToUri() {
URI uri = VfsUtil.toUri("file:///asd");
assertNotNull(uri);
assertEquals("file", uri.getScheme());
assertEquals("/asd", uri.getPath());
uri = VfsUtil.toUri("file:///asd/ ads/ad#test");
assertNotNull(uri);
assertEquals("file", uri.getScheme());
assertEquals("/asd/ ads/ad", uri.getPath());
assertEquals("test", uri.getFragment());
uri = VfsUtil.toUri("file:///asd/ ads/ad#");
assertNotNull(uri);
assertEquals("file:///asd/%20ads/ad#", uri.toString());
uri = VfsUtil.toUri("mailto:someone@example.com");
assertNotNull(uri);
assertEquals("someone@example.com", uri.getSchemeSpecificPart());
if (SystemInfo.isWindows) {
uri = VfsUtil.toUri("file://C:/p");
assertNotNull(uri);
assertEquals("file", uri.getScheme());
assertEquals("/C:/p", uri.getPath());
}
uri = VfsUtil.toUri("file:///Users/S pace");
assertNotNull(uri);
assertEquals("file", uri.getScheme());
assertEquals("/Users/S pace", uri.getPath());
assertEquals("/Users/S%20pace", uri.getRawPath());
assertEquals("file:///Users/S%20pace", uri.toString());
uri = VfsUtil.toUri("http://developer.android.com/guide/developing/tools/avd.html");
assertNotNull(uri);
assertEquals("http", uri.getScheme());
assertEquals("/guide/developing/tools/avd.html", uri.getRawPath());
assertEquals("http://developer.android.com/guide/developing/tools/avd.html", uri.toString());
uri = VfsUtil.toUri("http://developer.android.com/guide/developing/tools/avd.html?f=23r2ewd");
assertNotNull(uri);
assertEquals("http", uri.getScheme());
assertEquals("/guide/developing/tools/avd.html", uri.getRawPath());
assertEquals("http://developer.android.com/guide/developing/tools/avd.html?f=23r2ewd", uri.toString());
assertEquals("f=23r2ewd", uri.getQuery());
}
}
@@ -269,7 +269,7 @@ public class ExportTestResultsAction extends DumbAwareAction {
FileEditorManager.getInstance(project).openFile(result, true);
}
else {
BrowserUtil.launchBrowser(result.getUrl());
BrowserUtil.browse(result);
}
}
});
@@ -16,7 +16,6 @@
package com.intellij.openapi.vcs.changes.committed;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -29,6 +28,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.ChangeList;
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.UIUtil;
@@ -36,8 +36,6 @@ import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
/**
* @author yole
@@ -100,13 +98,7 @@ public class ChangeListDetailsAction extends AnAction implements DumbAware {
editorPane.setEditable(false);
editorPane.setBackground(HintUtil.INFORMATION_COLOR);
editorPane.select(0, 0);
editorPane.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(final HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
BrowserUtil.launchBrowser(e.getDescription());
}
}
});
editorPane.addHyperlinkListener(new BrowserHyperlinkListener());
JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(editorPane);
final JBPopup hint =
JBPopupFactory.getInstance().createComponentPopupBuilder(scrollPane, editorPane)
@@ -45,6 +45,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -220,7 +221,7 @@ public class CreateAvdDialog extends DialogWrapper {
myTargetBox.setSelectedItem(targets[0]);
}
myNameField.setText(generateAvdName());
final String url = "http://developer.android.com/guide/developing/tools/avd.html";
final URI url = URI.create("http://developer.android.com/guide/developing/tools/avd.html");
myAvdInfoLink.setText("<html>\n" +
" <body>\n" +
" <p style=\"margin-top: 0;\">\n" +
@@ -237,7 +238,7 @@ public class CreateAvdDialog extends DialogWrapper {
@Override
public boolean onClick(MouseEvent e, int clickCount) {
try {
BrowserUtil.launchBrowser(url);
BrowserUtil.browse(url);
}
catch (IllegalThreadStateException ex) {
/* not a problem */
@@ -39,7 +39,7 @@ public class GithubLoginPanel {
mySignupTextField.addHyperlinkListener(new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(final HyperlinkEvent e) {
BrowserUtil.launchBrowser(e.getURL().toExternalForm());
BrowserUtil.browse(e.getURL());
}
});
mySignupTextField.setText(
@@ -49,7 +49,7 @@ public class GithubSettingsPanel {
mySignupTextField.addHyperlinkListener(new HyperlinkAdapter() {
@Override
protected void hyperlinkActivated(final HyperlinkEvent e) {
BrowserUtil.launchBrowser(e.getURL().toExternalForm());
BrowserUtil.browse(e.getURL());
}
});
mySignupTextField.setText(
@@ -115,7 +115,7 @@ public final class GenerateGroovyDocAction extends AnAction implements DumbAware
if (configuration.OPEN_IN_BROWSER) {
File url = new File(configuration.OUTPUT_DIRECTORY, INDEX_HTML);
if (url.exists()) {
BrowserUtil.launchBrowser(url.getPath());
BrowserUtil.browse(url);
}
}
}