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