KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > awt > HtmlLabelUI


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.awt;
21
22
23 import java.awt.Color JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Font JavaDoc;
26 import java.awt.FontMetrics JavaDoc;
27 import java.awt.Graphics JavaDoc;
28 import java.awt.Graphics2D JavaDoc;
29 import java.awt.Insets JavaDoc;
30 import java.awt.RenderingHints JavaDoc;
31 import java.awt.Toolkit JavaDoc;
32
33 import java.util.HashMap JavaDoc;
34 import java.util.Map JavaDoc;
35
36 import javax.swing.Icon JavaDoc;
37 import javax.swing.JComponent JavaDoc;
38 import javax.swing.UIManager JavaDoc;
39 import javax.swing.plaf.ComponentUI JavaDoc;
40 import javax.swing.plaf.LabelUI JavaDoc;
41 import org.openide.util.Exceptions;
42
43 /**
44  * A LabelUI which uses the lightweight HTML renderer. Stateless - only one
45  * instance should ever exist.
46  */

47 class HtmlLabelUI extends LabelUI JavaDoc {
48
49     /** System property to automatically turn on antialiasing for html strings */
50     //static final boolean GTK = "GTK".equals(UIManager.getLookAndFeel().getID());//NOI18N
51
static final boolean AQUA = "Aqua".equals(UIManager.getLookAndFeel().getID());//NOI18N
52

53     private static final boolean antialias = Boolean.getBoolean("nb.cellrenderer.antialiasing") // NOI18N
54
||Boolean.getBoolean("swing.aatext") // NOI18N
55
||(isGTK() && gtkShouldAntialias()) // NOI18N
56
||AQUA;
57     
58     private static HtmlLabelUI uiInstance;
59     
60     private static int FIXED_HEIGHT;
61
62     static {
63         //Jesse mode
64
String JavaDoc ht = System.getProperty("nb.cellrenderer.fixedheight"); //NOI18N
65

66         if (ht != null) {
67             try {
68                 FIXED_HEIGHT = Integer.parseInt(ht);
69             } catch (Exception JavaDoc e) {
70                 //do nothing
71
}
72         }
73     }
74
75     private static Map JavaDoc hintsMap;
76     private static Color JavaDoc unfocusedSelBg;
77     private static Color JavaDoc unfocusedSelFg;
78     private static Boolean JavaDoc gtkAA;
79
80     public static ComponentUI JavaDoc createUI(JComponent JavaDoc 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 JavaDoc getPreferredSize(JComponent JavaDoc c) {
91         return calcPreferredSize((HtmlRendererImpl) c);
92     }
93
94     /** Get the width of the text */
95     private static int textWidth(String JavaDoc text, Graphics JavaDoc g, Font JavaDoc 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 JavaDoc calcPreferredSize(HtmlRendererImpl r) {
126         Insets JavaDoc ins = r.getInsets();
127         Dimension JavaDoc prefSize = new java.awt.Dimension JavaDoc(ins.left + ins.right, ins.top + ins.bottom);
128         String JavaDoc text = r.getText();
129
130         Graphics JavaDoc g = r.getGraphics();
131         Icon JavaDoc icon = r.getIcon();
132
133         if (text != null) {
134             FontMetrics JavaDoc 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         //Antialiasing affects the text metrics, so use it if needed when
149
//calculating preferred size or the result here will be narrower
150
//than the space actually needed
151
((Graphics2D JavaDoc) 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 JavaDoc getHints() {
169         //XXX We REALLY need to put this in a graphics utils lib
170
if (hintsMap == null) {
171             //Thanks to Phil Race for making this possible
172
hintsMap = (Map JavaDoc)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); //NOI18N
173
if (hintsMap == null) {
174                 hintsMap = new HashMap JavaDoc();
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 JavaDoc g, JComponent JavaDoc c) {
184         Color JavaDoc 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 JavaDoc focus = UIManager.getColor("Tree.selectionBorderColor"); // NOI18N
196

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 JavaDoc g, JComponent JavaDoc c) {
212
213         ((Graphics2D JavaDoc) 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     /** Actually paint the icon and text using our own html rendering engine. */
225     private void paintIconAndText(Graphics JavaDoc g, HtmlRendererImpl r) {
226         Font JavaDoc f = r.getFont();
227         g.setFont(f);
228
229         FontMetrics JavaDoc fm = g.getFontMetrics();
230
231         //Find out what height we need
232
int txtH = fm.getMaxAscent() + fm.getMaxDescent();
233         Insets JavaDoc ins = r.getInsets();
234
235         //find out the available height less the insets
236
int rHeight = r.getHeight();
237         int availH = rHeight - (ins.top + ins.bottom);
238
239         int txtY;
240
241         if (availH >= txtH) {
242             //Center the text if we have space
243
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             //Okay, it's not going to fit, punt.
248
txtY = fm.getMaxAscent();
249         }
250         
251         int txtX = r.getIndent();
252
253         Icon JavaDoc icon = r.getIcon();
254
255         //Check the icon non-null and height (see TabData.NO_ICON for why)
256
if ((icon != null) && (icon.getIconWidth() > 0) && (icon.getIconHeight() > 0)) {
257             int iconY;
258
259             if (availH > icon.getIconHeight()) {
260                 //add 2 to make sure icon top pixels are not cut off by outline
261
iconY = ins.top + ((availH / 2) - (icon.getIconHeight() / 2)); // + 2;
262
} else if (availH == icon.getIconHeight()) {
263                 //They're an exact match, make it 0
264
iconY = 0;
265             } else {
266                 //Won't fit; make the top visible and cut the rest off (option:
267
//center it and clip it on top and bottom - probably even harder
268
//to recognize that way, though)
269
iconY = ins.top;
270             }
271
272             //add in the insets
273
int iconX = ins.left + r.getIndent() + 1; //+1 to get it out of the way of the focus border
274

275             try {
276                 //Diagnostic - the CPP module currently is constructing
277
//some ImageIcon from a null image in Options. So, catch it and at
278
//least give a meaningful message that indicates what node
279
//is the culprit
280
icon.paintIcon(r, g, iconX, iconY);
281             } catch (NullPointerException JavaDoc npe) {
282                 Exceptions.attachMessage(npe,
283                                          "Probably an ImageIcon with a null source image: " +
284                                          icon + " - " + r.getText()); //NOI18N
285
Exceptions.printStackTrace(npe);
286             }
287
288             txtX = iconX + icon.getIconWidth() + r.getIconTextGap();
289         } else {
290             //If there's no icon, paint the text where the icon would start
291
txtX += ins.left;
292         }
293
294         String JavaDoc text = r.getText();
295
296         if (text == null) {
297             //No text, we're done
298
return;
299         }
300
301         //Get the available horizontal pixels for text
302
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 JavaDoc background = getBackgroundFor(r);
307         Color JavaDoc 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 JavaDoc g, HtmlRendererImpl r) {
317         Insets JavaDoc ins = r.getInsets();
318         Icon JavaDoc 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 JavaDoc f = r.getFont();
336         g.setFont(f);
337
338         FontMetrics JavaDoc fm = g.getFontMetrics(f);
339         txtY += fm.getMaxAscent();
340
341         Color JavaDoc background = getBackgroundFor(r);
342         Color JavaDoc 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     /*
356     (int pos, String s, Graphics g, int x,
357     int y, int w, int h, Font f, Color defaultColor, int style,
358     boolean paint, Color background) { */

359     static Color JavaDoc ensureContrastingColor(Color JavaDoc fg, Color JavaDoc bg) {
360         if (bg == null) {
361             bg = UIManager.getColor("text"); //NOI18N
362

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 JavaDoc a, Color JavaDoc b) {
401         return Math.abs(luminance(a) - luminance(b));
402     }
403
404     private static int luminance(Color JavaDoc c) {
405         return (299*c.getRed() + 587*c.getGreen() + 114*c.getBlue()) / 1000;
406     }
407
408     static Color JavaDoc 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 JavaDoc result = null;
418
419         if (r.isSelected()) {
420             switch (r.getType()) {
421             case HtmlRendererImpl.TYPE_LIST:
422                 result = UIManager.getColor("List.selectionBackground"); //NOI18N
423

424                 if (result == null) { //GTK
425

426                     //plaf library guarantees this one:
427
result = UIManager.getColor("Tree.selectionBackground"); //NOI18N
428
}
429
430                 //System.err.println(" now " + result);
431
break;
432
433             case HtmlRendererImpl.TYPE_TABLE:
434                 result = UIManager.getColor("Table.selectionBackground"); //NOI18N
435

436                 break;
437
438             case HtmlRendererImpl.TYPE_TREE:
439                 return UIManager.getColor("Tree.selectionBackground"); //NOI18N
440
}
441
442             return (result == null) ? r.getBackground() : result;
443         }
444
445         return null;
446     }
447
448     static Color JavaDoc getForegroundFor(HtmlRendererImpl r) {
449         if (r.isSelected() && !r.isParentFocused()) {
450             return getUnfocusedSelectionForeground();
451         }
452
453         if (!r.isEnabled()) {
454             return UIManager.getColor("textInactiveText"); //NOI18N
455
}
456
457         Color JavaDoc result = null;
458
459         if (r.isSelected()) {
460             switch (r.getType()) {
461             case HtmlRendererImpl.TYPE_LIST:
462                 result = UIManager.getColor("List.selectionForeground"); //NOI18N
463

464             case HtmlRendererImpl.TYPE_TABLE:
465                 result = UIManager.getColor("Table.selectionForeground"); //NOI18N
466

467             case HtmlRendererImpl.TYPE_TREE:
468                 result = UIManager.getColor("Tree.selectionForeground"); //NOI18N
469
}
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     /** Get the system-wide unfocused selection background color */
480     private static Color JavaDoc getUnfocusedSelectionBackground() {
481         if (unfocusedSelBg == null) {
482             //allow theme/ui custom definition
483
unfocusedSelBg = UIManager.getColor("nb.explorer.unfocusedSelBg"); //NOI18N
484

485             if (unfocusedSelBg == null) {
486                 //try to get standard shadow color
487
unfocusedSelBg = UIManager.getColor("controlShadow"); //NOI18N
488

489                 if (unfocusedSelBg == null) {
490                     //Okay, the look and feel doesn't suport it, punt
491
unfocusedSelBg = Color.lightGray;
492                 }
493
494                 //Lighten it a bit because disabled text will use controlShadow/
495
//gray
496
if (!Color.WHITE.equals(unfocusedSelBg.brighter())) {
497                     unfocusedSelBg = unfocusedSelBg.brighter();
498                 }
499             }
500         }
501
502         return unfocusedSelBg;
503     }
504
505     /** Get the system-wide unfocused selection foreground color */
506     private static Color JavaDoc getUnfocusedSelectionForeground() {
507         if (unfocusedSelFg == null) {
508             //allow theme/ui custom definition
509
unfocusedSelFg = UIManager.getColor("nb.explorer.unfocusedSelFg"); //NOI18N
510

511             if (unfocusedSelFg == null) {
512                 //try to get standard shadow color
513
unfocusedSelFg = UIManager.getColor("textText"); //NOI18N
514

515                 if (unfocusedSelFg == null) {
516                     //Okay, the look and feel doesn't suport it, punt
517
unfocusedSelFg = Color.BLACK;
518                 }
519             }
520         }
521
522         return unfocusedSelFg;
523     }
524
525     public static final boolean gtkShouldAntialias() {
526         if (gtkAA == null) {
527             Object JavaDoc o = Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/Antialias"); //NOI18N
528
gtkAA = new Integer JavaDoc(1).equals(o) ? Boolean.TRUE : Boolean.FALSE;
529         }
530
531         return gtkAA.booleanValue();
532     }
533 }
534
Popular Tags