summaryrefslogtreecommitdiff
path: root/platform/lang-impl/src/com/intellij/codeInsight/documentation
diff options
context:
space:
mode:
Diffstat (limited to 'platform/lang-impl/src/com/intellij/codeInsight/documentation')
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java75
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java96
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java248
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java72
5 files changed, 330 insertions, 163 deletions
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java
index 83f17299987b..e0d17d3c164b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DockablePopupManager.java
@@ -23,7 +23,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.AsyncResult;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowType;
@@ -34,6 +34,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.content.*;
+import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.Activatable;
import com.intellij.util.ui.update.UiNotifyConnector;
@@ -136,30 +137,33 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
protected AnAction[] createActions() {
- return new AnAction[]{
- new ToggleAction(getAutoUpdateTitle(), getAutoUpdateDescription(),
- AllIcons.General.AutoscrollFromSource) {
- @Override
- public boolean isSelected(AnActionEvent e) {
- return myAutoUpdateDocumentation;
- }
-
- @Override
- public void setSelected(AnActionEvent e, boolean state) {
- PropertiesComponent.getInstance().setValue(getAutoUpdateEnabledProperty(), String.valueOf(state));
- myAutoUpdateDocumentation = state;
- restartAutoUpdate(state);
- }
- },
- new AnAction("Restore Popup", getRestorePopupDescription(), AllIcons.Actions.Cancel) {
- @Override
- public void actionPerformed(AnActionEvent e) {
- restorePopupBehavior();
- }
- }};
+ ToggleAction toggleAutoUpdateAction = new ToggleAction(getAutoUpdateTitle(), getAutoUpdateDescription(),
+ AllIcons.General.AutoscrollFromSource) {
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ return myAutoUpdateDocumentation;
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ PropertiesComponent.getInstance().setValue(getAutoUpdateEnabledProperty(), String.valueOf(state));
+ myAutoUpdateDocumentation = state;
+ restartAutoUpdate(state);
+ }
+ };
+ return new AnAction[]{toggleAutoUpdateAction, createRestorePopupAction()};
+ }
+
+ @NotNull
+ protected AnAction createRestorePopupAction() {
+ return new AnAction("Restore Popup", getRestorePopupDescription(), AllIcons.Actions.Cancel) {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ restorePopupBehavior();
+ }
+ };
}
-
protected void restartAutoUpdate(final boolean state) {
if (state && myToolWindow != null) {
if (myAutoUpdateRequest == null) {
@@ -189,12 +193,16 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
public void updateComponent() {
if (myProject.isDisposed()) return;
- AsyncResult<DataContext> asyncResult = DataManager.getInstance().getDataContextFromFocus();
- DataContext dataContext = asyncResult.getResult();
- if (dataContext == null) {
- return;
- }
+ DataManager.getInstance().getDataContextFromFocus().doWhenDone(new Consumer<DataContext>() {
+ @Override
+ public void consume(@NotNull DataContext dataContext) {
+ if (!myProject.isOpen()) return;
+ updateComponentInner(dataContext);
+ }
+ });
+ }
+ private void updateComponentInner(@NotNull DataContext dataContext) {
if (CommonDataKeys.PROJECT.getData(dataContext) != myProject) {
return;
}
@@ -228,13 +236,10 @@ public abstract class DockablePopupManager<T extends JComponent & Disposable> {
protected void restorePopupBehavior() {
if (myToolWindow != null) {
PropertiesComponent.getInstance().setValue(getShowInToolWindowProperty(), Boolean.FALSE.toString());
-
- final Content[] contents = myToolWindow.getContentManager().getContents();
- for (final Content content : contents) {
- myToolWindow.getContentManager().removeContent(content, true);
- }
-
- ToolWindowManagerEx.getInstanceEx(myProject).unregisterToolWindow(getToolwindowId());
+ ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(myProject);
+ toolWindowManagerEx.hideToolWindow(getToolwindowId(), false);
+ toolWindowManagerEx.unregisterToolWindow(getToolwindowId());
+ Disposer.dispose(myToolWindow.getContentManager());
myToolWindow = null;
restartAutoUpdate(false);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
index cf9b5ad22798..50f69088033b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
@@ -32,6 +32,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.impl.ActionButton;
import com.intellij.openapi.application.ApplicationBundle;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
@@ -47,6 +48,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.JBColor;
import com.intellij.ui.SideBorder;
import com.intellij.ui.components.JBLayeredPane;
import com.intellij.ui.components.JBScrollPane;
@@ -66,10 +68,9 @@ import javax.swing.event.HyperlinkListener;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
-import java.util.Collections;
+import java.net.URL;
+import java.util.*;
import java.util.List;
-import java.util.Map;
-import java.util.Stack;
public class DocumentationComponent extends JPanel implements Disposable, DataProvider {
@@ -92,7 +93,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
private final Stack<Context> myBackStack = new Stack<Context>();
private final Stack<Context> myForwardStack = new Stack<Context>();
private final ActionToolbar myToolBar;
- private boolean myIsEmpty;
+ private volatile boolean myIsEmpty;
private boolean myIsShown;
private final JLabel myElementLabel;
private Style myFontSizeStyle;
@@ -101,6 +102,13 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
private final MyShowSettingsButton myShowSettingsButton;
private boolean myIgnoreFontSizeSliderChange;
private String myEffectiveExternalUrl;
+ private final MyDictionary<String, Image> myImageProvider = new MyDictionary<String, Image>() {
+ @Override
+ public Image get(Object key) {
+ PsiElement element = getElement();
+ return element == null ? null : myManager.getElementImage(element, ((URL)key).toExternalForm());
+ }
+ };
private static class Context {
final SmartPsiElementPointer element;
@@ -178,6 +186,14 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
GraphicsUtil.setupAntialiasing(g);
super.paintComponent(g);
}
+
+ @Override
+ public void setDocument(Document doc) {
+ super.setDocument(doc);
+ if (doc instanceof StyledDocument) {
+ doc.putProperty("imageCache", myImageProvider);
+ }
+ }
};
DataProvider helpDataProvider = new DataProvider() {
@Override
@@ -308,6 +324,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
if (additionalActions != null) {
for (final AnAction action : additionalActions) {
actions.add(action);
+ ShortcutSet shortcutSet = action.getShortcutSet();
+ if (shortcutSet != null) {
+ action.registerCustomShortcutSet(shortcutSet, this);
+ }
}
}
@@ -378,7 +398,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
myFontSizeSlider.setSnapToTicks(true);
UIUtil.setSliderIsFilled(myFontSizeSlider, true);
result.add(myFontSizeSlider);
- result.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor(), 1));
+ result.setBorder(BorderFactory.createLineBorder(JBColor.border(), 1));
myFontSizeSlider.addChangeListener(new ChangeListener() {
@Override
@@ -418,11 +438,11 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
}
}
- public synchronized boolean isEmpty() {
+ public boolean isEmpty() {
return myIsEmpty;
}
- public synchronized void startWait() {
+ public void startWait() {
myIsEmpty = true;
}
@@ -473,7 +493,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
}
public void replaceText(String text, PsiElement element) {
- if (element == null || getElement() != element) return;
+ PsiElement current = getElement();
+ if (current == null || !current.getManager().areElementsEquivalent(current, element)) return;
setText(text, element, false);
if (!myBackStack.empty()) myBackStack.pop();
}
@@ -530,6 +551,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
myText = text;
}
+ //noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
@@ -544,7 +566,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
return;
}
- StyledDocument styledDocument = (StyledDocument)document;
+ final StyledDocument styledDocument = (StyledDocument)document;
if (myFontSizeStyle == null) {
myFontSizeStyle = styledDocument.addStyle("active", null);
}
@@ -555,7 +577,14 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
if (Registry.is("documentation.component.editor.font")) {
StyleConstants.setFontFamily(myFontSizeStyle, scheme.getEditorFontName());
}
- styledDocument.setCharacterAttributes(0, document.getLength(), myFontSizeStyle, false);
+
+ final Style sizeStyle = myFontSizeStyle;
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ styledDocument.setCharacterAttributes(0, styledDocument.getLength(), sizeStyle, false);
+ }
+ });
}
private void goBack() {
@@ -631,15 +660,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
private class EditDocumentationSourceAction extends BaseNavigateToSourceAction {
- protected EditDocumentationSourceAction() {
+ EditDocumentationSourceAction() {
super(true);
- }
-
- @Override
- public void update(AnActionEvent event) {
- super.update(event);
- event.getPresentation().setIcon(AllIcons.Actions.EditSource);
- event.getPresentation().setText("Edit Source");
+ getTemplatePresentation().setIcon(AllIcons.Actions.EditSource);
+ getTemplatePresentation().setText("Edit Source");
}
@Override
@@ -678,8 +702,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
final PsiElement originalElement = DocumentationManager.getOriginalElement(element);
boolean processed = false;
if (provider instanceof CompositeDocumentationProvider) {
- for (final DocumentationProvider documentationProvider : ((CompositeDocumentationProvider)provider).getProviders()) {
- if (documentationProvider instanceof ExternalDocumentationHandler && ((ExternalDocumentationHandler)documentationProvider).handleExternal(element, originalElement)) {
+ for (DocumentationProvider p : ((CompositeDocumentationProvider)provider).getAllProviders()) {
+ if (p instanceof ExternalDocumentationHandler && ((ExternalDocumentationHandler)p).handleExternal(element, originalElement)) {
processed = true;
break;
}
@@ -874,4 +898,36 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
mySettingsPanel.setVisible(true);
}
}
+
+ private static abstract class MyDictionary<K, V> extends Dictionary<K, V> {
+ @Override
+ public int size() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<K> keys() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Enumeration<V> elements() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
index 05a1e01c6aa1..63484f890225 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
@@ -36,9 +36,11 @@ 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;
+import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderEntry;
@@ -58,13 +60,13 @@ import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.content.Content;
import com.intellij.ui.popup.AbstractPopup;
-import com.intellij.ui.popup.NotLookupOrSearchCondition;
import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.ui.popup.PopupUpdateProcessor;
import com.intellij.util.Alarm;
import com.intellij.util.BooleanFunction;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
+import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -125,6 +127,24 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return "Auto Show Documentation for Selected Element";
}
+ @NotNull
+ @Override
+ protected AnAction createRestorePopupAction() {
+ AnAction restorePopupAction = super.createRestorePopupAction();
+ ShortcutSet quickDocShortcut = ActionManager.getInstance().getAction(IdeActions.ACTION_QUICK_JAVADOC).getShortcutSet();
+ restorePopupAction.registerCustomShortcutSet(quickDocShortcut, null);
+ return restorePopupAction;
+ }
+
+ @Override
+ protected void restorePopupBehavior() {
+ if (myPreviouslyFocused != null) {
+ IdeFocusManager.getInstance(myProject).requestFocus(myPreviouslyFocused, true);
+ }
+ super.restorePopupBehavior();
+ updateComponent();
+ }
+
/**
* @return <code>true</code> if quick doc control is configured to not prevent user-IDE interaction (e.g. should be closed if
* the user presses a key);
@@ -165,7 +185,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
@Override
public void beforeEditorTyping(char c, DataContext dataContext) {
final JBPopup hint = getDocInfoHint();
- if (hint != null) {
+ if (hint != null && LookupManager.getActiveLookup(myEditor) == null) {
hint.cancel();
}
}
@@ -213,7 +233,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
public void showJavaDocInfo(@NotNull final PsiElement element, final PsiElement original) {
- showJavaDocInfo(element, original, false, null);
+ showJavaDocInfo(element, original, null);
}
/**
@@ -229,35 +249,31 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
* two possible situations - the quick doc is shown automatically on mouse over element; the quick doc is shown
* on explicit action call (Ctrl+Q). We want to close the doc on, say, editor viewport position change
* at the first situation but don't want to do that at the second
- * @param allowReuse defines whether currently requested documentation should reuse existing doc control (if any)
*/
public void showJavaDocInfo(@NotNull Editor editor,
@NotNull final PsiElement element,
@NotNull final PsiElement original,
@Nullable Runnable closeCallback,
- boolean closeOnSneeze,
- boolean allowReuse)
+ boolean closeOnSneeze)
{
myEditor = editor;
myCloseOnSneeze = closeOnSneeze;
- showJavaDocInfo(element, original, allowReuse, closeCallback);
+ showJavaDocInfo(element, original, closeCallback);
}
public void showJavaDocInfo(@NotNull final PsiElement element,
final PsiElement original,
- boolean allowReuse,
- @Nullable Runnable closeCallback)
- {
+ @Nullable Runnable closeCallback) {
PopupUpdateProcessor updateProcessor = new PopupUpdateProcessor(element.getProject()) {
@Override
public void updatePopup(Object lookupItemObject) {
if (lookupItemObject instanceof PsiElement) {
- doShowJavaDocInfo((PsiElement)lookupItemObject, false, this, original, false);
+ doShowJavaDocInfo((PsiElement)lookupItemObject, false, this, original, null);
}
}
};
- doShowJavaDocInfo(element, false, updateProcessor, original, allowReuse, closeCallback);
+ doShowJavaDocInfo(element, false, updateProcessor, original, closeCallback);
}
public void showJavaDocInfo(final Editor editor, @Nullable final PsiFile file, boolean requestFocus) {
@@ -267,14 +283,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
public void showJavaDocInfo(final Editor editor,
@Nullable final PsiFile file,
boolean requestFocus,
- final Runnable closeCallback) {
- showJavaDocInfo(editor, file, requestFocus, true, closeCallback);
- }
-
- private void showJavaDocInfo(final Editor editor,
- @Nullable final PsiFile file,
- boolean requestFocus,
- final boolean autoupdate, @Nullable final Runnable closeCallback) {
+ @Nullable final Runnable closeCallback) {
myEditor = editor;
final Project project = getProject(file);
PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -324,7 +333,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return;
}
if (lookupIteObject instanceof PsiElement) {
- doShowJavaDocInfo((PsiElement)lookupIteObject, false, this, originalElement, autoupdate, closeCallback);
+ doShowJavaDocInfo((PsiElement)lookupIteObject, false, this, originalElement, closeCallback);
return;
}
@@ -347,12 +356,12 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
}
else {
- doShowJavaDocInfo(element, false, this, originalElement, autoupdate, closeCallback);
+ doShowJavaDocInfo(element, false, this, originalElement, closeCallback);
}
}
};
- doShowJavaDocInfo(element, requestFocus, updateProcessor, originalElement, autoupdate, closeCallback);
+ doShowJavaDocInfo(element, requestFocus, updateProcessor, originalElement, closeCallback);
}
public PsiElement findTargetElement(Editor editor, PsiFile file) {
@@ -363,54 +372,56 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return file != null ? file.findElementAt(editor.getCaretModel().getOffset()) : null;
}
- private void doShowJavaDocInfo(final PsiElement element, boolean requestFocus, PopupUpdateProcessor updateProcessor,
- final PsiElement originalElement, final boolean autoupdate)
- {
- doShowJavaDocInfo(element, requestFocus, updateProcessor, originalElement, autoupdate, null);
- }
-
private void doShowJavaDocInfo(@NotNull final PsiElement element,
boolean requestFocus,
PopupUpdateProcessor updateProcessor,
final PsiElement originalElement,
- final boolean allowReuse,
- @Nullable final Runnable closeCallback)
- {
+ @Nullable final Runnable closeCallback) {
Project project = getProject(element);
storeOriginalElement(project, originalElement, element);
+ myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project);
+
+ JBPopup _oldHint = getDocInfoHint();
if (myToolWindow == null && PropertiesComponent.getInstance().isTrueValue(SHOW_DOCUMENTATION_IN_TOOL_WINDOW)) {
createToolWindow(element, originalElement);
- return;
}
else if (myToolWindow != null) {
- if (allowReuse && !myToolWindow.isAutoHide()) {
- 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);
+ Content content = myToolWindow.getContentManager().getSelectedContent();
+ if (content != null) {
+ DocumentationComponent component = (DocumentationComponent)content.getComponent();
+ if (element.getManager().areElementsEquivalent(component.getElement(), element)) {
+ JComponent preferredFocusableComponent = content.getPreferredFocusableComponent();
+ // focus toolwindow on the second actionPerformed
+ boolean focus = requestFocus || CommandProcessor.getInstance().getCurrentCommand() != null;
+ if (preferredFocusableComponent != null && focus) {
+ IdeFocusManager.getInstance(myProject).requestFocus(preferredFocusableComponent, true);
}
}
-
- if (!myToolWindow.isVisible()) {
- myToolWindow.show(null);
+ else {
+ content.setDisplayName(getTitle(element, true));
+ fetchDocInfo(getDefaultCollector(element, originalElement), component, true);
}
- return;
}
- else {
- restorePopupBehavior();
+
+ if (!myToolWindow.isVisible()) {
+ myToolWindow.show(null);
}
}
-
- final JBPopup _oldHint = getDocInfoHint();
- if (_oldHint != null && _oldHint.isVisible() && _oldHint instanceof AbstractPopup) {
- final DocumentationComponent oldComponent = (DocumentationComponent)((AbstractPopup)_oldHint).getComponent();
+ else if (_oldHint != null && _oldHint.isVisible() && _oldHint instanceof AbstractPopup) {
+ DocumentationComponent oldComponent = (DocumentationComponent)((AbstractPopup)_oldHint).getComponent();
fetchDocInfo(getDefaultCollector(element, originalElement), oldComponent);
- return;
}
+ else {
+ showInPopup(element, requestFocus, updateProcessor, originalElement, closeCallback);
+ }
+ }
+ private void showInPopup(@NotNull final PsiElement element,
+ boolean requestFocus,
+ PopupUpdateProcessor updateProcessor,
+ final PsiElement originalElement,
+ @Nullable final Runnable closeCallback) {
final DocumentationComponent component = new DocumentationComponent(this);
component.setNavigateCallback(new Consumer<PsiElement>() {
@Override
@@ -426,26 +437,30 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
@Override
public boolean process(JBPopup popup) {
createToolWindow(element, originalElement);
+ myToolWindow.setAutoHide(false);
popup.cancel();
return false;
}
};
- final KeyboardShortcut keyboardShortcut = ActionManagerEx.getInstanceEx().getKeyboardShortcut("QuickJavaDoc");
- final List<Pair<ActionListener, KeyStroke>> actions =
- Collections.singletonList(Pair.<ActionListener, KeyStroke>create(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- createToolWindow(element, originalElement);
- final JBPopup hint = getDocInfoHint();
- if (hint != null && hint.isVisible()) hint.cancel();
- }
- }, keyboardShortcut != null ? keyboardShortcut.getFirstKeyStroke() : null)); // Null keyStroke is ok here
+ ActionListener actionListener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ createToolWindow(element, originalElement);
+ final JBPopup hint = getDocInfoHint();
+ if (hint != null && hint.isVisible()) hint.cancel();
+ }
+ };
+ List<Pair<ActionListener, KeyStroke>> actions = ContainerUtil.newSmartList();
+ AnAction quickDocAction = ActionManagerEx.getInstanceEx().getAction(IdeActions.ACTION_QUICK_JAVADOC);
+ for (Shortcut shortcut : quickDocAction.getShortcutSet().getShortcuts()) {
+ if (!(shortcut instanceof KeyboardShortcut)) continue;
+ actions.add(Pair.create(actionListener, ((KeyboardShortcut)shortcut).getFirstKeyStroke()));
+ }
boolean hasLookup = LookupManager.getActiveLookup(myEditor) != null;
final JBPopup hint = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
- .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE)
- .setProject(project)
+ .setProject(element.getProject())
.addListener(updateProcessor)
.addUserData(updateProcessor)
.setKeyboardActions(actions)
@@ -490,20 +505,6 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
})
.createPopup();
-
- 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.cancel();
- }
-
component.setHint(hint);
if (myEditor == null) {
@@ -515,7 +516,6 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
fetchDocInfo(getDefaultCollector(element, originalElement), component);
myDocInfoHintRef = new WeakReference<JBPopup>(hint);
- myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project);
if (fromQuickSearch() && myPreviouslyFocused != null) {
((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).registerHint(hint);
@@ -666,11 +666,12 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
private ActionCallback doFetchDocInfo(final DocumentationComponent component, final DocumentationCollector provider, final boolean cancelRequests, final boolean clearHistory) {
final ActionCallback callback = new ActionCallback();
+ boolean wasEmpty = component.isEmpty();
component.startWait();
if (cancelRequests) {
myUpdateDocAlarm.cancelAllRequests();
}
- if (component.isEmpty()) {
+ if (wasEmpty) {
component.setText(CodeInsightBundle.message("javadoc.fetching.progress"), null, clearHistory);
final AbstractPopup jbPopup = (AbstractPopup)getDocInfoHint();
if (jbPopup != null) {
@@ -845,7 +846,26 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
} else if (url.startsWith(PSI_ELEMENT_PROTOCOL)) {
final String refText = url.substring(PSI_ELEMENT_PROTOCOL.length());
DocumentationProvider provider = getProviderFromElement(psiElement);
- final PsiElement targetElement = provider.getDocumentationElementForLink(manager, refText, psiElement);
+ PsiElement targetElement = provider.getDocumentationElementForLink(manager, refText, psiElement);
+ if (targetElement == null) {
+ for (DocumentationProvider documentationProvider : Extensions.getExtensions(DocumentationProvider.EP_NAME)) {
+ targetElement = documentationProvider.getDocumentationElementForLink(manager, refText, psiElement);
+ if (targetElement != null) {
+ break;
+ }
+ }
+ }
+ if (targetElement == null) {
+ for (Language language : Language.getRegisteredLanguages()) {
+ DocumentationProvider documentationProvider = LanguageDocumentation.INSTANCE.forLanguage(language);
+ if (documentationProvider != null) {
+ targetElement = documentationProvider.getDocumentationElementForLink(manager, refText, psiElement);
+ if (targetElement != null) {
+ break;
+ }
+ }
+ }
+ }
if (targetElement != null) {
fetchDocInfo(getDefaultCollector(targetElement, null), component);
}
@@ -854,33 +874,33 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
final DocumentationProvider provider = getProviderFromElement(psiElement);
boolean processed = false;
if (provider instanceof CompositeDocumentationProvider) {
- for (DocumentationProvider documentationProvider : ((CompositeDocumentationProvider)provider).getProviders()) {
- if (documentationProvider instanceof ExternalDocumentationHandler) {
- final ExternalDocumentationHandler externalDocumentationHandler = (ExternalDocumentationHandler)documentationProvider;
- if (externalDocumentationHandler.canFetchDocumentationLink(url)) {
- fetchDocInfo(new DocumentationCollector() {
- @Override
- public String getDocumentation() throws Exception {
- return externalDocumentationHandler.fetchExternalDocumentation(url, psiElement);
- }
+ for (DocumentationProvider p : ((CompositeDocumentationProvider)provider).getAllProviders()) {
+ if (!(p instanceof ExternalDocumentationHandler)) continue;
- @Override
- public PsiElement getElement() {
- return psiElement;
- }
+ final ExternalDocumentationHandler externalHandler = (ExternalDocumentationHandler)p;
+ if (externalHandler.canFetchDocumentationLink(url)) {
+ fetchDocInfo(new DocumentationCollector() {
+ @Override
+ public String getDocumentation() throws Exception {
+ return externalHandler.fetchExternalDocumentation(url, psiElement);
+ }
- @Nullable
- @Override
- public String getEffectiveExternalUrl() {
- return url;
- }
- }, component);
- processed = true;
- }
- else if (externalDocumentationHandler.handleExternalLink(manager, url, psiElement)) {
- processed = true;
- break;
- }
+ @Override
+ public PsiElement getElement() {
+ return psiElement;
+ }
+
+ @Nullable
+ @Override
+ public String getEffectiveExternalUrl() {
+ return url;
+ }
+ }, component);
+ processed = true;
+ }
+ else if (externalHandler.handleExternalLink(manager, url, psiElement)) {
+ processed = true;
+ break;
}
}
}
@@ -979,12 +999,12 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
@Override
protected void doUpdateComponent(Editor editor, PsiFile psiFile) {
- showJavaDocInfo(editor, psiFile, false, true, null);
+ showJavaDocInfo(editor, psiFile, false, null);
}
@Override
protected void doUpdateComponent(@NotNull PsiElement element) {
- showJavaDocInfo(element, element, true, null);
+ showJavaDocInfo(element, element, null);
}
@Override
@@ -992,6 +1012,20 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return getTitle(element, true);
}
+ @Nullable
+ public Image getElementImage(@NotNull PsiElement element, @NotNull String imageSpec) {
+ DocumentationProvider provider = getProviderFromElement(element);
+ if (provider instanceof CompositeDocumentationProvider) {
+ for (DocumentationProvider p : ((CompositeDocumentationProvider)provider).getAllProviders()) {
+ if (p instanceof DocumentationProviderEx) {
+ Image image = ((DocumentationProviderEx)p).getLocalImageForElement(element, imageSpec);
+ if (image != null) return image;
+ }
+ }
+ }
+ return null;
+ }
+
private interface DocumentationCollector {
@Nullable
String getDocumentation() throws Exception;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java
index 47bf01f2e7c8..0cd18020ad54 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverManager.java
@@ -301,7 +301,7 @@ public class QuickDocOnMouseOverManager {
info.editor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION,
info.editor.offsetToVisualPosition(info.originalElement.getTextRange().getStartOffset()));
try {
- info.docManager.showJavaDocInfo(info.editor, info.targetElement, info.originalElement, myHintCloseCallback, true, true);
+ info.docManager.showJavaDocInfo(info.editor, info.targetElement, info.originalElement, myHintCloseCallback, true);
myDocumentationManager = new WeakReference<DocumentationManager>(info.docManager);
}
finally {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java
new file mode 100644
index 000000000000..064bd020183b
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2014 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.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowId;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.popup.AbstractPopup;
+import com.intellij.util.Producer;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+/**
+ * @author gregsh
+ */
+public class QuickDocUtil {
+
+ public static void updateQuickDocAsync(@NotNull final PsiElement element, @NotNull final Producer<String> docProducer) {
+ final Project project = element.getProject();
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ final String documentation = docProducer.produce();
+ if (StringUtil.isEmpty(documentation)) return;
+ // modal dialogs with fragment editors fix: can't guess proper modality state here
+ //noinspection SSBasedInspection
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ DocumentationManager documentationManager = DocumentationManager.getInstance(project);
+ DocumentationComponent component;
+ JBPopup hint = documentationManager.getDocInfoHint();
+ if (hint != null) {
+ component = (DocumentationComponent)((AbstractPopup)hint).getComponent();
+ }
+ else if (documentationManager.hasActiveDockedDocWindow()) {
+ ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
+ Content selectedContent = toolWindow == null ? null : toolWindow.getContentManager().getSelectedContent();
+ component = selectedContent == null ? null : (DocumentationComponent)selectedContent.getComponent();
+ }
+ else {
+ component = null;
+ }
+ if (component != null) {
+ component.replaceText(documentation, element);
+ }
+ }
+ });
+ }
+ });
+ }
+}