1 19 20 package org.openide.awt; 21 22 23 import java.awt.Color ; 24 import java.awt.Dimension ; 25 import java.awt.Font ; 26 import java.awt.FontMetrics ; 27 import java.awt.Graphics ; 28 import java.awt.Graphics2D ; 29 import java.awt.Insets ; 30 import java.awt.RenderingHints ; 31 import java.awt.Toolkit ; 32 33 import java.util.HashMap ; 34 import java.util.Map ; 35 36 import javax.swing.Icon ; 37 import javax.swing.JComponent ; 38 import javax.swing.UIManager ; 39 import javax.swing.plaf.ComponentUI ; 40 import javax.swing.plaf.LabelUI ; 41 import org.openide.util.Exceptions; 42 43 47 class HtmlLabelUI extends LabelUI { 48 49 50 static final boolean AQUA = "Aqua".equals(UIManager.getLookAndFeel().getID()); 53 private static final boolean antialias = Boolean.getBoolean("nb.cellrenderer.antialiasing") ||Boolean.getBoolean("swing.aatext") ||(isGTK() && gtkShouldAntialias()) ||AQUA; 57 58 private static HtmlLabelUI uiInstance; 59 60 private static int FIXED_HEIGHT; 61 62 static { 63 String ht = System.getProperty("nb.cellrenderer.fixedheight"); 66 if (ht != null) { 67 try { 68 FIXED_HEIGHT = Integer.parseInt(ht); 69 } catch (Exception e) { 70 } 72 } 73 } 74 75 private static Map hintsMap; 76 private static Color unfocusedSelBg; 77 private static Color unfocusedSelFg; 78 private static Boolean gtkAA; 79 80 public static ComponentUI createUI(JComponent c) { 81 assert c instanceof HtmlRendererImpl; 82 83 if (uiInstance == null) { 84 uiInstance = new HtmlLabelUI(); 85 } 86 87 return uiInstance; 88 } 89 90 public Dimension getPreferredSize(JComponent c) { 91 return calcPreferredSize((HtmlRendererImpl) c); 92 } 93 94 95 private static int textWidth(String text, Graphics g, Font f, boolean html) { 96 if (text != null) { 97 if (html) { 98 return Math.round( 99 Math.round( 100 Math.ceil( 101 HtmlRenderer.renderHTML( 102 text, g, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, f, Color.BLACK, 103 HtmlRenderer.STYLE_CLIP, false 104 ) 105 ) 106 ) 107 ); 108 } else { 109 return Math.round( 110 Math.round( 111 Math.ceil( 112 HtmlRenderer.renderPlainString( 113 text, g, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, f, Color.BLACK, 114 HtmlRenderer.STYLE_CLIP, false 115 ) 116 ) 117 ) 118 ); 119 } 120 } else { 121 return 0; 122 } 123 } 124 125 private Dimension calcPreferredSize(HtmlRendererImpl r) { 126 Insets ins = r.getInsets(); 127 Dimension prefSize = new java.awt.Dimension (ins.left + ins.right, ins.top + ins.bottom); 128 String text = r.getText(); 129 130 Graphics g = r.getGraphics(); 131 Icon icon = r.getIcon(); 132 133 if (text != null) { 134 FontMetrics fm = g.getFontMetrics(r.getFont()); 135 prefSize.height += (fm.getMaxAscent() + fm.getMaxDescent()); 136 } 137 138 if (icon != null) { 139 if (r.isCentered()) { 140 prefSize.height += (icon.getIconHeight() + r.getIconTextGap()); 141 prefSize.width += icon.getIconWidth(); 142 } else { 143 prefSize.height = Math.max(icon.getIconHeight() + ins.top + ins.bottom, prefSize.height); 144 prefSize.width += (icon.getIconWidth() + r.getIconTextGap()); 145 } 146 } 147 148 ((Graphics2D ) g).addRenderingHints(getHints()); 152 153 int textwidth = textWidth(text, g, r.getFont(), r.isHtml()) + 4; 154 155 if (r.isCentered()) { 156 prefSize.width = Math.max(prefSize.width, textwidth + ins.right + ins.left); 157 } else { 158 prefSize.width += (textwidth + r.getIndent()); 159 } 160 161 if (FIXED_HEIGHT > 0) { 162 prefSize.height = FIXED_HEIGHT; 163 } 164 165 return prefSize; 166 } 167 168 static final Map getHints() { 169 if (hintsMap == null) { 171 hintsMap = (Map )(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if (hintsMap == null) { 174 hintsMap = new HashMap (); 175 if (antialias) { 176 hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 177 } 178 } 179 } 180 return hintsMap; 181 } 182 183 public void update(Graphics g, JComponent c) { 184 Color bg = getBackgroundFor((HtmlRendererImpl) c); 185 HtmlRendererImpl h = (HtmlRendererImpl) c; 186 187 if (bg != null) { 188 int x = h.isSelected() ? ((h.getIcon() == null) ? 0 : (h.getIcon().getIconWidth() + h.getIconTextGap())) : 0; 189 x += h.getIndent(); 190 g.setColor(bg); 191 g.fillRect(x, 0, c.getWidth() - x, c.getHeight()); 192 } 193 194 if (h.isLeadSelection()) { 195 Color focus = UIManager.getColor("Tree.selectionBorderColor"); 197 if ((focus == null) || focus.equals(bg)) { 198 focus = Color.BLUE; 199 } 200 201 if (!isGTK() && !AQUA) { 202 int x = ((h.getIcon() == null) ? 0 : (h.getIcon().getIconWidth() + h.getIconTextGap())); 203 g.setColor(focus); 204 g.drawRect(x, 0, c.getWidth() - (x + 1), c.getHeight() - 1); 205 } 206 } 207 208 paint(g, c); 209 } 210 211 public void paint(Graphics g, JComponent c) { 212 213 ((Graphics2D ) g).addRenderingHints(getHints()); 214 215 HtmlRendererImpl r = (HtmlRendererImpl) c; 216 217 if (r.isCentered()) { 218 paintIconAndTextCentered(g, r); 219 } else { 220 paintIconAndText(g, r); 221 } 222 } 223 224 225 private void paintIconAndText(Graphics g, HtmlRendererImpl r) { 226 Font f = r.getFont(); 227 g.setFont(f); 228 229 FontMetrics fm = g.getFontMetrics(); 230 231 int txtH = fm.getMaxAscent() + fm.getMaxDescent(); 233 Insets ins = r.getInsets(); 234 235 int rHeight = r.getHeight(); 237 int availH = rHeight - (ins.top + ins.bottom); 238 239 int txtY; 240 241 if (availH >= txtH) { 242 txtY = (txtH + ins.top + ((availH / 2) - (txtH / 2))) - fm.getMaxDescent(); 244 } else if (r.getHeight() > txtH) { 245 txtY = txtH + (rHeight - txtH) / 2 - fm.getMaxDescent(); 246 } else { 247 txtY = fm.getMaxAscent(); 249 } 250 251 int txtX = r.getIndent(); 252 253 Icon icon = r.getIcon(); 254 255 if ((icon != null) && (icon.getIconWidth() > 0) && (icon.getIconHeight() > 0)) { 257 int iconY; 258 259 if (availH > icon.getIconHeight()) { 260 iconY = ins.top + ((availH / 2) - (icon.getIconHeight() / 2)); } else if (availH == icon.getIconHeight()) { 263 iconY = 0; 265 } else { 266 iconY = ins.top; 270 } 271 272 int iconX = ins.left + r.getIndent() + 1; 275 try { 276 icon.paintIcon(r, g, iconX, iconY); 281 } catch (NullPointerException npe) { 282 Exceptions.attachMessage(npe, 283 "Probably an ImageIcon with a null source image: " + 284 icon + " - " + r.getText()); Exceptions.printStackTrace(npe); 286 } 287 288 txtX = iconX + icon.getIconWidth() + r.getIconTextGap(); 289 } else { 290 txtX += ins.left; 292 } 293 294 String text = r.getText(); 295 296 if (text == null) { 297 return; 299 } 300 301 int txtW = (icon != null) 303 ? (r.getWidth() - (ins.left + ins.right + icon.getIconWidth() + r.getIconTextGap() + r.getIndent())) 304 : (r.getWidth() - (ins.left + ins.right + r.getIndent())); 305 306 Color background = getBackgroundFor(r); 307 Color foreground = ensureContrastingColor(getForegroundFor(r), background); 308 309 if (r.isHtml()) { 310 HtmlRenderer._renderHTML(text, 0, g, txtX, txtY, txtW, txtH, f, foreground, r.getRenderStyle(), true, background); 311 } else { 312 HtmlRenderer.renderPlainString(text, g, txtX, txtY, txtW, txtH, f, foreground, r.getRenderStyle(), true); 313 } 314 } 315 316 private void paintIconAndTextCentered(Graphics g, HtmlRendererImpl r) { 317 Insets ins = r.getInsets(); 318 Icon ic = r.getIcon(); 319 int w = r.getWidth() - (ins.left + ins.right); 320 int txtX = ins.left; 321 int txtY = 0; 322 323 if ((ic != null) && (ic.getIconWidth() > 0) && (ic.getIconHeight() > 0)) { 324 int iconx = (w > ic.getIconWidth()) ? ((w / 2) - (ic.getIconWidth() / 2)) : txtX; 325 int icony = 0; 326 ic.paintIcon(r, g, iconx, icony); 327 txtY += (ic.getIconHeight() + r.getIconTextGap()); 328 } 329 330 int txtW = r.getPreferredSize().width; 331 txtX = (txtW < r.getWidth()) ? ((r.getWidth() / 2) - (txtW / 2)) : 0; 332 333 int txtH = r.getHeight() - txtY; 334 335 Font f = r.getFont(); 336 g.setFont(f); 337 338 FontMetrics fm = g.getFontMetrics(f); 339 txtY += fm.getMaxAscent(); 340 341 Color background = getBackgroundFor(r); 342 Color foreground = ensureContrastingColor(getForegroundFor(r), background); 343 344 if (r.isHtml()) { 345 HtmlRenderer._renderHTML( 346 r.getText(), 0, g, txtX, txtY, txtW, txtH, f, foreground, r.getRenderStyle(), true, background 347 ); 348 } else { 349 HtmlRenderer.renderString( 350 r.getText(), g, txtX, txtY, txtW, txtH, r.getFont(), foreground, r.getRenderStyle(), true 351 ); 352 } 353 } 354 355 359 static Color ensureContrastingColor(Color fg, Color bg) { 360 if (bg == null) { 361 bg = UIManager.getColor("text"); 363 if (bg == null) { 364 bg = Color.WHITE; 365 } 366 } 367 if (fg == null) { 368 fg = UIManager.getColor("textText"); 369 if (fg == null) { 370 fg = Color.BLACK; 371 } 372 } 373 374 if (Color.BLACK.equals(fg) && Color.WHITE.equals(fg)) { 375 return fg; 376 } 377 378 boolean replace = fg.equals(bg); 379 int dif = 0; 380 381 if (!replace) { 382 dif = difference(fg, bg); 383 replace = dif < 80; 384 } 385 386 if (replace) { 387 int lum = luminance(bg); 388 boolean darker = lum >= 128; 389 390 if (darker) { 391 fg = Color.BLACK; 392 } else { 393 fg = Color.WHITE; 394 } 395 } 396 397 return fg; 398 } 399 400 private static int difference(Color a, Color b) { 401 return Math.abs(luminance(a) - luminance(b)); 402 } 403 404 private static int luminance(Color c) { 405 return (299*c.getRed() + 587*c.getGreen() + 114*c.getBlue()) / 1000; 406 } 407 408 static Color getBackgroundFor(HtmlRendererImpl r) { 409 if (r.isOpaque()) { 410 return r.getBackground(); 411 } 412 413 if (r.isSelected() && !r.isParentFocused() && !isGTK()) { 414 return getUnfocusedSelectionBackground(); 415 } 416 417 Color result = null; 418 419 if (r.isSelected()) { 420 switch (r.getType()) { 421 case HtmlRendererImpl.TYPE_LIST: 422 result = UIManager.getColor("List.selectionBackground"); 424 if (result == null) { 426 result = UIManager.getColor("Tree.selectionBackground"); } 429 430 break; 432 433 case HtmlRendererImpl.TYPE_TABLE: 434 result = UIManager.getColor("Table.selectionBackground"); 436 break; 437 438 case HtmlRendererImpl.TYPE_TREE: 439 return UIManager.getColor("Tree.selectionBackground"); } 441 442 return (result == null) ? r.getBackground() : result; 443 } 444 445 return null; 446 } 447 448 static Color getForegroundFor(HtmlRendererImpl r) { 449 if (r.isSelected() && !r.isParentFocused()) { 450 return getUnfocusedSelectionForeground(); 451 } 452 453 if (!r.isEnabled()) { 454 return UIManager.getColor("textInactiveText"); } 456 457 Color result = null; 458 459 if (r.isSelected()) { 460 switch (r.getType()) { 461 case HtmlRendererImpl.TYPE_LIST: 462 result = UIManager.getColor("List.selectionForeground"); 464 case HtmlRendererImpl.TYPE_TABLE: 465 result = UIManager.getColor("Table.selectionForeground"); 467 case HtmlRendererImpl.TYPE_TREE: 468 result = UIManager.getColor("Tree.selectionForeground"); } 470 } 471 472 return (result == null) ? r.getForeground() : result; 473 } 474 475 static boolean isGTK() { 476 return "GTK".equals(UIManager.getLookAndFeel().getID()); 477 } 478 479 480 private static Color getUnfocusedSelectionBackground() { 481 if (unfocusedSelBg == null) { 482 unfocusedSelBg = UIManager.getColor("nb.explorer.unfocusedSelBg"); 485 if (unfocusedSelBg == null) { 486 unfocusedSelBg = UIManager.getColor("controlShadow"); 489 if (unfocusedSelBg == null) { 490 unfocusedSelBg = Color.lightGray; 492 } 493 494 if (!Color.WHITE.equals(unfocusedSelBg.brighter())) { 497 unfocusedSelBg = unfocusedSelBg.brighter(); 498 } 499 } 500 } 501 502 return unfocusedSelBg; 503 } 504 505 506 private static Color getUnfocusedSelectionForeground() { 507 if (unfocusedSelFg == null) { 508 unfocusedSelFg = UIManager.getColor("nb.explorer.unfocusedSelFg"); 511 if (unfocusedSelFg == null) { 512 unfocusedSelFg = UIManager.getColor("textText"); 515 if (unfocusedSelFg == null) { 516 unfocusedSelFg = Color.BLACK; 518 } 519 } 520 } 521 522 return unfocusedSelFg; 523 } 524 525 public static final boolean gtkShouldAntialias() { 526 if (gtkAA == null) { 527 Object o = Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/Antialias"); gtkAA = new Integer (1).equals(o) ? Boolean.TRUE : Boolean.FALSE; 529 } 530 531 return gtkAA.booleanValue(); 532 } 533 } 534 | Popular Tags |