diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index b340f458c38e..c8e8ed97e9e5 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -43,6 +43,7 @@ import java.util.Map; * * @author Vladimir Kondratyev */ +@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext", "FieldAccessedSynchronizedAndUnsynchronized", "UnusedDeclaration"}) public class SimpleColoredComponent extends JComponent implements Accessible { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.SimpleColoredComponent"); public static final Color STYLE_SEARCH_MATCH_BACKGROUND = new Color(250, 250, 250, 140); @@ -78,7 +79,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { * if the component represents a selected item in a focused JList. * Border can be null. */ - private MyBorder myBorder; + private Border myBorder; private int myMainTextLastIndex = -1; @@ -107,6 +108,8 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Appends string fragments to existing ones. Appended string * will have specified attributes. + * @param fragment text fragment + * @param attributes text attributes */ public final void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes) { append(fragment, attributes, myMainTextLastIndex < 0); @@ -115,17 +118,22 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Appends string fragments to existing ones. Appended string * will have specified attributes. + * @param fragment text fragment + * @param attributes text attributes + * @param isMainText main text of not */ public void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, boolean isMainText) { - synchronized (this) { - myFragments.add(fragment); - myAttributes.add(attributes); - if (isMainText) { - myMainTextLastIndex = myFragments.size() - 1; - } - } + _append(fragment, attributes, isMainText); revalidateAndRepaint(); } + + private synchronized void _append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, boolean isMainText) { + myFragments.add(fragment); + myAttributes.add(attributes); + if (isMainText) { + myMainTextLastIndex = myFragments.size() - 1; + } + } private void revalidateAndRepaint() { if (myAutoInvalidate) { @@ -136,19 +144,21 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } public void append(@NotNull final String fragment, @NotNull final SimpleTextAttributes attributes, Object tag) { - synchronized (this) { - append(fragment, attributes); - if (myFragmentTags == null) { - myFragmentTags = new ArrayList(); - } - while(myFragmentTags.size() < myFragments.size()-1) { - myFragmentTags.add(null); - } - myFragmentTags.add(tag); - } + _append(fragment, attributes, tag); revalidateAndRepaint(); } + private synchronized void _append(String fragment, SimpleTextAttributes attributes, Object tag) { + append(fragment, attributes); + if (myFragmentTags == null) { + myFragmentTags = new ArrayList(); + } + while(myFragmentTags.size() < myFragments.size()-1) { + myFragmentTags.add(null); + } + myFragmentTags.add(tag); + } + public synchronized void appendAlign(int alignWidth) { final int alignIndex = myFragments.size()-1; myAligns.put(alignIndex, alignWidth); @@ -159,18 +169,20 @@ public class SimpleColoredComponent extends JComponent implements Accessible { * They are icon, text fragments and their attributes, "paint focus border". */ public void clear() { - synchronized (this) { - myIcon = null; - myPaintFocusBorder = false; - myFragments.clear(); - myAttributes.clear(); - myFragmentTags = null; - myMainTextLastIndex = -1; - myAligns.clear(); - } + _clear(); revalidateAndRepaint(); } + private synchronized void _clear() { + myIcon = null; + myPaintFocusBorder = false; + myFragments.clear(); + myAttributes.clear(); + myFragmentTags = null; + myMainTextLastIndex = -1; + myAligns.clear(); + } + /** * @return component's icon. This method returns null * if there is no icon. @@ -181,6 +193,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Sets a new component icon + * @param icon icon */ public final void setIcon(final @Nullable Icon icon) { myIcon = icon; @@ -196,6 +209,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Sets specified internal paddings + * @param ipad insets */ public void setIpad(final Insets ipad) { myIpad = ipad; @@ -213,6 +227,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Sets a new gap between icon and text * + * @param iconTextGap the gap between text and icon * @throws java.lang.IllegalArgumentException * if the iconTextGap * has a negative value @@ -226,16 +241,17 @@ public class SimpleColoredComponent extends JComponent implements Accessible { revalidateAndRepaint(); } - public MyBorder getMyBorder() { + public Border getMyBorder() { return myBorder; } - public void setMyBorder(@Nullable MyBorder border) { + public void setMyBorder(@Nullable Border border) { myBorder = border; } /** * Sets whether focus border is painted or not + * @param paintFocusBorder true or false */ protected final void setPaintFocusBorder(final boolean paintFocusBorder) { myPaintFocusBorder = paintFocusBorder; @@ -246,6 +262,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { /** * Sets whether focus border extends to icon or not. If so then * component also extends the selection. + * @param focusBorderAroundIcon true or false */ protected final void setFocusBorderAroundIcon(final boolean focusBorderAroundIcon) { myFocusBorderAroundIcon = focusBorderAroundIcon; @@ -274,6 +291,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { return computePreferredSize(false); } + @Nullable public synchronized Object getFragmentTag(int index) { if (myFragmentTags != null && index < myFragmentTags.size()) { return myFragmentTags.get(index); @@ -368,7 +386,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { protected void paintComponent(final Graphics g) { try { - doPaint(g); + _doPaint(g); } catch (RuntimeException e) { LOG.error(logSwingPath(), e); @@ -376,55 +394,67 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } } - protected synchronized void doPaint(final Graphics g) { + private synchronized void _doPaint(final Graphics g) { checkCanPaint(g); - int xOffset = 0; - - // Paint icon and its background - final Icon icon = myIcon; // guard against concurrent modification (IDEADEV-12635) + doPaint((Graphics2D)g); + } + + protected void doPaint(final Graphics2D g) { + int offset = 0; + final Icon icon = myIcon; // guard against concurrent modification (IDEADEV-12635) if (icon != null) { - final Container parent = getParent(); - Color iconBackgroundColor = null; - if (isOpaque() || isIconOpaque()) { - if (parent != null && !myFocusBorderAroundIcon && !UIUtil.isFullRowSelectionLAF()) { - iconBackgroundColor = parent.getBackground(); - } - else { - iconBackgroundColor = getBackground(); - } - } - - if (iconBackgroundColor != null) { - g.setColor(iconBackgroundColor); - g.fillRect(0, 0, icon.getIconWidth() + myIpad.left + myIconTextGap, getHeight()); - } - - paintIcon(g, icon); - - xOffset += myIpad.left + icon.getIconWidth() + myIconTextGap; + doPaintIcon(g, icon); + offset += myIpad.left + icon.getIconWidth() + myIconTextGap; } + doPaintTextBackground(g, offset); + doPaintText(g, offset, myFocusBorderAroundIcon || icon == null); + } + + + protected void doPaintTextBackground(Graphics2D g, int offset) { if (isOpaque() || shouldDrawBackground()) { - // Paint text background g.setColor(getBackground()); - g.fillRect(xOffset, 0, getWidth() - xOffset, getHeight()); + g.fillRect(offset, 0, getWidth() - offset, getHeight()); + } + } + + protected void doPaintIcon(Graphics2D g, Icon icon) { + final Container parent = getParent(); + Color iconBackgroundColor = null; + if (isOpaque() || isIconOpaque()) { + if (parent != null && !myFocusBorderAroundIcon && !UIUtil.isFullRowSelectionLAF()) { + iconBackgroundColor = parent.getBackground(); + } + else { + iconBackgroundColor = getBackground(); + } } + if (iconBackgroundColor != null) { + g.setColor(iconBackgroundColor); + g.fillRect(0, 0, icon.getIconWidth() + myIpad.left + myIconTextGap, getHeight()); + } + + paintIcon(g, icon); + } + + protected int doPaintText(Graphics2D g, int offset, boolean focusAroundIcon) { // If there is no icon, then we have to add left internal padding - if (xOffset == 0) { - xOffset = myIpad.left; + if (offset == 0) { + offset = myIpad.left; } - int textStart = xOffset; + int textStart = offset; if (myBorder != null) { - xOffset += myBorder.getBorderInsets(this).left; + offset += myBorder.getBorderInsets(this).left; } final List searchMatches = new ArrayList(); - - // Paint text + UIUtil.applyRenderingHints(g); applyAdditionalHints(g); + for (int i = 0; i < myFragments.size(); i++) { final SimpleTextAttributes attributes = myAttributes.get(i); Font font = g.getFont(); @@ -440,7 +470,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { final Color bgColor = attributes.getBgColor(); if (isOpaque() && bgColor != null) { g.setColor(bgColor); - g.fillRect(xOffset, 0, fragmentWidth, getHeight()); + g.fillRect(offset, 0, fragmentWidth, getHeight()); } Color color = attributes.getFgColor(); @@ -457,17 +487,17 @@ public class SimpleColoredComponent extends JComponent implements Accessible { if (!attributes.isSearchMatch()) { if (shouldDrawMacShadow()) { g.setColor(STYLE_SEARCH_MATCH_BACKGROUND); - g.drawString(fragment, xOffset, textBaseline + 1); + g.drawString(fragment, offset, textBaseline + 1); } - + g.setColor(color); - g.drawString(fragment, xOffset, textBaseline); + g.drawString(fragment, offset, textBaseline); } // 1. Strikeout effect if (attributes.isStrikeout()) { final int strikeOutAt = textBaseline + (metrics.getDescent() - metrics.getAscent()) / 2; - UIUtil.drawLine(g, xOffset, strikeOutAt, xOffset + fragmentWidth, strikeOutAt); + UIUtil.drawLine(g, offset, strikeOutAt, offset + fragmentWidth, strikeOutAt); } // 2. Waved effect if (attributes.isWaved()) { @@ -475,7 +505,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { g.setColor(attributes.getWaveColor()); } final int wavedAt = textBaseline + 1; - for (int x = xOffset; x <= xOffset + fragmentWidth; x += 4) { + for (int x = offset; x <= offset + fragmentWidth; x += 4) { UIUtil.drawLine(g, x, wavedAt, x + 2, wavedAt + 2); UIUtil.drawLine(g, x + 3, wavedAt + 1, x + 4, wavedAt); } @@ -483,41 +513,40 @@ public class SimpleColoredComponent extends JComponent implements Accessible { // 3. Underline if (attributes.isUnderline()) { final int underlineAt = textBaseline + 1; - UIUtil.drawLine(g, xOffset, underlineAt, xOffset + fragmentWidth, underlineAt); + UIUtil.drawLine(g, offset, underlineAt, offset + fragmentWidth, underlineAt); } // 4. Bold Dotted Line if (attributes.isBoldDottedLine()) { final int dottedAt = SystemInfo.isMac ? textBaseline : textBaseline + 1; final Color lineColor = attributes.getWaveColor(); - UIUtil.drawBoldDottedLine((Graphics2D)g, xOffset, xOffset + fragmentWidth, dottedAt, bgColor, lineColor, isOpaque()); + UIUtil.drawBoldDottedLine(g, offset, offset + fragmentWidth, dottedAt, bgColor, lineColor, isOpaque()); } if (attributes.isSearchMatch()) { - searchMatches.add(new Object[] {xOffset, xOffset + fragmentWidth, textBaseline, fragment, g.getFont()}); + searchMatches.add(new Object[] {offset, offset + fragmentWidth, textBaseline, fragment, g.getFont()}); } final Integer fixedWidth = myAligns.get(i); if (fixedWidth != null && fragmentWidth < fixedWidth.intValue()) { - //if (fixedWidth != null) { - xOffset += fixedWidth.intValue(); + //if (fixedWidth != null) { + offset += fixedWidth.intValue(); } else { - xOffset += fragmentWidth; + offset += fragmentWidth; } } // Paint focus border around the text and icon (if necessary) if (myPaintFocusBorder && myBorder != null) { - if (myFocusBorderAroundIcon || icon == null) { + if (focusAroundIcon) { myBorder.paintBorder(this, g, 0, 0, getWidth(), getHeight()); - } - else { + } else { myBorder.paintBorder(this, g, textStart, 0, getWidth() - textStart, getHeight()); } } // draw search matches after all for (final Object[] info: searchMatches) { - UIUtil.drawSearchMatch((Graphics2D)g, (Integer) info[0], (Integer) info[1], getHeight()); + UIUtil.drawSearchMatch(g, (Integer) info[0], (Integer) info[1], getHeight()); g.setFont((Font) info[4]); if (shouldDrawMacShadow()) { @@ -528,8 +557,9 @@ public class SimpleColoredComponent extends JComponent implements Accessible { g.setColor(new Color(50, 50, 50)); g.drawString((String) info[3], (Integer) info[0], (Integer) info[2]); } + return offset; } - + protected boolean shouldDrawMacShadow() { return false; } @@ -583,8 +613,8 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } protected void setBorderInsets(Insets insets) { - if (myBorder != null) { - myBorder.setInsets(insets); + if (myBorder instanceof MyBorder) { + ((MyBorder)myBorder).setInsets(insets); } revalidateAndRepaint(); @@ -617,7 +647,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { @Override public String toString() { - StringBuffer result = new StringBuffer(); + final StringBuilder result = new StringBuilder(); for (String each : myFragments) { result.append(each); } @@ -662,6 +692,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { return 0; } + @Nullable @Override public Accessible getAccessibleChild(int i) { return null;