show error if we cannot launch browser

add "Fix" button — open web browser settings
This commit is contained in:
Vladimir Krivosheev
2014-02-06 17:49:28 +01:00
parent e80c761e5d
commit 0cdea4e19d
11 changed files with 140 additions and 45 deletions
@@ -167,11 +167,18 @@ public class ExecUtil {
@Nullable
public static String execAndReadLine(@Nullable Charset charset, final String... command) {
try {
final Process process = new GeneralCommandLine(command).createProcess();
InputStream inputStream = process.getInputStream();
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
InputStreamReader in = charset == null ? new InputStreamReader(inputStream) : new InputStreamReader(inputStream, charset);
final BufferedReader reader = new BufferedReader(in);
return readFirstLine(new GeneralCommandLine(command).createProcess().getInputStream(), charset);
}
catch (Exception ignored) {
return null;
}
}
@Nullable
public static String readFirstLine(@NotNull InputStream inputStream, @Nullable Charset charset) {
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
BufferedReader reader = new BufferedReader(charset == null ? new InputStreamReader(inputStream) : new InputStreamReader(inputStream, charset));
try {
try {
return reader.readLine();
}
@@ -179,8 +186,9 @@ public class ExecUtil {
reader.close();
}
}
catch (Exception ignored) { }
return null;
catch (IOException ignored) {
return null;
}
}
/**
@@ -51,10 +51,8 @@ import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.*;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -251,7 +249,7 @@ public class BrowserUtil {
@NotNull
public static List<String> getOpenBrowserCommand(@NonNls @NotNull String browserPathOrName, boolean newWindowIfPossible) {
if (new File(browserPathOrName).isFile()) {
return newSmartList(browserPathOrName);
return Collections.singletonList(browserPathOrName);
}
else if (SystemInfo.isMac) {
List<String> command = newArrayList(ExecUtil.getOpenCommandPath(), "-a", browserPathOrName);
@@ -261,10 +259,10 @@ public class BrowserUtil {
return command;
}
else if (SystemInfo.isWindows) {
return newArrayList(ExecUtil.getWindowsShellName(), "/c", "start", GeneralCommandLine.inescapableQuote(""), browserPathOrName);
return Arrays.asList(ExecUtil.getWindowsShellName(), "/c", "start", GeneralCommandLine.inescapableQuote(""), browserPathOrName);
}
else {
return newSmartList(browserPathOrName);
return Collections.singletonList(browserPathOrName);
}
}
@@ -39,7 +39,7 @@ public abstract class ShowSettingsUtil {
public abstract boolean editConfigurable(Project project, Configurable configurable);
public abstract boolean editConfigurable(Project project, Configurable configurable, Runnable advancedInitialization);
public abstract boolean editConfigurable(@Nullable Project project, Configurable configurable, @Nullable Runnable advancedInitialization);
public abstract boolean editConfigurable(Component parent, Configurable configurable);
@@ -19,6 +19,7 @@ import com.intellij.ide.IdeBundle;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Ref;
import com.intellij.ui.*;
import com.intellij.ui.table.TableView;
import com.intellij.util.Function;
@@ -340,6 +341,29 @@ public class TableModelEditor<T> implements ElementProducer<T> {
return model.isModified(oldItems);
}
public void selectItem(@NotNull final T item) {
table.clearSelection();
final Ref<T> ref;
if (model.modifiedToOriginal.isEmpty()) {
ref = null;
}
else {
ref = Ref.create();
model.modifiedToOriginal.forEachEntry(new TObjectObjectProcedure<T, T>() {
@Override
public boolean execute(T modified, T original) {
if (item == original) {
ref.set(modified);
}
return ref.isNull();
}
});
}
table.addSelection(ref == null || ref.isNull() ? item : ref.get());
}
@NotNull
public List<T> apply() {
return model.apply();
@@ -81,4 +81,9 @@ public class BrowserSettings implements SearchableConfigurable, Configurable.NoS
public void disposeUIResources() {
myPanel = null;
}
public void selectBrowser(@NotNull WebBrowser browser) {
createComponent();
myPanel.selectBrowser(browser);
}
}
@@ -20,7 +20,6 @@ import com.intellij.ide.GeneralSettings;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
@@ -54,7 +53,7 @@ import static com.intellij.ide.browsers.BrowsersConfiguration.BrowserFamily;
import static com.intellij.ide.browsers.WebBrowserManager.DefaultBrowser;
import static com.intellij.util.ui.table.TableModelEditor.EditableColumnInfo;
public class BrowserSettingsPanel {
final class BrowserSettingsPanel {
private static final FileChooserDescriptor APP_FILE_CHOOSER_DESCRIPTOR = FileChooserDescriptorFactory.createSingleFileOrExecutableAppDescriptor();
private static final EditableColumnInfo<ConfigurableWebBrowser, String> PATH_COLUMN_INFO =
@@ -323,7 +322,7 @@ public class BrowserSettingsPanel {
return browsersEditor.isModified(browserManager.getList());
}
public void apply() throws ConfigurationException {
public void apply() {
GeneralSettings settings = GeneralSettings.getInstance();
settings.setUseDefaultBrowser(getDefaultBrowser() == DefaultBrowser.SYSTEM);
@@ -356,4 +355,10 @@ public class BrowserSettingsPanel {
alternativeBrowserPathField.setEnabled(defaultBrowser == DefaultBrowser.ALTERNATIVE);
updateCustomPathTextFieldValue(defaultBrowser);
}
public void selectBrowser(@NotNull WebBrowser browser) {
if (browser instanceof ConfigurableWebBrowser) {
browsersEditor.selectItem((ConfigurableWebBrowser)browser);
}
}
}
@@ -48,7 +48,7 @@ public interface JavaScriptDebuggerStarter<RC extends RunConfiguration, U> {
@Nullable WebBrowser browser,
boolean startDebugger) {
if (!startDebugger || !start(runConfiguration, url)) {
UrlOpener.launchBrowser(url, browser);
UrlOpener.launchBrowser(url, browser, runConfiguration.getProject());
}
}
}
@@ -62,7 +62,7 @@ public final class OpenUrlHyperlinkInfo implements HyperlinkWithPopupMenuInfo {
group.add(new AnAction("Open in " + browser.getName(), "Open URL in " + browser.getName(), browser.getIcon()) {
@Override
public void actionPerformed(AnActionEvent e) {
UrlOpener.launchBrowser(url, browser);
UrlOpener.launchBrowser(url, browser, e.getProject());
}
});
}
@@ -79,6 +79,6 @@ public final class OpenUrlHyperlinkInfo implements HyperlinkWithPopupMenuInfo {
@Override
public void navigate(Project project) {
UrlOpener.launchBrowser(url, browser);
UrlOpener.launchBrowser(url, browser, project);
}
}
@@ -17,6 +17,7 @@ package com.intellij.ide.browsers;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,19 +28,24 @@ public abstract class UrlOpener {
launchBrowser(url, family == null ? null : WebBrowserManager.getInstance().findBrowser(family));
}
public static void launchBrowser(@NotNull String url, @Nullable WebBrowser browser) {
launchBrowser(url, browser, null);
}
// different params order in order not to break compilation for launchBrowser(null, url)
public static void launchBrowser(final @NotNull String url, final @Nullable WebBrowser browser) {
public static void launchBrowser(@NotNull String url, @Nullable WebBrowser browser, @Nullable Project project) {
if (browser == null) {
BrowserUtil.launchBrowser(url);
}
else {
for (UrlOpener urlOpener : EP_NAME.getExtensions()) {
if (urlOpener.openUrl(browser, url)) {
if (urlOpener.openUrl(browser, url, null)) {
return;
}
}
}
}
public abstract boolean openUrl(final @NotNull WebBrowser browser, final @NotNull String url);
public abstract boolean openUrl(@NotNull WebBrowser browser, @NotNull String url, @Nullable Project project);
}
@@ -195,7 +195,7 @@ public abstract class BaseOpenInBrowserAction extends DumbAwareAction {
open(createRequest(event.getDataContext()), (event.getModifiers() & InputEvent.SHIFT_MASK) != 0, browser);
}
public static void open(@Nullable OpenInBrowserRequest request, boolean preferLocalUrl, @Nullable final WebBrowser browser) {
public static void open(@Nullable final OpenInBrowserRequest request, boolean preferLocalUrl, @Nullable final WebBrowser browser) {
if (request == null) {
return;
}
@@ -207,7 +207,7 @@ public abstract class BaseOpenInBrowserAction extends DumbAwareAction {
@Override
public void consume(Url url) {
ApplicationManager.getApplication().saveAll();
UrlOpener.launchBrowser(url.toExternalForm(), browser);
UrlOpener.launchBrowser(url.toExternalForm(), browser, request.getProject());
}
});
}
@@ -15,15 +15,20 @@
*/
package com.intellij.ide.browsers.impl;
import com.intellij.concurrency.JobScheduler;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.util.ExecUtil;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.browsers.BrowserSettings;
import com.intellij.ide.browsers.BrowserSpecificSettings;
import com.intellij.ide.browsers.UrlOpener;
import com.intellij.ide.browsers.WebBrowser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
@@ -35,74 +40,118 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class DefaultUrlOpener extends UrlOpener {
private static final Logger LOG = Logger.getInstance(DefaultUrlOpener.class);
@Override
public boolean openUrl(@NotNull WebBrowser browser, @NotNull String url) {
return launchBrowser(browser, url, false);
public boolean openUrl(@NotNull WebBrowser browser, @NotNull String url, @Nullable Project project) {
return launchBrowser(browser, url, false, project);
}
public static boolean launchBrowser(@NotNull final WebBrowser browser,
@Nullable String url,
boolean newWindowIfPossible,
@Nullable final Project project,
@NotNull String... additionalParameters) {
final String browserPath = browser.getPath();
if (StringUtil.isEmpty(browserPath)) {
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
Messages.showErrorDialog(browser.getBrowserNotFoundMessage(), IdeBundle.message("title.browser.not.found"));
Messages.showErrorDialog(project, browser.getBrowserNotFoundMessage(), IdeBundle.message("title.browser.not.found"));
}
});
return false;
}
return doLaunchBrowser(browserPath, browser.getSpecificSettings(), url, newWindowIfPossible, additionalParameters);
return doLaunchBrowser(browserPath, browser.getSpecificSettings(), url, newWindowIfPossible, project, browser, additionalParameters);
}
private static boolean doLaunchBrowser(final String browserPath,
@Nullable BrowserSpecificSettings browserSpecificSettings,
final String url,
final boolean newWindowIfPossible,
@Nullable final Project project,
@NotNull final WebBrowser browser,
final String[] additionalParameters) {
List<String> command = BrowserUtil.getOpenBrowserCommand(browserPath, newWindowIfPossible);
GeneralCommandLine commandLine = new GeneralCommandLine(BrowserUtil.getOpenBrowserCommand(browserPath, newWindowIfPossible));
if (url != null) {
command.add(url);
commandLine.addParameter(url);
}
addArgs(command, browserSpecificSettings, additionalParameters);
addArgs(commandLine, browserSpecificSettings, additionalParameters);
try {
new GeneralCommandLine(command).createProcess();
final Process process = commandLine.createProcess();
if (isOpenCommandUsed(commandLine)) {
final Future<?> future = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
try {
if (process.waitFor() == 1) {
showError(ExecUtil.readFirstLine(process.getErrorStream(), null), browser, project);
}
}
catch (InterruptedException ignored) {
}
}
});
// 30 seconds is enough to start
JobScheduler.getScheduler().schedule(new Runnable() {
@Override
public void run() {
future.cancel(true);
}
}, 30, TimeUnit.MILLISECONDS);
}
return true;
}
catch (final ExecutionException e) {
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
Messages.showErrorDialog(e.getMessage(), XmlBundle.message("browser.error"));
}
});
catch (ExecutionException e) {
showError(e.getMessage(), browser, project);
return false;
}
}
private static void addArgs(List<String> command, @Nullable BrowserSpecificSettings settings, String[] additional) {
private static void showError(@Nullable final String error, @Nullable final WebBrowser browser, @Nullable final Project project) {
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
if (Messages.showYesNoDialog(StringUtil.notNullize(error, "Unknown error"), XmlBundle.message("browser.error"), Messages.OK_BUTTON, "Fix\u2026", null) == Messages.NO) {
final BrowserSettings browserSettings = new BrowserSettings();
ShowSettingsUtil.getInstance().editConfigurable(project, browserSettings, browser == null ? null : new Runnable() {
@Override
public void run() {
browserSettings.selectBrowser(browser);
}
});
}
}
});
}
private static void addArgs(@NotNull GeneralCommandLine command, @Nullable BrowserSpecificSettings settings, @NotNull String[] additional) {
List<String> specific = settings == null ? Collections.<String>emptyList() : settings.getAdditionalParameters();
if (specific.size() + additional.length > 0) {
if (SystemInfo.isMac && ExecUtil.getOpenCommandPath().equals(command.get(0))) {
if (isOpenCommandUsed(command)) {
if (BrowserUtil.isOpenCommandSupportArgs()) {
command.add("--args");
command.addParameter("--args");
}
else {
LOG.warn("'open' command doesn't allow to pass command line arguments so they will be ignored: " +
StringUtil.join(specific, ", ") + " " + Arrays.toString(additional));
return;
}
}
command.addAll(specific);
Collections.addAll(command, additional);
command.addParameters(specific);
command.addParameters(additional);
}
}
private static boolean isOpenCommandUsed(@NotNull GeneralCommandLine command) {
return SystemInfo.isMac && ExecUtil.getOpenCommandPath().equals(command.getExePath());
}
}