From 7364cc3b72dee48ed032cd6379c97f08602bfd3b Mon Sep 17 00:00:00 2001 From: Vassiliy Kudryashov Date: Mon, 1 Oct 2012 23:16:12 +0400 Subject: [PATCH] IDEA-89461 Open in browser: popup buttons are drawn with artifacts --- .../intellij/ide/BrowserSettingsProvider.java | 2 + .../openapi/actionSystem/ActionGroupUtil.java | 45 +++-- .../intellij/ide/BrowserSettingsPanel.java | 15 ++ .../actionSystem/impl/ActionToolbarImpl.java | 23 +-- .../openapi/editor/impl/ContextMenuImpl.java | 158 ++++++------------ .../src/messages/XmlBundle.properties | 1 + .../openapi/util/io/WindowsRegistryUtil.java | 136 +++++++++++++++ .../browsers/BrowserSettingsProviderImpl.java | 6 + .../ide/browsers/BrowsersConfiguration.java | 56 ++++++- .../ide/browsers/WebBrowsersPanel.java | 48 +++++- 10 files changed, 353 insertions(+), 137 deletions(-) create mode 100644 platform/util/src/com/intellij/openapi/util/io/WindowsRegistryUtil.java diff --git a/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java b/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java index d67d4022f4a5..01f628bb0e4f 100644 --- a/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java +++ b/platform/platform-api/src/com/intellij/ide/BrowserSettingsProvider.java @@ -23,4 +23,6 @@ import com.intellij.openapi.options.UnnamedConfigurable; public abstract class BrowserSettingsProvider implements UnnamedConfigurable { public void disposeUIResources() { } + + public void applySettingsFromWindowsRegistry() {} } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionGroupUtil.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionGroupUtil.java index bc5ab580fa25..967eb4f7c82c 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionGroupUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionGroupUtil.java @@ -17,43 +17,60 @@ package com.intellij.openapi.actionSystem; import com.intellij.openapi.actionSystem.ex.ActionUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class ActionGroupUtil { private static Presentation getPresentation(AnAction action, Map action2presentation) { Presentation presentation = action2presentation.get(action); if (presentation == null) { - presentation = (Presentation)action.getTemplatePresentation().clone(); + presentation = action.getTemplatePresentation().clone(); action2presentation.put(action, presentation); } return presentation; } - public static boolean isGroupEmpty(ActionGroup actionGroup, AnActionEvent e) { - return isGroupEmpty(actionGroup, e, new HashMap()); + public static boolean isGroupEmpty(@NotNull ActionGroup actionGroup, @NotNull AnActionEvent e) { + return getEnabledChildren(actionGroup, e, new HashMap()).isEmpty(); } - private static boolean isGroupEmpty(ActionGroup actionGroup, AnActionEvent e, Map action2presentation) { + @Nullable + public static AnAction getSingleActiveAction(@NotNull ActionGroup actionGroup, @NotNull AnActionEvent e) { + List children = getEnabledChildren(actionGroup, e, new HashMap()); + if (children.size() == 1) { + return children.get(0); + } + return null; + } + + private static List getEnabledChildren(@NotNull ActionGroup actionGroup, + @NotNull AnActionEvent e, + @NotNull Map action2presentation) { + List result = new ArrayList(); AnAction[] actions = actionGroup.getChildren(e); for (AnAction action : actions) { - if (action instanceof Separator) { - continue; + if (action instanceof ActionGroup) { + if (isActionEnabledAndVisible(e, action2presentation, action)) { + result.addAll(getEnabledChildren((ActionGroup)action, e, action2presentation)); + } } - else if (action instanceof ActionGroup) { - if (isActionEnabledAndVisible(e, action2presentation, action) && !isGroupEmpty((ActionGroup)action, e, action2presentation)) { - return false; + else if (!(action instanceof Separator)) { + if (isActionEnabledAndVisible(e, action2presentation, action)) { + result.add(action); } - } else { - if(isActionEnabledAndVisible(e, action2presentation, action)) return false; } } - return true; + return result; } - private static boolean isActionEnabledAndVisible(final AnActionEvent e, final Map action2presentation, - final AnAction action) { + private static boolean isActionEnabledAndVisible(@NotNull final AnActionEvent e, + @NotNull final Map action2presentation, + @NotNull final AnAction action) { Presentation presentation = getPresentation(action, action2presentation); AnActionEvent event = new AnActionEvent(e.getInputEvent(), e.getDataContext(), diff --git a/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java b/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java index ed54f3e591cd..54a77de5aa90 100644 --- a/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/BrowserSettingsPanel.java @@ -111,6 +111,21 @@ public class BrowserSettingsPanel extends JPanel { for (BrowserSettingsProvider settingsProvider : mySettingsProviders) { outerPanel.add(settingsProvider.createComponent()); } + if (SystemInfo.isWindows) { + JPanel wrapperPanel = new JPanel(new BorderLayout()); + JButton registryButton = new JButton("Retrieve settings from Windows registry"); + registryButton.setMnemonic('W'); + registryButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + for (BrowserSettingsProvider settingsProvider : mySettingsProviders) { + settingsProvider.applySettingsFromWindowsRegistry(); + } + } + }); + wrapperPanel.add(registryButton, BorderLayout.EAST); + outerPanel.add(wrapperPanel); + } add(outerPanel, BorderLayout.NORTH); } diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java index cc6189ef1e8e..ae00562d162d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java @@ -339,13 +339,18 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { } } + private Dimension getChildPreferredSize(int index) { + Component component = getComponent(index); + return component.isVisible() ? component.getPreferredSize() : new Dimension(); + } + /** * @return maximum button width */ private int getMaxButtonWidth() { int width = 0; for (int i = 0; i < getComponentCount(); i++) { - final Dimension dimension = getComponent(i).getPreferredSize(); + final Dimension dimension = getChildPreferredSize(i); width = Math.max(width, dimension.width); } return width; @@ -357,7 +362,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { public int getMaxButtonHeight() { int height = 0; for (int i = 0; i < getComponentCount(); i++) { - final Dimension dimension = getComponent(i).getPreferredSize(); + final Dimension dimension = getChildPreferredSize(i); height = Math.max(height, dimension.height); } return height; @@ -400,8 +405,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { int xOffset = insets.left; final int yOffset = insets.top; for (int i = 0; i < componentCount; i++) { - final Component component = getComponent(i); - final Dimension d = component.getPreferredSize(); + final Dimension d = getChildPreferredSize(i); final Rectangle r = bounds.get(i); r.setBounds(xOffset, yOffset + (maxHeight - d.height) / 2, d.width, d.height); xOffset += d.width; @@ -412,8 +416,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { final int xOffset = insets.left; int yOffset = insets.top; for (int i = 0; i < componentCount; i++) { - final Component component = getComponent(i); - final Dimension d = component.getPreferredSize(); + final Dimension d = getChildPreferredSize(i); final Rectangle r = bounds.get(i); r.setBounds(xOffset + (maxWidth - d.width) / 2, yOffset, d.width, d.height); yOffset += d.height; @@ -445,7 +448,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { final Component eachComp = getComponent(i); final boolean isLast = i == componentCount - 1; - final Rectangle eachBound = new Rectangle(eachComp.getPreferredSize()); + final Rectangle eachBound = new Rectangle(getChildPreferredSize(i)); maxHeight = Math.max(eachBound.height, maxHeight); if (!full) { @@ -500,7 +503,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { int eachX = insets.left; int eachY = insets.top; for (int i = 0; i < componentCount; i++) { - final Rectangle eachBound = new Rectangle(getComponent(i).getPreferredSize()); + final Rectangle eachBound = new Rectangle(getChildPreferredSize(i)); if (!full) { boolean outside; if (i < componentCount - 1) { @@ -604,7 +607,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { int rowHeight = 0; final Dimension[] dims = new Dimension[componentCount]; // we will use this dimesions later for (int i = 0; i < componentCount; i++) { - dims[i] = getComponent(i).getPreferredSize(); + dims[i] = getChildPreferredSize(i); final int height = dims[i].height; rowHeight = Math.max(rowHeight, height); } @@ -632,7 +635,7 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar { int rowWidth = 0; final Dimension[] dims = new Dimension[componentCount]; // we will use this dimesions later for (int i = 0; i < componentCount; i++) { - dims[i] = getComponent(i).getPreferredSize(); + dims[i] = getChildPreferredSize(i); final int width = dims[i].width; rowWidth = Math.max(rowWidth, width); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java index 328f925a6cd7..6674322c21e9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java @@ -40,7 +40,6 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.image.BufferedImage; /** * @author spleaner @@ -56,9 +55,9 @@ public class ContextMenuImpl extends JPanel implements Disposable { private int myCurrentOpacity; private Timer myTimer; private EditorImpl myEditor; - private ContextMenuPanel myContextMenuPanel; private boolean myDisposed; private final JLayeredPane myLayeredPane; + private ActionToolbar myActionToolbar; public ContextMenuImpl(JLayeredPane layeredPane, @NotNull final JScrollPane container, @NotNull final EditorImpl editor) { setLayout(new BorderLayout(0, 0)); @@ -118,6 +117,9 @@ public class ContextMenuImpl extends JPanel implements Disposable { if (myShow != show) { myShow = show; + if (myShow && myActionToolbar != null) { + myActionToolbar.updateActionsImmediately(); + } restartTimer(); } } @@ -134,7 +136,7 @@ public class ContextMenuImpl extends JPanel implements Disposable { if (myTimer != null && myTimer.isRunning()) myTimer.stop(); - myTimer = UIUtil.createNamedTimer("Restart context menu now",50, new ActionListener() { + myTimer = UIUtil.createNamedTimer("Restart context menu now", 50, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (myShow) { @@ -151,7 +153,7 @@ public class ContextMenuImpl extends JPanel implements Disposable { } myCurrentOpacity += 20; - if (myCurrentOpacity > 100) { + if (myCurrentOpacity >= 100) { myCurrentOpacity = 100; myVisible = true; myTimer.stop(); @@ -160,18 +162,19 @@ public class ContextMenuImpl extends JPanel implements Disposable { } repaint(); - } else { + } + else { if (!myVisible) { if (myTimer != null && myTimer.isRunning()) myTimer.stop(); return; } myCurrentOpacity -= 20; - if (myCurrentOpacity < 0) { + if (myCurrentOpacity <= 0) { myCurrentOpacity = 0; myVisible = false; myLayeredPane.remove(ContextMenuImpl.this); - myLayeredPane.revalidate(); + myLayeredPane.repaint(); } repaint(); @@ -197,7 +200,6 @@ public class ContextMenuImpl extends JPanel implements Disposable { myTimer.stop(); myTimer = null; } - } public static boolean mayShowToolbar(@Nullable final Document document) { @@ -214,7 +216,7 @@ public class ContextMenuImpl extends JPanel implements Disposable { myTimer.stop(); } - myTimer = UIUtil.createNamedTimer("Hide context menu",1500, new ActionListener() { + myTimer = UIUtil.createNamedTimer("Hide context menu", 1500, new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { if (myDisposed) return; @@ -226,7 +228,8 @@ public class ContextMenuImpl extends JPanel implements Disposable { SwingUtilities.convertPointFromScreen(location, myComponent); if (!myComponent.getBounds().contains(location)) { toggleContextToolbar(false); - } else { + } + else { scheduleHide(); } } @@ -243,25 +246,6 @@ public class ContextMenuImpl extends JPanel implements Disposable { new ActionToolbarImpl(ActionPlaces.CONTEXT_TOOLBAR, group, true, DataManager.getInstance(), ActionManagerEx.getInstanceEx(), KeymapManagerEx.getInstanceEx()) { - @Override - public void paint(final Graphics g) { - if (myContextMenuPanel.isPaintChildren()) { - paintChildren(g); - } - } - - @Override - protected void paintChildren(final Graphics g) { - if (myContextMenuPanel.isPaintChildren()) { - super.paintChildren(g); - } - } - - @Override - public boolean isOpaque() { - return myContextMenuPanel.isPaintChildren(); - } - @Override public ActionButton createToolbarButton(final AnAction action, final ActionButtonLook look, @@ -271,27 +255,9 @@ public class ContextMenuImpl extends JPanel implements Disposable { final ActionButton result = new ActionButton(action, presentation, place, minimumSize) { @Override public void paintComponent(final Graphics g) { - if (myContextMenuPanel.isPaintChildren()) { - final ActionButtonLook look = getButtonLook(); - look.paintIcon(g, this, getIcon()); - } - - if (myContextMenuPanel.isShown() && getPopState() == ActionButton.POPPED) { - final ActionButtonLook look = getButtonLook(); - look.paintBackground(g, this); - look.paintIcon(g, this, getIcon()); - } - } - - @Override - public boolean isOpaque() { - return myContextMenuPanel.isPaintChildren() || getPopState() == ActionButton.POPPED; - } - - @Override - public void paint(final Graphics g) { - final Graphics2D g2 = (Graphics2D)g; - paintComponent(g2); + final ActionButtonLook look = getButtonLook(); + look.paintBackground(g, this); + look.paintIcon(g, this, getIcon()); } }; @@ -301,26 +267,25 @@ public class ContextMenuImpl extends JPanel implements Disposable { }; actionToolbar.setTargetComponent(myEditor.getContentComponent()); - return actionToolbar; } private JComponent createComponent() { - final ActionToolbar toolbar = createToolbar(myActionGroup); - toolbar.setMinimumButtonSize(new Dimension(20, 20)); - toolbar.setReservePlaceAutoPopupIcon(false); + myActionToolbar = createToolbar(myActionGroup); + myActionToolbar.setMinimumButtonSize(new Dimension(20, 20)); + myActionToolbar.setReservePlaceAutoPopupIcon(false); - myContextMenuPanel = new ContextMenuPanel(this); - myContextMenuPanel.setLayout(new BorderLayout(0, 0)); - myContextMenuPanel.add(toolbar.getComponent()); + ContextMenuPanel contextMenuPanel = new ContextMenuPanel(this); + contextMenuPanel.setLayout(new BorderLayout(0, 0)); + JComponent toolbarComponent = myActionToolbar.getComponent(); + toolbarComponent.setOpaque(false); + contextMenuPanel.add(toolbarComponent); - return myContextMenuPanel; + return contextMenuPanel; } private static class ContextMenuPanel extends JPanel { private final ContextMenuImpl myContextMenu; - private BufferedImage myBufferedImage; - private boolean myPaintChildren = false; private ContextMenuPanel(final ContextMenuImpl contextMenu) { myContextMenu = contextMenu; @@ -328,64 +293,37 @@ public class ContextMenuImpl extends JPanel implements Disposable { setOpaque(false); } - @Override - public void invalidate() { - super.invalidate(); - - myBufferedImage = null; - } - - @Override - public void revalidate() { - super.revalidate(); - - myBufferedImage = null; - } - @Override protected void paintChildren(final Graphics g) { - if (myPaintChildren) { - super.paintChildren(g); + Graphics2D graphics = (Graphics2D)g.create(); + try { + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, myContextMenu.myCurrentOpacity / 100.0f)); + super.paintChildren(graphics); + } + finally { + graphics.dispose(); } - } - - public boolean isPaintChildren() { - return myPaintChildren; } @Override - public void paint(final Graphics g) { - final Rectangle r = getBounds(); - if (myBufferedImage == null) { - myBufferedImage = new BufferedImage(r.width, r.height, BufferedImage.TYPE_INT_ARGB); - - final Graphics graphics = myBufferedImage.getGraphics(); - final Graphics2D g2d2 = (Graphics2D)graphics; - final Composite old = g2d2.getComposite(); - - g2d2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f)); - - g2d2.setColor(Color.GRAY); - g2d2.fillRoundRect(0, 0, r.width - 1, r.height - 1, 6, 6); - - g2d2.setComposite(old); - - myPaintChildren = true; - paintChildren(g2d2); - myPaintChildren = false; - } - - final Graphics2D g2 = (Graphics2D)g; - final Composite old = g2.getComposite(); - - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, myContextMenu.myCurrentOpacity / 100.0f)); - g2.drawImage(myBufferedImage, 0, 0, myBufferedImage.getWidth(null), myBufferedImage.getHeight(null), null); - - g2.setComposite(old); + public void paint(Graphics g) { + paintComponent(g); + super.paint(g); } - public boolean isShown() { - return myContextMenu.myCurrentOpacity == 100; + @Override + public void paintComponent(final Graphics g) { + Rectangle r = getBounds(); + Graphics2D graphics = (Graphics2D)g.create(); + try { + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, myContextMenu.myCurrentOpacity / 500.0f)); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics.setColor(Color.GRAY); + graphics.fillRoundRect(0, 0, r.width - 1, r.height - 1, 6, 6); + } + finally { + graphics.dispose(); + } } } } diff --git a/platform/platform-resources-en/src/messages/XmlBundle.properties b/platform/platform-resources-en/src/messages/XmlBundle.properties index 00211cd8f9f8..ae8f03f7bfbb 100644 --- a/platform/platform-resources-en/src/messages/XmlBundle.properties +++ b/platform/platform-resources-en/src/messages/XmlBundle.properties @@ -175,6 +175,7 @@ xml.split.tag.intention.action=Split current tag tag.name.completion.hint=Press {0} to view tags from other namespaces tag.name.completion.display.name=Tag Name Completion open_in.list.popup.title=Preview file in... +open_in.list.prefix=Preview file in xml.inspections.unbound.prefix=Unbound XML namespace prefix html.add.table.column.after.action=Add a new column to the table after the current one diff --git a/platform/util/src/com/intellij/openapi/util/io/WindowsRegistryUtil.java b/platform/util/src/com/intellij/openapi/util/io/WindowsRegistryUtil.java new file mode 100644 index 000000000000..0edf17af0113 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/io/WindowsRegistryUtil.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util.io; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * User: Vassiliy.Kudryashov + */ +public class WindowsRegistryUtil { + private WindowsRegistryUtil() { + } + + @Nullable + private static String trimToValue(@Nullable StringBuilder output) { + if (output == null) { + return null; + } + int pos = output.lastIndexOf(" "); + int pos2 = output.lastIndexOf("\t"); + pos = Math.max(pos, pos2); + if (pos == -1) { + return null; + } + + output.delete(0, pos + 1); + String blackList = "\r\n \""; + int startPos = 0; + int endPos = output.length() - 1; + while (true) { + if (startPos >= endPos) { + return null; + } + if (blackList.indexOf(output.charAt(startPos)) != -1) { + startPos++; + } + else { + break; + } + } + while (true) { + if (blackList.indexOf(output.charAt(endPos)) != -1) { + endPos--; + } + else { + break; + } + } + return output.subSequence(startPos, endPos + 1).toString(); + } + + @NotNull + public static List readRegistryBranch(@NotNull String location) { + List result = new ArrayList(); + StringBuilder output = readRegistry("reg query \"" + location + "\" /s"); + if (output != null) { + for (int pos = output.indexOf(location); pos != -1; pos = output.indexOf(location, pos + location.length())) { + int pos2 = output.indexOf("\r\n", pos + location.length()); + if (pos2 <= pos + location.length()) { + continue; + } + String section = output.substring(pos + location.length() + 1, pos2); + if (!section.contains("\\")) { + result.add(section); + } + } + } + return result; + } + + @Nullable + public static String readRegistryDefault(@NotNull String location) { + return trimToValue(readRegistry("reg query \"" + location + "\" /ve")); + } + + @Nullable + public static String readRegistryValue(@NotNull String location, @NotNull String key) { + return trimToValue(readRegistry("reg query \"" + location + "\" /v " + key)); + } + + @Nullable + private static StringBuilder readRegistry(String command) { + try { + Process process = Runtime.getRuntime().exec(command); + StringBuilder output = null; + InputStream is = null; + ByteArrayOutputStream os = null; + try { + byte[] buffer = new byte[128]; + is = process.getInputStream(); + os = new ByteArrayOutputStream(); + for (int length = is.read(buffer); length > 0; length = is.read(buffer)) { + os.write(buffer, 0, length); + } + output = new StringBuilder(new String(os.toByteArray())); + } + catch (IOException ignored) { + + } + finally { + if (is != null) { + is.close(); + } + if (os != null) { + os.close(); + } + process.waitFor(); + } + + return output; + } + catch (Exception e) { + return null; + } + } +} diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java index c583f89b5428..e639095481a6 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowserSettingsProviderImpl.java @@ -35,6 +35,12 @@ public class BrowserSettingsProviderImpl extends BrowserSettingsProvider { myConfiguration = configuration; } + @Override + public void applySettingsFromWindowsRegistry() { + if (mySettingsPanel != null) + mySettingsPanel.applySettingsFromWindowsRegistry(); + } + public JComponent createComponent() { if (mySettingsPanel == null) { mySettingsPanel = new WebBrowsersPanel(myConfiguration); diff --git a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java index 7a5645488fe9..6ea712744ba0 100644 --- a/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java +++ b/xml/impl/src/com/intellij/ide/browsers/BrowsersConfiguration.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.WindowsRegistryUtil; import com.intellij.util.SystemProperties; import com.intellij.util.containers.HashMap; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; @@ -37,13 +38,14 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.ArrayList; +import java.util.EnumMap; import java.util.List; import java.util.Map; /** * @author spleaner */ -@State(name = "WebBrowsersConfiguration", storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/browsers.xml")}) +@State(name = "WebBrowsersConfiguration", storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/browsers.xml")}) public class BrowsersConfiguration implements PersistentStateComponent { public enum BrowserFamily { EXPLORER(XmlBundle.message("browsers.explorer"), "iexplore", null, null, AllIcons.Xml.Browsers.Explorer16), @@ -68,7 +70,11 @@ public class BrowsersConfiguration implements PersistentStateComponent private final String myMacPath; private final Icon myIcon; - BrowserFamily(final String name, @NonNls final String windowsPath, @NonNls final String linuxPath, @NonNls final String macPath, final Icon icon) { + BrowserFamily(final String name, + @NonNls final String windowsPath, + @NonNls final String linuxPath, + @NonNls final String macPath, + final Icon icon) { myName = name; myWindowsPath = windowsPath; myLinuxPath = linuxPath; @@ -237,4 +243,50 @@ public class BrowsersConfiguration implements PersistentStateComponent } return null; } + + /** + * Gets data from Windows registry, may take some time to run (up to ~300ms) + * + * @return Map[BrowserFamily -> "path to .exe"] + */ + @NotNull + public static EnumMap getWindowsBrowsersEXE() { + EnumMap map = new EnumMap(BrowserFamily.class); + if (SystemInfo.isWindows) { + List sections = WindowsRegistryUtil.readRegistryBranch("HKEY_LOCAL_MACHINE\\SOFTWARE\\Clients\\StartMenuInternet"); + for (String section : sections) { + BrowserFamily family = getFamily(section); + if (family == null) { + continue; //We ignore "unknown" browsers like Maxthon, RockMelt, SeaMonkey, Deepnet Explorer, Avant Browser etc. + } + String pathToExe = WindowsRegistryUtil.readRegistryDefault( + "HKLM\\SOFTWARE\\Clients\\StartMenuInternet\\" + section + "\\shell\\open\\command"); + if (pathToExe != null) { + map.put(family, pathToExe); + } + } + } + return map; + } + + @Nullable + private static BrowserFamily getFamily(String registryName) { + registryName = registryName.toLowerCase(); + if (registryName.contains("firefox")) { + return BrowserFamily.FIREFOX; + } + if (registryName.contains("iexplore")) { + return BrowserFamily.EXPLORER; + } + if (registryName.contains("opera")) { + return BrowserFamily.OPERA; + } + if (registryName.contains("safari")) { + return BrowserFamily.SAFARI; + } + if (registryName.contains("google")) { + return BrowserFamily.CHROME; + } + return null; + } } diff --git a/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java b/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java index b55881439222..e5f53e7f8268 100644 --- a/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java +++ b/xml/impl/src/com/intellij/ide/browsers/WebBrowsersPanel.java @@ -16,6 +16,7 @@ package com.intellij.ide.browsers; import com.intellij.ide.IdeBundle; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.ui.TextFieldWithBrowseButton; @@ -31,14 +32,17 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.EnumMap; import java.util.Map; +import java.util.concurrent.ExecutionException; /** * @author spleaner */ public class WebBrowsersPanel extends JPanel { private final JPanel mySettingsPanel; - private Map> myBrowserSettingsMap = new HashMap>(); + private Map> myBrowserSettingsMap = + new HashMap>(); private final BrowsersConfiguration myConfiguration; public WebBrowsersPanel(final BrowsersConfiguration configuration) { @@ -127,6 +131,48 @@ public class WebBrowsersPanel extends JPanel { } } + public void applySettingsFromWindowsRegistry() { + if (!SystemInfo.isWindows) { + return; + } + ApplicationManager.getApplication() + .executeOnPooledThread(new SwingWorker, Void>() { + @Override + protected EnumMap doInBackground() throws Exception { + return BrowsersConfiguration.getWindowsBrowsersEXE(); + } + + @Override + protected void done() { + EnumMap map = null; + try { + map = get(); + } + catch (InterruptedException ignored) { + } + catch (ExecutionException ignored) { + } + if (myBrowserSettingsMap == null) { + return;//we are disposed + } + if (map != null && !map.isEmpty()) { + for (BrowsersConfiguration.BrowserFamily family : BrowsersConfiguration.BrowserFamily.values()) { + Pair pair = myBrowserSettingsMap.get(family); + String pathToExe = map.get(family); + if (pathToExe != null) { + pair.first.setSelected(true); + pair.second.setText(pathToExe); + } + else { + pair.first.setSelected(false); + } + } + } + } + }); + } + + public void dispose() { myBrowserSettingsMap = null; }