package org.chartsy.main.utils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.LabelUI;
import org.openide.util.Exceptions;
/**
*
* @author Viorel
*/
public class HtmlLabelUI extends LabelUI
{
private static final boolean antialias
= Boolean.getBoolean("nb.cellrenderer.antialiasing")
||Boolean.getBoolean("swing.aatext")
||(isGTK() && gtkShouldAntialias())
|| isAqua();
private static HtmlLabelUI uiInstance;
private static int FIXED_HEIGHT;
static
{
String ht = System.getProperty("nb.cellrenderer.fixedheight");
if (ht != null)
{
try
{
FIXED_HEIGHT = Integer.parseInt(ht);
}
catch (Exception e)
{}
}
}
private static Map<Object,Object> hintsMap;
private static Color unfocusedSelBg;
private static Color unfocusedSelFg;
private static Boolean gtkAA;
public static ComponentUI createUI(JComponent c)
{
assert c instanceof HtmlRendererImpl;
if (uiInstance == null)
uiInstance = new HtmlLabelUI();
return uiInstance;
}
public @Override Dimension getPreferredSize(JComponent c)
{
return calcPreferredSize((HtmlRendererImpl) c);
}
private static int textWidth(String text, Graphics g, Font f, boolean html)
{
if (text != null)
{
if (html)
return Math.round(Math.round(Math.ceil(
HtmlRenderer.renderHTML
(text, g, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, f,
Color.BLACK, HtmlRenderer.STYLE_CLIP, false))));
else
return Math.round(Math.round(Math.ceil(
HtmlRenderer.renderPlainString
(text, g, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, f,
Color.BLACK, HtmlRenderer.STYLE_CLIP, false))));
}
else
{
return 0;
}
}
private Dimension calcPreferredSize(HtmlRendererImpl r)
{
Insets ins = r.getInsets();
Dimension prefSize = new java.awt.Dimension(ins.left + ins.right, ins.top + ins.bottom);
String text = r.getText();
Graphics g = r.getGraphics();
Icon icon = r.getIcon();
if (text != null)
{
FontMetrics fm = g.getFontMetrics(r.getFont());
prefSize.height += (fm.getMaxAscent() + fm.getMaxDescent());
}
if (icon != null)
{
if (r.isCentered())
{
prefSize.height += (icon.getIconHeight() + r.getIconTextGap());
prefSize.width += icon.getIconWidth();
}
else
{
prefSize.height = Math.max(icon.getIconHeight() + ins.top + ins.bottom, prefSize.height);
prefSize.width += (icon.getIconWidth() + r.getIconTextGap());
}
}
((Graphics2D) g).addRenderingHints(getHints());
int textwidth = textWidth(text, g, r.getFont(), r.isHtml()) + 4;
if (r.isCentered())
prefSize.width = Math.max(prefSize.width, textwidth + ins.right + ins.left);
else
prefSize.width += (textwidth + r.getIndent());
if (FIXED_HEIGHT > 0)
prefSize.height = FIXED_HEIGHT;
return prefSize;
}
@SuppressWarnings("unchecked")
static final Map<?,?> getHints()
{
if (hintsMap == null)
{
hintsMap = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"));
if (hintsMap == null)
{
hintsMap = new HashMap<Object,Object>();
if (antialias)
hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
}
Map<?,?> ret = hintsMap;
assert ret != null;
return ret;
}
public @Override void update(Graphics g, JComponent c)
{
Color bg = getBackgroundFor((HtmlRendererImpl) c);
HtmlRendererImpl h = (HtmlRendererImpl) c;
if (bg != null)
{
int x = h.isSelected() ? ((h.getIcon() == null)
? 0
: (h.getIcon().getIconWidth() + h.getIconTextGap())) : 0;
x += h.getIndent();
g.setColor(bg);
g.fillRect(x, 0, c.getWidth() - x, c.getHeight());
}
if (h.isLeadSelection())
{
Color focus = UIManager.getColor("Tree.selectionBorderColor");
if ((focus == null)
|| focus.equals(bg))
focus = Color.BLUE;
if (!isGTK()
&& !isAqua()
&& !isNimbus())
{
int x = ((h.getIcon() == null)
? 0
: (h.getIcon().getIconWidth() + h.getIconTextGap()));
g.setColor(focus);
g.drawRect(x, 0, c.getWidth() - (x + 1), c.getHeight() - 1);
}
}
paint(g, c);
}
public @Override void paint(Graphics g, JComponent c)
{
((Graphics2D) g).addRenderingHints(getHints());
HtmlRendererImpl r = (HtmlRendererImpl) c;
if (r.isCentered())
paintIconAndTextCentered(g, r);
else
paintIconAndText(g, r);
}
private void paintIconAndText(Graphics g, HtmlRendererImpl r)
{
Font f = r.getFont();
g.setFont(f);
FontMetrics fm = g.getFontMetrics();
int txtH = fm.getMaxAscent() + fm.getMaxDescent();
Insets ins = r.getInsets();
int rHeight = r.getHeight();
int availH = rHeight - (ins.top + ins.bottom);
int txtY;
if (availH >= txtH)
txtY = (txtH + ins.top + ((availH / 2) - (txtH / 2))) - fm.getMaxDescent();
else if (r.getHeight() > txtH)
txtY = txtH + (rHeight - txtH) / 2 - fm.getMaxDescent();
else
txtY = fm.getMaxAscent();
int txtX = r.getIndent();
Icon icon = r.getIcon();
if ((icon != null)
&& (icon.getIconWidth() > 0)
&& (icon.getIconHeight() > 0))
{
int iconY;
if (availH > icon.getIconHeight())
iconY = ins.top + ((availH / 2) - (icon.getIconHeight() / 2)); // + 2;
else if (availH == icon.getIconHeight())
iconY = 0;
else
iconY = ins.top;
int iconX = ins.left + r.getIndent() + 1;
try
{
icon.paintIcon(r, g, iconX, iconY);
}
catch (NullPointerException npe)
{
Exceptions.attachMessage(npe, "Probably an ImageIcon with a null source image: "
+ icon + " - " + r.getText());
Exceptions.printStackTrace(npe);
}
txtX = iconX + icon.getIconWidth() + r.getIconTextGap();
}
else
{
txtX += ins.left;
}
String text = r.getText();
if (text == null)
return;
int txtW = (icon != null)
? (r.getWidth() - (ins.left + ins.right + icon.getIconWidth() + r.getIconTextGap() + r.getIndent()))
: (r.getWidth() - (ins.left + ins.right + r.getIndent()));
Color background = getBackgroundFor(r);
Color foreground = ensureContrastingColor(getForegroundFor(r), background);
if (r.isHtml())
HtmlRenderer._renderHTML(text, 0, g, txtX, txtY, txtW, txtH, f, foreground, r.getRenderStyle(), true, background);
else
HtmlRenderer.renderPlainString(text, g, txtX, txtY, txtW, txtH, f, foreground, r.getRenderStyle(), true);
}
private void paintIconAndTextCentered(Graphics g, HtmlRendererImpl r)
{
Insets ins = r.getInsets();
Icon ic = r.getIcon();
int w = r.getWidth() - (ins.left + ins.right);
int txtX = ins.left;
int txtY = 0;
if ((ic != null)
&& (ic.getIconWidth() > 0)
&& (ic.getIconHeight() > 0))
{
int iconx = (w > ic.getIconWidth()) ? ((w / 2) - (ic.getIconWidth() / 2)) : txtX;
int icony = 0;
ic.paintIcon(r, g, iconx, icony);
txtY += (ic.getIconHeight() + r.getIconTextGap());
}
int txtW = r.getPreferredSize().width;
txtX = (txtW < r.getWidth()) ? ((r.getWidth() / 2) - (txtW / 2)) : 0;
int txtH = r.getHeight() - txtY;
Font f = r.getFont();
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
txtY += fm.getMaxAscent();
Color background = getBackgroundFor(r);
Color foreground = ensureContrastingColor(getForegroundFor(r), background);
if (r.isHtml())
HtmlRenderer._renderHTML
(r.getText(), 0, g, txtX, txtY, txtW, txtH, f,
foreground, r.getRenderStyle(), true, background);
else
HtmlRenderer.renderString
(r.getText(), g, txtX, txtY, txtW, txtH, r.getFont(),
foreground, r.getRenderStyle(), true);
}
static Color ensureContrastingColor(Color fg, Color bg)
{
if (bg == null)
{
if (isNimbus())
{
bg = Color.WHITE;
}
else
{
bg = UIManager.getColor("text");
if (bg == null)
bg = Color.WHITE;
}
}
if (fg == null)
{
if (isNimbus())
{
fg = Color.BLACK;
}
else
{
fg = UIManager.getColor("textText");
if (fg == null)
fg = Color.BLACK;
}
}
if (Color.BLACK.equals(fg)
&& Color.WHITE.equals(fg))
return fg;
boolean replace = fg.equals(bg);
int dif = 0;
if (!replace)
{
dif = difference(fg, bg);
replace = dif < 80;
}
if (replace)
{
int lum = luminance(bg);
boolean darker = lum >= 128;
if (darker)
fg = Color.BLACK;
else
fg = Color.WHITE;
}
return fg;
}
private static int difference(Color a, Color b)
{
return Math.abs(luminance(a) - luminance(b));
}
private static int luminance(Color c)
{
return (299*c.getRed() + 587*c.getGreen() + 114*c.getBlue()) / 1000;
}
static Color getBackgroundFor(HtmlRendererImpl r)
{
if (r.isOpaque())
return r.getBackground();
if (r.isSelected()
&& !r.isParentFocused()
&& !isGTK()
&& !isNimbus())
return getUnfocusedSelectionBackground();
Color result = null;
if (r.isSelected())
{
switch (r.getType())
{
case LIST:
result = UIManager.getColor("List.selectionBackground");
if (result == null)
result = UIManager.getColor("Tree.selectionBackground");
break;
}
return (result == null)
? r.getBackground()
: result;
}
return null;
}
static Color getForegroundFor(HtmlRendererImpl r)
{
if (r.isSelected()
&& !r.isParentFocused()
&& !isGTK()
&& !isNimbus())
return getUnfocusedSelectionForeground();
if (!r.isEnabled())
return UIManager.getColor("textInactiveText");
Color result = null;
if (r.isSelected())
{
switch (r.getType())
{
case LIST:
result = UIManager.getColor("List.selectionForeground");
break;
}
}
return (result == null)
? r.getForeground()
: result;
}
public static boolean isAqua()
{
return "Aqua".equals(UIManager.getLookAndFeel().getID());
}
public static boolean isGTK()
{
return "GTK".equals(UIManager.getLookAndFeel().getID());
}
public static boolean isNimbus()
{
return "Nimbus".equals(UIManager.getLookAndFeel().getID());
}
private static Color getUnfocusedSelectionBackground()
{
if (unfocusedSelBg == null)
{
unfocusedSelBg = UIManager.getColor("nb.explorer.unfocusedSelBg");
if (unfocusedSelBg == null)
{
unfocusedSelBg = UIManager.getColor("controlShadow");
if (unfocusedSelBg == null)
unfocusedSelBg = Color.lightGray;
if (!Color.WHITE.equals(unfocusedSelBg.brighter()))
unfocusedSelBg = unfocusedSelBg.brighter();
}
}
return unfocusedSelBg;
}
private static Color getUnfocusedSelectionForeground()
{
if (unfocusedSelFg == null)
{
unfocusedSelFg = UIManager.getColor("nb.explorer.unfocusedSelFg");
if (unfocusedSelFg == null)
{
unfocusedSelFg = UIManager.getColor("textText");
if (unfocusedSelFg == null)
unfocusedSelFg = Color.BLACK;
}
}
return unfocusedSelFg;
}
public static final boolean gtkShouldAntialias()
{
if (gtkAA == null)
{
Object o = Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/Antialias");
gtkAA = new Integer(1).equals(o)
? Boolean.TRUE
: Boolean.FALSE;
}
return gtkAA.booleanValue();
}
}