Home » openjdk-7 » sun » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package sun.swing;
   27   
   28   import java.security;
   29   import java.lang.reflect;
   30   import java.awt;
   31   import static java.awt.RenderingHints.*;
   32   import java.awt.event;
   33   import java.awt.font;
   34   import java.awt.geom;
   35   import java.awt.print.PrinterGraphics;
   36   import java.text.Bidi;
   37   import java.text.AttributedCharacterIterator;
   38   import java.text.AttributedString;
   39   
   40   import javax.swing;
   41   import javax.swing.plaf;
   42   import javax.swing.text.Highlighter;
   43   import javax.swing.text.JTextComponent;
   44   import javax.swing.text.DefaultHighlighter;
   45   import javax.swing.text.DefaultCaret;
   46   import javax.swing.table.TableCellRenderer;
   47   import javax.swing.table.TableColumnModel;
   48   
   49   import sun.swing.PrintColorUIResource;
   50   import sun.swing.ImageIconUIResource;
   51   import sun.print.ProxyPrintGraphics;
   52   import sun.awt;
   53   import sun.security.action.GetPropertyAction;
   54   import sun.security.util.SecurityConstants;
   55   import java.io;
   56   import java.util;
   57   import sun.font.FontDesignMetrics;
   58   import sun.font.FontUtilities;
   59   import sun.java2d.SunGraphicsEnvironment;
   60   
   61   import java.util.concurrent.Callable;
   62   import java.util.concurrent.Future;
   63   import java.util.concurrent.FutureTask;
   64   
   65   /**
   66    * A collection of utility methods for Swing.
   67    * <p>
   68    * <b>WARNING:</b> While this class is public, it should not be treated as
   69    * public API and its API may change in incompatable ways between dot dot
   70    * releases and even patch releases. You should not rely on this class even
   71    * existing.
   72    *
   73    */
   74   public class SwingUtilities2 {
   75       /**
   76        * The <code>AppContext</code> key for our one <code>LAFState</code>
   77        * instance.
   78        */
   79       public static final Object LAF_STATE_KEY =
   80               new StringBuffer("LookAndFeel State");
   81   
   82       // Maintain a cache of CACHE_SIZE fonts and the left side bearing
   83        // of the characters falling into the range MIN_CHAR_INDEX to
   84        // MAX_CHAR_INDEX. The values in fontCache are created as needed.
   85        private static LSBCacheEntry[] fontCache;
   86        // Windows defines 6 font desktop properties, we will therefore only
   87        // cache the metrics for 6 fonts.
   88        private static final int CACHE_SIZE = 6;
   89        // nextIndex in fontCache to insert a font into.
   90        private static int nextIndex;
   91        // LSBCacheEntry used to search in fontCache to see if we already
   92        // have an entry for a particular font
   93        private static LSBCacheEntry searchKey;
   94   
   95        // getLeftSideBearing will consult all characters that fall in the
   96        // range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
   97        private static final int MIN_CHAR_INDEX = (int)'W';
   98        private static final int MAX_CHAR_INDEX = (int)'W' + 1;
   99   
  100       public static final FontRenderContext DEFAULT_FRC =
  101           new FontRenderContext(null, false, false);
  102   
  103       /**
  104        * A JComponent client property is used to determine text aa settings.
  105        * To avoid having this property persist between look and feels changes
  106        * the value of the property is set to null in JComponent.setUI
  107        */
  108       public static final Object AA_TEXT_PROPERTY_KEY =
  109                             new StringBuffer("AATextInfoPropertyKey");
  110   
  111       /**
  112        * Attribute key for the content elements.  If it is set on an element, the
  113        * element is considered to be a line break.
  114        */
  115       public static final String IMPLIED_CR = "CR";
  116   
  117       /**
  118        * Used to tell a text component, being used as an editor for table
  119        * or tree, how many clicks it took to start editing.
  120        */
  121       private static final StringBuilder SKIP_CLICK_COUNT =
  122           new StringBuilder("skipClickCount");
  123   
  124       /* Presently this class assumes default fractional metrics.
  125        * This may need to change to emulate future platform L&Fs.
  126        */
  127       public static class AATextInfo {
  128   
  129           private static AATextInfo getAATextInfoFromMap(Map hints) {
  130   
  131               Object aaHint   = hints.get(KEY_TEXT_ANTIALIASING);
  132               Object contHint = hints.get(KEY_TEXT_LCD_CONTRAST);
  133   
  134               if (aaHint == null ||
  135                   aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
  136                   aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
  137                   return null;
  138               } else {
  139                   return new AATextInfo(aaHint, (Integer)contHint);
  140               }
  141           }
  142   
  143           public static AATextInfo getAATextInfo(boolean lafCondition) {
  144               SunToolkit.setAAFontSettingsCondition(lafCondition);
  145               Toolkit tk = Toolkit.getDefaultToolkit();
  146               Object map = tk.getDesktopProperty(SunToolkit.DESKTOPFONTHINTS);
  147               if (map instanceof Map) {
  148                   return getAATextInfoFromMap((Map)map);
  149               } else {
  150                   return null;
  151               }
  152           }
  153   
  154           Object aaHint;
  155           Integer lcdContrastHint;
  156           FontRenderContext frc;
  157   
  158           /* These are rarely constructed objects, and only when a complete
  159            * UI is being updated, so the cost of the tests here is minimal
  160            * and saves tests elsewhere.
  161            * We test that the values are ones we support/expect.
  162            */
  163           public AATextInfo(Object aaHint, Integer lcdContrastHint) {
  164               if (aaHint == null) {
  165                   throw new InternalError("null not allowed here");
  166               }
  167               if (aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
  168                   aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
  169                   throw new InternalError("AA must be on");
  170               }
  171               this.aaHint = aaHint;
  172               this.lcdContrastHint = lcdContrastHint;
  173               this.frc = new FontRenderContext(null, aaHint,
  174                                                VALUE_FRACTIONALMETRICS_DEFAULT);
  175           }
  176       }
  177   
  178       /**
  179        * Key used in client properties used to indicate that the
  180        * <code>ComponentUI</code> of the JComponent instance should be returned.
  181        */
  182       public static final Object COMPONENT_UI_PROPERTY_KEY =
  183                               new StringBuffer("ComponentUIPropertyKey");
  184   
  185       /** Client Property key for the text maximal offsets for BasicMenuItemUI */
  186       public static final StringUIClientPropertyKey BASICMENUITEMUI_MAX_TEXT_OFFSET =
  187           new StringUIClientPropertyKey ("maxTextOffset");
  188   
  189       // security stuff
  190       private static Field inputEvent_CanAccessSystemClipboard_Field = null;
  191       private static final String UntrustedClipboardAccess =
  192           "UNTRUSTED_CLIPBOARD_ACCESS_KEY";
  193   
  194       //all access to  charsBuffer is to be synchronized on charsBufferLock
  195       private static final int CHAR_BUFFER_SIZE = 100;
  196       private static final Object charsBufferLock = new Object();
  197       private static char[] charsBuffer = new char[CHAR_BUFFER_SIZE];
  198   
  199       static {
  200           fontCache = new LSBCacheEntry[CACHE_SIZE];
  201       }
  202   
  203       /**
  204        * Fill the character buffer cache.  Return the buffer length.
  205        */
  206       private static int syncCharsBuffer(String s) {
  207           int length = s.length();
  208           if ((charsBuffer == null) || (charsBuffer.length < length)) {
  209               charsBuffer = s.toCharArray();
  210           } else {
  211               s.getChars(0, length, charsBuffer, 0);
  212           }
  213           return length;
  214       }
  215   
  216       /**
  217        * checks whether TextLayout is required to handle characters.
  218        *
  219        * @param text characters to be tested
  220        * @param start start
  221        * @param limit limit
  222        * @return <tt>true</tt>  if TextLayout is required
  223        *         <tt>false</tt> if TextLayout is not required
  224        */
  225       public static final boolean isComplexLayout(char[] text, int start, int limit) {
  226           return FontUtilities.isComplexText(text, start, limit);
  227       }
  228   
  229       //
  230       // WARNING WARNING WARNING WARNING WARNING WARNING
  231       // Many of the following methods are invoked from older API.
  232       // As this older API was not passed a Component, a null Component may
  233       // now be passsed in.  For example, SwingUtilities.computeStringWidth
  234       // is implemented to call SwingUtilities2.stringWidth, the
  235       // SwingUtilities variant does not take a JComponent, as such
  236       // SwingUtilities2.stringWidth can be passed a null Component.
  237       // In other words, if you add new functionality to these methods you
  238       // need to gracefully handle null.
  239       //
  240   
  241       /**
  242        * Returns whether or not text should be drawn antialiased.
  243        *
  244        * @param c JComponent to test.
  245        * @return Whether or not text should be drawn antialiased for the
  246        *         specified component.
  247        */
  248       public static AATextInfo drawTextAntialiased(JComponent c) {
  249           if (c != null) {
  250               /* a non-null property implies some form of AA requested */
  251               return (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
  252           }
  253           // No component, assume aa is off
  254           return null;
  255       }
  256   
  257       /**
  258        * Returns the left side bearing of the first character of string. The
  259        * left side bearing is calculated from the passed in
  260        * FontMetrics.  If the passed in String is less than one
  261        * character {@code 0} is returned.
  262        *
  263        * @param c JComponent that will display the string
  264        * @param fm FontMetrics used to measure the String width
  265        * @param string String to get the left side bearing for.
  266        * @throws NullPointerException if {@code string} is {@code null}
  267        *
  268        * @return the left side bearing of the first character of string
  269        * or {@code 0} if the string is empty
  270        */
  271       public static int getLeftSideBearing(JComponent c, FontMetrics fm,
  272                                            String string) {
  273           if ((string == null) || (string.length() == 0)) {
  274               return 0;
  275           }
  276           return getLeftSideBearing(c, fm, string.charAt(0));
  277       }
  278   
  279       /**
  280        * Returns the left side bearing of the first character of string. The
  281        * left side bearing is calculated from the passed in FontMetrics.
  282        *
  283        * @param c JComponent that will display the string
  284        * @param fm FontMetrics used to measure the String width
  285        * @param firstChar Character to get the left side bearing for.
  286        */
  287       public static int getLeftSideBearing(JComponent c, FontMetrics fm,
  288                                            char firstChar) {
  289           int charIndex = (int) firstChar;
  290           if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {
  291               byte[] lsbs = null;
  292   
  293               FontRenderContext frc = getFontRenderContext(c, fm);
  294               Font font = fm.getFont();
  295               synchronized (SwingUtilities2.class) {
  296                   LSBCacheEntry entry = null;
  297                   if (searchKey == null) {
  298                       searchKey = new LSBCacheEntry(frc, font);
  299                   } else {
  300                       searchKey.reset(frc, font);
  301                   }
  302                   // See if we already have an entry for this pair
  303                   for (LSBCacheEntry cacheEntry : fontCache) {
  304                       if (searchKey.equals(cacheEntry)) {
  305                           entry = cacheEntry;
  306                           break;
  307                       }
  308                   }
  309                   if (entry == null) {
  310                       // No entry for this pair, add it.
  311                       entry = searchKey;
  312                       fontCache[nextIndex] = searchKey;
  313                       searchKey = null;
  314                       nextIndex = (nextIndex + 1) % CACHE_SIZE;
  315                   }
  316                   return entry.getLeftSideBearing(firstChar);
  317               }
  318           }
  319           return 0;
  320       }
  321   
  322       /**
  323        * Returns the FontMetrics for the current Font of the passed
  324        * in Graphics.  This method is used when a Graphics
  325        * is available, typically when painting.  If a Graphics is not
  326        * available the JComponent method of the same name should be used.
  327        * <p>
  328        * Callers should pass in a non-null JComponent, the exception
  329        * to this is if a JComponent is not readily available at the time of
  330        * painting.
  331        * <p>
  332        * This does not necessarily return the FontMetrics from the
  333        * Graphics.
  334        *
  335        * @param c JComponent requesting FontMetrics, may be null
  336        * @param g Graphics Graphics
  337        */
  338       public static FontMetrics getFontMetrics(JComponent c, Graphics g) {
  339           return getFontMetrics(c, g, g.getFont());
  340       }
  341   
  342   
  343       /**
  344        * Returns the FontMetrics for the specified Font.
  345        * This method is used when a Graphics is available, typically when
  346        * painting.  If a Graphics is not available the JComponent method of
  347        * the same name should be used.
  348        * <p>
  349        * Callers should pass in a non-null JComonent, the exception
  350        * to this is if a JComponent is not readily available at the time of
  351        * painting.
  352        * <p>
  353        * This does not necessarily return the FontMetrics from the
  354        * Graphics.
  355        *
  356        * @param c JComponent requesting FontMetrics, may be null
  357        * @param c Graphics Graphics
  358        * @param font Font to get FontMetrics for
  359        */
  360       public static FontMetrics getFontMetrics(JComponent c, Graphics g,
  361                                                Font font) {
  362           if (c != null) {
  363               // Note: We assume that we're using the FontMetrics
  364               // from the widget to layout out text, otherwise we can get
  365               // mismatches when printing.
  366               return c.getFontMetrics(font);
  367           }
  368           return Toolkit.getDefaultToolkit().getFontMetrics(font);
  369       }
  370   
  371   
  372       /**
  373        * Returns the width of the passed in String.
  374        * If the passed String is <code>null</code>, returns zero.
  375        *
  376        * @param c JComponent that will display the string, may be null
  377        * @param fm FontMetrics used to measure the String width
  378        * @param string String to get the width of
  379        */
  380       public static int stringWidth(JComponent c, FontMetrics fm, String string){
  381           if (string == null || string.equals("")) {
  382               return 0;
  383           }
  384           boolean needsTextLayout = ((c != null) &&
  385                   (c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));
  386           if (needsTextLayout) {
  387               synchronized(charsBufferLock) {
  388                   int length = syncCharsBuffer(string);
  389                   needsTextLayout = isComplexLayout(charsBuffer, 0, length);
  390               }
  391           }
  392           if (needsTextLayout) {
  393               TextLayout layout = createTextLayout(c, string,
  394                                       fm.getFont(), fm.getFontRenderContext());
  395               return (int) layout.getAdvance();
  396           } else {
  397               return fm.stringWidth(string);
  398           }
  399       }
  400   
  401   
  402       /**
  403        * Clips the passed in String to the space provided.
  404        *
  405        * @param c JComponent that will display the string, may be null
  406        * @param fm FontMetrics used to measure the String width
  407        * @param string String to display
  408        * @param availTextWidth Amount of space that the string can be drawn in
  409        * @return Clipped string that can fit in the provided space.
  410        */
  411       public static String clipStringIfNecessary(JComponent c, FontMetrics fm,
  412                                                  String string,
  413                                                  int availTextWidth) {
  414           if ((string == null) || (string.equals("")))  {
  415               return "";
  416           }
  417           int textWidth = SwingUtilities2.stringWidth(c, fm, string);
  418           if (textWidth > availTextWidth) {
  419               return SwingUtilities2.clipString(c, fm, string, availTextWidth);
  420           }
  421           return string;
  422       }
  423   
  424   
  425       /**
  426        * Clips the passed in String to the space provided.  NOTE: this assumes
  427        * the string does not fit in the available space.
  428        *
  429        * @param c JComponent that will display the string, may be null
  430        * @param fm FontMetrics used to measure the String width
  431        * @param string String to display
  432        * @param availTextWidth Amount of space that the string can be drawn in
  433        * @return Clipped string that can fit in the provided space.
  434        */
  435       public static String clipString(JComponent c, FontMetrics fm,
  436                                       String string, int availTextWidth) {
  437           // c may be null here.
  438           String clipString = "...";
  439           availTextWidth -= SwingUtilities2.stringWidth(c, fm, clipString);
  440           if (availTextWidth <= 0) {
  441               //can not fit any characters
  442               return clipString;
  443           }
  444   
  445           boolean needsTextLayout;
  446           synchronized (charsBufferLock) {
  447               int stringLength = syncCharsBuffer(string);
  448               needsTextLayout =
  449                   isComplexLayout(charsBuffer, 0, stringLength);
  450               if (!needsTextLayout) {
  451                   int width = 0;
  452                   for (int nChars = 0; nChars < stringLength; nChars++) {
  453                       width += fm.charWidth(charsBuffer[nChars]);
  454                       if (width > availTextWidth) {
  455                           string = string.substring(0, nChars);
  456                           break;
  457                       }
  458                   }
  459               }
  460           }
  461           if (needsTextLayout) {
  462               FontRenderContext frc = getFontRenderContext(c, fm);
  463               AttributedString aString = new AttributedString(string);
  464               if (c != null) {
  465                   aString.addAttribute(TextAttribute.NUMERIC_SHAPING,
  466                           c.getClientProperty(TextAttribute.NUMERIC_SHAPING));
  467               }
  468               LineBreakMeasurer measurer =
  469                   new LineBreakMeasurer(aString.getIterator(), frc);
  470               int nChars = measurer.nextOffset(availTextWidth);
  471               string = string.substring(0, nChars);
  472   
  473           }
  474           return string + clipString;
  475       }
  476   
  477   
  478       /**
  479        * Draws the string at the specified location.
  480        *
  481        * @param c JComponent that will display the string, may be null
  482        * @param g Graphics to draw the text to
  483        * @param text String to display
  484        * @param x X coordinate to draw the text at
  485        * @param y Y coordinate to draw the text at
  486        */
  487       public static void drawString(JComponent c, Graphics g, String text,
  488                                     int x, int y) {
  489           // c may be null
  490   
  491           // All non-editable widgets that draw strings call into this
  492           // methods.  By non-editable that means widgets like JLabel, JButton
  493           // but NOT JTextComponents.
  494           if ( text == null || text.length() <= 0 ) { //no need to paint empty strings
  495               return;
  496           }
  497           if (isPrinting(g)) {
  498               Graphics2D g2d = getGraphics2D(g);
  499               if (g2d != null) {
  500                   /* The printed text must scale linearly with the UI.
  501                    * Calculate the width on screen, obtain a TextLayout with
  502                    * advances for the printer graphics FRC, and then justify
  503                    * it to fit in the screen width. This distributes the spacing
  504                    * more evenly than directly laying out to the screen advances.
  505                    */
  506                   float screenWidth = (float)
  507                      g2d.getFont().getStringBounds(text, DEFAULT_FRC).getWidth();
  508                   TextLayout layout = createTextLayout(c, text, g2d.getFont(),
  509                                                      g2d.getFontRenderContext());
  510   
  511                   layout = layout.getJustifiedLayout(screenWidth);
  512                   /* Use alternate print color if specified */
  513                   Color col = g2d.getColor();
  514                   if (col instanceof PrintColorUIResource) {
  515                       g2d.setColor(((PrintColorUIResource)col).getPrintColor());
  516                   }
  517   
  518                   layout.draw(g2d, x, y);
  519   
  520                   g2d.setColor(col);
  521   
  522                   return;
  523               }
  524           }
  525   
  526           // If we get here we're not printing
  527           AATextInfo info = drawTextAntialiased(c);
  528           if (info != null && (g instanceof Graphics2D)) {
  529               Graphics2D g2 = (Graphics2D)g;
  530   
  531               Object oldContrast = null;
  532               Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
  533               if (info.aaHint != oldAAValue) {
  534                   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);
  535               } else {
  536                   oldAAValue = null;
  537               }
  538               if (info.lcdContrastHint != null) {
  539                   oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
  540                   if (info.lcdContrastHint.equals(oldContrast)) {
  541                       oldContrast = null;
  542                   } else {
  543                       g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
  544                                           info.lcdContrastHint);
  545                   }
  546               }
  547   
  548               boolean needsTextLayout = ((c != null) &&
  549                   (c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));
  550               if (needsTextLayout) {
  551                   synchronized(charsBufferLock) {
  552                       int length = syncCharsBuffer(text);
  553                       needsTextLayout = isComplexLayout(charsBuffer, 0, length);
  554                   }
  555               }
  556               if (needsTextLayout) {
  557                   TextLayout layout = createTextLayout(c, text, g2.getFont(),
  558                                                       g2.getFontRenderContext());
  559                   layout.draw(g2, x, y);
  560               } else {
  561                   g.drawString(text, x, y);
  562               }
  563   
  564               if (oldAAValue != null) {
  565                   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
  566               }
  567               if (oldContrast != null) {
  568                   g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);
  569               }
  570           }
  571           else {
  572               g.drawString(text, x, y);
  573           }
  574       }
  575   
  576   
  577       /**
  578        * Draws the string at the specified location underlining the specified
  579        * character.
  580        *
  581        * @param c JComponent that will display the string, may be null
  582        * @param g Graphics to draw the text to
  583        * @param text String to display
  584        * @param underlinedIndex Index of a character in the string to underline
  585        * @param x X coordinate to draw the text at
  586        * @param y Y coordinate to draw the text at
  587        */
  588       public static void drawStringUnderlineCharAt(JComponent c,Graphics g,
  589                              String text, int underlinedIndex, int x,int y) {
  590           if (text == null || text.length() <= 0) {
  591               return;
  592           }
  593           SwingUtilities2.drawString(c, g, text, x, y);
  594           int textLength = text.length();
  595           if (underlinedIndex >= 0 && underlinedIndex < textLength ) {
  596               int underlineRectY = y;
  597               int underlineRectHeight = 1;
  598               int underlineRectX = 0;
  599               int underlineRectWidth = 0;
  600               boolean isPrinting = isPrinting(g);
  601               boolean needsTextLayout = isPrinting;
  602               if (!needsTextLayout) {
  603                   synchronized (charsBufferLock) {
  604                       syncCharsBuffer(text);
  605                       needsTextLayout =
  606                           isComplexLayout(charsBuffer, 0, textLength);
  607                   }
  608               }
  609               if (!needsTextLayout) {
  610                   FontMetrics fm = g.getFontMetrics();
  611                   underlineRectX = x +
  612                       SwingUtilities2.stringWidth(c,fm,
  613                                           text.substring(0,underlinedIndex));
  614                   underlineRectWidth = fm.charWidth(text.
  615                                                     charAt(underlinedIndex));
  616               } else {
  617                   Graphics2D g2d = getGraphics2D(g);
  618                   if (g2d != null) {
  619                       TextLayout layout =
  620                           createTextLayout(c, text, g2d.getFont(),
  621                                          g2d.getFontRenderContext());
  622                       if (isPrinting) {
  623                           float screenWidth = (float)g2d.getFont().
  624                               getStringBounds(text, DEFAULT_FRC).getWidth();
  625                           layout = layout.getJustifiedLayout(screenWidth);
  626                       }
  627                       TextHitInfo leading =
  628                           TextHitInfo.leading(underlinedIndex);
  629                       TextHitInfo trailing =
  630                           TextHitInfo.trailing(underlinedIndex);
  631                       Shape shape =
  632                           layout.getVisualHighlightShape(leading, trailing);
  633                       Rectangle rect = shape.getBounds();
  634                       underlineRectX = x + rect.x;
  635                       underlineRectWidth = rect.width;
  636                   }
  637               }
  638               g.fillRect(underlineRectX, underlineRectY + 1,
  639                          underlineRectWidth, underlineRectHeight);
  640           }
  641       }
  642   
  643   
  644       /**
  645        * A variation of locationToIndex() which only returns an index if the
  646        * Point is within the actual bounds of a list item (not just in the cell)
  647        * and if the JList has the "List.isFileList" client property set.
  648        * Otherwise, this method returns -1.
  649        * This is used to make WindowsL&F JFileChooser act like native dialogs.
  650        */
  651       public static int loc2IndexFileList(JList list, Point point) {
  652           int index = list.locationToIndex(point);
  653           if (index != -1) {
  654               Object bySize = list.getClientProperty("List.isFileList");
  655               if (bySize instanceof Boolean && ((Boolean)bySize).booleanValue() &&
  656                   !pointIsInActualBounds(list, index, point)) {
  657                   index = -1;
  658               }
  659           }
  660           return index;
  661       }
  662   
  663   
  664       /**
  665        * Returns true if the given point is within the actual bounds of the
  666        * JList item at index (not just inside the cell).
  667        */
  668       private static boolean pointIsInActualBounds(JList list, int index,
  669                                                   Point point) {
  670           ListCellRenderer renderer = list.getCellRenderer();
  671           ListModel dataModel = list.getModel();
  672           Object value = dataModel.getElementAt(index);
  673           Component item = renderer.getListCellRendererComponent(list,
  674                             value, index, false, false);
  675           Dimension itemSize = item.getPreferredSize();
  676           Rectangle cellBounds = list.getCellBounds(index, index);
  677           if (!item.getComponentOrientation().isLeftToRight()) {
  678               cellBounds.x += (cellBounds.width - itemSize.width);
  679           }
  680           cellBounds.width = itemSize.width;
  681   
  682           return cellBounds.contains(point);
  683       }
  684   
  685   
  686       /**
  687        * Returns true if the given point is outside the preferredSize of the
  688        * item at the given row of the table.  (Column must be 0).
  689        * Does not check the "Table.isFileList" property. That should be checked
  690        * before calling this method.
  691        * This is used to make WindowsL&F JFileChooser act like native dialogs.
  692        */
  693       public static boolean pointOutsidePrefSize(JTable table, int row, int column, Point p) {
  694           if (table.convertColumnIndexToModel(column) != 0 || row == -1) {
  695               return true;
  696           }
  697           TableCellRenderer tcr = table.getCellRenderer(row, column);
  698           Object value = table.getValueAt(row, column);
  699           Component cell = tcr.getTableCellRendererComponent(table, value, false,
  700                   false, row, column);
  701           Dimension itemSize = cell.getPreferredSize();
  702           Rectangle cellBounds = table.getCellRect(row, column, false);
  703           cellBounds.width = itemSize.width;
  704           cellBounds.height = itemSize.height;
  705   
  706           // See if coords are inside
  707           // ASSUME: mouse x,y will never be < cell's x,y
  708           assert (p.x >= cellBounds.x && p.y >= cellBounds.y);
  709           return p.x > cellBounds.x + cellBounds.width ||
  710                   p.y > cellBounds.y + cellBounds.height;
  711       }
  712   
  713       /**
  714        * Set the lead and anchor without affecting selection.
  715        */
  716       public static void setLeadAnchorWithoutSelection(ListSelectionModel model,
  717                                                        int lead, int anchor) {
  718           if (anchor == -1) {
  719               anchor = lead;
  720           }
  721           if (lead == -1) {
  722               model.setAnchorSelectionIndex(-1);
  723               model.setLeadSelectionIndex(-1);
  724           } else {
  725               if (model.isSelectedIndex(lead)) {
  726                   model.addSelectionInterval(lead, lead);
  727               } else {
  728                   model.removeSelectionInterval(lead, lead);
  729               }
  730               model.setAnchorSelectionIndex(anchor);
  731           }
  732       }
  733   
  734       /**
  735        * Ignore mouse events if the component is null, not enabled, the event
  736        * is not associated with the left mouse button, or the event has been
  737        * consumed.
  738        */
  739       public static boolean shouldIgnore(MouseEvent me, JComponent c) {
  740           return c == null || !c.isEnabled()
  741                            || !SwingUtilities.isLeftMouseButton(me)
  742                            || me.isConsumed();
  743       }
  744   
  745       /**
  746        * Request focus on the given component if it doesn't already have it
  747        * and <code>isRequestFocusEnabled()</code> returns true.
  748        */
  749       public static void adjustFocus(JComponent c) {
  750           if (!c.hasFocus() && c.isRequestFocusEnabled()) {
  751               c.requestFocus();
  752           }
  753       }
  754   
  755       /**
  756        * The following draw functions have the same semantic as the
  757        * Graphics methods with the same names.
  758        *
  759        * this is used for printing
  760        */
  761       public static int drawChars(JComponent c, Graphics g,
  762                                    char[] data,
  763                                    int offset,
  764                                    int length,
  765                                    int x,
  766                                    int y) {
  767           if ( length <= 0 ) { //no need to paint empty strings
  768               return x;
  769           }
  770           int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
  771           if (isPrinting(g)) {
  772               Graphics2D g2d = getGraphics2D(g);
  773               if (g2d != null) {
  774                   FontRenderContext deviceFontRenderContext = g2d.
  775                       getFontRenderContext();
  776                   FontRenderContext frc = getFontRenderContext(c);
  777                   if (frc != null &&
  778                       !isFontRenderContextPrintCompatible
  779                       (deviceFontRenderContext, frc)) {
  780                       TextLayout layout =
  781                           createTextLayout(c, new String(data, offset, length),
  782                                          g2d.getFont(),
  783                                          deviceFontRenderContext);
  784                       float screenWidth = (float)g2d.getFont().
  785                           getStringBounds(data, offset, offset + length, frc).
  786                           getWidth();
  787                       layout = layout.getJustifiedLayout(screenWidth);
  788   
  789                       /* Use alternate print color if specified */
  790                       Color col = g2d.getColor();
  791                       if (col instanceof PrintColorUIResource) {
  792                           g2d.setColor(((PrintColorUIResource)col).getPrintColor());
  793                       }
  794   
  795                       layout.draw(g2d,x,y);
  796   
  797                       g2d.setColor(col);
  798   
  799                       return nextX;
  800                   }
  801               }
  802           }
  803           // Assume we're not printing if we get here, or that we are invoked
  804           // via Swing text printing which is laid out for the printer.
  805           AATextInfo info = drawTextAntialiased(c);
  806           if (info != null && (g instanceof Graphics2D)) {
  807               Graphics2D g2 = (Graphics2D)g;
  808   
  809               Object oldContrast = null;
  810               Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
  811               if (info.aaHint != null && info.aaHint != oldAAValue) {
  812                   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);
  813               } else {
  814                   oldAAValue = null;
  815               }
  816               if (info.lcdContrastHint != null) {
  817                   oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
  818                   if (info.lcdContrastHint.equals(oldContrast)) {
  819                       oldContrast = null;
  820                   } else {
  821                       g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
  822                                           info.lcdContrastHint);
  823                   }
  824               }
  825   
  826               g.drawChars(data, offset, length, x, y);
  827   
  828               if (oldAAValue != null) {
  829                   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
  830               }
  831               if (oldContrast != null) {
  832                   g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);
  833               }
  834           }
  835           else {
  836               g.drawChars(data, offset, length, x, y);
  837           }
  838           return nextX;
  839       }
  840   
  841       /*
  842        * see documentation for drawChars
  843        * returns the advance
  844        */
  845       public static float drawString(JComponent c, Graphics g,
  846                                      AttributedCharacterIterator iterator,
  847                                      int x,
  848                                      int y) {
  849   
  850           float retVal;
  851           boolean isPrinting = isPrinting(g);
  852           Color col = g.getColor();
  853   
  854           if (isPrinting) {
  855               /* Use alternate print color if specified */
  856               if (col instanceof PrintColorUIResource) {
  857                   g.setColor(((PrintColorUIResource)col).getPrintColor());
  858               }
  859           }
  860   
  861           Graphics2D g2d = getGraphics2D(g);
  862           if (g2d == null) {
  863               g.drawString(iterator,x,y); //for the cases where advance
  864                                           //matters it should not happen
  865               retVal = x;
  866   
  867           } else {
  868               FontRenderContext frc;
  869               if (isPrinting) {
  870                   frc = getFontRenderContext(c);
  871                   if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
  872                       frc = new FontRenderContext(frc.getTransform(), false, false);
  873                   }
  874               } else if ((frc = getFRCProperty(c)) != null) {
  875                   /* frc = frc; ! */
  876               } else {
  877                   frc = g2d.getFontRenderContext();
  878               }
  879               TextLayout layout = new TextLayout(iterator, frc);
  880               if (isPrinting) {
  881                   FontRenderContext deviceFRC = g2d.getFontRenderContext();
  882                   if (!isFontRenderContextPrintCompatible(frc, deviceFRC)) {
  883                       float screenWidth = layout.getAdvance();
  884                       layout = new TextLayout(iterator, deviceFRC);
  885                       layout = layout.getJustifiedLayout(screenWidth);
  886                   }
  887               }
  888               layout.draw(g2d, x, y);
  889               retVal = layout.getAdvance();
  890           }
  891   
  892           if (isPrinting) {
  893               g.setColor(col);
  894           }
  895   
  896           return retVal;
  897       }
  898   
  899       private static TextLayout createTextLayout(JComponent c, String s,
  900                                               Font f, FontRenderContext frc) {
  901           Object shaper = (c == null ?
  902                       null : c.getClientProperty(TextAttribute.NUMERIC_SHAPING));
  903           if (shaper == null) {
  904               return new TextLayout(s, f, frc);
  905           } else {
  906               Map<TextAttribute, Object> a = new HashMap<TextAttribute, Object>();
  907               a.put(TextAttribute.FONT, f);
  908               a.put(TextAttribute.NUMERIC_SHAPING, shaper);
  909               return new TextLayout(s, a, frc);
  910           }
  911       }
  912   
  913       /*
  914        * Checks if two given FontRenderContexts are compatible for printing.
  915        * We can't just use equals as we want to exclude from the comparison :
  916        * + whether AA is set as irrelevant for printing and shouldn't affect
  917        * printed metrics anyway
  918        * + any translation component in the transform of either FRC, as it
  919        * does not affect metrics.
  920        * Compatible means no special handling needed for text painting
  921        */
  922       private static boolean
  923           isFontRenderContextPrintCompatible(FontRenderContext frc1,
  924                                              FontRenderContext frc2) {
  925   
  926           if (frc1 == frc2) {
  927               return true;
  928           }
  929   
  930           if (frc1 == null || frc2 == null) { // not supposed to happen
  931               return false;
  932           }
  933   
  934           if (frc1.getFractionalMetricsHint() !=
  935               frc2.getFractionalMetricsHint()) {
  936               return false;
  937           }
  938   
  939           /* If both are identity, return true */
  940           if (!frc1.isTransformed() && !frc2.isTransformed()) {
  941               return true;
  942           }
  943   
  944           /* That's the end of the cheap tests, need to get and compare
  945            * the transform matrices. We don't care about the translation
  946            * components, so return true if they are otherwise identical.
  947            */
  948           double[] mat1 = new double[4];
  949           double[] mat2 = new double[4];
  950           frc1.getTransform().getMatrix(mat1);
  951           frc2.getTransform().getMatrix(mat2);
  952           return
  953               mat1[0] == mat2[0] &&
  954               mat1[1] == mat2[1] &&
  955               mat1[2] == mat2[2] &&
  956               mat1[3] == mat2[3];
  957       }
  958   
  959       /*
  960        * Tries it best to get Graphics2D out of the given Graphics
  961        * returns null if can not derive it.
  962        */
  963       public static Graphics2D getGraphics2D(Graphics g) {
  964           if (g instanceof Graphics2D) {
  965               return (Graphics2D) g;
  966           } else if (g instanceof ProxyPrintGraphics) {
  967               return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());
  968           } else {
  969               return null;
  970           }
  971       }
  972   
  973       /*
  974        * Returns FontRenderContext associated with Component.
  975        * FontRenderContext from Component.getFontMetrics is associated
  976        * with the component.
  977        *
  978        * Uses Component.getFontMetrics to get the FontRenderContext from.
  979        * see JComponent.getFontMetrics and TextLayoutStrategy.java
  980        */
  981       public static FontRenderContext getFontRenderContext(Component c) {
  982           assert c != null;
  983           if (c == null) {
  984               return DEFAULT_FRC;
  985           } else {
  986               return c.getFontMetrics(c.getFont()).getFontRenderContext();
  987           }
  988       }
  989   
  990       /**
  991        * A convenience method to get FontRenderContext.
  992        * Returns the FontRenderContext for the passed in FontMetrics or
  993        * for the passed in Component if FontMetrics is null
  994        */
  995       private static FontRenderContext getFontRenderContext(Component c, FontMetrics fm) {
  996           assert fm != null || c!= null;
  997           return (fm != null) ? fm.getFontRenderContext()
  998               : getFontRenderContext(c);
  999       }
 1000   
 1001       /*
 1002        * This method is to be used only for JComponent.getFontMetrics.
 1003        * In all other places to get FontMetrics we need to use
 1004        * JComponent.getFontMetrics.
 1005        *
 1006        */
 1007       public static FontMetrics getFontMetrics(JComponent c, Font font) {
 1008           FontRenderContext  frc = getFRCProperty(c);
 1009           if (frc == null) {
 1010               frc = DEFAULT_FRC;
 1011           }
 1012           return FontDesignMetrics.getMetrics(font, frc);
 1013       }
 1014   
 1015   
 1016       /* Get any FontRenderContext associated with a JComponent
 1017        * - may return null
 1018        */
 1019       private static FontRenderContext getFRCProperty(JComponent c) {
 1020           if (c != null) {
 1021               AATextInfo info =
 1022                   (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
 1023               if (info != null) {
 1024                   return info.frc;
 1025               }
 1026           }
 1027           return null;
 1028       }
 1029   
 1030       /*
 1031        * returns true if the Graphics is print Graphics
 1032        * false otherwise
 1033        */
 1034       static boolean isPrinting(Graphics g) {
 1035           return (g instanceof PrinterGraphics || g instanceof PrintGraphics);
 1036       }
 1037   
 1038       /**
 1039        * Determines whether the SelectedTextColor should be used for painting text
 1040        * foreground for the specified highlight.
 1041        *
 1042        * Returns true only if the highlight painter for the specified highlight
 1043        * is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter
 1044        * or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color
 1045        * is null or equals to the selection color of the text component.
 1046        *
 1047        * This is a hack for fixing both bugs 4761990 and 5003294
 1048        */
 1049       public static boolean useSelectedTextColor(Highlighter.Highlight h, JTextComponent c) {
 1050           Highlighter.HighlightPainter painter = h.getPainter();
 1051           String painterClass = painter.getClass().getName();
 1052           if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
 1053                   painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
 1054               return false;
 1055           }
 1056           try {
 1057               DefaultHighlighter.DefaultHighlightPainter defPainter =
 1058                       (DefaultHighlighter.DefaultHighlightPainter) painter;
 1059               if (defPainter.getColor() != null &&
 1060                       !defPainter.getColor().equals(c.getSelectionColor())) {
 1061                   return false;
 1062               }
 1063           } catch (ClassCastException e) {
 1064               return false;
 1065           }
 1066           return true;
 1067       }
 1068   
 1069       /**
 1070        * LSBCacheEntry is used to cache the left side bearing (lsb) for
 1071        * a particular <code>Font</code> and <code>FontRenderContext</code>.
 1072        * This only caches characters that fall in the range
 1073        * <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.
 1074        */
 1075       private static class LSBCacheEntry {
 1076           // Used to indicate a particular entry in lsb has not been set.
 1077           private static final byte UNSET = Byte.MAX_VALUE;
 1078           // Used in creating a GlyphVector to get the lsb
 1079           private static final char[] oneChar = new char[1];
 1080   
 1081           private byte[] lsbCache;
 1082           private Font font;
 1083           private FontRenderContext frc;
 1084   
 1085   
 1086           public LSBCacheEntry(FontRenderContext frc, Font font) {
 1087               lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
 1088               reset(frc, font);
 1089   
 1090           }
 1091   
 1092           public void reset(FontRenderContext frc, Font font) {
 1093               this.font = font;
 1094               this.frc = frc;
 1095               for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
 1096                   lsbCache[counter] = UNSET;
 1097               }
 1098           }
 1099   
 1100           public int getLeftSideBearing(char aChar) {
 1101               int index = aChar - MIN_CHAR_INDEX;
 1102               assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
 1103               byte lsb = lsbCache[index];
 1104               if (lsb == UNSET) {
 1105                   oneChar[0] = aChar;
 1106                   GlyphVector gv = font.createGlyphVector(frc, oneChar);
 1107                   lsb = (byte) gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
 1108                   if (lsb < 0) {
 1109                       /* HRGB/HBGR LCD glyph images will always have a pixel
 1110                        * on the left used in colour fringe reduction.
 1111                        * Text rendering positions this correctly but here
 1112                        * we are using the glyph image to adjust that position
 1113                        * so must account for it.
 1114                        */
 1115                       Object aaHint = frc.getAntiAliasingHint();
 1116                       if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||
 1117                               aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {
 1118                           lsb++;
 1119                       }
 1120                   }
 1121                   lsbCache[index] = lsb;
 1122               }
 1123               return lsb;
 1124   
 1125   
 1126           }
 1127   
 1128           public boolean equals(Object entry) {
 1129               if (entry == this) {
 1130                   return true;
 1131               }
 1132               if (!(entry instanceof LSBCacheEntry)) {
 1133                   return false;
 1134               }
 1135               LSBCacheEntry oEntry = (LSBCacheEntry) entry;
 1136               return (font.equals(oEntry.font) &&
 1137                       frc.equals(oEntry.frc));
 1138           }
 1139   
 1140           public int hashCode() {
 1141               int result = 17;
 1142               if (font != null) {
 1143                   result = 37 * result + font.hashCode();
 1144               }
 1145               if (frc != null) {
 1146                   result = 37 * result + frc.hashCode();
 1147               }
 1148               return result;
 1149           }
 1150       }
 1151   
 1152       /*
 1153        * here goes the fix for 4856343 [Problem with applet interaction
 1154        * with system selection clipboard]
 1155        *
 1156        * NOTE. In case isTrustedContext() no checking
 1157        * are to be performed
 1158        */
 1159   
 1160       /**
 1161       * checks the security permissions for accessing system clipboard
 1162       *
 1163       * for untrusted context (see isTrustedContext) checks the
 1164       * permissions for the current event being handled
 1165       *
 1166       */
 1167      public static boolean canAccessSystemClipboard() {
 1168          boolean canAccess = false;
 1169          if (!GraphicsEnvironment.isHeadless()) {
 1170              SecurityManager sm = System.getSecurityManager();
 1171              if (sm == null) {
 1172                  canAccess = true;
 1173              } else {
 1174                  try {
 1175                      sm.checkSystemClipboardAccess();
 1176                      canAccess = true;
 1177                  } catch (SecurityException e) {
 1178                  }
 1179                  if (canAccess && ! isTrustedContext()) {
 1180                      canAccess = canCurrentEventAccessSystemClipboard(true);
 1181                  }
 1182              }
 1183          }
 1184          return canAccess;
 1185      }
 1186       /**
 1187       * Returns true if EventQueue.getCurrentEvent() has the permissions to
 1188        * access the system clipboard
 1189        */
 1190       public static boolean canCurrentEventAccessSystemClipboard() {
 1191           return  isTrustedContext()
 1192               || canCurrentEventAccessSystemClipboard(false);
 1193       }
 1194   
 1195       /**
 1196        * Returns true if the given event has permissions to access the
 1197        * system clipboard
 1198        *
 1199        * @param e AWTEvent to check
 1200        */
 1201       public static boolean canEventAccessSystemClipboard(AWTEvent e) {
 1202           return isTrustedContext()
 1203               || canEventAccessSystemClipboard(e, false);
 1204       }
 1205   
 1206       /**
 1207        * returns canAccessSystemClipboard field from InputEvent
 1208        *
 1209        * @param ie InputEvent to get the field from
 1210        */
 1211       private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {
 1212           if (inputEvent_CanAccessSystemClipboard_Field == null) {
 1213               inputEvent_CanAccessSystemClipboard_Field =
 1214                   AccessController.doPrivileged(
 1215                       new java.security.PrivilegedAction<Field>() {
 1216                           public Field run() {
 1217                               try {
 1218                                   Field field = InputEvent.class.
 1219                                       getDeclaredField("canAccessSystemClipboard");
 1220                                   field.setAccessible(true);
 1221                                   return field;
 1222                               } catch (SecurityException e) {
 1223                               } catch (NoSuchFieldException e) {
 1224                               }
 1225                               return null;
 1226                           }
 1227                       });
 1228           }
 1229           if (inputEvent_CanAccessSystemClipboard_Field == null) {
 1230               return false;
 1231           }
 1232           boolean ret = false;
 1233           try {
 1234               ret = inputEvent_CanAccessSystemClipboard_Field.
 1235                   getBoolean(ie);
 1236           } catch(IllegalAccessException e) {
 1237           }
 1238           return ret;
 1239       }
 1240   
 1241       /**
 1242        * Returns true if the given event is corrent gesture for
 1243        * accessing clipboard
 1244        *
 1245        * @param ie InputEvent to check
 1246        */
 1247   
 1248       private static boolean isAccessClipboardGesture(InputEvent ie) {
 1249           boolean allowedGesture = false;
 1250           if (ie instanceof KeyEvent) { //we can validate only keyboard gestures
 1251               KeyEvent ke = (KeyEvent)ie;
 1252               int keyCode = ke.getKeyCode();
 1253               int keyModifiers = ke.getModifiers();
 1254               switch(keyCode) {
 1255               case KeyEvent.VK_C:
 1256               case KeyEvent.VK_V:
 1257               case KeyEvent.VK_X:
 1258                   allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);
 1259                   break;
 1260               case KeyEvent.VK_INSERT:
 1261                   allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||
 1262                                     keyModifiers == InputEvent.SHIFT_MASK);
 1263                   break;
 1264               case KeyEvent.VK_COPY:
 1265               case KeyEvent.VK_PASTE:
 1266               case KeyEvent.VK_CUT:
 1267                   allowedGesture = true;
 1268                   break;
 1269               case KeyEvent.VK_DELETE:
 1270                   allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);
 1271                   break;
 1272               }
 1273           }
 1274           return allowedGesture;
 1275       }
 1276   
 1277       /**
 1278        * Returns true if e has the permissions to
 1279        * access the system clipboard and if it is allowed gesture (if
 1280        * checkGesture is true)
 1281        *
 1282        * @param e AWTEvent to check
 1283        * @param checkGesture boolean
 1284        */
 1285       private static boolean canEventAccessSystemClipboard(AWTEvent e,
 1286                                                           boolean checkGesture) {
 1287           if (EventQueue.isDispatchThread()) {
 1288               /*
 1289                * Checking event permissions makes sense only for event
 1290                * dispathing thread
 1291                */
 1292               if (e instanceof InputEvent
 1293                   && (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {
 1294                   return inputEvent_canAccessSystemClipboard((InputEvent)e);
 1295               } else {
 1296                   return false;
 1297               }
 1298           } else {
 1299               return true;
 1300           }
 1301       }
 1302   
 1303       /**
 1304        * Returns true if EventQueue.getCurrentEvent() has the permissions to
 1305        * access the system clipboard and if it is allowed gesture (if
 1306        * checkGesture true)
 1307        *
 1308        * @param checkGesture boolean
 1309        */
 1310       private static boolean canCurrentEventAccessSystemClipboard(boolean
 1311                                                                  checkGesture) {
 1312           AWTEvent event = EventQueue.getCurrentEvent();
 1313           return canEventAccessSystemClipboard(event, checkGesture);
 1314       }
 1315   
 1316       /**
 1317        * see RFE 5012841 [Per AppContect security permissions] for the
 1318        * details
 1319        *
 1320        */
 1321       private static boolean isTrustedContext() {
 1322           return (System.getSecurityManager() == null)
 1323               || (AppContext.getAppContext().
 1324                   get(UntrustedClipboardAccess) == null);
 1325       }
 1326   
 1327       public static String displayPropertiesToCSS(Font font, Color fg) {
 1328           StringBuffer rule = new StringBuffer("body {");
 1329           if (font != null) {
 1330               rule.append(" font-family: ");
 1331               rule.append(font.getFamily());
 1332               rule.append(" ; ");
 1333               rule.append(" font-size: ");
 1334               rule.append(font.getSize());
 1335               rule.append("pt ;");
 1336               if (font.isBold()) {
 1337                   rule.append(" font-weight: 700 ; ");
 1338               }
 1339               if (font.isItalic()) {
 1340                   rule.append(" font-style: italic ; ");
 1341               }
 1342           }
 1343           if (fg != null) {
 1344               rule.append(" color: #");
 1345               if (fg.getRed() < 16) {
 1346                   rule.append('0');
 1347               }
 1348               rule.append(Integer.toHexString(fg.getRed()));
 1349               if (fg.getGreen() < 16) {
 1350                   rule.append('0');
 1351               }
 1352               rule.append(Integer.toHexString(fg.getGreen()));
 1353               if (fg.getBlue() < 16) {
 1354                   rule.append('0');
 1355               }
 1356               rule.append(Integer.toHexString(fg.getBlue()));
 1357               rule.append(" ; ");
 1358           }
 1359           rule.append(" }");
 1360           return rule.toString();
 1361       }
 1362   
 1363       /**
 1364        * Utility method that creates a <code>UIDefaults.LazyValue</code> that
 1365        * creates an <code>ImageIcon</code> <code>UIResource</code> for the
 1366        * specified image file name. The image is loaded using
 1367        * <code>getResourceAsStream</code>, starting with a call to that method
 1368        * on the base class parameter. If it cannot be found, searching will
 1369        * continue through the base class' inheritance hierarchy, up to and
 1370        * including <code>rootClass</code>.
 1371        *
 1372        * @param baseClass the first class to use in searching for the resource
 1373        * @param rootClass an ancestor of <code>baseClass</code> to finish the
 1374        *                  search at
 1375        * @param imageFile the name of the file to be found
 1376        * @return a lazy value that creates the <code>ImageIcon</code>
 1377        *         <code>UIResource</code> for the image,
 1378        *         or null if it cannot be found
 1379        */
 1380       public static Object makeIcon(final Class<?> baseClass,
 1381                                     final Class<?> rootClass,
 1382                                     final String imageFile) {
 1383   
 1384           return new UIDefaults.LazyValue() {
 1385               public Object createValue(UIDefaults table) {
 1386                   /* Copy resource into a byte array.  This is
 1387                    * necessary because several browsers consider
 1388                    * Class.getResource a security risk because it
 1389                    * can be used to load additional classes.
 1390                    * Class.getResourceAsStream just returns raw
 1391                    * bytes, which we can convert to an image.
 1392                    */
 1393                   byte[] buffer =
 1394                       java.security.AccessController.doPrivileged(
 1395                           new java.security.PrivilegedAction<byte[]>() {
 1396                       public byte[] run() {
 1397                           try {
 1398                               InputStream resource = null;
 1399                               Class<?> srchClass = baseClass;
 1400   
 1401                               while (srchClass != null) {
 1402                                   resource = srchClass.getResourceAsStream(imageFile);
 1403   
 1404                                   if (resource != null || srchClass == rootClass) {
 1405                                       break;
 1406                                   }
 1407   
 1408                                   srchClass = srchClass.getSuperclass();
 1409                               }
 1410   
 1411                               if (resource == null) {
 1412                                   return null;
 1413                               }
 1414   
 1415                               BufferedInputStream in =
 1416                                   new BufferedInputStream(resource);
 1417                               ByteArrayOutputStream out =
 1418                                   new ByteArrayOutputStream(1024);
 1419                               byte[] buffer = new byte[1024];
 1420                               int n;
 1421                               while ((n = in.read(buffer)) > 0) {
 1422                                   out.write(buffer, 0, n);
 1423                               }
 1424                               in.close();
 1425                               out.flush();
 1426                               return out.toByteArray();
 1427                           } catch (IOException ioe) {
 1428                               System.err.println(ioe.toString());
 1429                           }
 1430                           return null;
 1431                       }
 1432                   });
 1433   
 1434                   if (buffer == null) {
 1435                       return null;
 1436                   }
 1437                   if (buffer.length == 0) {
 1438                       System.err.println("warning: " + imageFile +
 1439                                          " is zero-length");
 1440                       return null;
 1441                   }
 1442   
 1443                   return new ImageIconUIResource(buffer);
 1444               }
 1445           };
 1446       }
 1447   
 1448       /* Used to help decide if AA text rendering should be used, so
 1449        * this local display test should be additionally qualified
 1450        * against whether we have XRender support on both ends of the wire,
 1451        * as with that support remote performance may be good enough to turn
 1452        * on by default. An additional complication there is XRender does not
 1453        * appear capable of performing gamma correction needed for LCD text.
 1454        */
 1455       public static boolean isLocalDisplay() {
 1456           boolean isLocal;
 1457           GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
 1458           if (ge instanceof SunGraphicsEnvironment) {
 1459               isLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal();
 1460           } else {
 1461               isLocal = true;
 1462           }
 1463           return isLocal;
 1464       }
 1465   
 1466       /**
 1467        * Returns an integer from the defaults table. If <code>key</code> does
 1468        * not map to a valid <code>Integer</code>, or can not be convered from
 1469        * a <code>String</code> to an integer, the value 0 is returned.
 1470        *
 1471        * @param key  an <code>Object</code> specifying the int.
 1472        * @return the int
 1473        */
 1474       public static int getUIDefaultsInt(Object key) {
 1475           return getUIDefaultsInt(key, 0);
 1476       }
 1477   
 1478       /**
 1479        * Returns an integer from the defaults table that is appropriate
 1480        * for the given locale. If <code>key</code> does not map to a valid
 1481        * <code>Integer</code>, or can not be convered from a <code>String</code>
 1482        * to an integer, the value 0 is returned.
 1483        *
 1484        * @param key  an <code>Object</code> specifying the int. Returned value
 1485        *             is 0 if <code>key</code> is not available,
 1486        * @param l the <code>Locale</code> for which the int is desired
 1487        * @return the int
 1488        */
 1489       public static int getUIDefaultsInt(Object key, Locale l) {
 1490           return getUIDefaultsInt(key, l, 0);
 1491       }
 1492   
 1493       /**
 1494        * Returns an integer from the defaults table. If <code>key</code> does
 1495        * not map to a valid <code>Integer</code>, or can not be convered from
 1496        * a <code>String</code> to an integer, <code>default</code> is
 1497        * returned.
 1498        *
 1499        * @param key  an <code>Object</code> specifying the int. Returned value
 1500        *             is 0 if <code>key</code> is not available,
 1501        * @param defaultValue Returned value if <code>key</code> is not available,
 1502        *                     or is not an Integer
 1503        * @return the int
 1504        */
 1505       public static int getUIDefaultsInt(Object key, int defaultValue) {
 1506           return getUIDefaultsInt(key, null, defaultValue);
 1507       }
 1508   
 1509       /**
 1510        * Returns an integer from the defaults table that is appropriate
 1511        * for the given locale. If <code>key</code> does not map to a valid
 1512        * <code>Integer</code>, or can not be convered from a <code>String</code>
 1513        * to an integer, <code>default</code> is returned.
 1514        *
 1515        * @param key  an <code>Object</code> specifying the int. Returned value
 1516        *             is 0 if <code>key</code> is not available,
 1517        * @param l the <code>Locale</code> for which the int is desired
 1518        * @param defaultValue Returned value if <code>key</code> is not available,
 1519        *                     or is not an Integer
 1520        * @return the int
 1521        */
 1522       public static int getUIDefaultsInt(Object key, Locale l, int defaultValue) {
 1523           Object value = UIManager.get(key, l);
 1524   
 1525           if (value instanceof Integer) {
 1526               return ((Integer)value).intValue();
 1527           }
 1528           if (value instanceof String) {
 1529               try {
 1530                   return Integer.parseInt((String)value);
 1531               } catch (NumberFormatException nfe) {}
 1532           }
 1533           return defaultValue;
 1534       }
 1535   
 1536       // At this point we need this method here. But we assume that there
 1537       // will be a common method for this purpose in the future releases.
 1538       public static Component compositeRequestFocus(Component component) {
 1539           if (component instanceof Container) {
 1540               Container container = (Container)component;
 1541               if (container.isFocusCycleRoot()) {
 1542                   FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
 1543                   Component comp = policy.getDefaultComponent(container);
 1544                   if (comp!=null) {
 1545                       comp.requestFocus();
 1546                       return comp;
 1547                   }
 1548               }
 1549               Container rootAncestor = container.getFocusCycleRootAncestor();
 1550               if (rootAncestor!=null) {
 1551                   FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
 1552                   Component comp = policy.getComponentAfter(rootAncestor, container);
 1553   
 1554                   if (comp!=null && SwingUtilities.isDescendingFrom(comp, container)) {
 1555                       comp.requestFocus();
 1556                       return comp;
 1557                   }
 1558               }
 1559           }
 1560           if (component.isFocusable()) {
 1561               component.requestFocus();
 1562               return component;
 1563           }
 1564           return null;
 1565       }
 1566   
 1567       /**
 1568        * Change focus to the visible component in {@code JTabbedPane}.
 1569        * This is not a general-purpose method and is here only to permit
 1570        * sharing code.
 1571        */
 1572       public static boolean tabbedPaneChangeFocusTo(Component comp) {
 1573           if (comp != null) {
 1574               if (comp.isFocusTraversable()) {
 1575                   SwingUtilities2.compositeRequestFocus(comp);
 1576                   return true;
 1577               } else if (comp instanceof JComponent
 1578                          && ((JComponent)comp).requestDefaultFocus()) {
 1579   
 1580                    return true;
 1581               }
 1582           }
 1583   
 1584           return false;
 1585       }
 1586   
 1587       /**
 1588        * Submits a value-returning task for execution on the EDT and
 1589        * returns a Future representing the pending results of the task.
 1590        *
 1591        * @param task the task to submit
 1592        * @return a Future representing pending completion of the task
 1593        * @throws NullPointerException if the task is null
 1594        */
 1595       public static <V> Future<V> submit(Callable<V> task) {
 1596           if (task == null) {
 1597               throw new NullPointerException();
 1598           }
 1599           FutureTask<V> future = new FutureTask<V>(task);
 1600           execute(future);
 1601           return future;
 1602       }
 1603   
 1604       /**
 1605        * Submits a Runnable task for execution on the EDT and returns a
 1606        * Future representing that task.
 1607        *
 1608        * @param task the task to submit
 1609        * @param result the result to return upon successful completion
 1610        * @return a Future representing pending completion of the task,
 1611        *         and whose <tt>get()</tt> method will return the given
 1612        *         result value upon completion
 1613        * @throws NullPointerException if the task is null
 1614        */
 1615       public static <V> Future<V> submit(Runnable task, V result) {
 1616           if (task == null) {
 1617               throw new NullPointerException();
 1618           }
 1619           FutureTask<V> future = new FutureTask<V>(task, result);
 1620           execute(future);
 1621           return future;
 1622       }
 1623   
 1624       /**
 1625        * Sends a Runnable to the EDT for the execution.
 1626        */
 1627       private static void execute(Runnable command) {
 1628           SwingUtilities.invokeLater(command);
 1629       }
 1630   
 1631       /**
 1632        * Sets the {@code SKIP_CLICK_COUNT} client property on the component
 1633        * if it is an instance of {@code JTextComponent} with a
 1634        * {@code DefaultCaret}. This property, used for text components acting
 1635        * as editors in a table or tree, tells {@code DefaultCaret} how many
 1636        * clicks to skip before starting selection.
 1637        */
 1638       public static void setSkipClickCount(Component comp, int count) {
 1639           if (comp instanceof JTextComponent
 1640                   && ((JTextComponent) comp).getCaret() instanceof DefaultCaret) {
 1641   
 1642               ((JTextComponent) comp).putClientProperty(SKIP_CLICK_COUNT, count);
 1643           }
 1644       }
 1645   
 1646       /**
 1647        * Return the MouseEvent's click count, possibly reduced by the value of
 1648        * the component's {@code SKIP_CLICK_COUNT} client property. Clears
 1649        * the {@code SKIP_CLICK_COUNT} property if the mouse event's click count
 1650        * is 1. In order for clearing of the property to work correctly, there
 1651        * must be a mousePressed implementation on the caller with this
 1652        * call as the first line.
 1653        */
 1654       public static int getAdjustedClickCount(JTextComponent comp, MouseEvent e) {
 1655           int cc = e.getClickCount();
 1656   
 1657           if (cc == 1) {
 1658               comp.putClientProperty(SKIP_CLICK_COUNT, null);
 1659           } else {
 1660               Integer sub = (Integer) comp.getClientProperty(SKIP_CLICK_COUNT);
 1661               if (sub != null) {
 1662                   return cc - sub;
 1663               }
 1664           }
 1665   
 1666           return cc;
 1667       }
 1668   
 1669       /**
 1670        * Used by the {@code liesIn} method to return which section
 1671        * the point lies in.
 1672        *
 1673        * @see #liesIn
 1674        */
 1675       public enum Section {
 1676   
 1677           /** The leading section */
 1678           LEADING,
 1679   
 1680           /** The middle section */
 1681           MIDDLE,
 1682   
 1683           /** The trailing section */
 1684           TRAILING
 1685       }
 1686   
 1687       /**
 1688        * This method divides a rectangle into two or three sections along
 1689        * the specified axis and determines which section the given point
 1690        * lies in on that axis; used by drag and drop when calculating drop
 1691        * locations.
 1692        * <p>
 1693        * For two sections, the rectangle is divided equally and the method
 1694        * returns whether the point lies in {@code Section.LEADING} or
 1695        * {@code Section.TRAILING}. For horizontal divisions, the calculation
 1696        * respects component orientation.
 1697        * <p>
 1698        * For three sections, if the rectangle is greater than or equal to
 1699        * 30 pixels in length along the axis, the calculation gives 10 pixels
 1700        * to each of the leading and trailing sections and the remainder to the
 1701        * middle. For smaller sizes, the rectangle is divided equally into three
 1702        * sections.
 1703        * <p>
 1704        * Note: This method assumes that the point is within the bounds of
 1705        * the given rectangle on the specified axis. However, in cases where
 1706        * it isn't, the results still have meaning: {@code Section.MIDDLE}
 1707        * remains the same, {@code Section.LEADING} indicates that the point
 1708        * is in or somewhere before the leading section, and
 1709        * {@code Section.TRAILING} indicates that the point is in or somewhere
 1710        * after the trailing section.
 1711        *
 1712        * @param rect the rectangle
 1713        * @param p the point the check
 1714        * @param horizontal {@code true} to use the horizontal axis,
 1715        *        or {@code false} for the vertical axis
 1716        * @param ltr {@code true} for left to right orientation,
 1717        *        or {@code false} for right to left orientation;
 1718        *        only used for horizontal calculations
 1719        * @param three {@code true} for three sections,
 1720        *        or {@code false} for two
 1721        *
 1722        * @return the {@code Section} where the point lies
 1723        *
 1724        * @throws NullPointerException if {@code rect} or {@code p} are
 1725        *         {@code null}
 1726        */
 1727       private static Section liesIn(Rectangle rect, Point p, boolean horizontal,
 1728                                     boolean ltr, boolean three) {
 1729   
 1730           /* beginning of the rectangle on the axis */
 1731           int p0;
 1732   
 1733           /* point on the axis we're interested in */
 1734           int pComp;
 1735   
 1736           /* length of the rectangle on the axis */
 1737           int length;
 1738   
 1739           /* value of ltr if horizontal, else true */
 1740           boolean forward;
 1741   
 1742           if (horizontal) {
 1743               p0 = rect.x;
 1744               pComp = p.x;
 1745               length = rect.width;
 1746               forward = ltr;
 1747           } else {
 1748               p0 = rect.y;
 1749               pComp = p.y;
 1750               length = rect.height;
 1751               forward = true;
 1752           }
 1753   
 1754           if (three) {
 1755               int boundary = (length >= 30) ? 10 : length / 3;
 1756   
 1757               if (pComp < p0 + boundary) {
 1758                  return forward ? Section.LEADING : Section.TRAILING;
 1759              } else if (pComp >= p0 + length - boundary) {
 1760                  return forward ? Section.TRAILING : Section.LEADING;
 1761              }
 1762   
 1763              return Section.MIDDLE;
 1764           } else {
 1765               int middle = p0 + length / 2;
 1766               if (forward) {
 1767                   return pComp >= middle ? Section.TRAILING : Section.LEADING;
 1768               } else {
 1769                   return pComp < middle ? Section.TRAILING : Section.LEADING;
 1770               }
 1771           }
 1772       }
 1773   
 1774       /**
 1775        * This method divides a rectangle into two or three sections along
 1776        * the horizontal axis and determines which section the given point
 1777        * lies in; used by drag and drop when calculating drop locations.
 1778        * <p>
 1779        * See the documentation for {@link #liesIn} for more information
 1780        * on how the section is calculated.
 1781        *
 1782        * @param rect the rectangle
 1783        * @param p the point the check
 1784        * @param ltr {@code true} for left to right orientation,
 1785        *        or {@code false} for right to left orientation
 1786        * @param three {@code true} for three sections,
 1787        *        or {@code false} for two
 1788        *
 1789        * @return the {@code Section} where the point lies
 1790        *
 1791        * @throws NullPointerException if {@code rect} or {@code p} are
 1792        *         {@code null}
 1793        */
 1794       public static Section liesInHorizontal(Rectangle rect, Point p,
 1795                                              boolean ltr, boolean three) {
 1796           return liesIn(rect, p, true, ltr, three);
 1797       }
 1798   
 1799       /**
 1800        * This method divides a rectangle into two or three sections along
 1801        * the vertical axis and determines which section the given point
 1802        * lies in; used by drag and drop when calculating drop locations.
 1803        * <p>
 1804        * See the documentation for {@link #liesIn} for more information
 1805        * on how the section is calculated.
 1806        *
 1807        * @param rect the rectangle
 1808        * @param p the point the check
 1809        * @param three {@code true} for three sections,
 1810        *        or {@code false} for two
 1811        *
 1812        * @return the {@code Section} where the point lies
 1813        *
 1814        * @throws NullPointerException if {@code rect} or {@code p} are
 1815        *         {@code null}
 1816        */
 1817       public static Section liesInVertical(Rectangle rect, Point p,
 1818                                            boolean three) {
 1819           return liesIn(rect, p, false, false, three);
 1820       }
 1821   
 1822       /**
 1823        * Maps the index of the column in the view at
 1824        * {@code viewColumnIndex} to the index of the column
 1825        * in the table model.  Returns the index of the corresponding
 1826        * column in the model.  If {@code viewColumnIndex}
 1827        * is less than zero, returns {@code viewColumnIndex}.
 1828        *
 1829        * @param cm the table model
 1830        * @param   viewColumnIndex     the index of the column in the view
 1831        * @return  the index of the corresponding column in the model
 1832        *
 1833        * @see JTable#convertColumnIndexToModel(int)
 1834        * @see javax.swing.plaf.basic.BasicTableHeaderUI
 1835        */
 1836       public static int convertColumnIndexToModel(TableColumnModel cm,
 1837                                                   int viewColumnIndex) {
 1838           if (viewColumnIndex < 0) {
 1839               return viewColumnIndex;
 1840           }
 1841           return cm.getColumn(viewColumnIndex).getModelIndex();
 1842       }
 1843   
 1844       /**
 1845        * Maps the index of the column in the {@code cm} at
 1846        * {@code modelColumnIndex} to the index of the column
 1847        * in the view.  Returns the index of the
 1848        * corresponding column in the view; returns {@code -1} if this column
 1849        * is not being displayed. If {@code modelColumnIndex} is less than zero,
 1850        * returns {@code modelColumnIndex}.
 1851        *
 1852        * @param cm the table model
 1853        * @param modelColumnIndex the index of the column in the model
 1854        * @return the index of the corresponding column in the view
 1855        *
 1856        * @see JTable#convertColumnIndexToView(int)
 1857        * @see javax.swing.plaf.basic.BasicTableHeaderUI
 1858        */
 1859       public static int convertColumnIndexToView(TableColumnModel cm,
 1860                                           int modelColumnIndex) {
 1861           if (modelColumnIndex < 0) {
 1862               return modelColumnIndex;
 1863           }
 1864           for (int column = 0; column < cm.getColumnCount(); column++) {
 1865               if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
 1866                   return column;
 1867               }
 1868           }
 1869           return -1;
 1870       }
 1871   }

Home » openjdk-7 » sun » swing » [javadoc | source]