sticky documentation popup [take 1]
authorAlexey Pegov <alexey.pegov@jetbrains.com>
Mon, 15 Feb 2010 14:59:41 +0000 (15 17:59 +0300)
committerAlexey Pegov <alexey.pegov@jetbrains.com>
Mon, 15 Feb 2010 14:59:41 +0000 (15 17:59 +0300)
16 files changed:
platform/icons/src/general/documentation.png [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java
platform/platform-api/src/com/intellij/openapi/ui/popup/ComponentPopupBuilder.java
platform/platform-api/src/com/intellij/openapi/wm/ToolWindowId.java
platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsListPanel.java
platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/ActionManagerEx.java
platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/wm/ex/WindowManagerEx.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/TestWindowManager.java
platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java
platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java
platform/platform-impl/src/com/intellij/ui/popup/ComponentPopupBuilderImpl.java
platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java
platform/platform-resources-en/src/messages/UIBundle.properties

diff --git a/platform/icons/src/general/documentation.png b/platform/icons/src/general/documentation.png
new file mode 100644 (file)
index 0000000..8c0df2e
Binary files /dev/null and b/platform/icons/src/general/documentation.png differ
dissimilarity index 88%
index eecfd73..bd47348 100644 (file)
-/*
- * Copyright 2000-2009 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.codeInsight.documentation;
-
-import com.intellij.codeInsight.CodeInsightBundle;
-import com.intellij.codeInsight.hint.ElementLocationUtil;
-import com.intellij.codeInsight.hint.HintManagerImpl;
-import com.intellij.codeInsight.hint.HintUtil;
-import com.intellij.ide.actions.ExternalJavaDocAction;
-import com.intellij.lang.documentation.DocumentationProvider;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.ui.popup.JBPopup;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.IconLoader;
-import com.intellij.openapi.wm.ex.WindowManagerEx;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.SmartPointerManager;
-import com.intellij.psi.SmartPsiElementPointer;
-import com.intellij.ui.EdgeBorder;
-import com.intellij.util.containers.HashMap;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import javax.swing.event.HyperlinkEvent;
-import javax.swing.event.HyperlinkListener;
-import javax.swing.text.View;
-import java.awt.*;
-import java.awt.event.*;
-import java.util.List;
-import java.util.Stack;
-
-public class DocumentationComponent extends JPanel implements Disposable{
-
-  private static final int MAX_WIDTH = 500;
-    private static final int MAX_HEIGHT = 300;
-    private static final int MIN_HEIGHT = 45;
-
-    private DocumentationManager myManager;
-    private SmartPsiElementPointer myElement;
-
-    private final Stack<Context> myBackStack = new Stack<Context>();
-    private final Stack<Context> myForwardStack = new Stack<Context>();
-    private final ActionToolbar myToolBar;
-    private boolean myIsEmpty;
-    private boolean myIsShown;
-    private final JLabel myElementLabel;
-
-    private static class Context {
-        final SmartPsiElementPointer element;
-        final String text;
-        final Rectangle viewRect;
-
-        public Context(SmartPsiElementPointer element, String text, Rectangle viewRect) {
-            this.element = element;
-            this.text = text;
-            this.viewRect = viewRect;
-        }
-    }
-
-    private final JScrollPane myScrollPane;
-    private final JEditorPane myEditorPane;
-    private String myText; // myEditorPane.getText() surprisingly crashes.., let's cache the text
-    private final JPanel myControlPanel;
-    private boolean myControlPanelVisible;
-    private final ExternalDocAction myExternalDocAction;
-
-    private JBPopup myHint;
-
-    private final HashMap<KeyStroke,ActionListener> myKeyboardActions = new HashMap<KeyStroke, ActionListener>(); // KeyStroke --> ActionListener
-
-    public boolean requestFocusInWindow() {
-        return myScrollPane.requestFocusInWindow();
-    }
-
-
-  public void requestFocus() {
-    myScrollPane.requestFocus();
-  }
-
-  public DocumentationComponent(final DocumentationManager manager) {
-      myManager = manager;
-      myIsEmpty = true;
-      myIsShown = false;
-
-      myEditorPane = new JEditorPane(UIUtil.HTML_MIME, "") {
-          public Dimension getPreferredScrollableViewportSize() {
-              if (getWidth() == 0 || getHeight() == 0) {
-                  setSize(MAX_WIDTH, MAX_HEIGHT);
-              }
-              Insets ins = myEditorPane.getInsets();
-              View rootView = myEditorPane.getUI().getRootView(myEditorPane);
-              rootView.setSize(MAX_WIDTH, MAX_HEIGHT);  // Necessary! Without this line, size will not increase then you go from small page to bigger one
-              int prefHeight = (int) rootView.getPreferredSpan(View.Y_AXIS);
-              prefHeight += ins.bottom + ins.top + myScrollPane.getHorizontalScrollBar().getMaximumSize().height;
-              return new Dimension(MAX_WIDTH, Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, prefHeight)));
-          }
-
-          {
-              enableEvents(KeyEvent.KEY_EVENT_MASK);
-          }
-
-          protected void processKeyEvent(KeyEvent e) {
-              KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
-              ActionListener listener = myKeyboardActions.get(keyStroke);
-              if (listener != null) {
-                  listener.actionPerformed(new ActionEvent(DocumentationComponent.this, 0, ""));
-                  e.consume();
-                  return;
-              }
-              super.processKeyEvent(e);
-          }
-      };
-      myText = "";
-      myEditorPane.setEditable(false);
-      myEditorPane.setBackground(HintUtil.INFORMATION_COLOR);
-
-      myScrollPane = new JScrollPane(myEditorPane);
-      myScrollPane.setBorder(null);
-
-      final MouseAdapter mouseAdapter = new MouseAdapter() {
-        public void mousePressed(MouseEvent e) {
-          myManager.requestFocus();
-        }
-      };
-      myEditorPane.addMouseListener(mouseAdapter);
-      Disposer.register(this, new Disposable() {
-        public void dispose() {
-          myEditorPane.removeMouseListener(mouseAdapter);
-        }
-      });
-
-      final FocusAdapter focusAdapter = new FocusAdapter() {
-        public void focusLost(FocusEvent e) {
-          Component previouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(manager.getProject(getElement()));
-
-          if (!(previouslyFocused == myEditorPane)) {
-            myHint.cancel();
-          }
-        }
-      };
-      myEditorPane.addFocusListener(focusAdapter);
-
-      Disposer.register(this, new Disposable() {
-        public void dispose() {
-          myEditorPane.removeFocusListener(focusAdapter);
-        }
-      });
-
-      setLayout(new BorderLayout());
-      add(myScrollPane, BorderLayout.CENTER);
-      myScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 2));
-
-      DefaultActionGroup group = new DefaultActionGroup();
-      group.add(new BackAction());
-      group.add(new ForwardAction());
-      group.add(myExternalDocAction = new ExternalDocAction());
-      myToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.JAVADOC_TOOLBAR, group, true);
-
-      myControlPanel = new JPanel();
-      myControlPanel.setLayout(new BorderLayout());
-      myControlPanel.setBorder(new EdgeBorder(EdgeBorder.EDGE_BOTTOM));
-      JPanel dummyPanel = new JPanel();
-
-      myElementLabel = new JLabel();
-
-      dummyPanel.setLayout(new BorderLayout());
-      dummyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
-
-      dummyPanel.add(myElementLabel, BorderLayout.EAST);
-
-      myControlPanel.add(myToolBar.getComponent(), BorderLayout.WEST);
-      myControlPanel.add(dummyPanel, BorderLayout.CENTER);
-      myControlPanelVisible = false;
-
-      final HyperlinkListener hyperlinkListener = new HyperlinkListener() {
-        public void hyperlinkUpdate(HyperlinkEvent e) {
-          HyperlinkEvent.EventType type = e.getEventType();
-          if (type == HyperlinkEvent.EventType.ACTIVATED) {
-            manager.navigateByLink(DocumentationComponent.this, e.getDescription());
-          }
-          else if (type == HyperlinkEvent.EventType.ENTERED) {
-            myEditorPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
-          }
-          else if (type == HyperlinkEvent.EventType.EXITED) {
-            myEditorPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
-          }
-        }
-      };
-      myEditorPane.addHyperlinkListener(hyperlinkListener);
-      Disposer.register(this, new Disposable() {
-        public void dispose() {
-          myEditorPane.removeHyperlinkListener(hyperlinkListener);
-        }
-      });
-
-      registerActions();
-
-      updateControlState();
-  }
-
-    public synchronized boolean isEmpty() {
-        return myIsEmpty;
-    }
-
-    public synchronized void startWait() {
-        myIsEmpty = true;
-    }
-
-    private void setControlPanelVisible(boolean visible) {
-        if (visible == myControlPanelVisible) return;
-        if (visible) {
-          add(myControlPanel, BorderLayout.NORTH);
-        } else {
-          remove(myControlPanel);
-        }
-        myControlPanelVisible = visible;
-    }
-
-    public void setHint(JBPopup hint) {
-        myHint = hint;
-    }
-
-    public JComponent getComponent() {
-        return myEditorPane;
-    }
-
-    @Nullable
-    public PsiElement getElement() {
-        return myElement != null ? myElement.getElement() : null;
-    }
-
-    public void setText(String text) {
-        setText(text, false);
-    }
-
-    public void setText(String text, boolean clean) {
-        if (clean && myElement != null) {
-          myBackStack.push(saveContext());
-          myForwardStack.clear();
-        }
-        updateControlState();
-        setDataInternal(myElement, text, new Rectangle(0, 0), !clean);
-        if (clean) {
-            myIsEmpty = false;
-        }
-    }
-
-    public void setData(PsiElement _element, String text) {
-        if (myElement != null) {
-            myBackStack.push(saveContext());
-            myForwardStack.clear();
-        }
-
-        final SmartPsiElementPointer element = _element != null && _element.isValid() ?
-          SmartPointerManager.getInstance(_element.getProject()).createSmartPsiElementPointer(_element):
-          null;
-
-        if (element != null) {
-            myElement = element;
-        }
-
-        myIsEmpty = false;
-        updateControlState();
-        setDataInternal(element, text, new Rectangle(0, 0));
-    }
-
-    private void setDataInternal(SmartPsiElementPointer element, String text, final Rectangle viewRect) {
-        setDataInternal(element, text, viewRect, false);
-    }
-
-    private void setDataInternal(SmartPsiElementPointer element, String text, final Rectangle viewRect, boolean skip) {
-        boolean justShown = false;
-
-        myElement = element;
-
-        if (!myIsShown && myHint != null) {
-            myEditorPane.setText(text);
-            myManager.showHint(myHint);
-            myIsShown = justShown = true;
-        }
-
-        if (!justShown) {
-            myEditorPane.setText(text);
-        }
-
-        if (!skip) {
-            myText = text;
-        }
-
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                myEditorPane.scrollRectToVisible(viewRect);
-            }
-        });
-    }
-
-    private void goBack() {
-        if (myBackStack.isEmpty()) return;
-        Context context = myBackStack.pop();
-        myForwardStack.push(saveContext());
-        restoreContext(context);
-        updateControlState();
-    }
-
-    private void goForward() {
-        if (myForwardStack.isEmpty()) return;
-        Context context = myForwardStack.pop();
-        myBackStack.push(saveContext());
-        restoreContext(context);
-        updateControlState();
-    }
-
-    private Context saveContext() {
-        Rectangle rect = myScrollPane.getViewport().getViewRect();
-        return new Context(myElement, myText, rect);
-    }
-
-    private void restoreContext(Context context) {
-      setDataInternal(context.element, context.text, context.viewRect);
-    }
-
-  private void updateControlState() {
-        ElementLocationUtil.customizeElementLabel(myElement != null ? myElement.getElement():null, myElementLabel);
-        myToolBar.updateActionsImmediately(); // update faster
-        setControlPanelVisible(true);//(!myBackStack.isEmpty() || !myForwardStack.isEmpty());
-    }
-
-    private class BackAction extends AnAction implements HintManagerImpl.ActionToIgnore {
-        public BackAction() {
-            super(CodeInsightBundle.message("javadoc.action.back"), null, IconLoader.getIcon("/actions/back.png"));
-        }
-
-        public void actionPerformed(AnActionEvent e) {
-            goBack();
-        }
-
-        public void update(AnActionEvent e) {
-            Presentation presentation = e.getPresentation();
-            presentation.setEnabled(!myBackStack.isEmpty());
-        }
-    }
-
-    private class ForwardAction extends AnAction implements HintManagerImpl.ActionToIgnore {
-        public ForwardAction() {
-            super(CodeInsightBundle.message("javadoc.action.forward"), null, IconLoader.getIcon("/actions/forward.png"));
-        }
-
-        public void actionPerformed(AnActionEvent e) {
-            goForward();
-        }
-
-        public void update(AnActionEvent e) {
-            Presentation presentation = e.getPresentation();
-            presentation.setEnabled(!myForwardStack.isEmpty());
-        }
-    }
-
-    private class ExternalDocAction extends AnAction implements HintManagerImpl.ActionToIgnore {
-        public ExternalDocAction() {
-            super(CodeInsightBundle.message("javadoc.action.view.external"), null, IconLoader.getIcon("/actions/browser-externalJavaDoc.png"));
-            registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EXTERNAL_JAVADOC).getShortcutSet(), null);
-        }
-
-        public void actionPerformed(AnActionEvent e) {
-            if (myElement != null) {
-              final PsiElement element = myElement.getElement();
-              final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element);
-              final List<String> urls = provider.getUrlFor(element, DocumentationManager.getOriginalElement(element));
-              assert urls != null;
-              assert !urls.isEmpty();
-              ExternalJavaDocAction.showExternalJavadoc(urls);
-            }
-        }
-
-        public void update(AnActionEvent e) {
-          final Presentation presentation = e.getPresentation();
-          presentation.setEnabled(false);
-          if (myElement != null) {
-            final PsiElement element = myElement.getElement();
-            final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element);
-            final List<String> urls = provider.getUrlFor(element, DocumentationManager.getOriginalElement(element));
-            presentation.setEnabled(element != null && urls!= null && !urls.isEmpty());
-          }
-        }
-    }
-
-    private void registerActions() {
-        myExternalDocAction.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EXTERNAL_JAVADOC).getShortcutSet(),
-                                                      myEditorPane);
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      int value = scrollBar.getValue() - scrollBar.getUnitIncrement(-1);
-                                      value = Math.max(value, 0);
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      int value = scrollBar.getValue() + scrollBar.getUnitIncrement(+1);
-                                      value = Math.min(value, scrollBar.getMaximum());
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
-                                      int value = scrollBar.getValue() - scrollBar.getUnitIncrement(-1);
-                                      value = Math.max(value, 0);
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
-                                      int value = scrollBar.getValue() + scrollBar.getUnitIncrement(+1);
-                                      value = Math.min(value, scrollBar.getMaximum());
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      int value = scrollBar.getValue() - scrollBar.getBlockIncrement(-1);
-                                      value = Math.max(value, 0);
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      int value = scrollBar.getValue() + scrollBar.getBlockIncrement(+1);
-                                      value = Math.min(value, scrollBar.getMaximum());
-                                      scrollBar.setValue(value);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
-                                      scrollBar.setValue(0);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
-                                      scrollBar.setValue(scrollBar.getMaximum());
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, KeyEvent.CTRL_MASK),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      scrollBar.setValue(0);
-                                  }
-                              });
-
-        myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK),
-                              new ActionListener() {
-                                  public void actionPerformed(ActionEvent e) {
-                                      JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
-                                      scrollBar.setValue(scrollBar.getMaximum());
-                                  }
-                              });
-    }
-
-    public String getText() {
-        return myText;
-    }
-  
-    public void dispose() {
-      myBackStack.clear();
-      myForwardStack.clear();
-      myKeyboardActions.clear();
-      myElement = null;
-      myManager = null;
-      myHint = null;
-    }
-
-}
+/*
+ * Copyright 2000-2009 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.codeInsight.documentation;
+
+import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.codeInsight.hint.ElementLocationUtil;
+import com.intellij.codeInsight.hint.HintManagerImpl;
+import com.intellij.codeInsight.hint.HintUtil;
+import com.intellij.ide.actions.ExternalJavaDocAction;
+import com.intellij.lang.documentation.DocumentationProvider;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.wm.ex.WindowManagerEx;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.SmartPointerManager;
+import com.intellij.psi.SmartPsiElementPointer;
+import com.intellij.ui.EdgeBorder;
+import com.intellij.util.containers.HashMap;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.View;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.List;
+import java.util.Stack;
+
+public class DocumentationComponent extends JPanel implements Disposable {
+
+  private static final int MAX_WIDTH = 500;
+  private static final int MAX_HEIGHT = 300;
+  private static final int MIN_HEIGHT = 45;
+
+  private DocumentationManager myManager;
+  private SmartPsiElementPointer myElement;
+
+  private final Stack<Context> myBackStack = new Stack<Context>();
+  private final Stack<Context> myForwardStack = new Stack<Context>();
+  private ActionToolbar myToolBar;
+  private boolean myIsEmpty;
+  private boolean myIsShown;
+  private final JLabel myElementLabel;
+
+  private static class Context {
+    final SmartPsiElementPointer element;
+    final String text;
+    final Rectangle viewRect;
+
+    public Context(SmartPsiElementPointer element, String text, Rectangle viewRect) {
+      this.element = element;
+      this.text = text;
+      this.viewRect = viewRect;
+    }
+  }
+
+  private final JScrollPane myScrollPane;
+  private final JEditorPane myEditorPane;
+  private String myText; // myEditorPane.getText() surprisingly crashes.., let's cache the text
+  private final JPanel myControlPanel;
+  private boolean myControlPanelVisible;
+  private final ExternalDocAction myExternalDocAction;
+
+  private JBPopup myHint;
+
+  private final HashMap<KeyStroke, ActionListener> myKeyboardActions = new HashMap<KeyStroke, ActionListener>();
+    // KeyStroke --> ActionListener
+
+  public boolean requestFocusInWindow() {
+    return myScrollPane.requestFocusInWindow();
+  }
+
+
+  public void requestFocus() {
+    myScrollPane.requestFocus();
+  }
+
+  public DocumentationComponent(final DocumentationManager manager, final AnAction[] additionalActions) {
+    myManager = manager;
+    myIsEmpty = true;
+    myIsShown = false;
+
+    myEditorPane = new JEditorPane(UIUtil.HTML_MIME, "") {
+      public Dimension getPreferredScrollableViewportSize() {
+        if (getWidth() == 0 || getHeight() == 0) {
+          setSize(MAX_WIDTH, MAX_HEIGHT);
+        }
+        Insets ins = myEditorPane.getInsets();
+        View rootView = myEditorPane.getUI().getRootView(myEditorPane);
+        rootView.setSize(MAX_WIDTH,
+                         MAX_HEIGHT);  // Necessary! Without this line, size will not increase then you go from small page to bigger one
+        int prefHeight = (int)rootView.getPreferredSpan(View.Y_AXIS);
+        prefHeight += ins.bottom + ins.top + myScrollPane.getHorizontalScrollBar().getMaximumSize().height;
+        return new Dimension(MAX_WIDTH, Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, prefHeight)));
+      }
+
+      {
+        enableEvents(KeyEvent.KEY_EVENT_MASK);
+      }
+
+      protected void processKeyEvent(KeyEvent e) {
+        KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
+        ActionListener listener = myKeyboardActions.get(keyStroke);
+        if (listener != null) {
+          listener.actionPerformed(new ActionEvent(DocumentationComponent.this, 0, ""));
+          e.consume();
+          return;
+        }
+        super.processKeyEvent(e);
+      }
+    };
+    myText = "";
+    myEditorPane.setEditable(false);
+    myEditorPane.setBackground(HintUtil.INFORMATION_COLOR);
+
+    myScrollPane = new JScrollPane(myEditorPane);
+    myScrollPane.setBorder(null);
+
+    final MouseAdapter mouseAdapter = new MouseAdapter() {
+      public void mousePressed(MouseEvent e) {
+        myManager.requestFocus();
+      }
+    };
+    myEditorPane.addMouseListener(mouseAdapter);
+    Disposer.register(this, new Disposable() {
+      public void dispose() {
+        myEditorPane.removeMouseListener(mouseAdapter);
+      }
+    });
+
+    final FocusAdapter focusAdapter = new FocusAdapter() {
+      public void focusLost(FocusEvent e) {
+        Component previouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(manager.getProject(getElement()));
+
+        if (!(previouslyFocused == myEditorPane)) {
+          if (myHint != null && !myHint.isDisposed()) myHint.cancel();
+        }
+      }
+    };
+    myEditorPane.addFocusListener(focusAdapter);
+
+    Disposer.register(this, new Disposable() {
+      public void dispose() {
+        myEditorPane.removeFocusListener(focusAdapter);
+      }
+    });
+
+    setLayout(new BorderLayout());
+    add(myScrollPane, BorderLayout.CENTER);
+    myScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 2));
+
+    final DefaultActionGroup actions = new DefaultActionGroup();
+    actions.add(new BackAction());
+    actions.add(new ForwardAction());
+    actions.add(myExternalDocAction = new ExternalDocAction());
+
+    if (additionalActions != null) {
+      for (final AnAction action : additionalActions) {
+        actions.add(action);
+      }
+    }
+
+    myToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.JAVADOC_TOOLBAR, actions, true);
+
+    myControlPanel = new JPanel();
+    myControlPanel.setLayout(new BorderLayout());
+    myControlPanel.setBorder(new EdgeBorder(EdgeBorder.EDGE_BOTTOM));
+    JPanel dummyPanel = new JPanel();
+
+    myElementLabel = new JLabel();
+
+    dummyPanel.setLayout(new BorderLayout());
+    dummyPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
+
+    dummyPanel.add(myElementLabel, BorderLayout.EAST);
+
+    myControlPanel.add(myToolBar.getComponent(), BorderLayout.WEST);
+    myControlPanel.add(dummyPanel, BorderLayout.CENTER);
+    myControlPanelVisible = false;
+
+    final HyperlinkListener hyperlinkListener = new HyperlinkListener() {
+      public void hyperlinkUpdate(HyperlinkEvent e) {
+        HyperlinkEvent.EventType type = e.getEventType();
+        if (type == HyperlinkEvent.EventType.ACTIVATED) {
+          manager.navigateByLink(DocumentationComponent.this, e.getDescription());
+        }
+        else if (type == HyperlinkEvent.EventType.ENTERED) {
+          myEditorPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        }
+        else if (type == HyperlinkEvent.EventType.EXITED) {
+          myEditorPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+        }
+      }
+    };
+    myEditorPane.addHyperlinkListener(hyperlinkListener);
+    Disposer.register(this, new Disposable() {
+      public void dispose() {
+        myEditorPane.removeHyperlinkListener(hyperlinkListener);
+      }
+    });
+
+    registerActions();
+
+    updateControlState();
+  }
+
+  public DocumentationComponent(final DocumentationManager manager) {
+    this(manager, null);
+  }
+
+  public synchronized boolean isEmpty() {
+    return myIsEmpty;
+  }
+
+  public synchronized void startWait() {
+    myIsEmpty = true;
+  }
+
+  private void setControlPanelVisible(boolean visible) {
+    if (visible == myControlPanelVisible) return;
+    if (visible) {
+      add(myControlPanel, BorderLayout.NORTH);
+    }
+    else {
+      remove(myControlPanel);
+    }
+    myControlPanelVisible = visible;
+  }
+
+  public void setHint(JBPopup hint) {
+    myHint = hint;
+  }
+
+  public JComponent getComponent() {
+    return myEditorPane;
+  }
+
+  @Nullable
+  public PsiElement getElement() {
+    return myElement != null ? myElement.getElement() : null;
+  }
+
+  public void setText(String text, PsiElement element, boolean clearHistory) {
+    setText(text, element, false, clearHistory);
+  }
+
+  public void setText(String text, PsiElement element, boolean clean, boolean clearHistory) {
+    if (clean && myElement != null) {
+      myBackStack.push(saveContext());
+      myForwardStack.clear();
+    }
+    updateControlState();
+    setData(element, text, !clean);
+    if (clean) {
+      myIsEmpty = false;
+    }
+
+    if (clearHistory) clearHistory();
+  }
+
+  private void clearHistory() {
+    myForwardStack.clear();
+    myBackStack.clear();
+  }
+
+  public void setData(PsiElement _element, String text, final boolean clearHistory) {
+    if (myElement != null) {
+      myBackStack.push(saveContext());
+      myForwardStack.clear();
+    }
+
+    final SmartPsiElementPointer element = _element != null && _element.isValid()
+                                           ? SmartPointerManager.getInstance(_element.getProject()).createSmartPsiElementPointer(_element)
+                                           : null;
+
+    if (element != null) {
+      myElement = element;
+    }
+
+    myIsEmpty = false;
+    updateControlState();
+    setDataInternal(element, text, new Rectangle(0, 0));
+
+    if (clearHistory) clearHistory();
+  }
+
+  private void setDataInternal(SmartPsiElementPointer element, String text, final Rectangle viewRect) {
+    setDataInternal(element, text, viewRect, false);
+  }
+
+  private void setDataInternal(SmartPsiElementPointer element, String text, final Rectangle viewRect, boolean skip) {
+    boolean justShown = false;
+
+    myElement = element;
+
+    if (!myIsShown && myHint != null) {
+      myEditorPane.setText(text);
+      myManager.showHint(myHint);
+      myIsShown = justShown = true;
+    }
+
+    if (!justShown) {
+      myEditorPane.setText(text);
+    }
+
+    if (!skip) {
+      myText = text;
+    }
+
+    SwingUtilities.invokeLater(new Runnable() {
+      public void run() {
+        myEditorPane.scrollRectToVisible(viewRect);
+      }
+    });
+  }
+
+  private void goBack() {
+    if (myBackStack.isEmpty()) return;
+    Context context = myBackStack.pop();
+    myForwardStack.push(saveContext());
+    restoreContext(context);
+    updateControlState();
+  }
+
+  private void goForward() {
+    if (myForwardStack.isEmpty()) return;
+    Context context = myForwardStack.pop();
+    myBackStack.push(saveContext());
+    restoreContext(context);
+    updateControlState();
+  }
+
+  private Context saveContext() {
+    Rectangle rect = myScrollPane.getViewport().getViewRect();
+    return new Context(myElement, myText, rect);
+  }
+
+  private void restoreContext(Context context) {
+    setDataInternal(context.element, context.text, context.viewRect);
+  }
+
+  private void updateControlState() {
+    ElementLocationUtil.customizeElementLabel(myElement != null ? myElement.getElement() : null, myElementLabel);
+    myToolBar.updateActionsImmediately(); // update faster
+    setControlPanelVisible(true);//(!myBackStack.isEmpty() || !myForwardStack.isEmpty());
+  }
+
+  private class BackAction extends AnAction implements HintManagerImpl.ActionToIgnore {
+    public BackAction() {
+      super(CodeInsightBundle.message("javadoc.action.back"), null, IconLoader.getIcon("/actions/back.png"));
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      goBack();
+    }
+
+    public void update(AnActionEvent e) {
+      Presentation presentation = e.getPresentation();
+      presentation.setEnabled(!myBackStack.isEmpty());
+    }
+  }
+
+  private class ForwardAction extends AnAction implements HintManagerImpl.ActionToIgnore {
+    public ForwardAction() {
+      super(CodeInsightBundle.message("javadoc.action.forward"), null, IconLoader.getIcon("/actions/forward.png"));
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      goForward();
+    }
+
+    public void update(AnActionEvent e) {
+      Presentation presentation = e.getPresentation();
+      presentation.setEnabled(!myForwardStack.isEmpty());
+    }
+  }
+
+  private class ExternalDocAction extends AnAction implements HintManagerImpl.ActionToIgnore {
+    public ExternalDocAction() {
+      super(CodeInsightBundle.message("javadoc.action.view.external"), null, IconLoader.getIcon("/actions/browser-externalJavaDoc.png"));
+      registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EXTERNAL_JAVADOC).getShortcutSet(), null);
+    }
+
+    public void actionPerformed(AnActionEvent e) {
+      if (myElement != null) {
+        final PsiElement element = myElement.getElement();
+        final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element);
+        final List<String> urls = provider.getUrlFor(element, DocumentationManager.getOriginalElement(element));
+        assert urls != null;
+        assert !urls.isEmpty();
+        ExternalJavaDocAction.showExternalJavadoc(urls);
+      }
+    }
+
+    public void update(AnActionEvent e) {
+      final Presentation presentation = e.getPresentation();
+      presentation.setEnabled(false);
+      if (myElement != null) {
+        final PsiElement element = myElement.getElement();
+        final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element);
+        final List<String> urls = provider.getUrlFor(element, DocumentationManager.getOriginalElement(element));
+        presentation.setEnabled(element != null && urls != null && !urls.isEmpty());
+      }
+    }
+  }
+
+  private void registerActions() {
+    myExternalDocAction
+      .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EXTERNAL_JAVADOC).getShortcutSet(), myEditorPane);
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        int value = scrollBar.getValue() - scrollBar.getUnitIncrement(-1);
+        value = Math.max(value, 0);
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        int value = scrollBar.getValue() + scrollBar.getUnitIncrement(+1);
+        value = Math.min(value, scrollBar.getMaximum());
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
+        int value = scrollBar.getValue() - scrollBar.getUnitIncrement(-1);
+        value = Math.max(value, 0);
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
+        int value = scrollBar.getValue() + scrollBar.getUnitIncrement(+1);
+        value = Math.min(value, scrollBar.getMaximum());
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        int value = scrollBar.getValue() - scrollBar.getBlockIncrement(-1);
+        value = Math.max(value, 0);
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        int value = scrollBar.getValue() + scrollBar.getBlockIncrement(+1);
+        value = Math.min(value, scrollBar.getMaximum());
+        scrollBar.setValue(value);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
+        scrollBar.setValue(0);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getHorizontalScrollBar();
+        scrollBar.setValue(scrollBar.getMaximum());
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, KeyEvent.CTRL_MASK), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        scrollBar.setValue(0);
+      }
+    });
+
+    myKeyboardActions.put(KeyStroke.getKeyStroke(KeyEvent.VK_END, KeyEvent.CTRL_MASK), new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
+        scrollBar.setValue(scrollBar.getMaximum());
+      }
+    });
+  }
+
+  public String getText() {
+    return myText;
+  }
+
+  public void dispose() {
+    myBackStack.clear();
+    myForwardStack.clear();
+    myKeyboardActions.clear();
+    myElement = null;
+    myManager = null;
+    myHint = null;
+  }
+
+}
index 3b1b009..1dfe156 100644 (file)
@@ -25,15 +25,14 @@ import com.intellij.codeInsight.lookup.LookupElement;
 import com.intellij.codeInsight.lookup.LookupManager;
 import com.intellij.ide.BrowserUtil;
 import com.intellij.ide.DataManager;
+import com.intellij.ide.IdeEventQueue;
+import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.ide.util.gotoByName.ChooseByNameBase;
 import com.intellij.lang.Language;
 import com.intellij.lang.LanguageDocumentation;
 import com.intellij.lang.documentation.CompositeDocumentationProvider;
 import com.intellij.lang.documentation.DocumentationProvider;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
 import com.intellij.openapi.actionSystem.ex.AnActionListener;
 import com.intellij.openapi.application.ApplicationManager;
@@ -44,26 +43,38 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.popup.JBPopup;
 import com.intellij.openapi.ui.popup.JBPopupFactory;
 import com.intellij.openapi.util.*;
+import com.intellij.openapi.wm.*;
+import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
 import com.intellij.openapi.wm.ex.WindowManagerEx;
 import com.intellij.psi.*;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
 import com.intellij.psi.presentation.java.SymbolPresentationUtil;
 import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.ui.content.*;
 import com.intellij.ui.popup.AbstractPopup;
 import com.intellij.ui.popup.NotLookupOrSearchCondition;
 import com.intellij.ui.popup.PopupUpdateProcessor;
 import com.intellij.util.Alarm;
+import com.intellij.util.Processor;
 import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.update.Activatable;
+import com.intellij.util.ui.update.UiNotifyConnector;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.lang.ref.WeakReference;
 import java.util.*;
 import java.util.List;
 
 public class DocumentationManager {
+  private static final String SHOW_DOCUMENTATION_IN_TOOL_WINDOW = "ShowDocumentationInToolWindow";
+  private static final String DOCUMENTATION_AUTO_UPDATE_ENABLED = "DocumentationAutoUpdateEnabled";
   @NonNls public static final String JAVADOC_LOCATION_AND_SIZE = "javadoc.popup";
   private final Project myProject;
   private Editor myEditor = null;
@@ -74,10 +85,13 @@ public class DocumentationManager {
   public static final Key<SmartPsiElementPointer> ORIGINAL_ELEMENT_KEY = Key.create("Original element");
   @NonNls public static final String PSI_ELEMENT_PROTOCOL = "psi_element://";
   @NonNls private static final String DOC_ELEMENT_PROTOCOL = "doc_element://";
+  private ToolWindow myToolWindow = null;
 
   private final ActionManagerEx myActionManagerEx;
 
   private static final int ourFlagsForTargetElements = TargetElementUtilBase.getInstance().getAllAccepted();
+  private boolean myAutoUpdateDocumentation = PropertiesComponent.getInstance().isTrueValue(DOCUMENTATION_AUTO_UPDATE_ENABLED);
+  private Runnable myAutoUpdateRequest;
 
   public static DocumentationManager getInstance(Project project) {
     return ServiceManager.getService(project, DocumentationManager.class);
@@ -115,7 +129,7 @@ public class DocumentationManager {
     myUpdateDocAlarm = new Alarm(Alarm.ThreadToUse.OWN_THREAD,myProject);
   }
 
-  public JBPopup showJavaDocInfo(@NotNull final PsiElement element, final PsiElement original) {
+  public void showJavaDocInfo(@NotNull final PsiElement element, final PsiElement original) {
     PopupUpdateProcessor updateProcessor = new PopupUpdateProcessor(element.getProject()) {
       public void updatePopup(Object lookupItemObject) {
         if (lookupItemObject instanceof PsiElement) {
@@ -123,11 +137,11 @@ public class DocumentationManager {
         }
       }
     };
-    return doShowJavaDocInfo(element, true, false, updateProcessor, original);
+
+    doShowJavaDocInfo(element, true, false, updateProcessor, original);
   }
 
-  @Nullable
-  public JBPopup showJavaDocInfo(final Editor editor, @Nullable final PsiFile file, boolean requestFocus) {
+  public void showJavaDocInfo(final Editor editor, @Nullable final PsiFile file, boolean requestFocus) {
     myEditor = editor;
     final Project project = getProject(file);
     PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -151,13 +165,13 @@ public class DocumentationManager {
       }
     }
 
-    if (element == null && file == null) return null; //file == null for text field editor
+    if (element == null && file == null) return; //file == null for text field editor
 
     if (element == null) { // look if we are within a javadoc comment
       element = originalElement;
-      if (element == null) return null;
+      if (element == null) return;
       PsiComment comment = PsiTreeUtil.getParentOfType(element, PsiComment.class);
-      if (comment == null) return null;
+      if (comment == null) return;
       element = comment.getParent();
       //if (!(element instanceof PsiDocCommentOwner)) return null;
     }
@@ -198,69 +212,211 @@ public class DocumentationManager {
       }
     };
 
-    return doShowJavaDocInfo(element, false, requestFocus, updateProcessor, originalElement);
+    doShowJavaDocInfo(element, false, requestFocus, updateProcessor, originalElement);
   }
 
-  private JBPopup doShowJavaDocInfo(PsiElement element, boolean heavyWeight, boolean requestFocus, PopupUpdateProcessor updateProcessor, PsiElement originalElement) {
+  private void doShowJavaDocInfo(final PsiElement element, boolean heavyWeight, boolean requestFocus, PopupUpdateProcessor updateProcessor, final PsiElement originalElement) {
     Project project = getProject(element);
-    final DocumentationComponent component = new DocumentationComponent(this);
-
-    final JBPopup hint = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
-        .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE)
-        .setProject(project)
-        .addListener(updateProcessor)
-        .addUserData(updateProcessor)
-        .setForceHeavyweight(heavyWeight)
-        .setDimensionServiceKey(myProject, JAVADOC_LOCATION_AND_SIZE, false)
-        .setResizable(true)
-        .setMovable(true)
-        .setTitle(getTitle(element))
-        .setCancelCallback(new Computable<Boolean>() {
-          public Boolean compute() {
-            if (fromQuickSearch()) {
-              ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).unregisterHint();
+
+    if (myToolWindow == null && PropertiesComponent.getInstance().isTrueValue(SHOW_DOCUMENTATION_IN_TOOL_WINDOW)) {
+      createToolWindow(element, originalElement);
+    } else if (myToolWindow != null) {
+      final Content content = myToolWindow.getContentManager().getSelectedContent();
+      if (content != null) {
+        final DocumentationComponent component = (DocumentationComponent) content.getComponent();
+        if (component.getElement() != element) {
+          content.setDisplayName(getTitle(element, true));
+          fetchDocInfo(getDefaultCollector(element, originalElement), component, true);
+        }
+
+        if (!myToolWindow.isVisible()) myToolWindow.show(null);
+      }
+    } else {
+      final DocumentationComponent component = new DocumentationComponent(this);
+      Processor<JBPopup> pinCallback = new Processor<JBPopup>() {
+        public boolean process(JBPopup popup) {
+          createToolWindow(element, originalElement);
+          popup.cancel();
+          return false;
+        }
+      };
+
+      final List<Pair<ActionListener, KeyStroke>> actions = Collections.singletonList(Pair.<ActionListener, KeyStroke>create(new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          createToolWindow(element, originalElement);
+          final JBPopup hint = getDocInfoHint();
+          if (hint != null && hint.isVisible()) hint.cancel();
+        }
+      }, ActionManagerEx.getInstanceEx().getKeyboardShortcut("QuickJavaDoc").getFirstKeyStroke()));
+
+      final JBPopup hint = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
+          .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE)
+          .setProject(project)
+          .addListener(updateProcessor)
+          .addUserData(updateProcessor)
+          .setKeyboardActions(actions)
+          .setForceHeavyweight(heavyWeight)
+          .setDimensionServiceKey(myProject, JAVADOC_LOCATION_AND_SIZE, false)
+          .setResizable(true)
+          .setMovable(true)
+          .setTitle(getTitle(element, false))
+          .setCouldPin(pinCallback)
+          .setCancelCallback(new Computable<Boolean>() {
+            public Boolean compute() {
+              if (fromQuickSearch()) {
+                ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).unregisterHint();
+              }
+
+              Disposer.dispose(component);
+              myEditor = null;
+              myPreviouslyFocused = null;
+              myParameterInfoController = null;
+              return Boolean.TRUE;
             }
+          })
+          .createPopup();
+
 
-            Disposer.dispose(component);
-            myEditor = null;
-            myPreviouslyFocused = null;
-            myParameterInfoController = null;
-            return Boolean.TRUE;
+      AbstractPopup oldHint = (AbstractPopup)getDocInfoHint();
+      if (oldHint != null) {
+        DocumentationComponent oldComponent = (DocumentationComponent)oldHint.getComponent();
+        PsiElement element1 = oldComponent.getElement();
+        if (Comparing.equal(element, element1)) {
+          if (requestFocus) {
+            component.getComponent().requestFocus();
           }
-        })
-        .createPopup();
+          return;
+        }
+        oldHint.cancel();
+      }
 
+      component.setHint(hint);
 
-    AbstractPopup oldHint = (AbstractPopup)getDocInfoHint();
-    if (oldHint != null) {
-      DocumentationComponent oldComponent = (DocumentationComponent)oldHint.getComponent();
-      PsiElement element1 = oldComponent.getElement();
-      if (Comparing.equal(element, element1)) {
-        if (requestFocus) {
-          component.getComponent().requestFocus();
-        }
-        return oldHint;
+      fetchDocInfo(getDefaultCollector(element, originalElement), component);
+
+      myDocInfoHintRef = new WeakReference<JBPopup>(hint);
+      myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project);
+
+      if (fromQuickSearch()) {
+        ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).registerHint(hint);
       }
-      oldHint.cancel();
     }
+  }
+
+  private void createToolWindow(final PsiElement element, PsiElement originalElement) {
+    assert myToolWindow == null;
+
+    final DocumentationComponent component = new DocumentationComponent(this, new AnAction[]{
+      new ToggleAction("Auto show documentation for selected element", "Show documentation for current element automatically",
+                          IconLoader.getIcon("/general/autoscrollFromSource.png")) {
+        @Override
+        public boolean isSelected(AnActionEvent e) {
+          return myAutoUpdateDocumentation;
+        }
+
+        @Override
+        public void setSelected(AnActionEvent e, boolean state) {
+          PropertiesComponent.getInstance().setValue(DOCUMENTATION_AUTO_UPDATE_ENABLED, Boolean.TRUE.toString());
+          myAutoUpdateDocumentation = state;
+          restartAutoUpdate(state);
+        }
+      },
+      new AnAction("Restore popup behavior", "Restore documentation popup behavior", IconLoader.getIcon("/actions/cancel.png")) {
+        @Override
+        public void actionPerformed(AnActionEvent e) {
+          restorePopupBehavior();
+        }
+      }});
 
-    component.setHint(hint);
+    final ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(myProject);
+    myToolWindow = toolWindowManagerEx.registerToolWindow(ToolWindowId.DOCUMENTATION, true, ToolWindowAnchor.RIGHT, myProject);
+    myToolWindow.setIcon(IconLoader.getIcon("/general/documentation.png"));
 
+    myToolWindow.setAvailable(true, null);
+    myToolWindow.setToHideOnEmptyContent(false);
+    myToolWindow.setAutoHide(false);
+
+    final Rectangle rectangle = WindowManager.getInstance().getIdeFrame(myProject).suggestChildFrameBounds();
+    myToolWindow.setDefaultState(ToolWindowAnchor.RIGHT, ToolWindowType.FLOATING, rectangle);
+
+    final ContentManager contentManager = myToolWindow.getContentManager();
+    final ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
+    final Content content = contentFactory.createContent(component, getTitle(element, true), false);
+    contentManager.addContent(content);
+
+    contentManager.addContentManagerListener(new ContentManagerAdapter() {
+      @Override
+      public void contentRemoved(ContentManagerEvent event) {
+        if (contentManager.getContentCount() == 0) {
+          restorePopupBehavior();
+        }
+      }
+    });
+
+    new UiNotifyConnector(component, new Activatable() {
+      public void showNotify() {
+        restartAutoUpdate(myAutoUpdateDocumentation);
+      }
+
+      public void hideNotify() {
+        restartAutoUpdate(false);
+      }
+    });
+
+    myToolWindow.show(null);
+    PropertiesComponent.getInstance().setValue(SHOW_DOCUMENTATION_IN_TOOL_WINDOW, Boolean.TRUE.toString());
+    restartAutoUpdate(PropertiesComponent.getInstance().isTrueValue(DOCUMENTATION_AUTO_UPDATE_ENABLED));
     fetchDocInfo(getDefaultCollector(element, originalElement), component);
+  }
+
+  private void restartAutoUpdate(final boolean state) {
+    if (state && myToolWindow != null) {
+      if (myAutoUpdateRequest == null) {
+        myAutoUpdateRequest = new Runnable() {
+          public void run() {
+            final DataContext dataContext = DataManager.getInstance().getDataContext();
+            final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
+            if (editor != null) {
+              final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject);
+
+              final Editor injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, file);
+              if (injectedEditor != null) {
+                final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(injectedEditor, myProject);
+                if (psiFile != null) {
+                  showJavaDocInfo(injectedEditor, psiFile, false);
+                  return;
+                }
+              }
 
-    myDocInfoHintRef = new WeakReference<JBPopup>(hint);
-    myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project);
+              if (file != null) {
+                showJavaDocInfo(editor, file, false);
+              }
+            }
+          }
+        };
 
-    if (fromQuickSearch()) {
-      ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).registerHint(hint);
+        IdeEventQueue.getInstance().addIdleListener(myAutoUpdateRequest, 500);
+      }
+    } else {
+      if (myAutoUpdateRequest != null) {
+        IdeEventQueue.getInstance().removeIdleListener(myAutoUpdateRequest);
+        myAutoUpdateRequest = null;
+      }
     }
+  }
 
-    return hint;
+  private void restorePopupBehavior() {
+    if (myToolWindow != null) {
+      PropertiesComponent.getInstance().setValue(SHOW_DOCUMENTATION_IN_TOOL_WINDOW, Boolean.FALSE.toString());
+      ToolWindowManagerEx.getInstanceEx(myProject).unregisterToolWindow(ToolWindowId.DOCUMENTATION);
+      myToolWindow = null;
+      restartAutoUpdate(false);
+    }
   }
 
-  private static String getTitle(@NotNull final PsiElement element) {
+  private static String getTitle(@NotNull final PsiElement element, final boolean _short) {
     final String title = SymbolPresentationUtil.getSymbolPresentableText(element);
-    return CodeInsightBundle.message("javadoc.info.title", title != null ? title : element.getText());
+    return _short ? title != null ? title : element.getText() : CodeInsightBundle.message("javadoc.info.title", title != null ? title : element.getText());
   }
 
   public static void storeOriginalElement(final Project project, final PsiElement originalElement, final PsiElement element) {
@@ -394,29 +550,33 @@ public class DocumentationManager {
   }
 
   public void fetchDocInfo(final DocumentationCollector provider, final DocumentationComponent component) {
-    doFetchDocInfo(component, provider, true);
+    doFetchDocInfo(component, provider, true, false);
+  }
+
+  public void fetchDocInfo(final DocumentationCollector provider, final DocumentationComponent component, final boolean clearHistory) {
+    doFetchDocInfo(component, provider, true, clearHistory);
   }
 
   public void fetchDocInfo(final PsiElement element, final DocumentationComponent component) {
-    doFetchDocInfo(component, getDefaultCollector(element, null), true);
+    doFetchDocInfo(component, getDefaultCollector(element, null), true, false);
   }
 
-  public ActionCallback queueFetchDocInfo(final DocumentationCollector provider, final DocumentationComponent component) {
-    return doFetchDocInfo(component, provider, false);
+  public ActionCallback queueFetchDocInfo(final DocumentationCollector provider, final DocumentationComponent component, final boolean clearHistory) {
+    return doFetchDocInfo(component, provider, false, clearHistory);
   }
 
   public ActionCallback queueFetchDocInfo(final PsiElement element, final DocumentationComponent component) {
-    return queueFetchDocInfo(getDefaultCollector(element, null), component);
+    return queueFetchDocInfo(getDefaultCollector(element, null), component, false);
   }
 
-  private ActionCallback doFetchDocInfo(final DocumentationComponent component, final DocumentationCollector provider, final boolean cancelRequests) {
+  private ActionCallback doFetchDocInfo(final DocumentationComponent component, final DocumentationCollector provider, final boolean cancelRequests, final boolean clearHistory) {
     final ActionCallback callback = new ActionCallback();
     component.startWait();
     if (cancelRequests) {
       myUpdateDocAlarm.cancelAllRequests();
     }
     if (component.isEmpty()) {
-      component.setText(CodeInsightBundle.message("javadoc.fetching.progress"));
+      component.setText(CodeInsightBundle.message("javadoc.fetching.progress"), null, clearHistory);
     }
 
     myUpdateDocAlarm.addRequest(new Runnable() {
@@ -441,7 +601,7 @@ public class DocumentationManager {
               String message = ex[0] instanceof IndexNotReadyException
                              ? "Documentation is not available until indices are built."
                              : CodeInsightBundle.message("javadoc.external.fetch.error.message", ex[0].getLocalizedMessage());
-              component.setText(message, true);
+              component.setText(message, null, true);
               callback.setDone();
             }
           });
@@ -472,13 +632,13 @@ public class DocumentationManager {
             }
 
             if (text == null) {
-              component.setText(CodeInsightBundle.message("no.documentation.found"), true);
+              component.setText(CodeInsightBundle.message("no.documentation.found"), element, true);
             }
             else if (text.length() == 0) {
-              component.setText(component.getText(), true);
+              component.setText(component.getText(), element, true, clearHistory);
             }
             else {
-              component.setData(element, text);
+              component.setData(element, text, clearHistory);
             }
 
             final AbstractPopup jbPopup = (AbstractPopup)getDocInfoHint();
@@ -486,7 +646,7 @@ public class DocumentationManager {
               callback.setDone();
               return;
             }
-            jbPopup.setCaption(getTitle(element));
+            jbPopup.setCaption(getTitle(element, false));
             final String dimensionServiceKey = jbPopup.getDimensionServiceKey();
             Dimension dimension = component.getPreferredSize();
             final Dimension storedSize = dimensionServiceKey != null ? DimensionService.getInstance().getSize(dimensionServiceKey, getProject(element)) : null;
index fe23251..69d7445 100644 (file)
@@ -26,6 +26,7 @@ import com.intellij.find.findUsages.FindUsagesManager;
 import com.intellij.find.impl.FindManagerImpl;
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.fileEditor.FileEditor;
 import com.intellij.openapi.fileEditor.FileEditorLocation;
@@ -574,20 +575,9 @@ public class ShowUsagesAction extends AnAction {
   }
 
   private static KeyboardShortcut getSettingsShortcut() {
-    AnAction action = ActionManager.getInstance().getAction("ShowUsagesSettings");
-    final ShortcutSet shortcutSet = action.getShortcutSet();
-    final Shortcut[] shortcuts = shortcutSet.getShortcuts();
-    for (final Shortcut shortcut : shortcuts) {
-      KeyboardShortcut kb = (KeyboardShortcut)shortcut;
-      if (kb.getSecondKeyStroke() == null) {
-        return (KeyboardShortcut)shortcut;
-      }
-    }
-
-    return null;
+    return ActionManagerEx.getInstanceEx().getKeyboardShortcut("ShowUsagesSettings");
   }
 
-
   private static void addUsageNodes(GroupNode root, final UsageViewImpl usageView, List<UsageNode> outNodes) {
     for (UsageNode node : root.getUsageNodes()) {
       Usage usage = node.getUsage();
index f6a8bf5..bc93253 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.util.Condition;
 import com.intellij.openapi.util.Pair;
 import com.intellij.ui.InplaceButton;
+import com.intellij.util.Processor;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -110,6 +111,9 @@ public interface ComponentPopupBuilder {
   ComponentPopupBuilder setCommandButton(@NotNull InplaceButton commandButton);
 
   @NotNull
+  ComponentPopupBuilder setCouldPin(@Nullable Processor<JBPopup> callback);
+
+  @NotNull
   ComponentPopupBuilder setKeyboardActions(@NotNull List<Pair<ActionListener, KeyStroke>> keyboardActions);
 
   @NotNull
index 0aabb76..08ebcaa 100644 (file)
@@ -35,4 +35,5 @@ public interface ToolWindowId {
   String VCS = UIBundle.message("tool.window.name.version.control");
   String MODULES_DEPENDENCIES = UIBundle.message("tool.window.name.module.dependencies");
   String DUPLICATES = UIBundle.message("tool.window.name.module.duplicates");
+  String DOCUMENTATION = UIBundle.message("tool.window.name.documentation");
 }
\ No newline at end of file
index f7fa5cc..3f6cfa4 100644 (file)
@@ -53,8 +53,6 @@ public class NotificationsListPanel extends JPanel implements NotificationModelL
   private static final Logger LOG = Logger.getInstance("#com.intellij.notification.impl.ui.NotificationsListPanel");
   private static final String REMOVE_KEY = "REMOVE";
 
-  private WeakReference<JBPopup> myPopupRef;
-
   private Project myProject;
   private Wrapper myWrapper;
   private JComponent myActiveComponent;
@@ -134,17 +132,6 @@ public class NotificationsListPanel extends JPanel implements NotificationModelL
     return size;
   }
 
-  public void clear() {
-    if (myPopupRef != null) {
-      final JBPopup jbPopup = myPopupRef.get();
-      if (jbPopup != null) {
-        jbPopup.cancel();
-      }
-
-      myPopupRef = null;
-    }
-  }
-
   public JComponent getPreferredFocusedComponent() {
     return myWrapper.getTargetComponent();
   }
index 7d963bc..a562efa 100644 (file)
@@ -18,11 +18,9 @@ package com.intellij.openapi.actionSystem.ex;
 
 
 import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.ActionManager;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.extensions.PluginId;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
@@ -54,6 +52,8 @@ public abstract class ActionManagerEx extends ActionManager{
 
   public abstract void fireAfterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event);
 
+  @Nullable
+  public abstract KeyboardShortcut getKeyboardShortcut(@NotNull String actionId);
 
 
   public abstract void fireBeforeEditorTyping(char c, DataContext dataContext);
index 013fb4e..520db07 100644 (file)
@@ -1030,6 +1030,21 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
     }
   }
 
+  @Override
+  public KeyboardShortcut getKeyboardShortcut(@NotNull String actionId) {
+    AnAction action = ActionManager.getInstance().getAction(actionId);
+    final ShortcutSet shortcutSet = action.getShortcutSet();
+    final Shortcut[] shortcuts = shortcutSet.getShortcuts();
+    for (final Shortcut shortcut : shortcuts) {
+      KeyboardShortcut kb = (KeyboardShortcut)shortcut;
+      if (kb.getSecondKeyStroke() == null) {
+        return (KeyboardShortcut)shortcut;
+      }
+    }
+
+    return null;
+  }
+
   public void fireBeforeEditorTyping(char c, DataContext dataContext) {
     myLastTimeEditorWasTypedIn = System.currentTimeMillis();
     AnActionListener[] listeners = getActionListeners();
index 2caa33a..c040a4f 100644 (file)
@@ -89,6 +89,11 @@ public abstract class WindowManagerEx extends WindowManager {
   public abstract Rectangle getScreenBounds();
 
   /**
+   * @return bounds for the screen device for the given project frame
+   */
+  public abstract Rectangle getScreenBounds(@NotNull final Project project);
+
+  /**
    * @return <code>true</code> is and only if current OS supports alpha mode for windows and
    * all native libraries were successfully loaded.
    */
index 113c19f..e2966ec 100644 (file)
@@ -59,6 +59,11 @@ public final class TestWindowManager extends WindowManagerEx implements Applicat
     return null;
   }
 
+  @Override
+  public Rectangle getScreenBounds(@NotNull Project project) {
+    return null;
+  }
+
   public void setWindowMask(final Window window, final Shape mask) {
   }
 
index 81b7a07..c5f0c2a 100644 (file)
@@ -206,6 +206,22 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
     return myScreenBounds;
   }
 
+  @Override
+  public Rectangle getScreenBounds(@NotNull Project project) {
+    final GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
+    final Point onScreen = getFrame(project).getLocationOnScreen();
+    final GraphicsDevice[] devices = environment.getScreenDevices();
+    for (final GraphicsDevice device : devices) {
+      final Rectangle bounds = device.getDefaultConfiguration().getBounds();
+      if (bounds.contains(onScreen)) {
+        return bounds;
+      }
+    }
+
+    return null;
+
+  }
+
   public final boolean isInsideScreenBounds(final int x, final int y, final int width) {
     return
       x >= myScreenBounds.x + 50 - width &&
index 846d59d..57bb88b 100644 (file)
@@ -40,6 +40,7 @@ import com.intellij.ui.*;
 import com.intellij.ui.awt.RelativePoint;
 import com.intellij.ui.speedSearch.SpeedSearch;
 import com.intellij.util.ImageLoader;
+import com.intellij.util.Processor;
 import com.intellij.util.ui.ChildFocusWatcher;
 import com.intellij.util.ui.EmptyIcon;
 import com.intellij.util.ui.UIUtil;
@@ -177,7 +178,8 @@ public class AbstractPopup implements JBPopup {
                      @Nullable String adText,
                      final boolean headerAlwaysFocusable,
                      @NotNull List<Pair<ActionListener, KeyStroke>> keyboardActions,
-                     Component settingsButtons) {
+                     Component settingsButtons,
+                     @Nullable final Processor<JBPopup> pinCallback) {
 
     if (requestFocus && !focusable) {
       assert false : "Incorrect argument combination: requestFocus=" + requestFocus + " focusable=" + focusable;
@@ -217,7 +219,16 @@ public class AbstractPopup implements JBPopup {
       else {
         myCaption = new CaptionPanel();
       }
-      if (cancelButton != null) {
+
+      if (pinCallback != null) {
+        myCaption.setButtonComponent(new InplaceButton(new IconButton("Pin", IconLoader.getIcon("/general/autohideOff.png"),
+                                                       IconLoader.getIcon("/general/autohideOff.png"),
+                                                       IconLoader.getIcon("/general/autohideOffInactive.png")), new ActionListener() {
+          public void actionPerformed(final ActionEvent e) {
+            pinCallback.process(AbstractPopup.this);
+          }
+        }));
+      } else if (cancelButton != null) {
         myCaption.setButtonComponent(new InplaceButton(cancelButton, new ActionListener() {
           public void actionPerformed(final ActionEvent e) {
             cancel();
index a65c331..a7cac6f 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.util.Condition;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.Pair;
+import com.intellij.util.Processor;
 import com.intellij.util.ui.EmptyIcon;
 import com.intellij.ui.InplaceButton;
 import org.jetbrains.annotations.NotNull;
@@ -60,6 +61,7 @@ public class ComponentPopupBuilderImpl implements ComponentPopupBuilder {
   private boolean myCancelKeyEnabled = true;
   private boolean myLocateByContent = false;
   private boolean myPlacewithinScreen = true;
+  private Processor<JBPopup> myPinCallback = null;
   private Dimension myMinSize;
   private MaskProvider myMaskProvider;
   private float myAlpha;
@@ -162,6 +164,12 @@ public class ComponentPopupBuilderImpl implements ComponentPopupBuilder {
   }
 
   @NotNull
+  public ComponentPopupBuilder setCouldPin(@Nullable final Processor<JBPopup> callback) {
+    myPinCallback = callback;
+    return this;
+  }
+
+  @NotNull
   public ComponentPopupBuilder setKeyboardActions(@NotNull List<Pair<ActionListener, KeyStroke>> keyboardActions) {
     myKeyboardActions = keyboardActions;
     return this;
@@ -193,7 +201,7 @@ public class ComponentPopupBuilderImpl implements ComponentPopupBuilder {
                                               myCancelButton,
                                               myCancelOnMouseOutCallback, myCancelOnWindow, myTitleIcon, myCancelKeyEnabled, myLocateByContent,
                                               myPlacewithinScreen, myMinSize, myAlpha, myMaskProvider, myInStack, myModalContext, myFocusOwners, myAd,
-                                              myHeaderAlwaysFocusable, myKeyboardActions, mySettingsButtons);
+                                              myHeaderAlwaysFocusable, myKeyboardActions, mySettingsButtons, myPinCallback);
     if (myUserData != null) {
       popup.setUserData(myUserData);
     }
index ea45e3b..a699e43 100644 (file)
@@ -88,7 +88,7 @@ public abstract class WizardPopup extends AbstractPopup implements ActionListene
     final Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
     init(project, scrollPane, getPreferredFocusableComponent(), true, true, true, true, null,
          false, aStep.getTitle(), null, true, null, false, null, null, null, false, null, true, false, true, null, 0f,
-         null, true, false, new Component[0], null, true, Collections.<Pair<ActionListener, KeyStroke>>emptyList(), null);
+         null, true, false, new Component[0], null, true, Collections.<Pair<ActionListener, KeyStroke>>emptyList(), null, null);
 
     registerAction("disposeAll", KeyEvent.VK_ESCAPE, InputEvent.SHIFT_MASK, new AbstractAction() {
       public void actionPerformed(ActionEvent e) {
index af1d063..6fcceb2 100644 (file)
@@ -158,4 +158,5 @@ row.move.up.without.mnemonic=Move Up
 row.move.down.without.mnemonic=Move Down
 move.up.action.name=Move Up
 move.down.action.name=Move Down
-file.chooser.save.dialog.file.name=File name:
\ No newline at end of file
+file.chooser.save.dialog.file.name=File name:
+tool.window.name.documentation=Documentation
\ No newline at end of file