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