diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java
index d28cda96e8ed..b2da6749b317 100644
--- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java
+++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.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.
@@ -78,7 +78,7 @@ public class JavaDocExternalFilter extends AbstractExternalFilter {
return
(JavaPsiFacade.getInstance(myProject).findClass(classRef, GlobalSearchScope.allScope(myProject)) != null)
- ? PSI_ELEMENT_PROTOCOL + elementRef
+ ? DocumentationManager.PSI_ELEMENT_PROTOCOL + elementRef
: DOC_ELEMENT_PROTOCOL + doAnnihilate(nakedRoot + href);
}
},
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/AbstractExternalFilter.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/AbstractExternalFilter.java
index ae7e2513784b..504ea5cdf8e6 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/AbstractExternalFilter.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/AbstractExternalFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -25,10 +25,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.openapi.vfs.*;
import com.intellij.psi.*;
import com.intellij.util.io.UrlConnectionUtil;
import com.intellij.util.net.HttpConfigurable;
@@ -38,7 +35,6 @@ import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
-import java.util.Locale;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -58,8 +54,6 @@ public abstract class AbstractExternalFilter {
protected static @NonNls final Pattern ourHTMLFilesuffix = Pattern.compile("/([^/]*[.][hH][tT][mM][lL]?)$");
private static @NonNls final Pattern ourAnnihilator = Pattern.compile("/[^/^.]*/[.][.]/");
private static @NonNls final Pattern ourIMGselector = Pattern.compile("
]*)\"", Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
- protected static @NonNls final String DOC_ELEMENT_PROTOCOL = "doc_element://";
- protected static @NonNls final String PSI_ELEMENT_PROTOCOL = "psi_element://";
private static @NonNls final String JAR_PROTOCOL = "jar:";
@NonNls private static final String HR = "
";
@NonNls private static final String P = "";
@@ -86,7 +80,7 @@ public abstract class AbstractExternalFilter {
public String refFilter(final String root, String read) {
String toMatch = StringUtilRt.toUpperCase(read);
- StringBuffer ready = new StringBuffer();
+ StringBuilder ready = new StringBuilder();
int prev = 0;
Matcher matcher = mySelector.matcher(toMatch);
@@ -115,7 +109,7 @@ public abstract class AbstractExternalFilter {
protected final RefConvertor myIMGConvertor = new RefConvertor(ourIMGselector) {
protected String convertReference(String root, String href) {
if (StringUtil.startsWithChar(href, '#')) {
- return DOC_ELEMENT_PROTOCOL + root + href;
+ return DocumentationManager.DOC_ELEMENT_PROTOCOL + root + href;
}
if (Comparing.strEqual(VirtualFileManager.extractProtocol(root), LocalFileSystem.PROTOCOL)) {
@@ -160,7 +154,7 @@ public abstract class AbstractExternalFilter {
return null;
}
- return new StringReader(VfsUtil.loadText(file));
+ return new StringReader(VfsUtilCore.loadText(file));
}
URL url = BrowserUtil.getURL(surl);
@@ -259,7 +253,7 @@ public abstract class AbstractExternalFilter {
}
}
}
- while (read != null && StringUtilRt.toUpperCase(read).indexOf(startSection) == -1);
+ while (read != null && !StringUtilRt.toUpperCase(read).contains(startSection));
if (input instanceof MyReader && contentEncoding != null) {
if (contentEncoding != null && !contentEncoding.equals("UTF-8") && !contentEncoding.equals(((MyReader)input).getEncoding())) { //restart page parsing with correct encoding
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 e9f38615c1e7..2d8469c26136 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
@@ -93,7 +93,7 @@ public class DocumentationManager extends DockablePopupManager 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://";
+ @NonNls public static final String DOC_ELEMENT_PROTOCOL = "doc_element://";
private final ActionManagerEx myActionManagerEx;
private boolean myCloseOnSneeze;
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 9e32e239595b..e3022dceeb20 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
import com.intellij.codeInsight.navigation.actions.GotoTypeDeclarationAction;
+import com.intellij.ide.IdeTooltipManager;
import com.intellij.ide.util.EditSourceUtil;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.navigation.ItemPresentation;
@@ -73,6 +74,8 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
@@ -250,19 +253,20 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
@Nullable
@TestOnly
public static String getInfo(PsiElement element, PsiElement atPointer) {
- return generateInfo(element, atPointer);
+ return generateInfo(element, atPointer).text;
}
- @Nullable
- private static String generateInfo(PsiElement element, PsiElement atPointer) {
+ @NotNull
+ 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;
- return DocPreviewUtil.buildPreview(result, qName, fullText, ourQuickDocRowsNumber, ourQuickDocSymbolsInRowNumber);
+ String text = DocPreviewUtil.buildPreview(result, qName, fullText, ourQuickDocRowsNumber, ourQuickDocSymbolsInRowNumber);
+ return new DocInfo(text, documentationProvider, atPointer);
}
- return result;
+ return DocInfo.EMPTY;
}
@Nullable
@@ -334,8 +338,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
return myRanges;
}
- @Nullable
- public abstract String getInfo();
+ @NotNull
+ public abstract DocInfo getInfo();
public abstract boolean isValid(Document document);
@@ -366,8 +370,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
myTargetElement = targetElement;
}
- @Nullable
- public String getInfo() {
+ @NotNull
+ public DocInfo getInfo() {
AccessToken token = ReadAction.start();
try {
return generateInfo(myTargetElement, myElementAtPointer);
@@ -395,9 +399,10 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
public InfoMultiple(@NotNull final PsiElement elementAtPointer) {
super(elementAtPointer);
}
-
- public String getInfo() {
- return CodeInsightBundle.message("multiple.implementations.tooltip");
+
+ @NotNull
+ public DocInfo getInfo() {
+ return new DocInfo(CodeInsightBundle.message("multiple.implementations.tooltip"), null, null);
}
public boolean isValid(Document document) {
@@ -594,21 +599,26 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
}
- if (info.isValid(myEditor.getDocument())) {
- myHighlighter = installHighlighterSet(info, myEditor);
-
- String text = info.getInfo();
-
- if (text == null) return;
-
- JComponent label = HintUtil.createInformationLabel(text);
- final LightweightHint hint = new LightweightHint(label);
- final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
- Point p = HintManagerImpl.getHintPosition(hint, myEditor, myPosition, HintManager.ABOVE);
- hintManager.showEditorHint(hint, myEditor, p,
- HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING,
- 0, false, HintManagerImpl.createHintHint(myEditor, p, hint, HintManager.ABOVE).setContentActive(false));
+ if (!info.isValid(myEditor.getDocument())) {
+ return;
}
+
+ myHighlighter = installHighlighterSet(info, myEditor);
+
+ DocInfo docInfo = info.getInfo();
+
+ if (docInfo.text == null) return;
+
+ HyperlinkListener listener = (docInfo.docProvider == null || docInfo.context == null)
+ ? null
+ : new QuickDocHyperlinkListener(myProject, docInfo.docProvider, docInfo.context);
+ JComponent label = HintUtil.createInformationLabel(docInfo.text, listener);
+ final LightweightHint hint = new LightweightHint(label);
+ final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
+ Point p = HintManagerImpl.getHintPosition(hint, myEditor, myPosition, HintManager.ABOVE);
+ hintManager.showEditorHint(hint, myEditor, p,
+ HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING,
+ 0, false, HintManagerImpl.createHintHint(myEditor, p, hint, HintManager.ABOVE).setContentActive(false));
}
}
@@ -662,4 +672,52 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
return myStoredInfo;
}
}
+
+ private static class DocInfo {
+
+ public static final DocInfo EMPTY = new DocInfo(null, null, null);
+
+ @Nullable public final String text;
+ @Nullable public final DocumentationProvider docProvider;
+ @Nullable public final PsiElement context;
+
+ DocInfo(@Nullable String text, @Nullable DocumentationProvider provider, @Nullable PsiElement context) {
+ this.text = text;
+ docProvider = provider;
+ this.context = context;
+ }
+ }
+
+ private static class QuickDocHyperlinkListener implements HyperlinkListener {
+
+ @NotNull private final Project myProject;
+ @NotNull private final DocumentationProvider myProvider;
+ @NotNull private final PsiElement myContext;
+
+ QuickDocHyperlinkListener(@NotNull Project project, @NotNull DocumentationProvider provider, @NotNull PsiElement context) {
+ myProject = project;
+ myProvider = provider;
+ myContext = context;
+ }
+
+ @Override
+ public void hyperlinkUpdate(@NotNull HyperlinkEvent e) {
+ if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
+ return;
+ }
+
+ String description = e.getDescription();
+ if (StringUtil.isEmpty(description) || !description.startsWith(DocumentationManager.PSI_ELEMENT_PROTOCOL)) {
+ return;
+ }
+
+ String elementName = e.getDescription().substring(DocumentationManager.PSI_ELEMENT_PROTOCOL.length());
+
+ final PsiElement targetElement = myProvider.getDocumentationElementForLink(PsiManager.getInstance(myProject), elementName, myContext);
+ if (targetElement != null) {
+ ApplicationManager.getApplication().getComponent(IdeTooltipManager.class).hideCurrentNow(false);
+ DocumentationManager.getInstance(myProject).showJavaDocInfo(targetElement, myContext, true, null);
+ }
+ }
+ }
}
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 e123688ec328..d048ba4c5f11 100644
--- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java
+++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.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.
@@ -23,11 +23,15 @@ import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleColoredText;
import com.intellij.util.ui.UIUtil;
import org.intellij.lang.annotations.JdkConstants;
+import org.jetbrains.annotations.NotNull;
+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.*;
public class HintUtil {
@@ -44,7 +48,11 @@ public class HintUtil {
private HintUtil() {
}
- public static JComponent createInformationLabel(String text) {
+ public static JComponent createInformationLabel(@NotNull String text) {
+ return createInformationLabel(text, null);
+ }
+
+ public static JComponent createInformationLabel(@NotNull String text, @Nullable HyperlinkListener listener) {
HintHint hintHint = new HintHint().setTextBg(INFORMATION_COLOR).setTextFg(Color.black).setFont(getBoldFont()).setAwtTooltip(true);
HintLabel label = new HintLabel();
@@ -59,6 +67,10 @@ public class HintUtil {
label.setOpaque(true);
}
+ if (listener != null) {
+ label.myPane.addHyperlinkListener(listener);
+ }
+
return label;
}
diff --git a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
index 26d92f9320dc..9a80da99d7f0 100644
--- a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
+++ b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
@@ -444,7 +444,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
return true;
}
- private void hideCurrentNow(boolean animationEnabled) {
+ public void hideCurrentNow(boolean animationEnabled) {
if (myCurrentTipUi != null) {
myCurrentTipUi.setAnimationEnabled(animationEnabled);
myCurrentTipUi.hide();
diff --git a/platform/util-rt/src/com/intellij/openapi/util/Pair.java b/platform/util-rt/src/com/intellij/openapi/util/Pair.java
index ce63e207fcfa..2057525a41cb 100644
--- a/platform/util-rt/src/com/intellij/openapi/util/Pair.java
+++ b/platform/util-rt/src/com/intellij/openapi/util/Pair.java
@@ -22,7 +22,7 @@ public class Pair {
public final A first;
public final B second;
- public static Pair create(A first, B second) {
+ public static Pair create(@Nullable A first, @Nullable B second) {
return new Pair(first, second);
}
@@ -52,15 +52,17 @@ public class Pair {
return EMPTY;
}
- public Pair(A first, B second) {
+ public Pair(@Nullable A first, @Nullable B second) {
this.first = first;
this.second = second;
}
-
+
+ @Nullable
public final A getFirst() {
return first;
}
+ @Nullable
public final B getSecond() {
return second;
}