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