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