KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > SwingUtilities2


1 /*
2  * @(#)SwingUtilities2.java 1.29 06/04/18
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.java.swing;
9
10 import java.security.*;
11 import java.lang.reflect.*;
12 import java.awt.*;
13 import java.awt.event.*;
14 import java.awt.font.*;
15 import java.awt.geom.*;
16 import java.awt.print.PrinterGraphics JavaDoc;
17 import java.text.AttributedCharacterIterator JavaDoc;
18 import javax.swing.*;
19 import javax.swing.plaf.*;
20 import javax.swing.text.Highlighter JavaDoc;
21 import javax.swing.text.JTextComponent JavaDoc;
22 import javax.swing.text.DefaultHighlighter JavaDoc;
23 import javax.swing.text.DefaultCaret JavaDoc;
24 import javax.swing.table.TableCellRenderer JavaDoc;
25 import sun.swing.PrintColorUIResource;
26 import sun.print.ProxyPrintGraphics;
27 import sun.awt.AppContext;
28 import sun.font.FontDesignMetrics;
29 import sun.java2d.SunGraphics2D;
30 import sun.security.action.GetPropertyAction;
31 import sun.security.util.SecurityConstants;
32 import java.io.*;
33
34 /**
35  * A collection of utility methods for Swing.
36  * <p>
37  * <b>WARNING:</b> While this class is public, it should not be treated as
38  * public API and its API may change in incompatable ways between dot dot
39  * releases and even patch releases. You should not rely on this class even
40  * existing.
41  *
42  * @version 1.29 04/18/06
43  */

44 public class SwingUtilities2 {
45     // Maintain a cache of CACHE_SIZE fonts and the left side bearing
46
// of the characters falling into the range MIN_CHAR_INDEX to
47
// MAX_CHAR_INDEX. The values in fontCache are created as needed.
48
private static LSBCacheEntry[] fontCache;
49     // Windows defines 6 font desktop properties, we will therefore only
50
// cache the metrics for 6 fonts.
51
private static final int CACHE_SIZE = 6;
52     // nextIndex in fontCache to insert a font into.
53
private static int nextIndex;
54     // LSBCacheEntry used to search in fontCache to see if we already
55
// have an entry for a particular font
56
private static LSBCacheEntry searchKey;
57
58     // getLeftSideBearing will consult all characters that fall in the
59
// range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
60
private static final int MIN_CHAR_INDEX = (int)'W';
61     private static final int MAX_CHAR_INDEX = (int)'W' + 1;
62
63     private static final FontRenderContext DEFAULT_FRC = new FontRenderContext(
64                              null, false, false);
65
66     /**
67      * FontRenderContext with antialiased turned on.
68      */

69     public static final FontRenderContext AA_FRC;
70
71     //
72
// To determine if a JComponent should use AA text the following is
73
// used:
74
// 1. Is the system property 'swing.aatext' defined, return the value of
75
// the system property.
76
// 2. Use the JComponent client property AA_TEXT_PROPERTY_KEY. To
77
// avoid having this property persist between look and feels changes
78
// the value of this property is set to false in JComponent.setUI
79
//
80

81     /**
82      * Whether or not text is drawn anti-aliased. This is only used if
83      * <code>AA_TEXT_DEFINED</code> is true.
84      */

85     private static final boolean AA_TEXT;
86
87     /**
88      * Whether or not the system property 'swing.aatext' is defined.
89      */

90     private static final boolean AA_TEXT_DEFINED;
91
92     /**
93      * Key used in client properties to indicate whether or not the component
94      * should use aa text.
95      */

96     public static final Object JavaDoc AA_TEXT_PROPERTY_KEY =
97                           new StringBuffer JavaDoc("AATextPropertyKey");
98
99     /**
100      * Used to tell a text component, being used as an editor for table
101      * or tree, how many clicks it took to start editing.
102      */

103     private static final StringBuilder JavaDoc SKIP_CLICK_COUNT =
104         new StringBuilder JavaDoc("skipClickCount");
105
106     /**
107      * Whether or not the system proprety 'sun.swing.enableImprovedDragGesture'
108      * is defined, indicating that we should enable the fix for 4521075
109      * and start drag recognition on the first press without requiring a
110      * selection.
111      */

112     public static final boolean DRAG_FIX;
113
114     // security stuff
115
private static Field inputEvent_CanAccessSystemClipboard_Field = null;
116     private static final String JavaDoc UntrustedClipboardAccess =
117         "UNTRUSTED_CLIPBOARD_ACCESS_KEY";
118
119     static {
120         fontCache = new LSBCacheEntry[CACHE_SIZE];
121         Object JavaDoc aa = java.security.AccessController.doPrivileged(
122                new GetPropertyAction("swing.aatext"));
123         AA_TEXT_DEFINED = (aa != null);
124         AA_TEXT = "true".equals(aa);
125         AA_FRC = new FontRenderContext(null, true, false);
126
127         Object JavaDoc dragFix = java.security.AccessController.doPrivileged(
128             new GetPropertyAction("sun.swing.enableImprovedDragGesture"));
129         DRAG_FIX = (dragFix != null);
130     }
131
132     //
133
// WARNING WARNING WARNING WARNING WARNING WARNING
134
// Many of the following methods are invoked from older API.
135
// As this older API was not passed a Component, a null Component may
136
// now be passsed in. For example, SwingUtilities.computeStringWidth
137
// is implemented to call SwingUtilities2.stringWidth, the
138
// SwingUtilities variant does not take a JComponent, as such
139
// SwingUtilities2.stringWidth can be passed a null Component.
140
// In other words, if you add new functionality to these methods you
141
// need to gracefully handle null.
142
//
143

144     /**
145      * Returns whether or not text should be drawn antialiased.
146      *
147      * @param c JComponent to test.
148      * @return Whether or not text should be drawn antialiased for the
149      * specified component.
150      */

151     private static boolean drawTextAntialiased(JComponent c) {
152         if (!AA_TEXT_DEFINED) {
153             if (c != null) {
154                 // Check if the component wants aa text
155
return ((Boolean JavaDoc)c.getClientProperty(
156                                   AA_TEXT_PROPERTY_KEY)).booleanValue();
157             }
158             // No component, assume aa is off
159
return false;
160         }
161         // 'swing.aatext' was defined, use its value.
162
return AA_TEXT;
163     }
164
165     /**
166      * Returns whether or not text should be drawn antialiased.
167      *
168      * @param aaText Whether or not aa text has been turned on for the
169      * component.
170      * @return Whether or not text should be drawn antialiased.
171      */

172     public static boolean drawTextAntialiased(boolean aaText) {
173         if (!AA_TEXT_DEFINED) {
174             // 'swing.aatext' wasn't defined, use the components aa text value.
175
return aaText;
176         }
177         // 'swing.aatext' was defined, use its value.
178
return AA_TEXT;
179     }
180
181     /**
182      * Returns the left side bearing of the first character of string. The
183      * left side bearing is calculated from the passed in
184      * FontMetrics. If the passed in String is less than one
185      * character, this will throw a StringIndexOutOfBoundsException exception.
186      *
187      * @param c JComponent that will display the string
188      * @param fm FontMetrics used to measure the String width
189      * @param string String to get the left side bearing for.
190      */

191     public static int getLeftSideBearing(JComponent c, FontMetrics fm,
192                                          String JavaDoc string) {
193         return getLeftSideBearing(c, fm, string.charAt(0));
194     }
195
196
197     /**
198      * Returns the left side bearing of the first character of string. The
199      * left side bearing is calculated from the passed in FontMetrics.
200      *
201      * @param c JComponent that will display the string
202      * @param fm FontMetrics used to measure the String width
203      * @param char Character to get the left side bearing for.
204      */

205     public static int getLeftSideBearing(JComponent c, FontMetrics fm,
206                                          char firstChar) {
207         int charIndex = (int)firstChar;
208         if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {
209             byte[] lsbs = null;
210
211             FontRenderContext frc = getFRC(c, fm);
212             Font font = fm.getFont();
213             synchronized(SwingUtilities2.class) {
214                 LSBCacheEntry entry = null;
215                 if (searchKey == null) {
216                     searchKey = new LSBCacheEntry(frc, font);
217                 }
218                 else {
219                     searchKey.reset(frc, font);
220                 }
221                 // See if we already have an entry for this pair
222
for (LSBCacheEntry cacheEntry : fontCache) {
223                     if (searchKey.equals(cacheEntry)) {
224                         entry = cacheEntry;
225                         break;
226                     }
227                 }
228                 if (entry == null) {
229                     // No entry for this pair, add it.
230
entry = searchKey;
231                     fontCache[nextIndex] = searchKey;
232                     searchKey = null;
233                     nextIndex = (nextIndex + 1) % CACHE_SIZE;
234                 }
235                 return entry.getLeftSideBearing(firstChar);
236             }
237         }
238         return 0;
239     }
240
241
242     /**
243      * Returns the FontMetrics for the current Font of the passed
244      * in Graphics. This method is used when a Graphics
245      * is available, typically when painting. If a Graphics is not
246      * available the JComponent method of the same name should be used.
247      * <p>
248      * Callers should pass in a non-null JComponent, the exception
249      * to this is if a JComponent is not readily available at the time of
250      * painting.
251      * <p>
252      * This does not necessarily return the FontMetrics from the
253      * Graphics.
254      *
255      * @param c JComponent requesting FontMetrics, may be null
256      * @param g Graphics Graphics
257      */

258     public static FontMetrics getFontMetrics(JComponent c, Graphics JavaDoc g) {
259         return getFontMetrics(c, g, g.getFont());
260     }
261
262
263     /**
264      * Returns the FontMetrics for the specified Font.
265      * This method is used when a Graphics is available, typically when
266      * painting. If a Graphics is not available the JComponent method of
267      * the same name should be used.
268      * <p>
269      * Callers should pass in a non-null JComonent, the exception
270      * to this is if a JComponent is not readily available at the time of
271      * painting.
272      * <p>
273      * This does not necessarily return the FontMetrics from the
274      * Graphics.
275      *
276      * @param c JComponent requesting FontMetrics, may be null
277      * @param c Graphics Graphics
278      * @param font Font to get FontMetrics for
279      */

280     public static FontMetrics getFontMetrics(JComponent c, Graphics JavaDoc g,
281                                              Font font) {
282         if (c != null) {
283             // Note: We assume that we're using the FontMetrics
284
// from the widget to layout out text, otherwise we can get
285
// mismatches when printing.
286
return c.getFontMetrics(font);
287         }
288         return Toolkit.getDefaultToolkit().getFontMetrics(font);
289     }
290
291
292     /**
293      * Returns the width of the passed in String.
294      *
295      * @param c JComponent that will display the string, may be null
296      * @param fm FontMetrics used to measure the String width
297      * @param string String to get the width of
298      */

299     public static int stringWidth(JComponent c, FontMetrics fm, String JavaDoc string){
300         return fm.stringWidth(string);
301     }
302
303
304
305     /**
306      * Clips the passed in String to the space provided.
307      *
308      * @param c JComponent that will display the string, may be null
309      * @param fm FontMetrics used to measure the String width
310      * @param string String to display
311      * @param availTextWidth Amount of space that the string can be drawn in
312      * @return Clipped string that can fit in the provided space.
313      */

314     public static String JavaDoc clipStringIfNecessary(JComponent c, FontMetrics fm,
315                                                String JavaDoc string,
316                                                int availTextWidth) {
317         if ((string == null) || (string.equals(""))) {
318             return "";
319         }
320         int textWidth = SwingUtilities2.stringWidth(c, fm, string);
321         if (textWidth > availTextWidth) {
322             return SwingUtilities2.clipString(c, fm, string, availTextWidth);
323         }
324         return string;
325     }
326
327
328     /**
329      * Clips the passed in String to the space provided. NOTE: this assumes
330      * the string does not fit in the available space.
331      *
332      * @param c JComponent that will display the string, may be null
333      * @param fm FontMetrics used to measure the String width
334      * @param string String to display
335      * @param availTextWidth Amount of space that the string can be drawn in
336      * @return Clipped string that can fit in the provided space.
337      */

338     public static String JavaDoc clipString(JComponent c, FontMetrics fm,
339                                     String JavaDoc string, int availTextWidth) {
340         // c may be null here.
341
String JavaDoc clipString = "...";
342         int width = SwingUtilities2.stringWidth(c, fm, clipString);
343         // NOTE: This does NOT work for surrogate pairs and other fun
344
// stuff
345
int nChars = 0;
346         for(int max = string.length(); nChars < max; nChars++) {
347             width += fm.charWidth(string.charAt(nChars));
348             if (width > availTextWidth) {
349                 break;
350             }
351         }
352         string = string.substring(0, nChars) + clipString;
353         return string;
354     }
355
356     /**
357      * Returns the FontRenderContext for the passed in FontMetrics or
358      * for the passed in JComponent if FontMetrics is null
359      */

360     private static FontRenderContext getFRC(JComponent c, FontMetrics fm) {
361         // c may be null.
362
if (fm instanceof FontDesignMetrics) {
363             return ((FontDesignMetrics)fm).getFRC();
364         }
365         if (fm == null && c != null) {
366             //we do it this way because we need first case to
367
//work as fast as possible
368
return getFRC(c, c.getFontMetrics(c.getFont()));
369         }
370
371         // PENDING: This shouldn't really happen, but if it does we
372
// should try and handle AA as necessary.
373
assert false;
374         return DEFAULT_FRC;
375     }
376
377
378     /**
379      * Draws the string at the specified location.
380      *
381      * @param c JComponent that will display the string, may be null
382      * @param g Graphics to draw the text to
383      * @param text String to display
384      * @param x X coordinate to draw the text at
385      * @param y Y coordinate to draw the text at
386      */

387     public static void drawString(JComponent c, Graphics JavaDoc g, String JavaDoc text,
388                                   int x, int y) {
389         // c may be null
390

391         // All non-editable widgets that draw strings call into this
392
// methods. By non-editable that means widgets like JLabel, JButton
393
// but NOT JTextComponents.
394
if ( text == null || text.length() <= 0 ) { //no need to paint empty strings
395
return;
396         }
397         if (isPrinting(g)) {
398             Graphics2D g2d = getGraphics2D(g);
399             if (g2d != null) {
400                 TextLayout layout = new TextLayout(text, g2d.getFont(),
401                                                    DEFAULT_FRC);
402
403                 /* Use alternate print color if specified */
404                 Color col = g2d.getColor();
405                 if (col instanceof PrintColorUIResource) {
406                     g2d.setColor(((PrintColorUIResource)col).getPrintColor());
407                 }
408
409                 layout.draw(g2d, x, y);
410                 
411                 g2d.setColor(col);
412
413                 return;
414             }
415         }
416
417         // If we get here we're not printing
418
if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
419             Graphics2D g2 = (Graphics2D)g;
420             Object JavaDoc oldAAValue = g2.getRenderingHint(
421                                        RenderingHints.KEY_TEXT_ANTIALIASING);
422             g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
423                                     RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
424             g.drawString(text, x, y);
425             g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
426                                     oldAAValue);
427         }
428         else {
429             g.drawString(text, x, y);
430         }
431     }
432
433
434     /**
435      * Draws the string at the specified location underlining the specified
436      * character.
437      *
438      * @param c JComponent that will display the string, may be null
439      * @param g Graphics to draw the text to
440      * @param text String to display
441      * @param underlinedIndex Index of a character in the string to underline
442      * @param x X coordinate to draw the text at
443      * @param y Y coordinate to draw the text at
444      */

445     public static void drawStringUnderlineCharAt(JComponent c,Graphics JavaDoc g,
446                            String JavaDoc text, int underlinedIndex, int x,int y) {
447         SwingUtilities2.drawString(c, g, text, x, y);
448         if (underlinedIndex >= 0 && underlinedIndex < text.length() ) {
449             // PENDING: this needs to change.
450
FontMetrics fm = g.getFontMetrics();
451             int underlineRectX = x + SwingUtilities2.stringWidth(c,
452                                       fm, text.substring(0,underlinedIndex));
453             int underlineRectY = y;
454             int underlineRectWidth = fm.charWidth(text.
455                                                   charAt(underlinedIndex));
456             int underlineRectHeight = 1;
457             g.fillRect(underlineRectX, underlineRectY + 1,
458                        underlineRectWidth, underlineRectHeight);
459         }
460     }
461
462
463     /**
464      * A variation of locationToIndex() which only returns an index if the
465      * Point is within the actual bounds of a list item (not just in the cell)
466      * and if the JList has the "List.isFileList" client property set.
467      * Otherwise, this method returns -1.
468      * This is used to make WindowsL&F JFileChooser act like native dialogs.
469      */

470     public static int loc2IndexFileList(JList list, Point point) {
471         int index = list.locationToIndex(point);
472         if (index != -1) {
473             Object JavaDoc bySize = list.getClientProperty("List.isFileList");
474             if (bySize instanceof Boolean JavaDoc && ((Boolean JavaDoc)bySize).booleanValue() &&
475                 !pointIsInActualBounds(list, index, point)) {
476                 index = -1;
477             }
478         }
479         return index;
480     }
481
482
483     /**
484      * Returns true if the given point is within the actual bounds of the
485      * JList item at index (not just inside the cell).
486      */

487     private static boolean pointIsInActualBounds(JList list, int index,
488                                                 Point point) {
489         ListCellRenderer renderer = list.getCellRenderer();
490         ListModel dataModel = list.getModel();
491         Object JavaDoc value = dataModel.getElementAt(index);
492         Component JavaDoc item = renderer.getListCellRendererComponent(list,
493                           value, index, false, false);
494         Dimension itemSize = item.getPreferredSize();
495         Rectangle cellBounds = list.getCellBounds(index, index);
496     if (!item.getComponentOrientation().isLeftToRight()) {
497         cellBounds.x += (cellBounds.width - itemSize.width);
498     }
499         cellBounds.width = itemSize.width;
500         cellBounds.height = itemSize.height;
501
502     return cellBounds.contains(point);
503     }
504
505
506     /**
507      * Returns true if the given point is outside the preferredSize of the
508      * item at the given row of the table. (Column must be 0).
509      * Does not check the "Table.isFileList" property. That should be checked
510      * before calling this method.
511      * This is used to make WindowsL&F JFileChooser act like native dialogs.
512      */

513     public static boolean pointOutsidePrefSize(JTable table, int row, int column, Point p) {
514         if (table.convertColumnIndexToModel(column) != 0 || row == -1) {
515             return true;
516         }
517         TableCellRenderer JavaDoc tcr = table.getCellRenderer(row, column);
518         Object JavaDoc value = table.getValueAt(row, column);
519         Component JavaDoc cell = tcr.getTableCellRendererComponent(table, value, false,
520                 false, row, column);
521         Dimension itemSize = cell.getPreferredSize();
522         Rectangle cellBounds = table.getCellRect(row, column, false);
523         cellBounds.width = itemSize.width;
524         cellBounds.height = itemSize.height;
525
526         // See if coords are inside
527
// ASSUME: mouse x,y will never be < cell's x,y
528
assert (p.x >= cellBounds.x && p.y >= cellBounds.y);
529         if (p.x > cellBounds.x + cellBounds.width ||
530                 p.y > cellBounds.y + cellBounds.height) {
531             return true;
532         }
533         return false;
534     }
535
536     /**
537      * Ignore mouse events if the component is null, not enabled, or the event
538      * is not associated with the left mouse button.
539      */

540     public static boolean shouldIgnore(MouseEvent me, JComponent c) {
541         return c == null || !c.isEnabled()
542                          || !SwingUtilities.isLeftMouseButton(me);
543     }
544
545     /**
546      * Request focus on the given component if it doesn't already have it
547      * and <code>isRequestFocusEnabled()</code> returns true.
548      */

549     public static void adjustFocus(JComponent c) {
550         if (!c.hasFocus() && c.isRequestFocusEnabled()) {
551             c.requestFocus();
552         }
553     }
554
555     /**
556      * The following draw functions have the same semantic as the
557      * Graphics methods with the same names.
558      *
559      * this is used for printing
560      */

561     public static int drawChars(JComponent c, Graphics JavaDoc g,
562                                  char[] data,
563                                  int offset,
564                                  int length,
565                                  int x,
566                                  int y) {
567         if ( length <= 0 ) { //no need to paint empty strings
568
return x;
569         }
570         int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
571         if (isPrinting(g)) {
572             Graphics2D g2d = getGraphics2D(g);
573             if (g2d != null) {
574                 FontRenderContext deviceFontRenderContext = g2d.
575                     getFontRenderContext();
576                 FontRenderContext frc = getFRC(c, null);
577                 if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
578                     frc = new FontRenderContext(frc.getTransform(), false, false);
579                 }
580                 if (frc != null
581                     && ! isFontRenderContextCompatible(deviceFontRenderContext,
582                                                        frc)) {
583                     TextLayout layout =
584                         new TextLayout(new String JavaDoc(data,offset,length),
585                                        g2d.getFont(),
586                                        frc);
587
588                     /* Use alternate print color if specified */
589                     Color col = g2d.getColor();
590                     if (col instanceof PrintColorUIResource) {
591                         g2d.setColor(((PrintColorUIResource)col).getPrintColor());
592                     }
593
594                     layout.draw(g2d,x,y);
595
596                     g2d.setColor(col);
597
598                     return nextX;
599                 }
600             }
601         }
602         // Assume we're not printing if we get here.
603
if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
604             Graphics2D g2 = (Graphics2D)g;
605             Object JavaDoc oldAAValue = g2.getRenderingHint(
606                                        RenderingHints.KEY_TEXT_ANTIALIASING);
607             g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
608                                 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
609             g.drawChars(data, offset, length, x, y);
610             g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
611                                 oldAAValue);
612         }
613         else {
614             g.drawChars(data, offset, length, x, y);
615         }
616         return nextX;
617     }
618
619     /*
620      * see documentation for drawChars
621      * returns the advance
622      */

623     public static float drawString(JComponent c, Graphics JavaDoc g,
624                                    AttributedCharacterIterator JavaDoc iterator,
625                                    int x,
626                                    int y) {
627
628         float retVal;
629         boolean isPrinting = isPrinting(g);
630         Color col = g.getColor();
631
632         if (isPrinting) {
633             /* Use alternate print color if specified */
634             if (col instanceof PrintColorUIResource) {
635                 g.setColor(((PrintColorUIResource)col).getPrintColor());
636             }
637         }
638
639         Graphics2D g2d = getGraphics2D(g);
640         if (g2d == null) {
641             g.drawString(iterator,x,y); //for the cases where advance
642
//matters it should not happen
643
retVal = x;
644
645         } else {
646             FontRenderContext frc;
647             if (isPrinting) {
648                 frc = getFRC(c, null);
649                 if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
650                     frc = new FontRenderContext(frc.getTransform(), false, false);
651                 }
652             } else if (drawTextAntialiased(c)) {
653                 frc = AA_FRC;
654             } else {
655                 frc = g2d.getFontRenderContext();
656             }
657             TextLayout layout = new TextLayout(iterator, frc);
658             layout.draw(g2d, x, y);
659             retVal = layout.getAdvance();
660         }
661
662         if (isPrinting) {
663             g.setColor(col);
664         }
665
666         return retVal;
667     }
668
669     /*
670      * Checks if two given FontRenderContexts are compatible.
671      * Compatible means no special handling needed for text painting
672      */

673     public static boolean isFontRenderContextCompatible(FontRenderContext frc1,
674                                                         FontRenderContext frc2) {
675         return (frc1 != null) ? frc1.equals(frc2) : frc2 == null;
676     }
677     
678     /*
679      * Tries it best to get Graphics2D out of the given Graphics
680      * returns null if can not derive it.
681      */

682     public static Graphics2D getGraphics2D(Graphics JavaDoc g) {
683         if (g instanceof Graphics2D) {
684             return (Graphics2D) g;
685         } else if (g instanceof ProxyPrintGraphics) {
686             return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());
687         } else {
688             return null;
689         }
690     }
691
692     /*
693      * Returns FontRendedrContext associated with JComponent
694      * see JComponent.getFontMetrics
695      */

696     public static FontRenderContext getFontRenderContext(Component JavaDoc c) {
697         if (c == null) {
698             return DEFAULT_FRC;
699         } else {
700             return getFRC(null, c.getFontMetrics(c.getFont()));
701         }
702     }
703
704     /*
705      * returns true if the Graphics is print Graphics
706      * false otherwise
707      */

708     static boolean isPrinting(Graphics JavaDoc g) {
709         return (g instanceof PrinterGraphics JavaDoc || g instanceof PrintGraphics);
710     }
711
712     /**
713      * Determines whether the SelectedTextColor should be used for painting text
714      * foreground for the specified highlight.
715      *
716      * Returns true only if the highlight painter for the specified highlight
717      * is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter
718      * or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color
719      * is null or equals to the selection color of the text component.
720      *
721      * This is a hack for fixing both bugs 4761990 and 5003294
722      */

723     public static boolean useSelectedTextColor(Highlighter.Highlight JavaDoc h, JTextComponent JavaDoc c) {
724         Highlighter.HighlightPainter JavaDoc painter = h.getPainter();
725         String JavaDoc painterClass = painter.getClass().getName();
726         if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
727                 painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
728             return false;
729         }
730         try {
731             DefaultHighlighter.DefaultHighlightPainter JavaDoc defPainter =
732                     (DefaultHighlighter.DefaultHighlightPainter JavaDoc) painter;
733             if (defPainter.getColor() != null &&
734                     !defPainter.getColor().equals(c.getSelectionColor())) {
735                 return false;
736             }
737         } catch (ClassCastException JavaDoc e) {
738             return false;
739         }
740         return true;
741     }
742
743     /**
744      * LSBCacheEntry is used to cache the left side bearing (lsb) for
745      * a particular <code>Font</code> and <code>FontRenderContext</code>.
746      * This only caches characters that fall in the range
747      * <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.
748      */

749     private static class LSBCacheEntry {
750         // Used to indicate a particular entry in lsb has not been set.
751
private static final byte UNSET = Byte.MAX_VALUE;
752         // Used in creating a GlyphVector to get the lsb
753
private static final char[] oneChar = new char[1];
754
755         private byte[] lsbCache;
756         private Font font;
757         private FontRenderContext frc;
758
759         public LSBCacheEntry(FontRenderContext frc, Font font) {
760             lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
761             reset(frc, font);
762         }
763
764         public void reset(FontRenderContext frc, Font font) {
765             this.font = font;
766             this.frc = frc;
767             for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
768                 lsbCache[counter] = UNSET;
769             }
770         }
771
772         public int getLeftSideBearing(char aChar) {
773             int index = aChar - MIN_CHAR_INDEX;
774             assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
775             byte lsb = lsbCache[index];
776             if (lsb == UNSET) {
777                 oneChar[0] = aChar;
778                 GlyphVector gv = font.createGlyphVector(frc, oneChar);
779                 lsb = (byte)gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
780                 lsbCache[index] = lsb;
781             }
782             return lsb;
783         }
784
785         public boolean equals(Object JavaDoc entry) {
786             if (entry == this) {
787                 return true;
788             }
789             if (!(entry instanceof LSBCacheEntry)) {
790                 return false;
791             }
792             LSBCacheEntry oEntry = (LSBCacheEntry)entry;
793             return (font.equals(oEntry.font) &&
794                     frc.equals(oEntry.frc));
795         }
796
797         public int hashCode() {
798             int result = 17;
799             if (font != null) {
800                 result = 37 * result + font.hashCode();
801             }
802             if (frc != null) {
803                 result = 37 * result + frc.hashCode();
804             }
805             return result;
806         }
807     }
808
809
810
811     /*
812      * here goes the fix for 4856343 [Problem with applet interaction
813      * with system selection clipboard]
814      *
815      * NOTE. In case isTrustedContext() no checking
816      * are to be performed
817      */

818
819
820     /**
821      * checks the security permissions for accessing system clipboard
822      *
823      * for untrusted context (see isTrustedContext) checks the
824      * permissions for the current event being handled
825      *
826      */

827     public static boolean canAccessSystemClipboard() {
828         boolean canAccess = false;
829         if (!GraphicsEnvironment.isHeadless()) {
830             SecurityManager JavaDoc sm = System.getSecurityManager();
831             if (sm == null) {
832                 canAccess = true;
833             } else {
834                 try {
835                     sm.checkSystemClipboardAccess();
836                     canAccess = true;
837                 } catch (SecurityException JavaDoc e) {
838                 }
839                 if (canAccess && ! isTrustedContext()) {
840                     canAccess = canCurrentEventAccessSystemClipboard(true);
841                 }
842             }
843         }
844         return canAccess;
845     }
846
847     /**
848      * Returns true if EventQueue.getCurrentEvent() has the permissions to
849      * access the system clipboard
850      */

851     public static boolean canCurrentEventAccessSystemClipboard() {
852         return isTrustedContext()
853             || canCurrentEventAccessSystemClipboard(false);
854     }
855     
856     /**
857      * Returns true if the given event has permissions to access the
858      * system clipboard
859      *
860      * @param e AWTEvent to check
861      */

862     public static boolean canEventAccessSystemClipboard(AWTEvent e) {
863         return isTrustedContext()
864             || canEventAccessSystemClipboard(e, false);
865     }
866     
867     /**
868      * returns canAccessSystemClipboard field from InputEvent
869      *
870      * @param ie InputEvent to get the field from
871      */

872     private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {
873         if (inputEvent_CanAccessSystemClipboard_Field == null) {
874             inputEvent_CanAccessSystemClipboard_Field =
875                 (Field)AccessController.doPrivileged(
876                     new java.security.PrivilegedAction JavaDoc() {
877                         public Object JavaDoc run() {
878                             Field field = null;
879                             try {
880                                 field = InputEvent.class.
881                                     getDeclaredField("canAccessSystemClipboard");
882                                 field.setAccessible(true);
883                                 return field;
884                             } catch (SecurityException JavaDoc e) {
885                             } catch (NoSuchFieldException JavaDoc e) {
886                             }
887                             return null;
888                         }
889                     });
890         }
891         if (inputEvent_CanAccessSystemClipboard_Field == null) {
892             return false;
893         }
894         boolean ret = false;
895         try {
896             ret = inputEvent_CanAccessSystemClipboard_Field.
897                 getBoolean(ie);
898         } catch(IllegalAccessException JavaDoc e) {
899         }
900         return ret;
901     }
902
903     /**
904      * Returns true if the given event is corrent gesture for
905      * accessing clipboard
906      *
907      * @param ie InputEvent to check
908      */

909
910     private static boolean isAccessClipboardGesture(InputEvent ie) {
911         boolean allowedGesture = false;
912         if (ie instanceof KeyEvent) { //we can validate only keyboard gestures
913
KeyEvent ke = (KeyEvent)ie;
914             int keyCode = ke.getKeyCode();
915             int keyModifiers = ke.getModifiers();
916             switch(keyCode) {
917             case KeyEvent.VK_C:
918             case KeyEvent.VK_V:
919             case KeyEvent.VK_X:
920                 allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);
921                 break;
922             case KeyEvent.VK_INSERT:
923                 allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||
924                                   keyModifiers == InputEvent.SHIFT_MASK);
925                 break;
926             case KeyEvent.VK_COPY:
927             case KeyEvent.VK_PASTE:
928             case KeyEvent.VK_CUT:
929                 allowedGesture = true;
930                 break;
931             case KeyEvent.VK_DELETE:
932                 allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);
933                 break;
934             }
935         }
936         return allowedGesture;
937     }
938
939     /**
940      * Returns true if e has the permissions to
941      * access the system clipboard and if it is allowed gesture (if
942      * checkGesture is true)
943      *
944      * @param e AWTEvent to check
945      * @param checkGesture boolean
946      */

947     private static boolean canEventAccessSystemClipboard(AWTEvent e,
948                                                         boolean checkGesture) {
949         if (EventQueue.isDispatchThread()) {
950             /*
951              * Checking event permissions makes sense only for event
952              * dispathing thread
953              */

954             if (e instanceof InputEvent
955                 && (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {
956                 return inputEvent_canAccessSystemClipboard((InputEvent)e);
957             } else {
958                 return false;
959             }
960         } else {
961             return true;
962         }
963     }
964
965     /**
966      * Returns true if EventQueue.getCurrentEvent() has the permissions to
967      * access the system clipboard and if it is allowed gesture (if
968      * checkGesture true)
969      *
970      * @param checkGesture boolean
971      */

972     private static boolean canCurrentEventAccessSystemClipboard(boolean
973                                                                checkGesture) {
974         AWTEvent event = EventQueue.getCurrentEvent();
975         return canEventAccessSystemClipboard(event, checkGesture);
976     }
977
978     /**
979      * see RFE 5012841 [Per AppContect security permissions] for the
980      * details
981      *
982      */

983     private static boolean isTrustedContext() {
984         return (System.getSecurityManager() == null)
985             || (AppContext.getAppContext().
986                 get(UntrustedClipboardAccess) == null);
987     }
988
989     public static String JavaDoc displayPropertiesToCSS(Font font, Color fg) {
990         StringBuffer JavaDoc rule = new StringBuffer JavaDoc("body {");
991         if (font != null) {
992             rule.append(" font-family: ");
993             rule.append(font.getFamily());
994             rule.append(" ; ");
995             rule.append(" font-size: ");
996             rule.append(font.getSize());
997             rule.append("pt ;");
998             if (font.isBold()) {
999                 rule.append(" font-weight: 700 ; ");
1000            }
1001            if (font.isItalic()) {
1002                rule.append(" font-style: italic ; ");
1003            }
1004        }
1005        if (fg != null) {
1006            rule.append(" color: #");
1007            if (fg.getRed() < 16) {
1008                rule.append('0');
1009            }
1010            rule.append(Integer.toHexString(fg.getRed()));
1011            if (fg.getGreen() < 16) {
1012                rule.append('0');
1013            }
1014            rule.append(Integer.toHexString(fg.getGreen()));
1015            if (fg.getBlue() < 16) {
1016                rule.append('0');
1017            }
1018            rule.append(Integer.toHexString(fg.getBlue()));
1019            rule.append(" ; ");
1020        }
1021        rule.append(" }");
1022        return rule.toString();
1023    }
1024
1025    /**
1026     * Utility method that creates a <code>UIDefaults.LazyValue</code> that
1027     * creates an <code>ImageIcon</code> <code>UIResource</code> for the
1028     * specified image file name. The image is loaded using
1029     * <code>getResourceAsStream</code>, starting with a call to that method
1030     * on the base class parameter. If it cannot be found, searching will
1031     * continue through the base class' inheritance hierarchy, up to and
1032     * including <code>rootClass</code>.
1033     *
1034     * @param baseClass the first class to use in searching for the resource
1035     * @param rootClass an ancestor of <code>baseClass</code> to finish the
1036     * search at
1037     * @param imageFile the name of the file to be found
1038     * @return a lazy value that creates the <code>ImageIcon</code>
1039     * <code>UIResource</code> for the image,
1040     * or null if it cannot be found
1041     */

1042    public static Object JavaDoc makeIcon(final Class JavaDoc<?> baseClass,
1043                                  final Class JavaDoc<?> rootClass,
1044                                  final String JavaDoc imageFile) {
1045
1046        return new UIDefaults.LazyValue() {
1047            public Object JavaDoc createValue(UIDefaults table) {
1048                /* Copy resource into a byte array. This is
1049                 * necessary because several browsers consider
1050                 * Class.getResource a security risk because it
1051                 * can be used to load additional classes.
1052                 * Class.getResourceAsStream just returns raw
1053                 * bytes, which we can convert to an image.
1054                 */

1055                byte[] buffer = (byte[])
1056                    java.security.AccessController.doPrivileged(
1057                        new java.security.PrivilegedAction JavaDoc() {
1058                    public Object JavaDoc run() {
1059                        try {
1060                            InputStream resource = null;
1061                            Class JavaDoc<?> srchClass = baseClass;
1062
1063                            while (srchClass != null) {
1064                                resource = srchClass.getResourceAsStream(imageFile);
1065
1066                                if (resource != null || srchClass == rootClass) {
1067                                    break;
1068                                }
1069
1070                                srchClass = srchClass.getSuperclass();
1071                            }
1072
1073                            if (resource == null) {
1074                                return null;
1075                            }
1076
1077                            BufferedInputStream in =
1078                                new BufferedInputStream(resource);
1079                            ByteArrayOutputStream out =
1080                                new ByteArrayOutputStream(1024);
1081                            byte[] buffer = new byte[1024];
1082                            int n;
1083                            while ((n = in.read(buffer)) > 0) {
1084                                out.write(buffer, 0, n);
1085                            }
1086                            in.close();
1087                            out.flush();
1088                            return out.toByteArray();
1089                        } catch (IOException ioe) {
1090                            System.err.println(ioe.toString());
1091                        }
1092                        return null;
1093                    }
1094                });
1095
1096                if (buffer == null) {
1097                    return null;
1098                }
1099                if (buffer.length == 0) {
1100                    System.err.println("warning: " + imageFile +
1101                                       " is zero-length");
1102                    return null;
1103                }
1104
1105                return new IconUIResource(new ImageIcon(buffer));
1106            }
1107        };
1108    }
1109
1110    /**
1111     * Sets the {@code SKIP_CLICK_COUNT} client property on the component
1112     * if it is an instance of {@code JTextComponent} with a
1113     * {@code DefaultCaret}. This property, used for text components acting
1114     * as editors in a table or tree, tells {@code DefaultCaret} how many
1115     * clicks to skip before starting selection.
1116     */

1117    public static void setSkipClickCount(Component JavaDoc comp, int count) {
1118        if (comp instanceof JTextComponent JavaDoc
1119                && ((JTextComponent JavaDoc) comp).getCaret() instanceof DefaultCaret JavaDoc) {
1120
1121            ((JTextComponent JavaDoc) comp).putClientProperty(SKIP_CLICK_COUNT, count);
1122        }
1123    }
1124
1125    /**
1126     * Return the MouseEvent's click count, possibly reduced by the value of
1127     * the component's {@code SKIP_CLICK_COUNT} client property. Clears
1128     * the {@code SKIP_CLICK_COUNT} property if the mouse event's click count
1129     * is 1. In order for clearing of the property to work correctly, there
1130     * must be a mousePressed implementation on the caller with this
1131     * call as the first line.
1132     */

1133    public static int getAdjustedClickCount(JTextComponent JavaDoc comp, MouseEvent e) {
1134        int cc = e.getClickCount();
1135
1136        if (cc == 1) {
1137            comp.putClientProperty(SKIP_CLICK_COUNT, null);
1138        } else {
1139            Integer JavaDoc sub = (Integer JavaDoc) comp.getClientProperty(SKIP_CLICK_COUNT);
1140            if (sub != null) {
1141                return cc - sub;
1142            }
1143        }
1144
1145        return cc;
1146    }
1147}
1148
Popular Tags