IDEA-219354 Inspection text cutoff in error popup

GitOrigin-RevId: b3b0791d8af0ffb193854ae8c7be5caee19b8551
This commit is contained in:
Dmitry Batrak
2019-08-22 01:50:10 +03:00
committed by intellij-monorepo-bot
parent ea957aee53
commit fa1cd9c489
6 changed files with 110 additions and 23 deletions
@@ -96,10 +96,11 @@ internal class DaemonTooltipWithActionRenderer(text: String?,
hintHint: HintHint,
newLayout: Boolean,
highlightActions: Boolean,
limitWidthToScreen: Boolean,
tooltipReloader: TooltipReloader?): LightweightHint {
return super.createHint(editor, p, alignToRight, group, hintHint, newLayout,
highlightActions || !(isShowActions() && tooltipAction != null && hintHint.isAwtTooltip),
tooltipReloader)
limitWidthToScreen, tooltipReloader)
}
override fun fillPanel(editor: Editor,
@@ -4,6 +4,7 @@ package com.intellij.codeInsight.documentation;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.ui.WidthBasedLayout;
import com.intellij.codeInsight.lookup.LookupEx;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.icons.AllIcons;
@@ -107,7 +108,7 @@ import java.net.URL;
import java.util.List;
import java.util.*;
public class DocumentationComponent extends JPanel implements Disposable, DataProvider {
public class DocumentationComponent extends JPanel implements Disposable, DataProvider, WidthBasedLayout {
private static final Logger LOG = Logger.getInstance(DocumentationComponent.class);
private static final String DOCUMENTATION_TOPIC_ID = "reference.toolWindows.Documentation";
@@ -876,6 +877,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
return new Dimension(width, height);
}
@Override
public int getPreferredWidth() {
int minWidth = JBUIScale.scale(300);
int maxWidth = getPopupAnchor() != null ? JBUIScale.scale(435) : MAX_DEFAULT.width;
@@ -891,6 +893,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
return Math.min(maxWidth, Math.max(minWidth, width)) + insets.left + insets.right;
}
@Override
public int getPreferredHeight(int width) {
myEditorPane.setBounds(0, 0, width, MAX_DEFAULT.height);
myEditorPane.setText(myDecoratedText);
@@ -11,6 +11,7 @@ import com.intellij.codeInsight.documentation.QuickDocUtil;
import com.intellij.codeInsight.hint.LineTooltipRenderer;
import com.intellij.codeInsight.hint.TooltipGroup;
import com.intellij.codeInsight.hint.TooltipRenderer;
import com.intellij.ui.WidthBasedLayout;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.openapi.Disposable;
@@ -508,7 +509,7 @@ public final class EditorMouseHoverPopupManager implements Disposable {
Ref<LightweightHint> mockHintRef = new Ref<>();
HintHint hintHint = new HintHint().setAwtTooltip(true).setRequestFocus(requestFocus);
LightweightHint hint =
renderer.createHint(editor, new Point(), false, EDITOR_INFO_GROUP, hintHint, true, highlightActions, expand -> {
renderer.createHint(editor, new Point(), false, EDITOR_INFO_GROUP, hintHint, true, highlightActions, false, expand -> {
LineTooltipRenderer newRenderer = renderer.createRenderer(renderer.getText(), expand ? 1 : 0);
JComponent newComponent = createHighlightInfoComponent(editor, newRenderer, highlightActions, popupBridge, requestFocus);
AbstractPopup popup = popupBridge.getPopup();
@@ -523,7 +524,9 @@ public final class EditorMouseHoverPopupManager implements Disposable {
if (hint == null) return null;
mockHintRef.set(hint);
bindHintHiding(hint, popupBridge);
WrapperPanel wrapper = new WrapperPanel(hint.getComponent());
JComponent component = hint.getComponent();
LOG.assertTrue(component instanceof WidthBasedLayout, "Unexpected type of tooltip component: " + component.getClass());
WrapperPanel wrapper = new WrapperPanel(component);
wrapperPanelRef.set(wrapper);
// emulating LightweightHint+IdeTooltipManager+BalloonImpl - they use the same background
wrapper.setBackground(hintHint.getTextBackground());
@@ -671,7 +674,7 @@ public final class EditorMouseHoverPopupManager implements Disposable {
}
}
private static class WrapperPanel extends JPanel {
private static class WrapperPanel extends JPanel implements WidthBasedLayout {
private WrapperPanel(JComponent content) {
super(new BorderLayout());
setBorder(null);
@@ -682,6 +685,20 @@ public final class EditorMouseHoverPopupManager implements Disposable {
removeAll();
add(content, BorderLayout.CENTER);
}
private JComponent getComponent() {
return (JComponent)getComponent(0);
}
@Override
public int getPreferredWidth() {
return WidthBasedLayout.getPreferredWidth(getComponent());
}
@Override
public int getPreferredHeight(int width) {
return WidthBasedLayout.getPreferredHeight(getComponent(), width);
}
}
private static class CombinedPopupLayout implements LayoutManager {
@@ -701,11 +718,12 @@ public final class EditorMouseHoverPopupManager implements Disposable {
@Override
public Dimension preferredLayoutSize(Container parent) {
Dimension d1 = highlightInfoComponent == null ? new Dimension() : highlightInfoComponent.getPreferredSize();
int w2 = quickDocComponent == null ? 0 : quickDocComponent.getPreferredWidth();
int preferredWidth = Math.min(JBUI.scale(MAX_POPUP_WIDTH), Math.max(d1.width, w2));
int h2 = quickDocComponent == null ? 0 : quickDocComponent.getPreferredHeight(preferredWidth);
return new Dimension(preferredWidth, d1.height + h2);
int w1 = WidthBasedLayout.getPreferredWidth(highlightInfoComponent);
int w2 = WidthBasedLayout.getPreferredWidth(quickDocComponent);
int preferredWidth = Math.min(JBUI.scale(MAX_POPUP_WIDTH), Math.max(w1, w2));
int h1 = WidthBasedLayout.getPreferredHeight(highlightInfoComponent, preferredWidth);
int h2 = WidthBasedLayout.getPreferredHeight(quickDocComponent, preferredWidth);
return new Dimension(preferredWidth, h1 + h2);
}
@Override
@@ -719,11 +737,15 @@ public final class EditorMouseHoverPopupManager implements Disposable {
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
int h1 = highlightInfoComponent == null ? 0 : Math.min(height, highlightInfoComponent.getPreferredSize().height);
if (highlightInfoComponent != null) {
highlightInfoComponent.setBounds(0, 0, width, h1);
if (highlightInfoComponent == null) {
if (quickDocComponent != null) quickDocComponent.setBounds(0, 0, width, height);
}
if (quickDocComponent != null) {
else if (quickDocComponent == null) {
highlightInfoComponent.setBounds(0, 0, width, height);
}
else {
int h1 = Math.min(height, highlightInfoComponent.getPreferredSize().height);
highlightInfoComponent.setBounds(0, 0, width, h1);
quickDocComponent.setBounds(0, h1, width, height - h1);
}
}
@@ -79,7 +79,32 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
boolean newLayout,
boolean highlightActions,
boolean hasSeparators) {
JPanel grid = new JPanel(new GridBagLayout()) {
int leftBorder = newLayout ? 10 : 8;
int rightBorder = 12;
class MyPanel extends JPanel implements WidthBasedLayout {
private MyPanel() {
super(new GridBagLayout());
}
@Override
public int getPreferredWidth() {
return getPreferredSize().width;
}
@Override
public int getPreferredHeight(int width) {
Dimension size = editorPane.getSize();
editorPane.setSize(width - leftBorder - rightBorder, Math.max(1, size.height));
int height;
try {
height = getPreferredSize().height;
}
finally {
editorPane.setSize(size);
}
return height;
}
@Override
public AccessibleContext getAccessibleContext() {
return new AccessibleContextDelegate(editorPane.getAccessibleContext()) {
@@ -89,7 +114,8 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
}
};
}
};
}
JPanel grid = new MyPanel();
GridBag bag = new GridBag()
.anchor(GridBagConstraints.CENTER)
//weight is required for correct working scrollpane inside gridbaglayout
@@ -98,9 +124,9 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
.fillCell();
pane.setBorder(JBUI.Borders.empty(newLayout ? 10 : 6,
newLayout ? 10 : 8,
leftBorder,
newLayout ? (highlightActions ? 10 : (hasSeparators ? 8 : 3)) : 6,
12));
rightBorder));
grid.add(pane, bag);
grid.setBackground(hintHint.getTextBackground());
grid.setBorder(JBUI.Borders.empty());
@@ -115,7 +141,8 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
final boolean alignToRight,
@NotNull final TooltipGroup group,
@NotNull final HintHint hintHint) {
LightweightHint hint = createHint(editor, p, alignToRight, group, hintHint, Registry.is("editor.new.mouse.hover.popups"), true, null);
LightweightHint hint = createHint(editor, p, alignToRight, group, hintHint, Registry.is("editor.new.mouse.hover.popups"), true, true,
null);
if (hint != null) {
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, HintManager.HIDE_BY_ANY_KEY |
HintManager.HIDE_BY_TEXT_CHANGE |
@@ -132,6 +159,7 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
@NotNull final HintHint hintHint,
boolean newLayout,
boolean highlightActions,
boolean limitWidthToScreen,
@Nullable TooltipReloader tooltipReloader) {
if (myText == null) return null;
@@ -148,7 +176,8 @@ public class LineTooltipRenderer extends ComparableObject.Impl implements Toolti
final JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
String textToDisplay = newLayout ? colorizeSeparators(dressedText) : dressedText;
JEditorPane editorPane = IdeTooltipManager.initPane(new Html(textToDisplay).setKeepFont(true), hintHint, layeredPane);
JEditorPane editorPane = IdeTooltipManager.initPane(new Html(textToDisplay).setKeepFont(true), hintHint, layeredPane,
limitWidthToScreen);
editorPane.putClientProperty(UIUtil.TEXT_COPY_ROOT, Boolean.TRUE);
hintHint.setContentActive(isContentAction(dressedText));
if (!hintHint.isAwtTooltip()) {
@@ -675,11 +675,16 @@ public final class IdeTooltipManager implements Disposable, AWTEventListener {
}
public static JEditorPane initPane(@NonNls Html html, final HintHint hintHint, @Nullable final JLayeredPane layeredPane) {
return initPane(html, hintHint, layeredPane, true);
}
public static JEditorPane initPane(@NonNls Html html, final HintHint hintHint, @Nullable final JLayeredPane layeredPane,
boolean limitWidthToScreen) {
final Ref<Dimension> prefSize = new Ref<>(null);
@NonNls String text = HintUtil.prepareHintText(html, hintHint);
final boolean[] prefSizeWasComputed = {false};
final JEditorPane pane = new JEditorPane() {
final JEditorPane pane = limitWidthToScreen ? new JEditorPane() {
@Override
public Dimension getPreferredSize() {
if (!prefSizeWasComputed[0] && hintHint.isAwtTooltip()) {
@@ -706,7 +711,7 @@ public final class IdeTooltipManager implements Disposable, AWTEventListener {
setSize(new Dimension(fitWidth, Integer.MAX_VALUE));
Dimension fixedWidthSize = super.getPreferredSize();
Dimension minSize = super.getMinimumSize();
prefSize.set(new Dimension(fitWidth > minSize.width ? fitWidth : minSize.width, fixedWidthSize.height));
prefSize.set(new Dimension(Math.max(fitWidth, minSize.width), fixedWidthSize.height));
}
else {
prefSize.set(new Dimension(prefSizeOriginal));
@@ -726,7 +731,7 @@ public final class IdeTooltipManager implements Disposable, AWTEventListener {
super.setPreferredSize(preferredSize);
prefSize.set(preferredSize);
}
};
} : new JEditorPane();
HTMLEditorKit kit = new JBHtmlEditorKit() {
final HTMLFactory factory = new HTMLFactory() {
@@ -787,6 +792,8 @@ public final class IdeTooltipManager implements Disposable, AWTEventListener {
pane.setOpaque(opaque);
pane.setBackground(hintHint.getTextBackground());
if (!limitWidthToScreen) AppUIUtil.targetToDevice(pane, layeredPane);
return pane;
}
@@ -0,0 +1,25 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui;
import java.awt.*;
/**
* This interface is supposed to be implemented by Swing components, for which preferred width and height are not independent. Example is a
* text component where text is broken into lines according to available width. Laying out such a component usually implies calculating its
* preferred width, then calculating actual width to use (e.g. by fitting it to horizontal space, available to the parent component), and
* finally calculating the component preferred height, based on the chosen width. *
*/
public interface WidthBasedLayout {
int getPreferredWidth();
int getPreferredHeight(int width);
static int getPreferredWidth(Component component) {
return component == null ? 0 : component instanceof WidthBasedLayout ? ((WidthBasedLayout)component).getPreferredWidth()
: component.getPreferredSize().width;
}
static int getPreferredHeight(Component component, int width) {
return component == null ? 0 : component instanceof WidthBasedLayout ? ((WidthBasedLayout)component).getPreferredHeight(width)
: component.getPreferredSize().height;
}
}