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 sun.security.util.SecurityConstants;
  57 import java.io.*;
  58 import java.util.*;
  59 import sun.font.FontDesignMetrics;
  60 import sun.font.FontUtilities;
  61 import sun.java2d.SunGraphicsEnvironment;
  62 
  63 import java.util.concurrent.Callable;
  64 import java.util.concurrent.Future;
  65 import java.util.concurrent.FutureTask;
  66 
  67 /**
  68  * A collection of utility methods for Swing.
  69  * <p>
  70  * <b>WARNING:</b> While this class is public, it should not be treated as
  71  * public API and its API may change in incompatable ways between dot dot
  72  * releases and even patch releases. You should not rely on this class even
  73  * existing.
  74  *
  75  */
  76 public class SwingUtilities2 {
  77     /**
  78      * The <code>AppContext</code> key for our one <code>LAFState</code>
  79      * instance.
  80      */
  81     public static final Object LAF_STATE_KEY =
  82             new StringBuffer("LookAndFeel State");
  83 
  84     // Maintain a cache of CACHE_SIZE fonts and the left side bearing
  85      // of the characters falling into the range MIN_CHAR_INDEX to
  86      // MAX_CHAR_INDEX. The values in fontCache are created as needed.
  87      private static LSBCacheEntry[] fontCache;
  88      // Windows defines 6 font desktop properties, we will therefore only
  89      // cache the metrics for 6 fonts.
  90      private static final int CACHE_SIZE = 6;
  91      // nextIndex in fontCache to insert a font into.
  92      private static int nextIndex;
  93      // LSBCacheEntry used to search in fontCache to see if we already
  94      // have an entry for a particular font
  95      private static LSBCacheEntry searchKey;
  96 
  97      // getLeftSideBearing will consult all characters that fall in the
  98      // range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
  99      private static final int MIN_CHAR_INDEX = (int)'W';
 100      private static final int MAX_CHAR_INDEX = (int)'W' + 1;
 101 
 102     public static final FontRenderContext DEFAULT_FRC =
 103         new FontRenderContext(null, false, false);
 104 
 105     /**
 106      * A JComponent client property is used to determine text aa settings.
 107      * To avoid having this property persist between look and feels changes
 108      * the value of the property is set to null in JComponent.setUI
 109      */
 110     public static final Object AA_TEXT_PROPERTY_KEY =
 111                           new StringBuffer("AATextInfoPropertyKey");
 112 
 113     /**
 114      * Attribute key for the content elements.  If it is set on an element, the
 115      * element is considered to be a line break.
 116      */
 117     public static final String IMPLIED_CR = "CR";
 118 
 119     /**
 120      * Used to tell a text component, being used as an editor for table
 121      * or tree, how many clicks it took to start editing.
 122      */
 123     private static final StringBuilder SKIP_CLICK_COUNT =
 124         new StringBuilder("skipClickCount");
 125 
 126     /* Presently this class assumes default fractional metrics.
 127      * This may need to change to emulate future platform L&Fs.
 128      */
 129     public static class AATextInfo {
 130 
 131         private static AATextInfo getAATextInfoFromMap(Map hints) {
 132 
 133             Object aaHint   = hints.get(KEY_TEXT_ANTIALIASING);
 134             Object contHint = hints.get(KEY_TEXT_LCD_CONTRAST);
 135 
 136             if (aaHint == null ||
 137                 aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
 138                 aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
 139                 return null;
 140             } else {
 141                 return new AATextInfo(aaHint, (Integer)contHint);
 142             }
 143         }
 144 
 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)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 boolean pointIsInActualBounds(JList list, int index,
 685                                                 Point point) {
 686         ListCellRenderer renderer = list.getCellRenderer();
 687         ListModel dataModel = list.getModel();
 688         Object value = dataModel.getElementAt(index);
 689         Component item = renderer.getListCellRendererComponent(list,
 690                           value, index, false, false);
 691         Dimension itemSize = item.getPreferredSize();
 692         Rectangle cellBounds = list.getCellBounds(index, index);
 693         if (!item.getComponentOrientation().isLeftToRight()) {
 694             cellBounds.x += (cellBounds.width - itemSize.width);
 695         }
 696         cellBounds.width = itemSize.width;
 697 
 698         return cellBounds.contains(point);
 699     }
 700 
 701 
 702     /**
 703      * Returns true if the given point is outside the preferredSize of the
 704      * item at the given row of the table.  (Column must be 0).
 705      * Does not check the "Table.isFileList" property. That should be checked
 706      * before calling this method.
 707      * This is used to make WindowsL&F JFileChooser act like native dialogs.
 708      */
 709     public static boolean pointOutsidePrefSize(JTable table, int row, int column, Point p) {
 710         if (table.convertColumnIndexToModel(column) != 0 || row == -1) {
 711             return true;
 712         }
 713         TableCellRenderer tcr = table.getCellRenderer(row, column);
 714         Object value = table.getValueAt(row, column);
 715         Component cell = tcr.getTableCellRendererComponent(table, value, false,
 716                 false, row, column);
 717         Dimension itemSize = cell.getPreferredSize();
 718         Rectangle cellBounds = table.getCellRect(row, column, false);
 719         cellBounds.width = itemSize.width;
 720         cellBounds.height = itemSize.height;
 721 
 722         // See if coords are inside
 723         // ASSUME: mouse x,y will never be < cell's x,y
 724         assert (p.x >= cellBounds.x && p.y >= cellBounds.y);
 725         return p.x > cellBounds.x + cellBounds.width ||
 726                 p.y > cellBounds.y + cellBounds.height;
 727     }
 728 
 729     /**
 730      * Set the lead and anchor without affecting selection.
 731      */
 732     public static void setLeadAnchorWithoutSelection(ListSelectionModel model,
 733                                                      int lead, int anchor) {
 734         if (anchor == -1) {
 735             anchor = lead;
 736         }
 737         if (lead == -1) {
 738             model.setAnchorSelectionIndex(-1);
 739             model.setLeadSelectionIndex(-1);
 740         } else {
 741             if (model.isSelectedIndex(lead)) {
 742                 model.addSelectionInterval(lead, lead);
 743             } else {
 744                 model.removeSelectionInterval(lead, lead);
 745             }
 746             model.setAnchorSelectionIndex(anchor);
 747         }
 748     }
 749 
 750     /**
 751      * Ignore mouse events if the component is null, not enabled, the event
 752      * is not associated with the left mouse button, or the event has been
 753      * consumed.
 754      */
 755     public static boolean shouldIgnore(MouseEvent me, JComponent c) {
 756         return c == null || !c.isEnabled()
 757                          || !SwingUtilities.isLeftMouseButton(me)
 758                          || me.isConsumed();
 759     }
 760 
 761     /**
 762      * Request focus on the given component if it doesn't already have it
 763      * and <code>isRequestFocusEnabled()</code> returns true.
 764      */
 765     public static void adjustFocus(JComponent c) {
 766         if (!c.hasFocus() && c.isRequestFocusEnabled()) {
 767             c.requestFocus();
 768         }
 769     }
 770 
 771     /**
 772      * The following draw functions have the same semantic as the
 773      * Graphics methods with the same names.
 774      *
 775      * this is used for printing
 776      */
 777     public static int drawChars(JComponent c, Graphics g,
 778                                  char[] data,
 779                                  int offset,
 780                                  int length,
 781                                  int x,
 782                                  int y) {
 783         if ( length <= 0 ) { //no need to paint empty strings
 784             return x;
 785         }
 786         int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
 787         if (isPrinting(g)) {
 788             Graphics2D g2d = getGraphics2D(g);
 789             if (g2d != null) {
 790                 FontRenderContext deviceFontRenderContext = g2d.
 791                     getFontRenderContext();
 792                 FontRenderContext frc = getFontRenderContext(c);
 793                 if (frc != null &&
 794                     !isFontRenderContextPrintCompatible
 795                     (deviceFontRenderContext, frc)) {
 796 
 797                     String text = new String(data, offset, length);
 798                     TextLayout layout = new TextLayout(text, g2d.getFont(),
 799                                     deviceFontRenderContext);
 800                     String trimmedText = trimTrailingSpaces(text);
 801                     if (!trimmedText.isEmpty()) {
 802                         float screenWidth = (float)g2d.getFont().
 803                             getStringBounds(trimmedText, frc).getWidth();
 804                         layout = layout.getJustifiedLayout(screenWidth);
 805 
 806                         /* Use alternate print color if specified */
 807                         Color col = g2d.getColor();
 808                         if (col instanceof PrintColorUIResource) {
 809                             g2d.setColor(((PrintColorUIResource)col).getPrintColor());
 810                         }
 811 
 812                         layout.draw(g2d,x,y);
 813 
 814                         g2d.setColor(col);
 815                     }
 816 
 817                     return nextX;
 818                 }
 819             }
 820         }
 821         // Assume we're not printing if we get here, or that we are invoked
 822         // via Swing text printing which is laid out for the printer.
 823         AATextInfo info = drawTextAntialiased(c);
 824         if (info != null && (g instanceof Graphics2D)) {
 825             Graphics2D g2 = (Graphics2D)g;
 826 
 827             Object oldContrast = null;
 828             Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
 829             if (info.aaHint != null && info.aaHint != oldAAValue) {
 830                 g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);
 831             } else {
 832                 oldAAValue = null;
 833             }
 834             if (info.lcdContrastHint != null) {
 835                 oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);
 836                 if (info.lcdContrastHint.equals(oldContrast)) {
 837                     oldContrast = null;
 838                 } else {
 839                     g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,
 840                                         info.lcdContrastHint);
 841                 }
 842             }
 843 
 844             g.drawChars(data, offset, length, x, y);
 845 
 846             if (oldAAValue != null) {
 847                 g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
 848             }
 849             if (oldContrast != null) {
 850                 g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);
 851             }
 852         }
 853         else {
 854             g.drawChars(data, offset, length, x, y);
 855         }
 856         return nextX;
 857     }
 858 
 859     /*
 860      * see documentation for drawChars
 861      * returns the advance
 862      */
 863     public static float drawString(JComponent c, Graphics g,
 864                                    AttributedCharacterIterator iterator,
 865                                    int x,
 866                                    int y) {
 867 
 868         float retVal;
 869         boolean isPrinting = isPrinting(g);
 870         Color col = g.getColor();
 871 
 872         if (isPrinting) {
 873             /* Use alternate print color if specified */
 874             if (col instanceof PrintColorUIResource) {
 875                 g.setColor(((PrintColorUIResource)col).getPrintColor());
 876             }
 877         }
 878 
 879         Graphics2D g2d = getGraphics2D(g);
 880         if (g2d == null) {
 881             g.drawString(iterator,x,y); //for the cases where advance
 882                                         //matters it should not happen
 883             retVal = x;
 884 
 885         } else {
 886             FontRenderContext frc;
 887             if (isPrinting) {
 888                 frc = getFontRenderContext(c);
 889                 if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
 890                     frc = new FontRenderContext(frc.getTransform(), false, false);
 891                 }
 892             } else if ((frc = getFRCProperty(c)) != null) {
 893                 /* frc = frc; ! */
 894             } else {
 895                 frc = g2d.getFontRenderContext();
 896             }
 897             TextLayout layout;
 898             if (isPrinting) {
 899                 FontRenderContext deviceFRC = g2d.getFontRenderContext();
 900                 if (!isFontRenderContextPrintCompatible(frc, deviceFRC)) {
 901                     layout = new TextLayout(iterator, deviceFRC);
 902                     AttributedCharacterIterator trimmedIt =
 903                             getTrimmedTrailingSpacesIterator(iterator);
 904                     if (trimmedIt != null) {
 905                         float screenWidth = new TextLayout(trimmedIt, frc).
 906                                 getAdvance();
 907                         layout = layout.getJustifiedLayout(screenWidth);
 908                     }
 909                 } else {
 910                     layout = new TextLayout(iterator, frc);
 911                 }
 912             } else {
 913                 layout = new TextLayout(iterator, frc);
 914             }
 915             layout.draw(g2d, x, y);
 916             retVal = layout.getAdvance();
 917         }
 918 
 919         if (isPrinting) {
 920             g.setColor(col);
 921         }
 922 
 923         return retVal;
 924     }
 925 
 926     private static TextLayout createTextLayout(JComponent c, String s,
 927                                             Font f, FontRenderContext frc) {
 928         Object shaper = (c == null ?
 929                     null : c.getClientProperty(TextAttribute.NUMERIC_SHAPING));
 930         if (shaper == null) {
 931             return new TextLayout(s, f, frc);
 932         } else {
 933             Map<TextAttribute, Object> a = new HashMap<TextAttribute, Object>();
 934             a.put(TextAttribute.FONT, f);
 935             a.put(TextAttribute.NUMERIC_SHAPING, shaper);
 936             return new TextLayout(s, a, frc);
 937         }
 938     }
 939 
 940     /*
 941      * Checks if two given FontRenderContexts are compatible for printing.
 942      * We can't just use equals as we want to exclude from the comparison :
 943      * + whether AA is set as irrelevant for printing and shouldn't affect
 944      * printed metrics anyway
 945      * + any translation component in the transform of either FRC, as it
 946      * does not affect metrics.
 947      * Compatible means no special handling needed for text painting
 948      */
 949     private static boolean
 950         isFontRenderContextPrintCompatible(FontRenderContext frc1,
 951                                            FontRenderContext frc2) {
 952 
 953         if (frc1 == frc2) {
 954             return true;
 955         }
 956 
 957         if (frc1 == null || frc2 == null) { // not supposed to happen
 958             return false;
 959         }
 960 
 961         if (frc1.getFractionalMetricsHint() !=
 962             frc2.getFractionalMetricsHint()) {
 963             return false;
 964         }
 965 
 966         /* If both are identity, return true */
 967         if (!frc1.isTransformed() && !frc2.isTransformed()) {
 968             return true;
 969         }
 970 
 971         /* That's the end of the cheap tests, need to get and compare
 972          * the transform matrices. We don't care about the translation
 973          * components, so return true if they are otherwise identical.
 974          */
 975         double[] mat1 = new double[4];
 976         double[] mat2 = new double[4];
 977         frc1.getTransform().getMatrix(mat1);
 978         frc2.getTransform().getMatrix(mat2);
 979         return
 980             mat1[0] == mat2[0] &&
 981             mat1[1] == mat2[1] &&
 982             mat1[2] == mat2[2] &&
 983             mat1[3] == mat2[3];
 984     }
 985 
 986     /*
 987      * Tries it best to get Graphics2D out of the given Graphics
 988      * returns null if can not derive it.
 989      */
 990     public static Graphics2D getGraphics2D(Graphics g) {
 991         if (g instanceof Graphics2D) {
 992             return (Graphics2D) g;
 993         } else if (g instanceof ProxyPrintGraphics) {
 994             return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());
 995         } else {
 996             return null;
 997         }
 998     }
 999 
1000     /*
1001      * Returns FontRenderContext associated with Component.
1002      * FontRenderContext from Component.getFontMetrics is associated
1003      * with the component.
1004      *
1005      * Uses Component.getFontMetrics to get the FontRenderContext from.
1006      * see JComponent.getFontMetrics and TextLayoutStrategy.java
1007      */
1008     public static FontRenderContext getFontRenderContext(Component c) {
1009         assert c != null;
1010         if (c == null) {
1011             return DEFAULT_FRC;
1012         } else {
1013             return c.getFontMetrics(c.getFont()).getFontRenderContext();
1014         }
1015     }
1016 
1017     /**
1018      * A convenience method to get FontRenderContext.
1019      * Returns the FontRenderContext for the passed in FontMetrics or
1020      * for the passed in Component if FontMetrics is null
1021      */
1022     private static FontRenderContext getFontRenderContext(Component c, FontMetrics fm) {
1023         assert fm != null || c!= null;
1024         return (fm != null) ? fm.getFontRenderContext()
1025             : getFontRenderContext(c);
1026     }
1027 
1028     /*
1029      * This method is to be used only for JComponent.getFontMetrics.
1030      * In all other places to get FontMetrics we need to use
1031      * JComponent.getFontMetrics.
1032      *
1033      */
1034     public static FontMetrics getFontMetrics(JComponent c, Font font) {
1035         FontRenderContext  frc = getFRCProperty(c);
1036         if (frc == null) {
1037             frc = DEFAULT_FRC;
1038         }
1039         return FontDesignMetrics.getMetrics(font, frc);
1040     }
1041 
1042 
1043     /* Get any FontRenderContext associated with a JComponent
1044      * - may return null
1045      */
1046     private static FontRenderContext getFRCProperty(JComponent c) {
1047         if (c != null) {
1048             AATextInfo info =
1049                 (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);
1050             if (info != null) {
1051                 return info.frc;
1052             }
1053         }
1054         return null;
1055     }
1056 
1057     /*
1058      * returns true if the Graphics is print Graphics
1059      * false otherwise
1060      */
1061     static boolean isPrinting(Graphics g) {
1062         return (g instanceof PrinterGraphics || g instanceof PrintGraphics);
1063     }
1064 
1065     private static String trimTrailingSpaces(String s) {
1066         int i = s.length() - 1;
1067         while(i >= 0 && Character.isWhitespace(s.charAt(i))) {
1068             i--;
1069         }
1070         return s.substring(0, i + 1);
1071     }
1072 
1073     private static AttributedCharacterIterator getTrimmedTrailingSpacesIterator
1074             (AttributedCharacterIterator iterator) {
1075         int curIdx = iterator.getIndex();
1076 
1077         char c = iterator.last();
1078         while(c != CharacterIterator.DONE && Character.isWhitespace(c)) {
1079             c = iterator.previous();
1080         }
1081 
1082         if (c != CharacterIterator.DONE) {
1083             int endIdx = iterator.getIndex();
1084 
1085             if (endIdx == iterator.getEndIndex() - 1) {
1086                 iterator.setIndex(curIdx);
1087                 return iterator;
1088             } else {
1089                 AttributedString trimmedText = new AttributedString(iterator,
1090                         iterator.getBeginIndex(), endIdx + 1);
1091                 return trimmedText.getIterator();
1092             }
1093         } else {
1094             return null;
1095         }
1096     }
1097 
1098     /**
1099      * Determines whether the SelectedTextColor should be used for painting text
1100      * foreground for the specified highlight.
1101      *
1102      * Returns true only if the highlight painter for the specified highlight
1103      * is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter
1104      * or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color
1105      * is null or equals to the selection color of the text component.
1106      *
1107      * This is a hack for fixing both bugs 4761990 and 5003294
1108      */
1109     public static boolean useSelectedTextColor(Highlighter.Highlight h, JTextComponent c) {
1110         Highlighter.HighlightPainter painter = h.getPainter();
1111         String painterClass = painter.getClass().getName();
1112         if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
1113                 painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
1114             return false;
1115         }
1116         try {
1117             DefaultHighlighter.DefaultHighlightPainter defPainter =
1118                     (DefaultHighlighter.DefaultHighlightPainter) painter;
1119             if (defPainter.getColor() != null &&
1120                     !defPainter.getColor().equals(c.getSelectionColor())) {
1121                 return false;
1122             }
1123         } catch (ClassCastException e) {
1124             return false;
1125         }
1126         return true;
1127     }
1128 
1129     /**
1130      * LSBCacheEntry is used to cache the left side bearing (lsb) for
1131      * a particular <code>Font</code> and <code>FontRenderContext</code>.
1132      * This only caches characters that fall in the range
1133      * <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.
1134      */
1135     private static class LSBCacheEntry {
1136         // Used to indicate a particular entry in lsb has not been set.
1137         private static final byte UNSET = Byte.MAX_VALUE;
1138         // Used in creating a GlyphVector to get the lsb
1139         private static final char[] oneChar = new char[1];
1140 
1141         private byte[] lsbCache;
1142         private Font font;
1143         private FontRenderContext frc;
1144 
1145 
1146         public LSBCacheEntry(FontRenderContext frc, Font font) {
1147             lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
1148             reset(frc, font);
1149 
1150         }
1151 
1152         public void reset(FontRenderContext frc, Font font) {
1153             this.font = font;
1154             this.frc = frc;
1155             for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
1156                 lsbCache[counter] = UNSET;
1157             }
1158         }
1159 
1160         public int getLeftSideBearing(char aChar) {
1161             int index = aChar - MIN_CHAR_INDEX;
1162             assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
1163             byte lsb = lsbCache[index];
1164             if (lsb == UNSET) {
1165                 oneChar[0] = aChar;
1166                 GlyphVector gv = font.createGlyphVector(frc, oneChar);
1167                 lsb = (byte) gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
1168                 if (lsb < 0) {
1169                     /* HRGB/HBGR LCD glyph images will always have a pixel
1170                      * on the left used in colour fringe reduction.
1171                      * Text rendering positions this correctly but here
1172                      * we are using the glyph image to adjust that position
1173                      * so must account for it.
1174                      */
1175                     Object aaHint = frc.getAntiAliasingHint();
1176                     if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||
1177                             aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {
1178                         lsb++;
1179                     }
1180                 }
1181                 lsbCache[index] = lsb;
1182             }
1183             return lsb;
1184 
1185 
1186         }
1187 
1188         public boolean equals(Object entry) {
1189             if (entry == this) {
1190                 return true;
1191             }
1192             if (!(entry instanceof LSBCacheEntry)) {
1193                 return false;
1194             }
1195             LSBCacheEntry oEntry = (LSBCacheEntry) entry;
1196             return (font.equals(oEntry.font) &&
1197                     frc.equals(oEntry.frc));
1198         }
1199 
1200         public int hashCode() {
1201             int result = 17;
1202             if (font != null) {
1203                 result = 37 * result + font.hashCode();
1204             }
1205             if (frc != null) {
1206                 result = 37 * result + frc.hashCode();
1207             }
1208             return result;
1209         }
1210     }
1211 
1212     /*
1213      * here goes the fix for 4856343 [Problem with applet interaction
1214      * with system selection clipboard]
1215      *
1216      * NOTE. In case isTrustedContext() no checking
1217      * are to be performed
1218      */
1219 
1220     /**
1221     * checks the security permissions for accessing system clipboard
1222     *
1223     * for untrusted context (see isTrustedContext) checks the
1224     * permissions for the current event being handled
1225     *
1226     */
1227    public static boolean canAccessSystemClipboard() {
1228        boolean canAccess = false;
1229        if (!GraphicsEnvironment.isHeadless()) {
1230            SecurityManager sm = System.getSecurityManager();
1231            if (sm == null) {
1232                canAccess = true;
1233            } else {
1234                try {
1235                    sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
1236                    canAccess = true;
1237                } catch (SecurityException e) {
1238                }
1239                if (canAccess && ! isTrustedContext()) {
1240                    canAccess = canCurrentEventAccessSystemClipboard(true);
1241                }
1242            }
1243        }
1244        return canAccess;
1245    }
1246     /**
1247     * Returns true if EventQueue.getCurrentEvent() has the permissions to
1248      * access the system clipboard
1249      */
1250     public static boolean canCurrentEventAccessSystemClipboard() {
1251         return  isTrustedContext()
1252             || canCurrentEventAccessSystemClipboard(false);
1253     }
1254 
1255     /**
1256      * Returns true if the given event has permissions to access the
1257      * system clipboard
1258      *
1259      * @param e AWTEvent to check
1260      */
1261     public static boolean canEventAccessSystemClipboard(AWTEvent e) {
1262         return isTrustedContext()
1263             || canEventAccessSystemClipboard(e, false);
1264     }
1265 
1266     /**
1267      * returns canAccessSystemClipboard field from InputEvent
1268      *
1269      * @param ie InputEvent to get the field from
1270      */
1271     private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {
1272         if (inputEvent_CanAccessSystemClipboard_Field == null) {
1273             inputEvent_CanAccessSystemClipboard_Field =
1274                 AccessController.doPrivileged(
1275                     new java.security.PrivilegedAction<Field>() {
1276                         public Field run() {
1277                             try {
1278                                 Field field = InputEvent.class.
1279                                     getDeclaredField("canAccessSystemClipboard");
1280                                 field.setAccessible(true);
1281                                 return field;
1282                             } catch (SecurityException e) {
1283                             } catch (NoSuchFieldException e) {
1284                             }
1285                             return null;
1286                         }
1287                     });
1288         }
1289         if (inputEvent_CanAccessSystemClipboard_Field == null) {
1290             return false;
1291         }
1292         boolean ret = false;
1293         try {
1294             ret = inputEvent_CanAccessSystemClipboard_Field.
1295                 getBoolean(ie);
1296         } catch(IllegalAccessException e) {
1297         }
1298         return ret;
1299     }
1300 
1301     /**
1302      * Returns true if the given event is corrent gesture for
1303      * accessing clipboard
1304      *
1305      * @param ie InputEvent to check
1306      */
1307 
1308     private static boolean isAccessClipboardGesture(InputEvent ie) {
1309         boolean allowedGesture = false;
1310         if (ie instanceof KeyEvent) { //we can validate only keyboard gestures
1311             KeyEvent ke = (KeyEvent)ie;
1312             int keyCode = ke.getKeyCode();
1313             int keyModifiers = ke.getModifiers();
1314             switch(keyCode) {
1315             case KeyEvent.VK_C:
1316             case KeyEvent.VK_V:
1317             case KeyEvent.VK_X:
1318                 allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);
1319                 break;
1320             case KeyEvent.VK_INSERT:
1321                 allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||
1322                                   keyModifiers == InputEvent.SHIFT_MASK);
1323                 break;
1324             case KeyEvent.VK_COPY:
1325             case KeyEvent.VK_PASTE:
1326             case KeyEvent.VK_CUT:
1327                 allowedGesture = true;
1328                 break;
1329             case KeyEvent.VK_DELETE:
1330                 allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);
1331                 break;
1332             }
1333         }
1334         return allowedGesture;
1335     }
1336 
1337     /**
1338      * Returns true if e has the permissions to
1339      * access the system clipboard and if it is allowed gesture (if
1340      * checkGesture is true)
1341      *
1342      * @param e AWTEvent to check
1343      * @param checkGesture boolean
1344      */
1345     private static boolean canEventAccessSystemClipboard(AWTEvent e,
1346                                                         boolean checkGesture) {
1347         if (EventQueue.isDispatchThread()) {
1348             /*
1349              * Checking event permissions makes sense only for event
1350              * dispathing thread
1351              */
1352             if (e instanceof InputEvent
1353                 && (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {
1354                 return inputEvent_canAccessSystemClipboard((InputEvent)e);
1355             } else {
1356                 return false;
1357             }
1358         } else {
1359             return true;
1360         }
1361     }
1362 
1363     /**
1364      * Utility method that throws SecurityException if SecurityManager is set
1365      * and modifiers are not public
1366      *
1367      * @param modifiers a set of modifiers
1368      */
1369     public static void checkAccess(int modifiers) {
1370         if (System.getSecurityManager() != null
1371                 && !Modifier.isPublic(modifiers)) {
1372             throw new SecurityException("Resource is not accessible");
1373         }
1374     }
1375 
1376     /**
1377      * Returns true if EventQueue.getCurrentEvent() has the permissions to
1378      * access the system clipboard and if it is allowed gesture (if
1379      * checkGesture true)
1380      *
1381      * @param checkGesture boolean
1382      */
1383     private static boolean canCurrentEventAccessSystemClipboard(boolean
1384                                                                checkGesture) {
1385         AWTEvent event = EventQueue.getCurrentEvent();
1386         return canEventAccessSystemClipboard(event, checkGesture);
1387     }
1388 
1389     /**
1390      * see RFE 5012841 [Per AppContect security permissions] for the
1391      * details
1392      *
1393      */
1394     private static boolean isTrustedContext() {
1395         return (System.getSecurityManager() == null)
1396             || (AppContext.getAppContext().
1397                 get(UntrustedClipboardAccess) == null);
1398     }
1399 
1400     public static String displayPropertiesToCSS(Font font, Color fg) {
1401         StringBuffer rule = new StringBuffer("body {");
1402         if (font != null) {
1403             rule.append(" font-family: ");
1404             rule.append(font.getFamily());
1405             rule.append(" ; ");
1406             rule.append(" font-size: ");
1407             rule.append(font.getSize());
1408             rule.append("pt ;");
1409             if (font.isBold()) {
1410                 rule.append(" font-weight: 700 ; ");
1411             }
1412             if (font.isItalic()) {
1413                 rule.append(" font-style: italic ; ");
1414             }
1415         }
1416         if (fg != null) {
1417             rule.append(" color: #");
1418             if (fg.getRed() < 16) {
1419                 rule.append('0');
1420             }
1421             rule.append(Integer.toHexString(fg.getRed()));
1422             if (fg.getGreen() < 16) {
1423                 rule.append('0');
1424             }
1425             rule.append(Integer.toHexString(fg.getGreen()));
1426             if (fg.getBlue() < 16) {
1427                 rule.append('0');
1428             }
1429             rule.append(Integer.toHexString(fg.getBlue()));
1430             rule.append(" ; ");
1431         }
1432         rule.append(" }");
1433         return rule.toString();
1434     }
1435 
1436     /**
1437      * Utility method that creates a <code>UIDefaults.LazyValue</code> that
1438      * creates an <code>ImageIcon</code> <code>UIResource</code> for the
1439      * specified image file name. The image is loaded using
1440      * <code>getResourceAsStream</code>, starting with a call to that method
1441      * on the base class parameter. If it cannot be found, searching will
1442      * continue through the base class' inheritance hierarchy, up to and
1443      * including <code>rootClass</code>.
1444      *
1445      * @param baseClass the first class to use in searching for the resource
1446      * @param rootClass an ancestor of <code>baseClass</code> to finish the
1447      *                  search at
1448      * @param imageFile the name of the file to be found
1449      * @return a lazy value that creates the <code>ImageIcon</code>
1450      *         <code>UIResource</code> for the image,
1451      *         or null if it cannot be found
1452      */
1453     public static Object makeIcon(final Class<?> baseClass,
1454                                   final Class<?> rootClass,
1455                                   final String imageFile) {
1456 
1457         return new UIDefaults.LazyValue() {
1458             public Object createValue(UIDefaults table) {
1459                 /* Copy resource into a byte array.  This is
1460                  * necessary because several browsers consider
1461                  * Class.getResource a security risk because it
1462                  * can be used to load additional classes.
1463                  * Class.getResourceAsStream just returns raw
1464                  * bytes, which we can convert to an image.
1465                  */
1466                 byte[] buffer =
1467                     java.security.AccessController.doPrivileged(
1468                         new java.security.PrivilegedAction<byte[]>() {
1469                     public byte[] run() {
1470                         try {
1471                             InputStream resource = null;
1472                             Class<?> srchClass = baseClass;
1473 
1474                             while (srchClass != null) {
1475                                 resource = srchClass.getResourceAsStream(imageFile);
1476 
1477                                 if (resource != null || srchClass == rootClass) {
1478                                     break;
1479                                 }
1480 
1481                                 srchClass = srchClass.getSuperclass();
1482                             }
1483 
1484                             if (resource == null) {
1485                                 return null;
1486                             }
1487 
1488                             BufferedInputStream in =
1489                                 new BufferedInputStream(resource);
1490                             ByteArrayOutputStream out =
1491                                 new ByteArrayOutputStream(1024);
1492                             byte[] buffer = new byte[1024];
1493                             int n;
1494                             while ((n = in.read(buffer)) > 0) {
1495                                 out.write(buffer, 0, n);
1496                             }
1497                             in.close();
1498                             out.flush();
1499                             return out.toByteArray();
1500                         } catch (IOException ioe) {
1501                             System.err.println(ioe.toString());
1502                         }
1503                         return null;
1504                     }
1505                 });
1506 
1507                 if (buffer == null) {
1508                     return null;
1509                 }
1510                 if (buffer.length == 0) {
1511                     System.err.println("warning: " + imageFile +
1512                                        " is zero-length");
1513                     return null;
1514                 }
1515 
1516                 return new ImageIconUIResource(buffer);
1517             }
1518         };
1519     }
1520 
1521     /* Used to help decide if AA text rendering should be used, so
1522      * this local display test should be additionally qualified
1523      * against whether we have XRender support on both ends of the wire,
1524      * as with that support remote performance may be good enough to turn
1525      * on by default. An additional complication there is XRender does not
1526      * appear capable of performing gamma correction needed for LCD text.
1527      */
1528     public static boolean isLocalDisplay() {
1529         boolean isLocal;
1530         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
1531         if (ge instanceof SunGraphicsEnvironment) {
1532             isLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal();
1533         } else {
1534             isLocal = true;
1535         }
1536         return isLocal;
1537     }
1538 
1539     /**
1540      * Returns an integer from the defaults table. If <code>key</code> does
1541      * not map to a valid <code>Integer</code>, or can not be convered from
1542      * a <code>String</code> to an integer, the value 0 is returned.
1543      *
1544      * @param key  an <code>Object</code> specifying the int.
1545      * @return the int
1546      */
1547     public static int getUIDefaultsInt(Object key) {
1548         return getUIDefaultsInt(key, 0);
1549     }
1550 
1551     /**
1552      * Returns an integer from the defaults table that is appropriate
1553      * for the given locale. If <code>key</code> does not map to a valid
1554      * <code>Integer</code>, or can not be convered from a <code>String</code>
1555      * to an integer, the value 0 is returned.
1556      *
1557      * @param key  an <code>Object</code> specifying the int. Returned value
1558      *             is 0 if <code>key</code> is not available,
1559      * @param l the <code>Locale</code> for which the int is desired
1560      * @return the int
1561      */
1562     public static int getUIDefaultsInt(Object key, Locale l) {
1563         return getUIDefaultsInt(key, l, 0);
1564     }
1565 
1566     /**
1567      * Returns an integer from the defaults table. If <code>key</code> does
1568      * not map to a valid <code>Integer</code>, or can not be convered from
1569      * a <code>String</code> to an integer, <code>default</code> is
1570      * returned.
1571      *
1572      * @param key  an <code>Object</code> specifying the int. Returned value
1573      *             is 0 if <code>key</code> is not available,
1574      * @param defaultValue Returned value if <code>key</code> is not available,
1575      *                     or is not an Integer
1576      * @return the int
1577      */
1578     public static int getUIDefaultsInt(Object key, int defaultValue) {
1579         return getUIDefaultsInt(key, null, defaultValue);
1580     }
1581 
1582     /**
1583      * Returns an integer from the defaults table that is appropriate
1584      * for the given locale. If <code>key</code> does not map to a valid
1585      * <code>Integer</code>, or can not be convered from a <code>String</code>
1586      * to an integer, <code>default</code> is returned.
1587      *
1588      * @param key  an <code>Object</code> specifying the int. Returned value
1589      *             is 0 if <code>key</code> is not available,
1590      * @param l the <code>Locale</code> for which the int is desired
1591      * @param defaultValue Returned value if <code>key</code> is not available,
1592      *                     or is not an Integer
1593      * @return the int
1594      */
1595     public static int getUIDefaultsInt(Object key, Locale l, int defaultValue) {
1596         Object value = UIManager.get(key, l);
1597 
1598         if (value instanceof Integer) {
1599             return ((Integer)value).intValue();
1600         }
1601         if (value instanceof String) {
1602             try {
1603                 return Integer.parseInt((String)value);
1604             } catch (NumberFormatException nfe) {}
1605         }
1606         return defaultValue;
1607     }
1608 
1609     // At this point we need this method here. But we assume that there
1610     // will be a common method for this purpose in the future releases.
1611     public static Component compositeRequestFocus(Component component) {
1612         if (component instanceof Container) {
1613             Container container = (Container)component;
1614             if (container.isFocusCycleRoot()) {
1615                 FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
1616                 Component comp = policy.getDefaultComponent(container);
1617                 if (comp!=null) {
1618                     comp.requestFocus();
1619                     return comp;
1620                 }
1621             }
1622             Container rootAncestor = container.getFocusCycleRootAncestor();
1623             if (rootAncestor!=null) {
1624                 FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
1625                 Component comp = policy.getComponentAfter(rootAncestor, container);
1626 
1627                 if (comp!=null && SwingUtilities.isDescendingFrom(comp, container)) {
1628                     comp.requestFocus();
1629                     return comp;
1630                 }
1631             }
1632         }
1633         if (component.isFocusable()) {
1634             component.requestFocus();
1635             return component;
1636         }
1637         return null;
1638     }
1639 
1640     /**
1641      * Change focus to the visible component in {@code JTabbedPane}.
1642      * This is not a general-purpose method and is here only to permit
1643      * sharing code.
1644      */
1645     public static boolean tabbedPaneChangeFocusTo(Component comp) {
1646         if (comp != null) {
1647             if (comp.isFocusTraversable()) {
1648                 SwingUtilities2.compositeRequestFocus(comp);
1649                 return true;
1650             } else if (comp instanceof JComponent
1651                        && ((JComponent)comp).requestDefaultFocus()) {
1652 
1653                  return true;
1654             }
1655         }
1656 
1657         return false;
1658     }
1659 
1660     /**
1661      * Submits a value-returning task for execution on the EDT and
1662      * returns a Future representing the pending results of the task.
1663      *
1664      * @param task the task to submit
1665      * @return a Future representing pending completion of the task
1666      * @throws NullPointerException if the task is null
1667      */
1668     public static <V> Future<V> submit(Callable<V> task) {
1669         if (task == null) {
1670             throw new NullPointerException();
1671         }
1672         FutureTask<V> future = new FutureTask<V>(task);
1673         execute(future);
1674         return future;
1675     }
1676 
1677     /**
1678      * Submits a Runnable task for execution on the EDT and returns a
1679      * Future representing that task.
1680      *
1681      * @param task the task to submit
1682      * @param result the result to return upon successful completion
1683      * @return a Future representing pending completion of the task,
1684      *         and whose <tt>get()</tt> method will return the given
1685      *         result value upon completion
1686      * @throws NullPointerException if the task is null
1687      */
1688     public static <V> Future<V> submit(Runnable task, V result) {
1689         if (task == null) {
1690             throw new NullPointerException();
1691         }
1692         FutureTask<V> future = new FutureTask<V>(task, result);
1693         execute(future);
1694         return future;
1695     }
1696 
1697     /**
1698      * Sends a Runnable to the EDT for the execution.
1699      */
1700     private static void execute(Runnable command) {
1701         SwingUtilities.invokeLater(command);
1702     }
1703 
1704     /**
1705      * Sets the {@code SKIP_CLICK_COUNT} client property on the component
1706      * if it is an instance of {@code JTextComponent} with a
1707      * {@code DefaultCaret}. This property, used for text components acting
1708      * as editors in a table or tree, tells {@code DefaultCaret} how many
1709      * clicks to skip before starting selection.
1710      */
1711     public static void setSkipClickCount(Component comp, int count) {
1712         if (comp instanceof JTextComponent
1713                 && ((JTextComponent) comp).getCaret() instanceof DefaultCaret) {
1714 
1715             ((JTextComponent) comp).putClientProperty(SKIP_CLICK_COUNT, count);
1716         }
1717     }
1718 
1719     /**
1720      * Return the MouseEvent's click count, possibly reduced by the value of
1721      * the component's {@code SKIP_CLICK_COUNT} client property. Clears
1722      * the {@code SKIP_CLICK_COUNT} property if the mouse event's click count
1723      * is 1. In order for clearing of the property to work correctly, there
1724      * must be a mousePressed implementation on the caller with this
1725      * call as the first line.
1726      */
1727     public static int getAdjustedClickCount(JTextComponent comp, MouseEvent e) {
1728         int cc = e.getClickCount();
1729 
1730         if (cc == 1) {
1731             comp.putClientProperty(SKIP_CLICK_COUNT, null);
1732         } else {
1733             Integer sub = (Integer) comp.getClientProperty(SKIP_CLICK_COUNT);
1734             if (sub != null) {
1735                 return cc - sub;
1736             }
1737         }
1738 
1739         return cc;
1740     }
1741 
1742     /**
1743      * Used by the {@code liesIn} method to return which section
1744      * the point lies in.
1745      *
1746      * @see #liesIn
1747      */
1748     public enum Section {
1749 
1750         /** The leading section */
1751         LEADING,
1752 
1753         /** The middle section */
1754         MIDDLE,
1755 
1756         /** The trailing section */
1757         TRAILING
1758     }
1759 
1760     /**
1761      * This method divides a rectangle into two or three sections along
1762      * the specified axis and determines which section the given point
1763      * lies in on that axis; used by drag and drop when calculating drop
1764      * locations.
1765      * <p>
1766      * For two sections, the rectangle is divided equally and the method
1767      * returns whether the point lies in {@code Section.LEADING} or
1768      * {@code Section.TRAILING}. For horizontal divisions, the calculation
1769      * respects component orientation.
1770      * <p>
1771      * For three sections, if the rectangle is greater than or equal to
1772      * 30 pixels in length along the axis, the calculation gives 10 pixels
1773      * to each of the leading and trailing sections and the remainder to the
1774      * middle. For smaller sizes, the rectangle is divided equally into three
1775      * sections.
1776      * <p>
1777      * Note: This method assumes that the point is within the bounds of
1778      * the given rectangle on the specified axis. However, in cases where
1779      * it isn't, the results still have meaning: {@code Section.MIDDLE}
1780      * remains the same, {@code Section.LEADING} indicates that the point
1781      * is in or somewhere before the leading section, and
1782      * {@code Section.TRAILING} indicates that the point is in or somewhere
1783      * after the trailing section.
1784      *
1785      * @param rect the rectangle
1786      * @param p the point the check
1787      * @param horizontal {@code true} to use the horizontal axis,
1788      *        or {@code false} for the vertical axis
1789      * @param ltr {@code true} for left to right orientation,
1790      *        or {@code false} for right to left orientation;
1791      *        only used for horizontal calculations
1792      * @param three {@code true} for three sections,
1793      *        or {@code false} for two
1794      *
1795      * @return the {@code Section} where the point lies
1796      *
1797      * @throws NullPointerException if {@code rect} or {@code p} are
1798      *         {@code null}
1799      */
1800     private static Section liesIn(Rectangle rect, Point p, boolean horizontal,
1801                                   boolean ltr, boolean three) {
1802 
1803         /* beginning of the rectangle on the axis */
1804         int p0;
1805 
1806         /* point on the axis we're interested in */
1807         int pComp;
1808 
1809         /* length of the rectangle on the axis */
1810         int length;
1811 
1812         /* value of ltr if horizontal, else true */
1813         boolean forward;
1814 
1815         if (horizontal) {
1816             p0 = rect.x;
1817             pComp = p.x;
1818             length = rect.width;
1819             forward = ltr;
1820         } else {
1821             p0 = rect.y;
1822             pComp = p.y;
1823             length = rect.height;
1824             forward = true;
1825         }
1826 
1827         if (three) {
1828             int boundary = (length >= 30) ? 10 : length / 3;
1829 
1830             if (pComp < p0 + boundary) {
1831                return forward ? Section.LEADING : Section.TRAILING;
1832            } else if (pComp >= p0 + length - boundary) {
1833                return forward ? Section.TRAILING : Section.LEADING;
1834            }
1835 
1836            return Section.MIDDLE;
1837         } else {
1838             int middle = p0 + length / 2;
1839             if (forward) {
1840                 return pComp >= middle ? Section.TRAILING : Section.LEADING;
1841             } else {
1842                 return pComp < middle ? Section.TRAILING : Section.LEADING;
1843             }
1844         }
1845     }
1846 
1847     /**
1848      * This method divides a rectangle into two or three sections along
1849      * the horizontal axis and determines which section the given point
1850      * lies in; used by drag and drop when calculating drop locations.
1851      * <p>
1852      * See the documentation for {@link #liesIn} for more information
1853      * on how the section is calculated.
1854      *
1855      * @param rect the rectangle
1856      * @param p the point the check
1857      * @param ltr {@code true} for left to right orientation,
1858      *        or {@code false} for right to left orientation
1859      * @param three {@code true} for three sections,
1860      *        or {@code false} for two
1861      *
1862      * @return the {@code Section} where the point lies
1863      *
1864      * @throws NullPointerException if {@code rect} or {@code p} are
1865      *         {@code null}
1866      */
1867     public static Section liesInHorizontal(Rectangle rect, Point p,
1868                                            boolean ltr, boolean three) {
1869         return liesIn(rect, p, true, ltr, three);
1870     }
1871 
1872     /**
1873      * This method divides a rectangle into two or three sections along
1874      * the vertical axis and determines which section the given point
1875      * lies in; used by drag and drop when calculating drop locations.
1876      * <p>
1877      * See the documentation for {@link #liesIn} for more information
1878      * on how the section is calculated.
1879      *
1880      * @param rect the rectangle
1881      * @param p the point the check
1882      * @param three {@code true} for three sections,
1883      *        or {@code false} for two
1884      *
1885      * @return the {@code Section} where the point lies
1886      *
1887      * @throws NullPointerException if {@code rect} or {@code p} are
1888      *         {@code null}
1889      */
1890     public static Section liesInVertical(Rectangle rect, Point p,
1891                                          boolean three) {
1892         return liesIn(rect, p, false, false, three);
1893     }
1894 
1895     /**
1896      * Maps the index of the column in the view at
1897      * {@code viewColumnIndex} to the index of the column
1898      * in the table model.  Returns the index of the corresponding
1899      * column in the model.  If {@code viewColumnIndex}
1900      * is less than zero, returns {@code viewColumnIndex}.
1901      *
1902      * @param cm the table model
1903      * @param   viewColumnIndex     the index of the column in the view
1904      * @return  the index of the corresponding column in the model
1905      *
1906      * @see JTable#convertColumnIndexToModel(int)
1907      * @see javax.swing.plaf.basic.BasicTableHeaderUI
1908      */
1909     public static int convertColumnIndexToModel(TableColumnModel cm,
1910                                                 int viewColumnIndex) {
1911         if (viewColumnIndex < 0) {
1912             return viewColumnIndex;
1913         }
1914         return cm.getColumn(viewColumnIndex).getModelIndex();
1915     }
1916 
1917     /**
1918      * Maps the index of the column in the {@code cm} at
1919      * {@code modelColumnIndex} to the index of the column
1920      * in the view.  Returns the index of the
1921      * corresponding column in the view; returns {@code -1} if this column
1922      * is not being displayed. If {@code modelColumnIndex} is less than zero,
1923      * returns {@code modelColumnIndex}.
1924      *
1925      * @param cm the table model
1926      * @param modelColumnIndex the index of the column in the model
1927      * @return the index of the corresponding column in the view
1928      *
1929      * @see JTable#convertColumnIndexToView(int)
1930      * @see javax.swing.plaf.basic.BasicTableHeaderUI
1931      */
1932     public static int convertColumnIndexToView(TableColumnModel cm,
1933                                         int modelColumnIndex) {
1934         if (modelColumnIndex < 0) {
1935             return modelColumnIndex;
1936         }
1937         for (int column = 0; column < cm.getColumnCount(); column++) {
1938             if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {
1939                 return column;
1940             }
1941         }
1942         return -1;
1943     }
1944 
1945     public static int getSystemMnemonicKeyMask() {
1946         Toolkit toolkit = Toolkit.getDefaultToolkit();
1947         if (toolkit instanceof SunToolkit) {
1948             return ((SunToolkit) toolkit).getFocusAcceleratorKeyMask();
1949         }
1950         return InputEvent.ALT_MASK;
1951     }
1952 
1953     /**
1954      * Returns the {@link TreePath} that identifies the changed nodes.
1955      *
1956      * @param event  changes in a tree model
1957      * @param model  corresponing tree model
1958      * @return  the path to the changed nodes
1959      */
1960     public static TreePath getTreePath(TreeModelEvent event, TreeModel model) {
1961         TreePath path = event.getTreePath();
1962         if ((path == null) && (model != null)) {
1963             Object root = model.getRoot();
1964             if (root != null) {
1965                 path = new TreePath(root);
1966             }
1967         }
1968         return path;
1969     }
1970     
1971     /**
1972      * Used to listen to "blit" repaints in RepaintManager.
1973      */
1974     public interface RepaintListener {
1975         void repaintPerformed(JComponent c, int x, int y, int w, int h);
1976     }
1977 }