From 5d5c55a8767ef4c6b99162bc6e43b730161e3d45 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Fri, 20 Jul 2012 11:33:11 +0400 Subject: [PATCH] EA-37556 - assert: RemoteProcessSupport.acquire 1. DocumentationProvider.generateDoc() contract is clarified; 2. Don't call DocumentationProvider.generateDoc() from EDT; --- .../documentation/DocumentationProvider.java | 11 +++- .../navigation/CtrlMouseHandler.java | 66 +++++++++++++++---- .../intellij/codeInsight/hint/HintUtil.java | 37 +++++------ 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java index eacdb5538eb4..7269465e093a 100644 --- a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java +++ b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,15 @@ public interface DocumentationProvider { @Nullable List getUrlFor(PsiElement element, PsiElement originalElement); + /** + * Callback for asking the doc provider for the complete documentation. + *

+ * Underlying implementation may be time-consuming, that's why this method is expected not to be called from EDT. + * + * @param element target element which documentation is being requested + * @param originalElement element initially picked up from the current context + * @return target element's documentation (if any) + */ @Nullable String generateDoc(PsiElement element, PsiElement originalElement); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index a49b4f3c8506..0abd022d367c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java @@ -72,7 +72,10 @@ import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.LightweightHint; import com.intellij.usageView.UsageViewShortNameLocation; import com.intellij.usageView.UsageViewTypeLocation; +import com.intellij.util.Alarm; +import com.intellij.util.Consumer; import com.intellij.util.Processor; +import com.intellij.util.ui.UIUtil; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -168,7 +171,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { return; } MouseEvent mouseEvent = e.getMouseEvent(); - + if (isMouseOverTooltip(mouseEvent.getLocationOnScreen()) || isMouseMovedTowardTooltip(mouseEvent.getLocationOnScreen())) { myPrevMouseLocation = mouseEvent.getLocationOnScreen(); return; @@ -212,6 +215,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent { TextAttributesKey .createTextAttributesKey("CTRL_CLICKABLE", new TextAttributes(Color.blue, null, Color.blue, EffectType.LINE_UNDERSCORE, 0)); + @NotNull private final Alarm myDocAlarm; + public CtrlMouseHandler(final Project project, StartupManager startupManager, EditorColorsManager colorsManager, FileEditorManager fileEditorManager, @NotNull DocumentationManager documentationManager, @NotNull final EditorFactory editorFactory, @NotNull IdeTooltipManager tooltipManager) @@ -234,6 +239,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { myFileEditorManager = fileEditorManager; myDocumentationManager = documentationManager; myTooltipManager = tooltipManager; + myDocAlarm = new Alarm(Alarm.ThreadToUse.OWN_THREAD, myProject); } @NotNull @@ -265,7 +271,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { if (dx == 0) { return mouseLocationOnScreen.x > bounds.x && mouseLocationOnScreen.x < bounds.x + bounds.width; } - + // Check if the mouse goes out of the control. if (mouseLocationOnScreen.x < prevLocation.x && bounds.x > prevLocation.x) return false; if (mouseLocationOnScreen.y < prevLocation.y && bounds.y > prevLocation.y) return false; @@ -341,13 +347,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { private static DocInfo generateInfo(PsiElement element, PsiElement atPointer) { final DocumentationProvider documentationProvider = DocumentationManager.getProviderFromElement(element, atPointer); String result = doGenerateInfo(element, atPointer, documentationProvider); - if (result != null) { - String fullText = documentationProvider.generateDoc(element, atPointer); - String qName = element instanceof PsiQualifiedNamedElement ? ((PsiQualifiedNamedElement)element).getQualifiedName() : null; - String text = DocPreviewUtil.buildPreview(result, qName, fullText); - return new DocInfo(text, documentationProvider, element); - } - return DocInfo.EMPTY; + return result == null ? DocInfo.EMPTY : new DocInfo(result, documentationProvider, element); } @Nullable @@ -611,6 +611,40 @@ public class CtrlMouseHandler extends AbstractProjectComponent { } } + private void fulfillDocInfo(@NotNull final String header, + @NotNull final DocumentationProvider provider, + @NotNull final PsiElement originalElement, + @NotNull final PsiElement anchorElement, + @NotNull final Consumer newTextConsumer) + { + myDocAlarm.cancelAllRequests(); + myDocAlarm.addRequest(new Runnable() { + @Override + public void run() { + final Ref fullTextRef = new Ref(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + fullTextRef.set(provider.generateDoc(anchorElement, originalElement)); + } + }); + String fullText = fullTextRef.get(); + if (fullText == null) { + return; + } + String qName = anchorElement instanceof PsiQualifiedNamedElement ? ((PsiQualifiedNamedElement)anchorElement).getQualifiedName() + : null; + final String updatedText = DocPreviewUtil.buildPreview(header, qName, fullText); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + newTextConsumer.consume(updatedText); + } + }); + } + }, 0); + } + private class TooltipProvider { private final Editor myEditor; private final LogicalPosition myPosition; @@ -727,8 +761,14 @@ public class CtrlMouseHandler extends AbstractProjectComponent { pane.mouseExited(e); } } - }; - JComponent label = HintUtil.createInformationLabel(docInfo.text, hyperlinkListener, mouseListener); + }; + Ref> newTextConsumerRef = new Ref>(); + JComponent label = HintUtil.createInformationLabel(docInfo.text, hyperlinkListener, mouseListener, newTextConsumerRef); + Consumer newTextConsumer = newTextConsumerRef.get(); + myDocAlarm.cancelAllRequests(); + if (newTextConsumer != null && docInfo.docProvider != null && docInfo.documentationAnchor != null) { + fulfillDocInfo(docInfo.text, docInfo.docProvider, info.myElementAtPointer, docInfo.documentationAnchor, newTextConsumer); + } QuickDocInfoPane quickDocPane = null; if (docInfo.documentationAnchor != null) { quickDocPane = new QuickDocInfoPane(docInfo.documentationAnchor, info.myElementAtPointer, label); @@ -744,7 +784,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { 0, false, HintManagerImpl.createHintHint(myEditor, p, hint, HintManager.ABOVE).setContentActive(false)); } } - + private HighlightersSet installHighlighterSet(Info info, Editor editor) { final JComponent internalComponent = editor.getContentComponent(); internalComponent.addKeyListener(myEditorKeyListener); @@ -875,7 +915,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent { if (myDocumentationManager.hasActiveDockedDocWindow()) { return; } - + // Skip event triggered when mouse leaves action button area. if (!mouseEntered && new Rectangle(getLocationOnScreen(), getSize()).contains(mouseScreenLocation)) { return; diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java index fa155286244f..314eb6e2fd18 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java @@ -17,10 +17,12 @@ package com.intellij.codeInsight.hint; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeTooltipManager; +import com.intellij.openapi.util.Ref; import com.intellij.ui.ColoredSideBorder; import com.intellij.ui.HintHint; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleColoredText; +import com.intellij.util.Consumer; import com.intellij.util.ui.UIUtil; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NotNull; @@ -29,12 +31,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; -import javax.swing.border.EmptyBorder; -import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class HintUtil { @@ -52,16 +50,17 @@ public class HintUtil { } public static JComponent createInformationLabel(@NotNull String text) { - return createInformationLabel(text, null, null); + return createInformationLabel(text, null, null, null); } public static JComponent createInformationLabel(@NotNull String text, @Nullable HyperlinkListener hyperlinkListener, - @Nullable MouseListener mouseListener) + @Nullable MouseListener mouseListener, + @Nullable Ref> updatedTextConsumer) { HintHint hintHint = new HintHint().setTextBg(INFORMATION_COLOR).setTextFg(Color.black).setFont(getBoldFont()).setAwtTooltip(true); - HintLabel label = new HintLabel(); + final HintLabel label = new HintLabel(); label.setText(text, hintHint); label.setIcon(INFORMATION_ICON); @@ -79,6 +78,14 @@ public class HintUtil { if (mouseListener != null) { label.myPane.addMouseListener(mouseListener); } + if (updatedTextConsumer != null) { + updatedTextConsumer.set(new Consumer() { + @Override + public void consume(String s) { + label.myPane.setText(s); + } + }); + } return label; } @@ -148,18 +155,6 @@ public class HintUtil { return UIUtil.getLabelFont().deriveFont(Font.BOLD); } - public static JLabel createAdComponent(final String bottomText) { - return createAdComponent(bottomText, getDefaultAdComponentBorder()); - } - - public static EmptyBorder getDefaultAdComponentBorder() { - return new EmptyBorder(1, 2, 1, 2); - } - - public static JLabel createAdComponent(final String bottomText, final Border border) { - return createAdComponent(bottomText, border, SwingUtilities.LEFT); - } - public static JLabel createAdComponent(final String bottomText, final Border border, @JdkConstants.HorizontalAlignment int alignment) { JLabel label = new JLabel(); label.setText(bottomText); @@ -227,8 +222,8 @@ public class HintUtil { remove(myIcon); } - myIcon = new JLabel(icon, JLabel.CENTER); - myIcon.setVerticalAlignment(JLabel.TOP); + myIcon = new JLabel(icon, SwingConstants.CENTER); + myIcon.setVerticalAlignment(SwingConstants.TOP); add(myIcon, BorderLayout.WEST);