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