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 399dcceed108..62b2eef4945e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -96,15 +96,14 @@ import java.util.List; public class DocumentationComponent extends JPanel implements Disposable, DataProvider { private static final Logger LOG = Logger.getInstance(DocumentationComponent.class); + private static final String DOCUMENTATION_TOPIC_ID = "reference.toolWindows.Documentation"; private static final Color DOCUMENTATION_COLOR = new JBColor(new Color(0xf7f7f7), new Color(0x46484a)); - static final JBColor BORDER_COLOR = new JBColor(new Color(0xadadad), new Color(0x616366)); + private static final JBColor BORDER_COLOR = new JBColor(new Color(0xadadad), new Color(0x616366)); public static final ColorKey COLOR_KEY = ColorKey.createColorKey("DOCUMENTATION_COLOR", DOCUMENTATION_COLOR); - public static final Color SECTION_COLOR = Gray.get(0x90); private static final Highlighter.HighlightPainter LINK_HIGHLIGHTER = new LinkHighlighter(); - @NonNls private static final String DOCUMENTATION_TOPIC_ID = "reference.toolWindows.Documentation"; private static final int PREFERRED_HEIGHT_MAX_EM = 10; private static final JBDimension MAX_DEFAULT = new JBDimension(650, 500); @@ -132,81 +131,13 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr private final MyDictionary myImageProvider = new MyDictionary() { @Override public Image get(Object key) { - if (myManager == null || key == null) return null; - PsiElement element = getElement(); - if (element == null) return null; - URL url = (URL)key; - Image inMemory = myManager.getElementImage(element, url.toExternalForm()); - if (inMemory != null) { - return inMemory; - } - - Url parsedUrl = Urls.parseEncoded(url.toExternalForm()); - BuiltInServerManager builtInServerManager = BuiltInServerManager.getInstance(); - if (parsedUrl != null && builtInServerManager.isOnBuiltInWebServer(parsedUrl)) { - try { - url = new URL(builtInServerManager.addAuthToken(parsedUrl).toExternalForm()); - } - catch (MalformedURLException e) { - LOG.warn(e); - } - } - Image image = ImageLoader.loadFromUrl(url); - return image != null ? ImageUtil.toBufferedImage(image) : Toolkit.getDefaultToolkit().createImage(url); + return getImageByKeyImpl(key); } }; + private Runnable myToolwindowCallback; private final ActionButton myCorner; - public AnAction[] getActions() { - return myToolBar.getActions().stream().filter((action -> !(action instanceof Separator))).toArray(AnAction[]::new); - } - - public AnAction getFontSizeAction() { - return new MyShowSettingsAction(); - } - - public void removeCornerMenu() { - myCorner.setVisible(false); - } - - public void setToolwindowCallback(Runnable callback) { - myToolwindowCallback = callback; - } - - public void showExternalDoc() { - final DataContext dataContext = DataManager.getInstance().getDataContext(this); - myExternalDocAction.actionPerformed(AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, dataContext)); - } - - private static class Context { - final SmartPsiElementPointer element; - final String text; - final String externalUrl; - final DocumentationProvider provider; - final Rectangle viewRect; - final int highlightedLink; - - Context(SmartPsiElementPointer element, - String text, - String externalUrl, - DocumentationProvider provider, - Rectangle viewRect, - int highlightedLink) { - this.element = element; - this.text = text; - this.externalUrl = externalUrl; - this.provider = provider; - this.viewRect = viewRect; - this.highlightedLink = highlightedLink; - } - - @NotNull - Context withText(@NotNull String text) { - return new Context(element, text, externalUrl, provider, viewRect, highlightedLink); - } - } - private final MyScrollPane myScrollPane; private final JEditorPane myEditorPane; private String myText; // myEditorPane.getText() surprisingly crashes.., let's cache the text @@ -219,34 +150,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr private final Map myKeyboardActions = new HashMap<>(); - @Override - public boolean requestFocusInWindow() { - // With a screen reader active, set the focus directly to the editor because - // it makes it easier for users to read/navigate the documentation contents. - if (ScreenReader.isActive()) { - return myEditorPane.requestFocusInWindow(); - } - else { - return myScrollPane.requestFocusInWindow(); - } - } - - - @Override - public void requestFocus() { - // With a screen reader active, set the focus directly to the editor because - // it makes it easier for users to read/navigate the documentation contents. - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> { - if (ScreenReader.isActive()) { - IdeFocusManager.getGlobalInstance().requestFocus(myEditorPane, true); - } - else { - IdeFocusManager.getGlobalInstance().requestFocus(myScrollPane, true); - } - }); - } - - public static DocumentationComponent createAndFetch(Project project, PsiElement element, Disposable disposable) { + @NotNull + public static DocumentationComponent createAndFetch(@NotNull Project project, + @NotNull PsiElement element, + @NotNull Disposable disposable) { DocumentationManager manager = DocumentationManager.getInstance(project); DocumentationComponent component = new DocumentationComponent(manager); Disposer.register(disposable, component); @@ -254,13 +161,12 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr return component; } - public DocumentationComponent(final DocumentationManager manager) { + public DocumentationComponent(DocumentationManager manager) { myManager = manager; myIsEmpty = true; myIsShown = false; myEditorPane = new JEditorPane(UIUtil.HTML_MIME, "") { - private Point initialClick; { enableEvents(AWTEvent.KEY_EVENT_MASK); } @@ -277,6 +183,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr super.processKeyEvent(e); } + Point initialClick; + @Override protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_PRESSED && myHint != null) { @@ -357,10 +265,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr @Override public View create(Element elem) { if ("icon".equals(elem.getName())) { - final Object src = elem.getAttributes().getAttribute(HTML.Attribute.SRC); + Object src = elem.getAttributes().getAttribute(HTML.Attribute.SRC); Icon icon = src != null ? IconLoader.findIcon((String)src, false) : null; if (icon == null) { - final ModuleType id = ModuleTypeManager.getInstance().findByID((String)src); + ModuleType id = ModuleTypeManager.getInstance().findByID((String)src); if (id != null) icon = id.getIcon(); } if (icon != null) { @@ -400,7 +308,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr @Override public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) { - Rectangle alloc = (Rectangle) a; + Rectangle alloc = (Rectangle)a; if (x < alloc.x + (alloc.width / 2)) { bias[0] = Position.Bias.Forward; return getStartOffset(); @@ -422,7 +330,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr myScrollPane = new MyScrollPane(); myScrollPane.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, helpDataProvider); - final FocusListener focusAdapter = new FocusAdapter() { + FocusListener focusAdapter = new FocusAdapter() { @Override public void focusLost(FocusEvent e) { Component previouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(manager.getProject(getElement())); @@ -448,9 +356,9 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr setOpaque(true); myScrollPane.setBorder(JBUI.Borders.empty()); - final DefaultActionGroup actions = new DefaultActionGroup(); - final BackAction back = new BackAction(); - final ForwardAction forward = new ForwardAction(); + DefaultActionGroup actions = new DefaultActionGroup(); + BackAction back = new BackAction(); + ForwardAction forward = new ForwardAction(); EditDocumentationSourceAction edit = new EditDocumentationSourceAction(); myExternalDocAction = new ExternalDocAction(); actions.add(back); @@ -469,18 +377,18 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr forward.registerCustomShortcutSet(forwardShortcutSet, this); // mouse actions are checked only for exact component over which click was performed, // so we need to register shortcuts for myEditorPane as well - back.registerCustomShortcutSet(backShortcutSet, myEditorPane); + back.registerCustomShortcutSet(backShortcutSet, myEditorPane); forward.registerCustomShortcutSet(forwardShortcutSet, myEditorPane); } catch (InvalidDataException e) { LOG.error(e); } - + myExternalDocAction.registerCustomShortcutSet(CustomShortcutSet.fromString("UP"), this); myExternalDocAction.registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_EXTERNAL_JAVADOC).getShortcutSet(), myEditorPane); edit.registerCustomShortcutSet(CommonShortcuts.getEditSource(), this); - ActionPopupMenu contextMenu = ((ActionManagerImpl)ActionManager.getInstance()).createActionPopupMenu(ActionPlaces.JAVADOC_TOOLBAR, actions, - new MenuItemPresentationFactory(true)); + ActionPopupMenu contextMenu = ((ActionManagerImpl)ActionManager.getInstance()).createActionPopupMenu( + ActionPlaces.JAVADOC_TOOLBAR, actions, new MenuItemPresentationFactory(true)); PopupHandler popupHandler = new PopupHandler() { @Override public void invokePopup(Component comp, int x, int y) { @@ -499,7 +407,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr JLayeredPane layeredPane = new JBLayeredPane() { @Override public void doLayout() { - final Rectangle r = getBounds(); + Rectangle r = getBounds(); for (Component component : getComponents()) { if (component instanceof JScrollPane) { component.setBounds(0, 0, r.width, r.height); @@ -526,7 +434,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr layeredPane.add(myScrollPane); layeredPane.setLayer(myScrollPane, 0); - final DefaultActionGroup gearActions = new MyGearActionGroup(); + DefaultActionGroup gearActions = new MyGearActionGroup(); gearActions.add(new ShowAsToolwindowAction()); gearActions.add(new MyShowSettingsAction()); gearActions.add(new ShowToolbarAction()); @@ -553,7 +461,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr myControlPanel.add(new MyShowSettingsButton(), BorderLayout.EAST); myControlPanelVisible = false; - final HyperlinkListener hyperlinkListener = new HyperlinkListener() { + HyperlinkListener hyperlinkListener = new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { HyperlinkEvent.EventType type = e.getEventType(); @@ -572,7 +480,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr if (myHint != null) { Disposer.register(myHint, this); - } else if (myManager.myToolWindow != null) { + } + else if (myManager.myToolWindow != null) { Disposer.register(myManager.myToolWindow.getContentManager(), this); } @@ -581,14 +490,62 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr updateControlState(); } + public AnAction[] getActions() { + return myToolBar.getActions().stream().filter((action -> !(action instanceof Separator))).toArray(AnAction[]::new); + } + + public AnAction getFontSizeAction() { + return new MyShowSettingsAction(); + } + + public void removeCornerMenu() { + myCorner.setVisible(false); + } + + public void setToolwindowCallback(Runnable callback) { + myToolwindowCallback = callback; + } + + public void showExternalDoc() { + DataContext dataContext = DataManager.getInstance().getDataContext(this); + myExternalDocAction.actionPerformed(AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, dataContext)); + } + + @Override + public boolean requestFocusInWindow() { + // With a screen reader active, set the focus directly to the editor because + // it makes it easier for users to read/navigate the documentation contents. + if (ScreenReader.isActive()) { + return myEditorPane.requestFocusInWindow(); + } + else { + return myScrollPane.requestFocusInWindow(); + } + } + + @Override + public void requestFocus() { + // With a screen reader active, set the focus directly to the editor because + // it makes it easier for users to read/navigate the documentation contents. + IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> { + if (ScreenReader.isActive()) { + IdeFocusManager.getGlobalInstance().requestFocus(myEditorPane, true); + } + else { + IdeFocusManager.getGlobalInstance().requestFocus(myScrollPane, true); + } + }); + } + private static void prepareCSS(HTMLEditorKit editorKit) { + Color borderColor = ColorUtil.mix(DOCUMENTATION_COLOR, BORDER_COLOR, 0.5); String editorFontName = StringUtil.escapeQuotes(EditorColorsManager.getInstance().getGlobalScheme().getEditorFontName()); editorKit.getStyleSheet().addRule("code {font-family:\"" + editorFontName + "\"}"); editorKit.getStyleSheet().addRule("pre {font-family:\"" + editorFontName + "\"}"); editorKit.getStyleSheet().addRule(".pre {font-family:\"" + editorFontName + "\"}"); editorKit.getStyleSheet().addRule("html { padding-bottom: 5px; }"); editorKit.getStyleSheet().addRule("a { color: #" + ColorUtil.toHex(getLinkColor()) + "; text-decoration: none;}"); - editorKit.getStyleSheet().addRule(".definition { padding: 3px 17px 1px 7px; border-bottom: thin solid #" + ColorUtil.toHex(ColorUtil.mix(DOCUMENTATION_COLOR, BORDER_COLOR, 0.5)) + "; }"); + editorKit.getStyleSheet().addRule(".definition { padding: 3px 17px 1px 7px; border-bottom: thin solid #" + ColorUtil.toHex(borderColor) + "; }"); editorKit.getStyleSheet().addRule(".content { padding: 5px 16px 0 7px; max-width: 100% }"); editorKit.getStyleSheet().addRule(".bottom { padding: 3px 16px 0 7px; }"); editorKit.getStyleSheet().addRule(".bottom-no-content { padding: 5px 16px 0 7px; }"); @@ -616,7 +573,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr // Javadocs often contain   symbols (non-breakable white space). We don't want to copy them as is and replace // with raw white spaces. See IDEA-86633 for more details. String selectedText = myEditorPane.getSelectedText(); - return selectedText == null? null : selectedText.replace((char)160, ' '); + return selectedText == null ? null : selectedText.replace((char)160, ' '); } return null; @@ -768,7 +725,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr pointer = SmartPointerManager.getInstance(element.getProject()).createSmartPsiElementPointer(element); } setDataInternal(pointer, text, new Rectangle(0, 0), ref); -} + } private void setDataInternal(@Nullable SmartPsiElementPointer element, @NotNull String text, @@ -779,7 +736,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr updateControlState(); setElement(element); - + highlightLink(-1); myEditorPane.setText(decorate(text)); @@ -794,10 +751,13 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr myEditorPane.scrollRectToVisible(viewRect); // if ref is defined but is not found in document, this provides a default location if (ref != null) { myEditorPane.scrollToReference(ref); - } else if (ScreenReader.isActive()) { + } + else if (ScreenReader.isActive()) { myEditorPane.setCaretPosition(0); - }}); + } + }); } + private void showHint() { Editor editor = myManager.getEditor(); Component popupAnchor = getPopupAnchor(editor); @@ -820,7 +780,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr int height = preferredSize.height + (needsToolbar() ? myControlPanel.getPreferredSize().height : 0); height = Math.min(MAX_DEFAULT.height, Math.max(MIN_DEFAULT.height, height)); hintSize = new Dimension(width, height); - } else { + } + else { hintSize = DimensionService.getInstance().getSize(DocumentationManager.NEW_JAVADOC_LOCATION_AND_SIZE, myManager.myProject); if (hintSize == null) { hintSize = new Dimension(MIN_DEFAULT); @@ -836,7 +797,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr // pin upper right corner (instead of default upper left) location = new RelativePoint(popupAnchor, new Point(-hintSize.width - 5, 0)).getScreenPoint(); myHint.setLocation(location); - } else if (editor != null && editor.getComponent().isShowing()) { + } + else if (editor != null && editor.getComponent().isShowing()) { // pin lower bound (instead of default upper) Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); preferredLocation.y -= editor.getLineHeight(); @@ -883,7 +845,8 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr // if documentation doesn't fit into screen, put it on the left hand side if (x + Math.max(hintSize.width, maxWidth) > screenRectangle.width) { point = new RelativePoint(popupAnchor, new Point(-hintSize.width - 5, 0)); - } else { + } + else { point = new RelativePoint(popupAnchor, new Point(lookupWidthAndGap, 0)); } myHint.show(point); @@ -892,14 +855,15 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr lookup.addLookupListener(new LookupAdapter() { @Override public void lookupCanceled(LookupEvent event) { - final AbstractPopup hint = myHint; + AbstractPopup hint = myHint; if (hint != null && hint.canClose() && hint.isVisible()) { hint.cancel(); } } }); } - } else if (editor != null && editor.getComponent().isShowing()) { + } + else if (editor != null && editor.getComponent().isShowing()) { // let's try to fit at least of half of maximum size on the bottom Point preferredLocation = JBPopupFactory.getInstance().guessBestPopupLocation(editor).getScreenPoint(); Rectangle preferred = new Rectangle(preferredLocation.x, preferredLocation.y, MAX_DEFAULT.width, MAX_DEFAULT.height / 2); @@ -935,7 +899,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr if (lookup != null && lookup.getCurrentItem() != null && lookup.getComponent().isShowing()) { return lookup.getComponent(); } - final Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); JBPopup popup = PopupUtil.getPopupContainerFor(focusOwner); if (popup != null) { return popup.getContent(); @@ -944,10 +908,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private void registerSizeTracker() { - final AbstractPopup hint = myHint; + AbstractPopup hint = myHint; if (hint == null) return; - final Window window = hint.getPopupWindow(); - final ComponentAdapter listener = new ComponentAdapter() { + Window window = hint.getPopupWindow(); + ComponentAdapter listener = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { if (myResizing) { @@ -962,9 +926,9 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private int definitionPreferredWidth() { - final TextUI ui = myEditorPane.getUI(); - final View view = ui.getRootView(myEditorPane); - final View definition = findDefinition(view); + TextUI ui = myEditorPane.getUI(); + View view = ui.getRootView(myEditorPane); + View definition = findDefinition(view); return definition != null ? (int)definition.getPreferredSpan(View.X_AXIS) : -1; } @@ -973,7 +937,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr return view; } for (int i = 0; i < view.getViewCount(); i++) { - final View definition = findDefinition(view.getView(i)); + View definition = findDefinition(view.getView(i)); if (definition != null) return definition; } return null; @@ -990,12 +954,13 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr DocumentationMarkup.CONTENT_START + text.substring(bodyStart) + DocumentationMarkup.CONTENT_END; - } else { + } + else { text = DocumentationMarkup.CONTENT_START + text + DocumentationMarkup.CONTENT_END; } hasContent = true; } - final String location = getLocationText(); + String location = getLocationText(); if (location != null) { text = text + getBottom(hasContent) + location + ""; } @@ -1020,7 +985,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr return null; } - final String title = manager.getTitle(element); + String title = manager.getTitle(element); if (externalUrl == null) { List urls = provider.getUrlFor(element, originalElement); if (urls != null) { @@ -1086,7 +1051,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr try { return new URL(url).toURI().getHost(); } - catch (URISyntaxException|MalformedURLException ignored) {} + catch (URISyntaxException | MalformedURLException ignored) { } return null; } @@ -1113,22 +1078,22 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private String getLocationText() { - final PsiElement element = getElement(); + PsiElement element = getElement(); if (element != null) { PsiFile file = element.getContainingFile(); VirtualFile vfile = file == null ? null : file.getVirtualFile(); if (vfile == null) return null; - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(element.getProject()).getFileIndex(); - final Module module = fileIndex.getModuleForFile(vfile); + ProjectFileIndex fileIndex = ProjectRootManager.getInstance(element.getProject()).getFileIndex(); + Module module = fileIndex.getModuleForFile(vfile); if (module != null) { if (ModuleManager.getInstance(element.getProject()).getModules().length == 1) return null; return " " + module.getName().replace("<", "<"); } else { - final List entries = fileIndex.getOrderEntriesForFile(vfile); + List entries = fileIndex.getOrderEntriesForFile(vfile); for (OrderEntry order : entries) { if (order instanceof LibraryOrderEntry || order instanceof JdkOrderEntry) { return " " + order.getPresentableName().replace("<", "<"); @@ -1153,6 +1118,31 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr myEditorPane.setFont(UIUtil.getFontWithFallback(fontName, Font.PLAIN, JBUI.scale(getQuickDocFontSize().getSize()))); } + @Nullable + private Image getImageByKeyImpl(Object key) { + if (myManager == null || key == null) return null; + PsiElement element = getElement(); + if (element == null) return null; + URL url = (URL)key; + Image inMemory = myManager.getElementImage(element, url.toExternalForm()); + if (inMemory != null) { + return inMemory; + } + + Url parsedUrl = Urls.parseEncoded(url.toExternalForm()); + BuiltInServerManager builtInServerManager = BuiltInServerManager.getInstance(); + if (parsedUrl != null && builtInServerManager.isOnBuiltInWebServer(parsedUrl)) { + try { + url = new URL(builtInServerManager.addAuthToken(parsedUrl).toExternalForm()); + } + catch (MalformedURLException e) { + LOG.warn(e); + } + } + Image image = ImageLoader.loadFromUrl(url); + return image != null ? ImageUtil.toBufferedImage(image) : Toolkit.getDefaultToolkit().createImage(url); + } + private void goBack() { if (myBackStack.isEmpty()) return; Context context = myBackStack.pop(); @@ -1198,14 +1188,14 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private static class MyGearActionGroup extends DefaultActionGroup implements HintManagerImpl.ActionToIgnore { - public MyGearActionGroup(@NotNull AnAction... actions) { + MyGearActionGroup(@NotNull AnAction... actions) { super(actions); setPopup(true); } } private class BackAction extends AnAction implements HintManagerImpl.ActionToIgnore { - public BackAction() { + BackAction() { super(CodeInsightBundle.message("javadoc.action.back"), null, AllIcons.Actions.Back); } @@ -1225,7 +1215,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class ForwardAction extends AnAction implements HintManagerImpl.ActionToIgnore { - public ForwardAction() { + ForwardAction() { super(CodeInsightBundle.message("javadoc.action.forward"), null, AllIcons.Actions.Forward); } @@ -1255,7 +1245,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr @Override public void actionPerformed(AnActionEvent e) { super.actionPerformed(e); - final JBPopup hint = myHint; + JBPopup hint = myHint; if (hint != null && hint.isVisible()) { hint.cancel(); } @@ -1267,7 +1257,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr SmartPsiElementPointer element = myElement; if (element != null) { PsiElement psiElement = element.getElement(); - return psiElement instanceof Navigatable ? new Navigatable[] {(Navigatable)psiElement} : null; + return psiElement instanceof Navigatable ? new Navigatable[]{(Navigatable)psiElement} : null; } return null; } @@ -1290,15 +1280,15 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr return; } - final PsiElement element = myElement.getElement(); - final PsiElement originalElement = DocumentationManager.getOriginalElement(element); - + PsiElement element = myElement.getElement(); + PsiElement originalElement = DocumentationManager.getOriginalElement(element); + ExternalJavaDocAction.showExternalJavadoc(element, originalElement, myExternalUrl, e.getDataContext()); } @Override public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); + Presentation presentation = e.getPresentation(); presentation.setEnabled(hasExternalDoc()); } } @@ -1445,7 +1435,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } return null; } - + private void highlightLink(int n) { myHighlightedLink = n; Highlighter highlighter = myEditorPane.getHighlighter(); @@ -1480,10 +1470,41 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } } + private static class Context { + final SmartPsiElementPointer element; + final String text; + final String externalUrl; + final DocumentationProvider provider; + final Rectangle viewRect; + final int highlightedLink; + + Context(SmartPsiElementPointer element, + String text, + String externalUrl, + DocumentationProvider provider, + Rectangle viewRect, + int highlightedLink) { + this.element = element; + this.text = text; + this.externalUrl = externalUrl; + this.provider = provider; + this.viewRect = viewRect; + this.highlightedLink = highlightedLink; + } + + @NotNull + Context withText(@NotNull String text) { + return new Context(element, text, externalUrl, provider, viewRect, highlightedLink); + } + } + private class MyShowSettingsButton extends ActionButton { - public MyShowSettingsButton() { - this(new MyGearActionGroup(new ShowAsToolwindowAction(), new MyShowSettingsAction(), new ShowToolbarAction(), new RestoreDefaultSizeAction()), + MyShowSettingsButton() { + this(new MyGearActionGroup(new ShowAsToolwindowAction(), + new MyShowSettingsAction(), + new ShowToolbarAction(), + new RestoreDefaultSizeAction()), new Presentation(), ActionPlaces.JAVADOC_INPLACE_SETTINGS, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); } @@ -1494,7 +1515,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class MyShowSettingsAction extends AnAction implements HintManagerImpl.ActionToIgnore { - public MyShowSettingsAction() { + MyShowSettingsAction() { super("Adjust font size..."); } @@ -1565,10 +1586,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr activateLink(myHighlightedLink); } } - + private static class LinkHighlighter implements Highlighter.HighlightPainter { private static final Stroke STROKE = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[]{1}, 0); - + @Override public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) { try { @@ -1590,7 +1611,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class ShowToolbarAction extends ToggleAction implements HintManagerImpl.ActionToIgnore { - public ShowToolbarAction() { + ShowToolbarAction() { super("Show Toolbar"); } @@ -1608,7 +1629,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class MyScrollPane extends JBScrollPane { - public MyScrollPane() { + MyScrollPane() { super(myEditorPane, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); setLayout(new Layout() { @Override @@ -1665,7 +1686,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class ShowAsToolwindowAction extends AnAction implements HintManagerImpl.ActionToIgnore { - public ShowAsToolwindowAction() { + ShowAsToolwindowAction() { super("Open as Tool Window"); } @@ -1681,7 +1702,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } private class RestoreDefaultSizeAction extends AnAction implements HintManagerImpl.ActionToIgnore { - public RestoreDefaultSizeAction() { + RestoreDefaultSizeAction() { super("Restore Size"); } 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 cd53b19f2e9d..52f5ba6a3a15 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -89,7 +89,7 @@ public class DocumentationManager extends DockablePopupManager component.clearHistory()); } - public void showJavaDocInfo(@NotNull final PsiElement element, final PsiElement original) { + public void showJavaDocInfo(@NotNull PsiElement element, PsiElement original) { showJavaDocInfo(element, original, null); } /** * Asks to show quick doc for the target element. * - * @param editor editor with an element for which quick do should be shown - * @param element target element which documentation should be shown - * @param original element that was used as a quick doc anchor. Example: consider a code like {@code Runnable task;}. - * A user wants to see javadoc for the {@code Runnable}, so, original element is a class name from the variable - * declaration but {@code 'element'} argument is a {@code Runnable} descriptor - * @param closeCallback callback to be notified on target hint close (if any) - * @param documentation precalculated documentation - * @param closeOnSneeze flag that defines whether quick doc control should be as non-obtrusive as possible. E.g. there are at least - * 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 editor editor with an element for which quick do should be shown + * @param element target element which documentation should be shown + * @param original element that was used as a quick doc anchor. Example: consider a code like {@code Runnable task;}. + * A user wants to see javadoc for the {@code Runnable}, so, original element is a class name from the variable + * declaration but {@code 'element'} argument is a {@code Runnable} descriptor + * @param closeCallback callback to be notified on target hint close (if any) + * @param documentation precalculated documentation + * @param closeOnSneeze flag that defines whether quick doc control should be as non-obtrusive as possible. E.g. there are at least + * 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 */ public void showJavaDocInfo(@NotNull Editor editor, - @NotNull final PsiElement element, - @NotNull final PsiElement original, + @NotNull PsiElement element, + @NotNull PsiElement original, @Nullable Runnable closeCallback, @Nullable String documentation, - boolean closeOnSneeze) - { + boolean closeOnSneeze) { myEditor = editor; myCloseOnSneeze = closeOnSneeze; showJavaDocInfo(element, original, false, closeCallback, documentation); } - public void showJavaDocInfo(@NotNull final PsiElement element, - final PsiElement original, + public void showJavaDocInfo(@NotNull PsiElement element, + PsiElement original, @Nullable Runnable closeCallback) { showJavaDocInfo(element, original, false, closeCallback); } - public void showJavaDocInfo(@NotNull final PsiElement element, - final PsiElement original, - final boolean requestFocus, + public void showJavaDocInfo(@NotNull PsiElement element, + PsiElement original, + boolean requestFocus, @Nullable Runnable closeCallback) { showJavaDocInfo(element, original, requestFocus, closeCallback, null); } - public void showJavaDocInfo(@NotNull final PsiElement element, - final PsiElement original, - final boolean requestFocus, + public void showJavaDocInfo(@NotNull PsiElement element, + PsiElement original, + boolean requestFocus, @Nullable Runnable closeCallback, @Nullable String documentation) { if (!element.isValid()) { @@ -341,31 +340,31 @@ public class DocumentationManager extends DockablePopupManager quickSearch.registerHint(hint)); } - static String getTitle(@NotNull final PsiElement element, final boolean _short) { - final String title = SymbolPresentationUtil.getSymbolPresentableText(element); - return _short ? title != null ? title : element.getText() : CodeInsightBundle.message("javadoc.info.title", title != null ? title : element.getText()); + static String getTitle(@NotNull PsiElement element, boolean isShort) { + String title = SymbolPresentationUtil.getSymbolPresentableText(element); + return isShort ? 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) { + public static void storeOriginalElement(Project project, PsiElement originalElement, PsiElement element) { if (element == null) return; try { element.putUserData( ORIGINAL_ELEMENT_KEY, SmartPointerManager.getInstance(project).createSmartPsiElementPointer(originalElement) ); - } catch (RuntimeException ex) { + } + catch (RuntimeException ex) { // PsiPackage does not allow putUserData } } @Nullable - public PsiElement findTargetElement(@NotNull final Editor editor, @Nullable final PsiFile file, PsiElement contextElement) { + public PsiElement findTargetElement(@NotNull Editor editor, @Nullable PsiFile file, PsiElement contextElement) { return findTargetElement(editor, editor.getCaretModel().getOffset(), file, contextElement); } - + @Nullable - public PsiElement findTargetElement(final Editor editor, int offset, @Nullable final PsiFile file, PsiElement contextElement) { + public PsiElement findTargetElement(Editor editor, int offset, @Nullable PsiFile file, PsiElement contextElement) { try { return findTargetElementUnsafe(editor, offset, file, contextElement); } @@ -617,7 +619,7 @@ public class DocumentationManager extends DockablePopupManager 0 && offset == editor.getDocument().getTextLength()) offset--; PsiReference ref = TargetElementUtil.findReference(editor, offset); - PsiElement contextElement = file == null? null : file.findElementAt(offset); + PsiElement contextElement = file == null ? null : file.findElementAt(offset); PsiElement targetElement = ref != null ? ref.getElement() : contextElement; if (targetElement != null) { PsiUtilCore.ensureValid(targetElement); @@ -698,15 +700,15 @@ public class DocumentationManager extends DockablePopupManager { String message = finalFail instanceof IndexNotReadyException - ? "Documentation is not available until indices are built." - : CodeInsightBundle.message("javadoc.external.fetch.error.message"); + ? "Documentation is not available until indices are built." + : CodeInsightBundle.message("javadoc.external.fetch.error.message"); component.setText(message, null, collector.provider); component.clearHistory(); callback.setDone(); @@ -771,7 +773,7 @@ public class DocumentationManager extends DockablePopupManager { if (!element.isValid()) { LOG.debug("Element for which documentation was requested is not valid"); @@ -809,8 +811,8 @@ public class DocumentationManager extends DockablePopupManager - getGlobalInstance().doWhenFocusSettlesDown(() -> getGlobalInstance().requestFocus(quickSearch.asComponent(), true)) + findQuickSearchComponent(myPreviouslyFocused).ifPresent( + quickSearch -> + getGlobalInstance().doWhenFocusSettlesDown( + () -> getGlobalInstance().requestFocus(quickSearch.asComponent(), true)) ); } - public Project getProject(@Nullable final PsiElement element) { + public Project getProject(@Nullable PsiElement element) { assertSameProject(element); return myProject; } @@ -994,7 +998,7 @@ public class DocumentationManager extends DockablePopupManagerSize: " + StringUtil.formatFileSize(attr.size()) + - "

Type: " + typeName + (type.isBinary() || typeName.equals(languageName) ? "" : " (" + languageName + ")") + - "

Modified: " + DateFormatUtil.formatDateTime(attr.lastModifiedTime().toMillis()) + - "

Created: " + DateFormatUtil.formatDateTime(attr.creationTime().toMillis()) + - (withUrl ? DocumentationMarkup.CONTENT_END : ""); + return (withUrl ? DocumentationMarkup.DEFINITION_START + + file.getPresentableUrl() + + DocumentationMarkup.DEFINITION_END + + DocumentationMarkup.CONTENT_START : "") + + "

Size: " + StringUtil.formatFileSize(attr.size()) + + "

Type: " + typeName + (type.isBinary() || typeName.equals(languageName) ? "" : " (" + languageName + ")") + + "

Modified: " + DateFormatUtil.formatDateTime(attr.lastModifiedTime().toMillis()) + + "

Created: " + DateFormatUtil.formatDateTime(attr.creationTime().toMillis()) + (withUrl ? DocumentationMarkup.CONTENT_END : ""); } private static Optional findQuickSearchComponent(Component c) { while (c != null) { if (c instanceof QuickSearchComponent) { - return Optional.of((QuickSearchComponent) c); + return Optional.of((QuickSearchComponent)c); } c = c.getParent(); }