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