diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java index 082468b77c69..00c20735da1b 100644 --- a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java +++ b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java @@ -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; + } } /** diff --git a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java index 94f21fe672d6..16a250b98024 100644 --- a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java +++ b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java @@ -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 getOpenBrowserCommand(@NonNls @NotNull String browserPathOrName, boolean newWindowIfPossible) { if (new File(browserPathOrName).isFile()) { - return newSmartList(browserPathOrName); + return Collections.singletonList(browserPathOrName); } else if (SystemInfo.isMac) { List 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); } } diff --git a/platform/platform-api/src/com/intellij/openapi/options/ShowSettingsUtil.java b/platform/platform-api/src/com/intellij/openapi/options/ShowSettingsUtil.java index a5ac41297c21..aa6d9618482a 100644 --- a/platform/platform-api/src/com/intellij/openapi/options/ShowSettingsUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/options/ShowSettingsUtil.java @@ -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); diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java index 54cec25ae307..23f49f699b7f 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java @@ -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 implements ElementProducer { return model.isModified(oldItems); } + public void selectItem(@NotNull final T item) { + table.clearSelection(); + + final Ref ref; + if (model.modifiedToOriginal.isEmpty()) { + ref = null; + } + else { + ref = Ref.create(); + model.modifiedToOriginal.forEachEntry(new TObjectObjectProcedure() { + @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 apply() { return model.apply(); diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java b/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java index f6db37f4869e..2fb773852948 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowserSettings.java @@ -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); + } } diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java index 744ada576515..97fae1571977 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsPanel.java @@ -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 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); + } + } } \ No newline at end of file diff --git a/xml/impl/src/com/intellij/ide/browsers/JavaScriptDebuggerStarter.java b/xml/impl/src/com/intellij/ide/browsers/JavaScriptDebuggerStarter.java index 85b5c33a98fe..ff5182abd92f 100644 --- a/xml/impl/src/com/intellij/ide/browsers/JavaScriptDebuggerStarter.java +++ b/xml/impl/src/com/intellij/ide/browsers/JavaScriptDebuggerStarter.java @@ -48,7 +48,7 @@ public interface JavaScriptDebuggerStarter { @Nullable WebBrowser browser, boolean startDebugger) { if (!startDebugger || !start(runConfiguration, url)) { - UrlOpener.launchBrowser(url, browser); + UrlOpener.launchBrowser(url, browser, runConfiguration.getProject()); } } } diff --git a/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java b/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java index 3c94bd202a7c..70cacb054de6 100644 --- a/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java +++ b/xml/impl/src/com/intellij/ide/browsers/OpenUrlHyperlinkInfo.java @@ -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); } } diff --git a/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java index 19226d817fff..16250913d306 100644 --- a/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java +++ b/xml/impl/src/com/intellij/ide/browsers/UrlOpener.java @@ -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); } + diff --git a/xml/impl/src/com/intellij/ide/browsers/actions/BaseOpenInBrowserAction.java b/xml/impl/src/com/intellij/ide/browsers/actions/BaseOpenInBrowserAction.java index 5923cbe1f9c4..8ab0c13b5d2d 100644 --- a/xml/impl/src/com/intellij/ide/browsers/actions/BaseOpenInBrowserAction.java +++ b/xml/impl/src/com/intellij/ide/browsers/actions/BaseOpenInBrowserAction.java @@ -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()); } }); } diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java index e50c3794935c..c9c1eb98e1a6 100644 --- a/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/DefaultUrlOpener.java @@ -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 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 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 specific = settings == null ? Collections.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()); + } }