Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/swing/SwingUtilities2.java
38829 views
/*1* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.swing;2627import java.security.*;28import java.lang.reflect.*;29import java.awt.*;30import static java.awt.RenderingHints.*;31import java.awt.event.*;32import java.awt.font.*;33import java.awt.geom.*;34import java.awt.print.PrinterGraphics;35import java.text.BreakIterator;36import java.text.CharacterIterator;37import java.text.AttributedCharacterIterator;38import java.text.AttributedString;3940import javax.swing.*;41import javax.swing.event.TreeModelEvent;42import javax.swing.text.Highlighter;43import javax.swing.text.JTextComponent;44import javax.swing.text.DefaultHighlighter;45import javax.swing.text.DefaultCaret;46import javax.swing.table.TableCellRenderer;47import javax.swing.table.TableColumnModel;48import javax.swing.tree.TreeModel;49import javax.swing.tree.TreePath;5051import sun.swing.PrintColorUIResource;52import sun.swing.ImageIconUIResource;53import sun.print.ProxyPrintGraphics;54import sun.awt.*;55import sun.security.action.GetPropertyAction;56import sun.security.util.SecurityConstants;57import java.io.*;58import java.util.*;59import sun.font.FontDesignMetrics;60import sun.font.FontUtilities;61import sun.java2d.SunGraphicsEnvironment;6263import java.util.concurrent.Callable;64import java.util.concurrent.Future;65import java.util.concurrent.FutureTask;6667/**68* A collection of utility methods for Swing.69* <p>70* <b>WARNING:</b> While this class is public, it should not be treated as71* public API and its API may change in incompatable ways between dot dot72* releases and even patch releases. You should not rely on this class even73* existing.74*75*/76public class SwingUtilities2 {77/**78* The <code>AppContext</code> key for our one <code>LAFState</code>79* instance.80*/81public static final Object LAF_STATE_KEY =82new StringBuffer("LookAndFeel State");8384public static final Object MENU_SELECTION_MANAGER_LISTENER_KEY =85new StringBuffer("MenuSelectionManager listener key");8687// Maintain a cache of CACHE_SIZE fonts and the left side bearing88// of the characters falling into the range MIN_CHAR_INDEX to89// MAX_CHAR_INDEX. The values in fontCache are created as needed.90private static LSBCacheEntry[] fontCache;91// Windows defines 6 font desktop properties, we will therefore only92// cache the metrics for 6 fonts.93private static final int CACHE_SIZE = 6;94// nextIndex in fontCache to insert a font into.95private static int nextIndex;96// LSBCacheEntry used to search in fontCache to see if we already97// have an entry for a particular font98private static LSBCacheEntry searchKey;99100// getLeftSideBearing will consult all characters that fall in the101// range MIN_CHAR_INDEX to MAX_CHAR_INDEX.102private static final int MIN_CHAR_INDEX = (int)'W';103private static final int MAX_CHAR_INDEX = (int)'W' + 1;104105public static final FontRenderContext DEFAULT_FRC =106new FontRenderContext(null, false, false);107108/**109* A JComponent client property is used to determine text aa settings.110* To avoid having this property persist between look and feels changes111* the value of the property is set to null in JComponent.setUI112*/113public static final Object AA_TEXT_PROPERTY_KEY =114new StringBuffer("AATextInfoPropertyKey");115116/**117* Attribute key for the content elements. If it is set on an element, the118* element is considered to be a line break.119*/120public static final String IMPLIED_CR = "CR";121122/**123* Used to tell a text component, being used as an editor for table124* or tree, how many clicks it took to start editing.125*/126private static final StringBuilder SKIP_CLICK_COUNT =127new StringBuilder("skipClickCount");128129/* Presently this class assumes default fractional metrics.130* This may need to change to emulate future platform L&Fs.131*/132public static class AATextInfo {133134private static AATextInfo getAATextInfoFromMap(Map hints) {135136Object aaHint = hints.get(KEY_TEXT_ANTIALIASING);137Object contHint = hints.get(KEY_TEXT_LCD_CONTRAST);138139if (aaHint == null ||140aaHint == VALUE_TEXT_ANTIALIAS_OFF ||141aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {142return null;143} else {144return new AATextInfo(aaHint, (Integer)contHint);145}146}147148public static AATextInfo getAATextInfo(boolean lafCondition) {149SunToolkit.setAAFontSettingsCondition(lafCondition);150Toolkit tk = Toolkit.getDefaultToolkit();151Object map = tk.getDesktopProperty(SunToolkit.DESKTOPFONTHINTS);152if (map instanceof Map) {153return getAATextInfoFromMap((Map)map);154} else {155return null;156}157}158159Object aaHint;160Integer lcdContrastHint;161FontRenderContext frc;162163/* These are rarely constructed objects, and only when a complete164* UI is being updated, so the cost of the tests here is minimal165* and saves tests elsewhere.166* We test that the values are ones we support/expect.167*/168public AATextInfo(Object aaHint, Integer lcdContrastHint) {169if (aaHint == null) {170throw new InternalError("null not allowed here");171}172if (aaHint == VALUE_TEXT_ANTIALIAS_OFF ||173aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {174throw new InternalError("AA must be on");175}176this.aaHint = aaHint;177this.lcdContrastHint = lcdContrastHint;178this.frc = new FontRenderContext(null, aaHint,179VALUE_FRACTIONALMETRICS_DEFAULT);180}181}182183/**184* Key used in client properties used to indicate that the185* <code>ComponentUI</code> of the JComponent instance should be returned.186*/187public static final Object COMPONENT_UI_PROPERTY_KEY =188new StringBuffer("ComponentUIPropertyKey");189190/** Client Property key for the text maximal offsets for BasicMenuItemUI */191public static final StringUIClientPropertyKey BASICMENUITEMUI_MAX_TEXT_OFFSET =192new StringUIClientPropertyKey ("maxTextOffset");193194// security stuff195private static Field inputEvent_CanAccessSystemClipboard_Field = null;196private static final String UntrustedClipboardAccess =197"UNTRUSTED_CLIPBOARD_ACCESS_KEY";198199//all access to charsBuffer is to be synchronized on charsBufferLock200private static final int CHAR_BUFFER_SIZE = 100;201private static final Object charsBufferLock = new Object();202private static char[] charsBuffer = new char[CHAR_BUFFER_SIZE];203204static {205fontCache = new LSBCacheEntry[CACHE_SIZE];206}207208/**209* Fill the character buffer cache. Return the buffer length.210*/211private static int syncCharsBuffer(String s) {212int length = s.length();213if ((charsBuffer == null) || (charsBuffer.length < length)) {214charsBuffer = s.toCharArray();215} else {216s.getChars(0, length, charsBuffer, 0);217}218return length;219}220221/**222* checks whether TextLayout is required to handle characters.223*224* @param text characters to be tested225* @param start start226* @param limit limit227* @return <tt>true</tt> if TextLayout is required228* <tt>false</tt> if TextLayout is not required229*/230public static final boolean isComplexLayout(char[] text, int start, int limit) {231return FontUtilities.isComplexText(text, start, limit);232}233234//235// WARNING WARNING WARNING WARNING WARNING WARNING236// Many of the following methods are invoked from older API.237// As this older API was not passed a Component, a null Component may238// now be passsed in. For example, SwingUtilities.computeStringWidth239// is implemented to call SwingUtilities2.stringWidth, the240// SwingUtilities variant does not take a JComponent, as such241// SwingUtilities2.stringWidth can be passed a null Component.242// In other words, if you add new functionality to these methods you243// need to gracefully handle null.244//245246/**247* Returns whether or not text should be drawn antialiased.248*249* @param c JComponent to test.250* @return Whether or not text should be drawn antialiased for the251* specified component.252*/253public static AATextInfo drawTextAntialiased(JComponent c) {254if (c != null) {255/* a non-null property implies some form of AA requested */256return (AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);257}258// No component, assume aa is off259return null;260}261262/**263* Returns the left side bearing of the first character of string. The264* left side bearing is calculated from the passed in265* FontMetrics. If the passed in String is less than one266* character {@code 0} is returned.267*268* @param c JComponent that will display the string269* @param fm FontMetrics used to measure the String width270* @param string String to get the left side bearing for.271* @throws NullPointerException if {@code string} is {@code null}272*273* @return the left side bearing of the first character of string274* or {@code 0} if the string is empty275*/276public static int getLeftSideBearing(JComponent c, FontMetrics fm,277String string) {278if ((string == null) || (string.length() == 0)) {279return 0;280}281return getLeftSideBearing(c, fm, string.charAt(0));282}283284/**285* Returns the left side bearing of the first character of string. The286* left side bearing is calculated from the passed in FontMetrics.287*288* @param c JComponent that will display the string289* @param fm FontMetrics used to measure the String width290* @param firstChar Character to get the left side bearing for.291*/292public static int getLeftSideBearing(JComponent c, FontMetrics fm,293char firstChar) {294int charIndex = (int) firstChar;295if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {296byte[] lsbs = null;297298FontRenderContext frc = getFontRenderContext(c, fm);299Font font = fm.getFont();300synchronized (SwingUtilities2.class) {301LSBCacheEntry entry = null;302if (searchKey == null) {303searchKey = new LSBCacheEntry(frc, font);304} else {305searchKey.reset(frc, font);306}307// See if we already have an entry for this pair308for (LSBCacheEntry cacheEntry : fontCache) {309if (searchKey.equals(cacheEntry)) {310entry = cacheEntry;311break;312}313}314if (entry == null) {315// No entry for this pair, add it.316entry = searchKey;317fontCache[nextIndex] = searchKey;318searchKey = null;319nextIndex = (nextIndex + 1) % CACHE_SIZE;320}321return entry.getLeftSideBearing(firstChar);322}323}324return 0;325}326327/**328* Returns the FontMetrics for the current Font of the passed329* in Graphics. This method is used when a Graphics330* is available, typically when painting. If a Graphics is not331* available the JComponent method of the same name should be used.332* <p>333* Callers should pass in a non-null JComponent, the exception334* to this is if a JComponent is not readily available at the time of335* painting.336* <p>337* This does not necessarily return the FontMetrics from the338* Graphics.339*340* @param c JComponent requesting FontMetrics, may be null341* @param g Graphics Graphics342*/343public static FontMetrics getFontMetrics(JComponent c, Graphics g) {344return getFontMetrics(c, g, g.getFont());345}346347348/**349* Returns the FontMetrics for the specified Font.350* This method is used when a Graphics is available, typically when351* painting. If a Graphics is not available the JComponent method of352* the same name should be used.353* <p>354* Callers should pass in a non-null JComonent, the exception355* to this is if a JComponent is not readily available at the time of356* painting.357* <p>358* This does not necessarily return the FontMetrics from the359* Graphics.360*361* @param c JComponent requesting FontMetrics, may be null362* @param c Graphics Graphics363* @param font Font to get FontMetrics for364*/365public static FontMetrics getFontMetrics(JComponent c, Graphics g,366Font font) {367if (c != null) {368// Note: We assume that we're using the FontMetrics369// from the widget to layout out text, otherwise we can get370// mismatches when printing.371return c.getFontMetrics(font);372}373return Toolkit.getDefaultToolkit().getFontMetrics(font);374}375376377/**378* Returns the width of the passed in String.379* If the passed String is <code>null</code>, returns zero.380*381* @param c JComponent that will display the string, may be null382* @param fm FontMetrics used to measure the String width383* @param string String to get the width of384*/385public static int stringWidth(JComponent c, FontMetrics fm, String string){386if (string == null || string.equals("")) {387return 0;388}389boolean needsTextLayout = ((c != null) &&390(c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));391if (needsTextLayout) {392synchronized(charsBufferLock) {393int length = syncCharsBuffer(string);394needsTextLayout = isComplexLayout(charsBuffer, 0, length);395}396}397if (needsTextLayout) {398TextLayout layout = createTextLayout(c, string,399fm.getFont(), fm.getFontRenderContext());400return (int) layout.getAdvance();401} else {402return fm.stringWidth(string);403}404}405406407/**408* Clips the passed in String to the space provided.409*410* @param c JComponent that will display the string, may be null411* @param fm FontMetrics used to measure the String width412* @param string String to display413* @param availTextWidth Amount of space that the string can be drawn in414* @return Clipped string that can fit in the provided space.415*/416public static String clipStringIfNecessary(JComponent c, FontMetrics fm,417String string,418int availTextWidth) {419if ((string == null) || (string.equals(""))) {420return "";421}422int textWidth = SwingUtilities2.stringWidth(c, fm, string);423if (textWidth > availTextWidth) {424return SwingUtilities2.clipString(c, fm, string, availTextWidth);425}426return string;427}428429430/**431* Clips the passed in String to the space provided. NOTE: this assumes432* the string does not fit in the available space.433*434* @param c JComponent that will display the string, may be null435* @param fm FontMetrics used to measure the String width436* @param string String to display437* @param availTextWidth Amount of space that the string can be drawn in438* @return Clipped string that can fit in the provided space.439*/440public static String clipString(JComponent c, FontMetrics fm,441String string, int availTextWidth) {442// c may be null here.443String clipString = "...";444availTextWidth -= SwingUtilities2.stringWidth(c, fm, clipString);445if (availTextWidth <= 0) {446//can not fit any characters447return clipString;448}449450boolean needsTextLayout;451synchronized (charsBufferLock) {452int stringLength = syncCharsBuffer(string);453needsTextLayout =454isComplexLayout(charsBuffer, 0, stringLength);455if (!needsTextLayout) {456int width = 0;457for (int nChars = 0; nChars < stringLength; nChars++) {458width += fm.charWidth(charsBuffer[nChars]);459if (width > availTextWidth) {460string = string.substring(0, nChars);461break;462}463}464}465}466if (needsTextLayout) {467AttributedString aString = new AttributedString(string);468if (c != null) {469aString.addAttribute(TextAttribute.NUMERIC_SHAPING,470c.getClientProperty(TextAttribute.NUMERIC_SHAPING));471}472LineBreakMeasurer measurer = new LineBreakMeasurer(473aString.getIterator(), BreakIterator.getCharacterInstance(),474getFontRenderContext(c, fm));475string = string.substring(0, measurer.nextOffset(availTextWidth));476477}478return string + clipString;479}480481482/**483* Draws the string at the specified location.484*485* @param c JComponent that will display the string, may be null486* @param g Graphics to draw the text to487* @param text String to display488* @param x X coordinate to draw the text at489* @param y Y coordinate to draw the text at490*/491public static void drawString(JComponent c, Graphics g, String text,492int x, int y) {493// c may be null494495// All non-editable widgets that draw strings call into this496// methods. By non-editable that means widgets like JLabel, JButton497// but NOT JTextComponents.498if ( text == null || text.length() <= 0 ) { //no need to paint empty strings499return;500}501if (isPrinting(g)) {502Graphics2D g2d = getGraphics2D(g);503if (g2d != null) {504/* The printed text must scale linearly with the UI.505* Calculate the width on screen, obtain a TextLayout with506* advances for the printer graphics FRC, and then justify507* it to fit in the screen width. This distributes the spacing508* more evenly than directly laying out to the screen advances.509*/510String trimmedText = trimTrailingSpaces(text);511if (!trimmedText.isEmpty()) {512float screenWidth = (float) g2d.getFont().getStringBounds513(trimmedText, getFontRenderContext(c)).getWidth();514TextLayout layout = createTextLayout(c, text, g2d.getFont(),515g2d.getFontRenderContext());516517// If text fits the screenWidth, then do not need to justify518if (SwingUtilities2.stringWidth(c, g2d.getFontMetrics(),519trimmedText) > screenWidth) {520layout = layout.getJustifiedLayout(screenWidth);521}522/* Use alternate print color if specified */523Color col = g2d.getColor();524if (col instanceof PrintColorUIResource) {525g2d.setColor(((PrintColorUIResource)col).getPrintColor());526}527528layout.draw(g2d, x, y);529530g2d.setColor(col);531}532533return;534}535}536537// If we get here we're not printing538if (g instanceof Graphics2D) {539AATextInfo info = drawTextAntialiased(c);540Graphics2D g2 = (Graphics2D)g;541542boolean needsTextLayout = ((c != null) &&543(c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null));544545if (needsTextLayout) {546synchronized(charsBufferLock) {547int length = syncCharsBuffer(text);548needsTextLayout = isComplexLayout(charsBuffer, 0, length);549}550}551552if (info != null) {553Object oldContrast = null;554Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);555if (info.aaHint != oldAAValue) {556g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);557} else {558oldAAValue = null;559}560if (info.lcdContrastHint != null) {561oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);562if (info.lcdContrastHint.equals(oldContrast)) {563oldContrast = null;564} else {565g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,566info.lcdContrastHint);567}568}569570if (needsTextLayout) {571TextLayout layout = createTextLayout(c, text, g2.getFont(),572g2.getFontRenderContext());573layout.draw(g2, x, y);574} else {575g.drawString(text, x, y);576}577578if (oldAAValue != null) {579g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);580}581if (oldContrast != null) {582g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);583}584585return;586}587588if (needsTextLayout){589TextLayout layout = createTextLayout(c, text, g2.getFont(),590g2.getFontRenderContext());591layout.draw(g2, x, y);592return;593}594}595596g.drawString(text, x, y);597}598599/**600* Draws the string at the specified location underlining the specified601* character.602*603* @param c JComponent that will display the string, may be null604* @param g Graphics to draw the text to605* @param text String to display606* @param underlinedIndex Index of a character in the string to underline607* @param x X coordinate to draw the text at608* @param y Y coordinate to draw the text at609*/610public static void drawStringUnderlineCharAt(JComponent c,Graphics g,611String text, int underlinedIndex, int x,int y) {612if (text == null || text.length() <= 0) {613return;614}615SwingUtilities2.drawString(c, g, text, x, y);616int textLength = text.length();617if (underlinedIndex >= 0 && underlinedIndex < textLength ) {618int underlineRectY = y;619int underlineRectHeight = 1;620int underlineRectX = 0;621int underlineRectWidth = 0;622boolean isPrinting = isPrinting(g);623boolean needsTextLayout = isPrinting;624if (!needsTextLayout) {625synchronized (charsBufferLock) {626syncCharsBuffer(text);627needsTextLayout =628isComplexLayout(charsBuffer, 0, textLength);629}630}631if (!needsTextLayout) {632FontMetrics fm = g.getFontMetrics();633underlineRectX = x +634SwingUtilities2.stringWidth(c,fm,635text.substring(0,underlinedIndex));636underlineRectWidth = fm.charWidth(text.637charAt(underlinedIndex));638} else {639Graphics2D g2d = getGraphics2D(g);640if (g2d != null) {641TextLayout layout =642createTextLayout(c, text, g2d.getFont(),643g2d.getFontRenderContext());644if (isPrinting) {645float screenWidth = (float)g2d.getFont().646getStringBounds(text, getFontRenderContext(c)).getWidth();647// If text fits the screenWidth, then do not need to justify648if (SwingUtilities2.stringWidth(c, g2d.getFontMetrics(),649text) > screenWidth) {650layout = layout.getJustifiedLayout(screenWidth);651}652}653TextHitInfo leading =654TextHitInfo.leading(underlinedIndex);655TextHitInfo trailing =656TextHitInfo.trailing(underlinedIndex);657Shape shape =658layout.getVisualHighlightShape(leading, trailing);659Rectangle rect = shape.getBounds();660underlineRectX = x + rect.x;661underlineRectWidth = rect.width;662}663}664g.fillRect(underlineRectX, underlineRectY + 1,665underlineRectWidth, underlineRectHeight);666}667}668669670/**671* A variation of locationToIndex() which only returns an index if the672* Point is within the actual bounds of a list item (not just in the cell)673* and if the JList has the "List.isFileList" client property set.674* Otherwise, this method returns -1.675* This is used to make WindowsL&F JFileChooser act like native dialogs.676*/677public static int loc2IndexFileList(JList list, Point point) {678int index = list.locationToIndex(point);679if (index != -1) {680Object bySize = list.getClientProperty("List.isFileList");681if (bySize instanceof Boolean && ((Boolean)bySize).booleanValue() &&682!pointIsInActualBounds(list, index, point)) {683index = -1;684}685}686return index;687}688689690/**691* Returns true if the given point is within the actual bounds of the692* JList item at index (not just inside the cell).693*/694private static boolean pointIsInActualBounds(JList list, int index,695Point point) {696ListCellRenderer renderer = list.getCellRenderer();697ListModel dataModel = list.getModel();698Object value = dataModel.getElementAt(index);699Component item = renderer.getListCellRendererComponent(list,700value, index, false, false);701Dimension itemSize = item.getPreferredSize();702Rectangle cellBounds = list.getCellBounds(index, index);703if (!item.getComponentOrientation().isLeftToRight()) {704cellBounds.x += (cellBounds.width - itemSize.width);705}706cellBounds.width = itemSize.width;707708return cellBounds.contains(point);709}710711712/**713* Returns true if the given point is outside the preferredSize of the714* item at the given row of the table. (Column must be 0).715* Does not check the "Table.isFileList" property. That should be checked716* before calling this method.717* This is used to make WindowsL&F JFileChooser act like native dialogs.718*/719public static boolean pointOutsidePrefSize(JTable table, int row, int column, Point p) {720if (table.convertColumnIndexToModel(column) != 0 || row == -1) {721return true;722}723TableCellRenderer tcr = table.getCellRenderer(row, column);724Object value = table.getValueAt(row, column);725Component cell = tcr.getTableCellRendererComponent(table, value, false,726false, row, column);727Dimension itemSize = cell.getPreferredSize();728Rectangle cellBounds = table.getCellRect(row, column, false);729cellBounds.width = itemSize.width;730cellBounds.height = itemSize.height;731732// See if coords are inside733// ASSUME: mouse x,y will never be < cell's x,y734assert (p.x >= cellBounds.x && p.y >= cellBounds.y);735return p.x > cellBounds.x + cellBounds.width ||736p.y > cellBounds.y + cellBounds.height;737}738739/**740* Set the lead and anchor without affecting selection.741*/742public static void setLeadAnchorWithoutSelection(ListSelectionModel model,743int lead, int anchor) {744if (anchor == -1) {745anchor = lead;746}747if (lead == -1) {748model.setAnchorSelectionIndex(-1);749model.setLeadSelectionIndex(-1);750} else {751if (model.isSelectedIndex(lead)) {752model.addSelectionInterval(lead, lead);753} else {754model.removeSelectionInterval(lead, lead);755}756model.setAnchorSelectionIndex(anchor);757}758}759760/**761* Ignore mouse events if the component is null, not enabled, the event762* is not associated with the left mouse button, or the event has been763* consumed.764*/765public static boolean shouldIgnore(MouseEvent me, JComponent c) {766return c == null || !c.isEnabled()767|| !SwingUtilities.isLeftMouseButton(me)768|| me.isConsumed();769}770771/**772* Request focus on the given component if it doesn't already have it773* and <code>isRequestFocusEnabled()</code> returns true.774*/775public static void adjustFocus(JComponent c) {776if (!c.hasFocus() && c.isRequestFocusEnabled()) {777c.requestFocus();778}779}780781/**782* The following draw functions have the same semantic as the783* Graphics methods with the same names.784*785* this is used for printing786*/787public static int drawChars(JComponent c, Graphics g,788char[] data,789int offset,790int length,791int x,792int y) {793if ( length <= 0 ) { //no need to paint empty strings794return x;795}796int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);797if (isPrinting(g)) {798Graphics2D g2d = getGraphics2D(g);799if (g2d != null) {800FontRenderContext deviceFontRenderContext = g2d.801getFontRenderContext();802FontRenderContext frc = getFontRenderContext(c);803if (frc != null &&804!isFontRenderContextPrintCompatible805(deviceFontRenderContext, frc)) {806807String text = new String(data, offset, length);808TextLayout layout = new TextLayout(text, g2d.getFont(),809deviceFontRenderContext);810String trimmedText = trimTrailingSpaces(text);811if (!trimmedText.isEmpty()) {812float screenWidth = (float)g2d.getFont().813getStringBounds(trimmedText, frc).getWidth();814// If text fits the screenWidth, then do not need to justify815if (SwingUtilities2.stringWidth(c, g2d.getFontMetrics(),816trimmedText) > screenWidth) {817layout = layout.getJustifiedLayout(screenWidth);818}819820/* Use alternate print color if specified */821Color col = g2d.getColor();822if (col instanceof PrintColorUIResource) {823g2d.setColor(((PrintColorUIResource)col).getPrintColor());824}825826layout.draw(g2d,x,y);827828g2d.setColor(col);829}830831return nextX;832}833}834}835// Assume we're not printing if we get here, or that we are invoked836// via Swing text printing which is laid out for the printer.837AATextInfo info = drawTextAntialiased(c);838if (info != null && (g instanceof Graphics2D)) {839Graphics2D g2 = (Graphics2D)g;840841Object oldContrast = null;842Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);843if (info.aaHint != null && info.aaHint != oldAAValue) {844g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint);845} else {846oldAAValue = null;847}848if (info.lcdContrastHint != null) {849oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST);850if (info.lcdContrastHint.equals(oldContrast)) {851oldContrast = null;852} else {853g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST,854info.lcdContrastHint);855}856}857858g.drawChars(data, offset, length, x, y);859860if (oldAAValue != null) {861g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);862}863if (oldContrast != null) {864g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast);865}866}867else {868g.drawChars(data, offset, length, x, y);869}870return nextX;871}872873/*874* see documentation for drawChars875* returns the advance876*/877public static float drawString(JComponent c, Graphics g,878AttributedCharacterIterator iterator,879int x,880int y) {881882float retVal;883boolean isPrinting = isPrinting(g);884Color col = g.getColor();885886if (isPrinting) {887/* Use alternate print color if specified */888if (col instanceof PrintColorUIResource) {889g.setColor(((PrintColorUIResource)col).getPrintColor());890}891}892893Graphics2D g2d = getGraphics2D(g);894if (g2d == null) {895g.drawString(iterator,x,y); //for the cases where advance896//matters it should not happen897retVal = x;898899} else {900FontRenderContext frc;901if (isPrinting) {902frc = getFontRenderContext(c);903if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {904frc = new FontRenderContext(frc.getTransform(), false, false);905}906} else if ((frc = getFRCProperty(c)) != null) {907/* frc = frc; ! */908} else {909frc = g2d.getFontRenderContext();910}911TextLayout layout;912if (isPrinting) {913FontRenderContext deviceFRC = g2d.getFontRenderContext();914if (!isFontRenderContextPrintCompatible(frc, deviceFRC)) {915layout = new TextLayout(iterator, deviceFRC);916AttributedCharacterIterator trimmedIt =917getTrimmedTrailingSpacesIterator(iterator);918if (trimmedIt != null) {919float screenWidth = new TextLayout(trimmedIt, frc).920getAdvance();921layout = layout.getJustifiedLayout(screenWidth);922}923} else {924layout = new TextLayout(iterator, frc);925}926} else {927layout = new TextLayout(iterator, frc);928}929layout.draw(g2d, x, y);930retVal = layout.getAdvance();931}932933if (isPrinting) {934g.setColor(col);935}936937return retVal;938}939940/**941* This method should be used for drawing a borders over a filled rectangle.942* Draws vertical line, using the current color, between the points {@code943* (x, y1)} and {@code (x, y2)} in graphics context's coordinate system.944* Note: it use {@code Graphics.fillRect()} internally.945*946* @param g Graphics to draw the line to.947* @param x the <i>x</i> coordinate.948* @param y1 the first point's <i>y</i> coordinate.949* @param y2 the second point's <i>y</i> coordinate.950*/951public static void drawVLine(Graphics g, int x, int y1, int y2) {952if (y2 < y1) {953final int temp = y2;954y2 = y1;955y1 = temp;956}957g.fillRect(x, y1, 1, y2 - y1 + 1);958}959960/**961* This method should be used for drawing a borders over a filled rectangle.962* Draws horizontal line, using the current color, between the points {@code963* (x1, y)} and {@code (x2, y)} in graphics context's coordinate system.964* Note: it use {@code Graphics.fillRect()} internally.965*966* @param g Graphics to draw the line to.967* @param x1 the first point's <i>x</i> coordinate.968* @param x2 the second point's <i>x</i> coordinate.969* @param y the <i>y</i> coordinate.970*/971public static void drawHLine(Graphics g, int x1, int x2, int y) {972if (x2 < x1) {973final int temp = x2;974x2 = x1;975x1 = temp;976}977g.fillRect(x1, y, x2 - x1 + 1, 1);978}979980/**981* This method should be used for drawing a borders over a filled rectangle.982* Draws the outline of the specified rectangle. The left and right edges of983* the rectangle are at {@code x} and {@code x + w}. The top and bottom984* edges are at {@code y} and {@code y + h}. The rectangle is drawn using985* the graphics context's current color. Note: it use {@code986* Graphics.fillRect()} internally.987*988* @param g Graphics to draw the rectangle to.989* @param x the <i>x</i> coordinate of the rectangle to be drawn.990* @param y the <i>y</i> coordinate of the rectangle to be drawn.991* @param w the w of the rectangle to be drawn.992* @param h the h of the rectangle to be drawn.993* @see SwingUtilities2#drawVLine(java.awt.Graphics, int, int, int)994* @see SwingUtilities2#drawHLine(java.awt.Graphics, int, int, int)995*/996public static void drawRect(Graphics g, int x, int y, int w, int h) {997if (w < 0 || h < 0) {998return;999}10001001if (h == 0 || w == 0) {1002g.fillRect(x, y, w + 1, h + 1);1003} else {1004g.fillRect(x, y, w, 1);1005g.fillRect(x + w, y, 1, h);1006g.fillRect(x + 1, y + h, w, 1);1007g.fillRect(x, y + 1, 1, h);1008}1009}10101011private static TextLayout createTextLayout(JComponent c, String s,1012Font f, FontRenderContext frc) {1013Object shaper = (c == null ?1014null : c.getClientProperty(TextAttribute.NUMERIC_SHAPING));1015if (shaper == null) {1016return new TextLayout(s, f, frc);1017} else {1018Map<TextAttribute, Object> a = new HashMap<TextAttribute, Object>();1019a.put(TextAttribute.FONT, f);1020a.put(TextAttribute.NUMERIC_SHAPING, shaper);1021return new TextLayout(s, a, frc);1022}1023}10241025/*1026* Checks if two given FontRenderContexts are compatible for printing.1027* We can't just use equals as we want to exclude from the comparison :1028* + whether AA is set as irrelevant for printing and shouldn't affect1029* printed metrics anyway1030* + any translation component in the transform of either FRC, as it1031* does not affect metrics.1032* Compatible means no special handling needed for text painting1033*/1034private static boolean1035isFontRenderContextPrintCompatible(FontRenderContext frc1,1036FontRenderContext frc2) {10371038if (frc1 == frc2) {1039return true;1040}10411042if (frc1 == null || frc2 == null) { // not supposed to happen1043return false;1044}10451046if (frc1.getFractionalMetricsHint() !=1047frc2.getFractionalMetricsHint()) {1048return false;1049}10501051/* If both are identity, return true */1052if (!frc1.isTransformed() && !frc2.isTransformed()) {1053return true;1054}10551056/* That's the end of the cheap tests, need to get and compare1057* the transform matrices. We don't care about the translation1058* components, so return true if they are otherwise identical.1059*/1060double[] mat1 = new double[4];1061double[] mat2 = new double[4];1062frc1.getTransform().getMatrix(mat1);1063frc2.getTransform().getMatrix(mat2);1064return1065mat1[0] == mat2[0] &&1066mat1[1] == mat2[1] &&1067mat1[2] == mat2[2] &&1068mat1[3] == mat2[3];1069}10701071/*1072* Tries it best to get Graphics2D out of the given Graphics1073* returns null if can not derive it.1074*/1075public static Graphics2D getGraphics2D(Graphics g) {1076if (g instanceof Graphics2D) {1077return (Graphics2D) g;1078} else if (g instanceof ProxyPrintGraphics) {1079return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());1080} else {1081return null;1082}1083}10841085/*1086* Returns FontRenderContext associated with Component.1087* FontRenderContext from Component.getFontMetrics is associated1088* with the component.1089*1090* Uses Component.getFontMetrics to get the FontRenderContext from.1091* see JComponent.getFontMetrics and TextLayoutStrategy.java1092*/1093public static FontRenderContext getFontRenderContext(Component c) {1094assert c != null;1095if (c == null) {1096return DEFAULT_FRC;1097} else {1098return c.getFontMetrics(c.getFont()).getFontRenderContext();1099}1100}11011102/**1103* A convenience method to get FontRenderContext.1104* Returns the FontRenderContext for the passed in FontMetrics or1105* for the passed in Component if FontMetrics is null1106*/1107private static FontRenderContext getFontRenderContext(Component c, FontMetrics fm) {1108assert fm != null || c!= null;1109return (fm != null) ? fm.getFontRenderContext()1110: getFontRenderContext(c);1111}11121113/*1114* This method is to be used only for JComponent.getFontMetrics.1115* In all other places to get FontMetrics we need to use1116* JComponent.getFontMetrics.1117*1118*/1119public static FontMetrics getFontMetrics(JComponent c, Font font) {1120FontRenderContext frc = getFRCProperty(c);1121if (frc == null) {1122frc = DEFAULT_FRC;1123}1124return FontDesignMetrics.getMetrics(font, frc);1125}112611271128/* Get any FontRenderContext associated with a JComponent1129* - may return null1130*/1131private static FontRenderContext getFRCProperty(JComponent c) {1132if (c != null) {1133AATextInfo info =1134(AATextInfo)c.getClientProperty(AA_TEXT_PROPERTY_KEY);1135if (info != null) {1136return info.frc;1137}1138}1139return null;1140}11411142/*1143* returns true if the Graphics is print Graphics1144* false otherwise1145*/1146static boolean isPrinting(Graphics g) {1147return (g instanceof PrinterGraphics || g instanceof PrintGraphics);1148}11491150private static String trimTrailingSpaces(String s) {1151int i = s.length() - 1;1152while(i >= 0 && Character.isWhitespace(s.charAt(i))) {1153i--;1154}1155return s.substring(0, i + 1);1156}11571158private static AttributedCharacterIterator getTrimmedTrailingSpacesIterator1159(AttributedCharacterIterator iterator) {1160int curIdx = iterator.getIndex();11611162char c = iterator.last();1163while(c != CharacterIterator.DONE && Character.isWhitespace(c)) {1164c = iterator.previous();1165}11661167if (c != CharacterIterator.DONE) {1168int endIdx = iterator.getIndex();11691170if (endIdx == iterator.getEndIndex() - 1) {1171iterator.setIndex(curIdx);1172return iterator;1173} else {1174AttributedString trimmedText = new AttributedString(iterator,1175iterator.getBeginIndex(), endIdx + 1);1176return trimmedText.getIterator();1177}1178} else {1179return null;1180}1181}11821183/**1184* Determines whether the SelectedTextColor should be used for painting text1185* foreground for the specified highlight.1186*1187* Returns true only if the highlight painter for the specified highlight1188* is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter1189* or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color1190* is null or equals to the selection color of the text component.1191*1192* This is a hack for fixing both bugs 4761990 and 50032941193*/1194public static boolean useSelectedTextColor(Highlighter.Highlight h, JTextComponent c) {1195Highlighter.HighlightPainter painter = h.getPainter();1196String painterClass = painter.getClass().getName();1197if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&1198painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {1199return false;1200}1201try {1202DefaultHighlighter.DefaultHighlightPainter defPainter =1203(DefaultHighlighter.DefaultHighlightPainter) painter;1204if (defPainter.getColor() != null &&1205!defPainter.getColor().equals(c.getSelectionColor())) {1206return false;1207}1208} catch (ClassCastException e) {1209return false;1210}1211return true;1212}12131214/**1215* LSBCacheEntry is used to cache the left side bearing (lsb) for1216* a particular <code>Font</code> and <code>FontRenderContext</code>.1217* This only caches characters that fall in the range1218* <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.1219*/1220private static class LSBCacheEntry {1221// Used to indicate a particular entry in lsb has not been set.1222private static final byte UNSET = Byte.MAX_VALUE;1223// Used in creating a GlyphVector to get the lsb1224private static final char[] oneChar = new char[1];12251226private byte[] lsbCache;1227private Font font;1228private FontRenderContext frc;122912301231public LSBCacheEntry(FontRenderContext frc, Font font) {1232lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];1233reset(frc, font);12341235}12361237public void reset(FontRenderContext frc, Font font) {1238this.font = font;1239this.frc = frc;1240for (int counter = lsbCache.length - 1; counter >= 0; counter--) {1241lsbCache[counter] = UNSET;1242}1243}12441245public int getLeftSideBearing(char aChar) {1246int index = aChar - MIN_CHAR_INDEX;1247assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));1248byte lsb = lsbCache[index];1249if (lsb == UNSET) {1250oneChar[0] = aChar;1251GlyphVector gv = font.createGlyphVector(frc, oneChar);1252lsb = (byte) gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;1253if (lsb < 0) {1254/* HRGB/HBGR LCD glyph images will always have a pixel1255* on the left used in colour fringe reduction.1256* Text rendering positions this correctly but here1257* we are using the glyph image to adjust that position1258* so must account for it.1259*/1260Object aaHint = frc.getAntiAliasingHint();1261if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||1262aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {1263lsb++;1264}1265}1266lsbCache[index] = lsb;1267}1268return lsb;126912701271}12721273public boolean equals(Object entry) {1274if (entry == this) {1275return true;1276}1277if (!(entry instanceof LSBCacheEntry)) {1278return false;1279}1280LSBCacheEntry oEntry = (LSBCacheEntry) entry;1281return (font.equals(oEntry.font) &&1282frc.equals(oEntry.frc));1283}12841285public int hashCode() {1286int result = 17;1287if (font != null) {1288result = 37 * result + font.hashCode();1289}1290if (frc != null) {1291result = 37 * result + frc.hashCode();1292}1293return result;1294}1295}12961297/*1298* here goes the fix for 4856343 [Problem with applet interaction1299* with system selection clipboard]1300*1301* NOTE. In case isTrustedContext() no checking1302* are to be performed1303*/13041305/**1306* checks the security permissions for accessing system clipboard1307*1308* for untrusted context (see isTrustedContext) checks the1309* permissions for the current event being handled1310*1311*/1312public static boolean canAccessSystemClipboard() {1313boolean canAccess = false;1314if (!GraphicsEnvironment.isHeadless()) {1315SecurityManager sm = System.getSecurityManager();1316if (sm == null) {1317canAccess = true;1318} else {1319try {1320sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);1321canAccess = true;1322} catch (SecurityException e) {1323}1324if (canAccess && ! isTrustedContext()) {1325canAccess = canCurrentEventAccessSystemClipboard(true);1326}1327}1328}1329return canAccess;1330}1331/**1332* Returns true if EventQueue.getCurrentEvent() has the permissions to1333* access the system clipboard1334*/1335public static boolean canCurrentEventAccessSystemClipboard() {1336return isTrustedContext()1337|| canCurrentEventAccessSystemClipboard(false);1338}13391340/**1341* Returns true if the given event has permissions to access the1342* system clipboard1343*1344* @param e AWTEvent to check1345*/1346public static boolean canEventAccessSystemClipboard(AWTEvent e) {1347return isTrustedContext()1348|| canEventAccessSystemClipboard(e, false);1349}13501351/**1352* returns canAccessSystemClipboard field from InputEvent1353*1354* @param ie InputEvent to get the field from1355*/1356private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {1357if (inputEvent_CanAccessSystemClipboard_Field == null) {1358inputEvent_CanAccessSystemClipboard_Field =1359AccessController.doPrivileged(1360new java.security.PrivilegedAction<Field>() {1361public Field run() {1362try {1363Field field = InputEvent.class.1364getDeclaredField("canAccessSystemClipboard");1365field.setAccessible(true);1366return field;1367} catch (SecurityException e) {1368} catch (NoSuchFieldException e) {1369}1370return null;1371}1372});1373}1374if (inputEvent_CanAccessSystemClipboard_Field == null) {1375return false;1376}1377boolean ret = false;1378try {1379ret = inputEvent_CanAccessSystemClipboard_Field.1380getBoolean(ie);1381} catch(IllegalAccessException e) {1382}1383return ret;1384}13851386/**1387* Returns true if the given event is corrent gesture for1388* accessing clipboard1389*1390* @param ie InputEvent to check1391*/13921393private static boolean isAccessClipboardGesture(InputEvent ie) {1394boolean allowedGesture = false;1395if (ie instanceof KeyEvent) { //we can validate only keyboard gestures1396KeyEvent ke = (KeyEvent)ie;1397int keyCode = ke.getKeyCode();1398int keyModifiers = ke.getModifiers();1399switch(keyCode) {1400case KeyEvent.VK_C:1401case KeyEvent.VK_V:1402case KeyEvent.VK_X:1403allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);1404break;1405case KeyEvent.VK_INSERT:1406allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||1407keyModifiers == InputEvent.SHIFT_MASK);1408break;1409case KeyEvent.VK_COPY:1410case KeyEvent.VK_PASTE:1411case KeyEvent.VK_CUT:1412allowedGesture = true;1413break;1414case KeyEvent.VK_DELETE:1415allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);1416break;1417}1418}1419return allowedGesture;1420}14211422/**1423* Returns true if e has the permissions to1424* access the system clipboard and if it is allowed gesture (if1425* checkGesture is true)1426*1427* @param e AWTEvent to check1428* @param checkGesture boolean1429*/1430private static boolean canEventAccessSystemClipboard(AWTEvent e,1431boolean checkGesture) {1432if (EventQueue.isDispatchThread()) {1433/*1434* Checking event permissions makes sense only for event1435* dispathing thread1436*/1437if (e instanceof InputEvent1438&& (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {1439return inputEvent_canAccessSystemClipboard((InputEvent)e);1440} else {1441return false;1442}1443} else {1444return true;1445}1446}14471448/**1449* Utility method that throws SecurityException if SecurityManager is set1450* and modifiers are not public1451*1452* @param modifiers a set of modifiers1453*/1454public static void checkAccess(int modifiers) {1455if (System.getSecurityManager() != null1456&& !Modifier.isPublic(modifiers)) {1457throw new SecurityException("Resource is not accessible");1458}1459}14601461/**1462* Returns true if EventQueue.getCurrentEvent() has the permissions to1463* access the system clipboard and if it is allowed gesture (if1464* checkGesture true)1465*1466* @param checkGesture boolean1467*/1468private static boolean canCurrentEventAccessSystemClipboard(boolean1469checkGesture) {1470AWTEvent event = EventQueue.getCurrentEvent();1471return canEventAccessSystemClipboard(event, checkGesture);1472}14731474/**1475* see RFE 5012841 [Per AppContect security permissions] for the1476* details1477*1478*/1479private static boolean isTrustedContext() {1480return (System.getSecurityManager() == null)1481|| (AppContext.getAppContext().1482get(UntrustedClipboardAccess) == null);1483}14841485public static String displayPropertiesToCSS(Font font, Color fg) {1486StringBuffer rule = new StringBuffer("body {");1487if (font != null) {1488rule.append(" font-family: ");1489rule.append(font.getFamily());1490rule.append(" ; ");1491rule.append(" font-size: ");1492rule.append(font.getSize());1493rule.append("pt ;");1494if (font.isBold()) {1495rule.append(" font-weight: 700 ; ");1496}1497if (font.isItalic()) {1498rule.append(" font-style: italic ; ");1499}1500}1501if (fg != null) {1502rule.append(" color: #");1503if (fg.getRed() < 16) {1504rule.append('0');1505}1506rule.append(Integer.toHexString(fg.getRed()));1507if (fg.getGreen() < 16) {1508rule.append('0');1509}1510rule.append(Integer.toHexString(fg.getGreen()));1511if (fg.getBlue() < 16) {1512rule.append('0');1513}1514rule.append(Integer.toHexString(fg.getBlue()));1515rule.append(" ; ");1516}1517rule.append(" }");1518return rule.toString();1519}15201521/**1522* Utility method that creates a <code>UIDefaults.LazyValue</code> that1523* creates an <code>ImageIcon</code> <code>UIResource</code> for the1524* specified image file name. The image is loaded using1525* <code>getResourceAsStream</code>, starting with a call to that method1526* on the base class parameter. If it cannot be found, searching will1527* continue through the base class' inheritance hierarchy, up to and1528* including <code>rootClass</code>.1529*1530* @param baseClass the first class to use in searching for the resource1531* @param rootClass an ancestor of <code>baseClass</code> to finish the1532* search at1533* @param imageFile the name of the file to be found1534* @return a lazy value that creates the <code>ImageIcon</code>1535* <code>UIResource</code> for the image,1536* or null if it cannot be found1537*/1538public static Object makeIcon(final Class<?> baseClass,1539final Class<?> rootClass,1540final String imageFile) {15411542return new UIDefaults.LazyValue() {1543public Object createValue(UIDefaults table) {1544/* Copy resource into a byte array. This is1545* necessary because several browsers consider1546* Class.getResource a security risk because it1547* can be used to load additional classes.1548* Class.getResourceAsStream just returns raw1549* bytes, which we can convert to an image.1550*/1551byte[] buffer =1552java.security.AccessController.doPrivileged(1553new java.security.PrivilegedAction<byte[]>() {1554public byte[] run() {1555try {1556InputStream resource = null;1557Class<?> srchClass = baseClass;15581559while (srchClass != null) {1560resource = srchClass.getResourceAsStream(imageFile);15611562if (resource != null || srchClass == rootClass) {1563break;1564}15651566srchClass = srchClass.getSuperclass();1567}15681569if (resource == null) {1570return null;1571}15721573BufferedInputStream in =1574new BufferedInputStream(resource);1575ByteArrayOutputStream out =1576new ByteArrayOutputStream(1024);1577byte[] buffer = new byte[1024];1578int n;1579while ((n = in.read(buffer)) > 0) {1580out.write(buffer, 0, n);1581}1582in.close();1583out.flush();1584return out.toByteArray();1585} catch (IOException ioe) {1586System.err.println(ioe.toString());1587}1588return null;1589}1590});15911592if (buffer == null) {1593return null;1594}1595if (buffer.length == 0) {1596System.err.println("warning: " + imageFile +1597" is zero-length");1598return null;1599}16001601return new ImageIconUIResource(buffer);1602}1603};1604}16051606/* Used to help decide if AA text rendering should be used, so1607* this local display test should be additionally qualified1608* against whether we have XRender support on both ends of the wire,1609* as with that support remote performance may be good enough to turn1610* on by default. An additional complication there is XRender does not1611* appear capable of performing gamma correction needed for LCD text.1612*/1613public static boolean isLocalDisplay() {1614boolean isLocal;1615GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();1616if (ge instanceof SunGraphicsEnvironment) {1617isLocal = ((SunGraphicsEnvironment) ge).isDisplayLocal();1618} else {1619isLocal = true;1620}1621return isLocal;1622}16231624/**1625* Returns an integer from the defaults table. If <code>key</code> does1626* not map to a valid <code>Integer</code>, or can not be convered from1627* a <code>String</code> to an integer, the value 0 is returned.1628*1629* @param key an <code>Object</code> specifying the int.1630* @return the int1631*/1632public static int getUIDefaultsInt(Object key) {1633return getUIDefaultsInt(key, 0);1634}16351636/**1637* Returns an integer from the defaults table that is appropriate1638* for the given locale. If <code>key</code> does not map to a valid1639* <code>Integer</code>, or can not be convered from a <code>String</code>1640* to an integer, the value 0 is returned.1641*1642* @param key an <code>Object</code> specifying the int. Returned value1643* is 0 if <code>key</code> is not available,1644* @param l the <code>Locale</code> for which the int is desired1645* @return the int1646*/1647public static int getUIDefaultsInt(Object key, Locale l) {1648return getUIDefaultsInt(key, l, 0);1649}16501651/**1652* Returns an integer from the defaults table. If <code>key</code> does1653* not map to a valid <code>Integer</code>, or can not be convered from1654* a <code>String</code> to an integer, <code>default</code> is1655* returned.1656*1657* @param key an <code>Object</code> specifying the int. Returned value1658* is 0 if <code>key</code> is not available,1659* @param defaultValue Returned value if <code>key</code> is not available,1660* or is not an Integer1661* @return the int1662*/1663public static int getUIDefaultsInt(Object key, int defaultValue) {1664return getUIDefaultsInt(key, null, defaultValue);1665}16661667/**1668* Returns an integer from the defaults table that is appropriate1669* for the given locale. If <code>key</code> does not map to a valid1670* <code>Integer</code>, or can not be convered from a <code>String</code>1671* to an integer, <code>default</code> is returned.1672*1673* @param key an <code>Object</code> specifying the int. Returned value1674* is 0 if <code>key</code> is not available,1675* @param l the <code>Locale</code> for which the int is desired1676* @param defaultValue Returned value if <code>key</code> is not available,1677* or is not an Integer1678* @return the int1679*/1680public static int getUIDefaultsInt(Object key, Locale l, int defaultValue) {1681Object value = UIManager.get(key, l);16821683if (value instanceof Integer) {1684return ((Integer)value).intValue();1685}1686if (value instanceof String) {1687try {1688return Integer.parseInt((String)value);1689} catch (NumberFormatException nfe) {}1690}1691return defaultValue;1692}16931694// At this point we need this method here. But we assume that there1695// will be a common method for this purpose in the future releases.1696public static Component compositeRequestFocus(Component component) {1697if (component instanceof Container) {1698Container container = (Container)component;1699if (container.isFocusCycleRoot()) {1700FocusTraversalPolicy policy = container.getFocusTraversalPolicy();1701Component comp = policy.getDefaultComponent(container);1702if (comp!=null) {1703comp.requestFocus();1704return comp;1705}1706}1707Container rootAncestor = container.getFocusCycleRootAncestor();1708if (rootAncestor!=null) {1709FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();1710Component comp = policy.getComponentAfter(rootAncestor, container);17111712if (comp!=null && SwingUtilities.isDescendingFrom(comp, container)) {1713comp.requestFocus();1714return comp;1715}1716}1717}1718if (component.isFocusable()) {1719component.requestFocus();1720return component;1721}1722return null;1723}17241725/**1726* Change focus to the visible component in {@code JTabbedPane}.1727* This is not a general-purpose method and is here only to permit1728* sharing code.1729*/1730public static boolean tabbedPaneChangeFocusTo(Component comp) {1731if (comp != null) {1732if (comp.isFocusTraversable()) {1733SwingUtilities2.compositeRequestFocus(comp);1734return true;1735} else if (comp instanceof JComponent1736&& ((JComponent)comp).requestDefaultFocus()) {17371738return true;1739}1740}17411742return false;1743}17441745/**1746* Submits a value-returning task for execution on the EDT and1747* returns a Future representing the pending results of the task.1748*1749* @param task the task to submit1750* @return a Future representing pending completion of the task1751* @throws NullPointerException if the task is null1752*/1753public static <V> Future<V> submit(Callable<V> task) {1754if (task == null) {1755throw new NullPointerException();1756}1757FutureTask<V> future = new FutureTask<V>(task);1758execute(future);1759return future;1760}17611762/**1763* Submits a Runnable task for execution on the EDT and returns a1764* Future representing that task.1765*1766* @param task the task to submit1767* @param result the result to return upon successful completion1768* @return a Future representing pending completion of the task,1769* and whose <tt>get()</tt> method will return the given1770* result value upon completion1771* @throws NullPointerException if the task is null1772*/1773public static <V> Future<V> submit(Runnable task, V result) {1774if (task == null) {1775throw new NullPointerException();1776}1777FutureTask<V> future = new FutureTask<V>(task, result);1778execute(future);1779return future;1780}17811782/**1783* Sends a Runnable to the EDT for the execution.1784*/1785private static void execute(Runnable command) {1786SwingUtilities.invokeLater(command);1787}17881789/**1790* Sets the {@code SKIP_CLICK_COUNT} client property on the component1791* if it is an instance of {@code JTextComponent} with a1792* {@code DefaultCaret}. This property, used for text components acting1793* as editors in a table or tree, tells {@code DefaultCaret} how many1794* clicks to skip before starting selection.1795*/1796public static void setSkipClickCount(Component comp, int count) {1797if (comp instanceof JTextComponent1798&& ((JTextComponent) comp).getCaret() instanceof DefaultCaret) {17991800((JTextComponent) comp).putClientProperty(SKIP_CLICK_COUNT, count);1801}1802}18031804/**1805* Return the MouseEvent's click count, possibly reduced by the value of1806* the component's {@code SKIP_CLICK_COUNT} client property. Clears1807* the {@code SKIP_CLICK_COUNT} property if the mouse event's click count1808* is 1. In order for clearing of the property to work correctly, there1809* must be a mousePressed implementation on the caller with this1810* call as the first line.1811*/1812public static int getAdjustedClickCount(JTextComponent comp, MouseEvent e) {1813int cc = e.getClickCount();18141815if (cc == 1) {1816comp.putClientProperty(SKIP_CLICK_COUNT, null);1817} else {1818Integer sub = (Integer) comp.getClientProperty(SKIP_CLICK_COUNT);1819if (sub != null) {1820return cc - sub;1821}1822}18231824return cc;1825}18261827/**1828* Used by the {@code liesIn} method to return which section1829* the point lies in.1830*1831* @see #liesIn1832*/1833public enum Section {18341835/** The leading section */1836LEADING,18371838/** The middle section */1839MIDDLE,18401841/** The trailing section */1842TRAILING1843}18441845/**1846* This method divides a rectangle into two or three sections along1847* the specified axis and determines which section the given point1848* lies in on that axis; used by drag and drop when calculating drop1849* locations.1850* <p>1851* For two sections, the rectangle is divided equally and the method1852* returns whether the point lies in {@code Section.LEADING} or1853* {@code Section.TRAILING}. For horizontal divisions, the calculation1854* respects component orientation.1855* <p>1856* For three sections, if the rectangle is greater than or equal to1857* 30 pixels in length along the axis, the calculation gives 10 pixels1858* to each of the leading and trailing sections and the remainder to the1859* middle. For smaller sizes, the rectangle is divided equally into three1860* sections.1861* <p>1862* Note: This method assumes that the point is within the bounds of1863* the given rectangle on the specified axis. However, in cases where1864* it isn't, the results still have meaning: {@code Section.MIDDLE}1865* remains the same, {@code Section.LEADING} indicates that the point1866* is in or somewhere before the leading section, and1867* {@code Section.TRAILING} indicates that the point is in or somewhere1868* after the trailing section.1869*1870* @param rect the rectangle1871* @param p the point the check1872* @param horizontal {@code true} to use the horizontal axis,1873* or {@code false} for the vertical axis1874* @param ltr {@code true} for left to right orientation,1875* or {@code false} for right to left orientation;1876* only used for horizontal calculations1877* @param three {@code true} for three sections,1878* or {@code false} for two1879*1880* @return the {@code Section} where the point lies1881*1882* @throws NullPointerException if {@code rect} or {@code p} are1883* {@code null}1884*/1885private static Section liesIn(Rectangle rect, Point p, boolean horizontal,1886boolean ltr, boolean three) {18871888/* beginning of the rectangle on the axis */1889int p0;18901891/* point on the axis we're interested in */1892int pComp;18931894/* length of the rectangle on the axis */1895int length;18961897/* value of ltr if horizontal, else true */1898boolean forward;18991900if (horizontal) {1901p0 = rect.x;1902pComp = p.x;1903length = rect.width;1904forward = ltr;1905} else {1906p0 = rect.y;1907pComp = p.y;1908length = rect.height;1909forward = true;1910}19111912if (three) {1913int boundary = (length >= 30) ? 10 : length / 3;19141915if (pComp < p0 + boundary) {1916return forward ? Section.LEADING : Section.TRAILING;1917} else if (pComp >= p0 + length - boundary) {1918return forward ? Section.TRAILING : Section.LEADING;1919}19201921return Section.MIDDLE;1922} else {1923int middle = p0 + length / 2;1924if (forward) {1925return pComp >= middle ? Section.TRAILING : Section.LEADING;1926} else {1927return pComp < middle ? Section.TRAILING : Section.LEADING;1928}1929}1930}19311932/**1933* This method divides a rectangle into two or three sections along1934* the horizontal axis and determines which section the given point1935* lies in; used by drag and drop when calculating drop locations.1936* <p>1937* See the documentation for {@link #liesIn} for more information1938* on how the section is calculated.1939*1940* @param rect the rectangle1941* @param p the point the check1942* @param ltr {@code true} for left to right orientation,1943* or {@code false} for right to left orientation1944* @param three {@code true} for three sections,1945* or {@code false} for two1946*1947* @return the {@code Section} where the point lies1948*1949* @throws NullPointerException if {@code rect} or {@code p} are1950* {@code null}1951*/1952public static Section liesInHorizontal(Rectangle rect, Point p,1953boolean ltr, boolean three) {1954return liesIn(rect, p, true, ltr, three);1955}19561957/**1958* This method divides a rectangle into two or three sections along1959* the vertical axis and determines which section the given point1960* lies in; used by drag and drop when calculating drop locations.1961* <p>1962* See the documentation for {@link #liesIn} for more information1963* on how the section is calculated.1964*1965* @param rect the rectangle1966* @param p the point the check1967* @param three {@code true} for three sections,1968* or {@code false} for two1969*1970* @return the {@code Section} where the point lies1971*1972* @throws NullPointerException if {@code rect} or {@code p} are1973* {@code null}1974*/1975public static Section liesInVertical(Rectangle rect, Point p,1976boolean three) {1977return liesIn(rect, p, false, false, three);1978}19791980/**1981* Maps the index of the column in the view at1982* {@code viewColumnIndex} to the index of the column1983* in the table model. Returns the index of the corresponding1984* column in the model. If {@code viewColumnIndex}1985* is less than zero, returns {@code viewColumnIndex}.1986*1987* @param cm the table model1988* @param viewColumnIndex the index of the column in the view1989* @return the index of the corresponding column in the model1990*1991* @see JTable#convertColumnIndexToModel(int)1992* @see javax.swing.plaf.basic.BasicTableHeaderUI1993*/1994public static int convertColumnIndexToModel(TableColumnModel cm,1995int viewColumnIndex) {1996if (viewColumnIndex < 0) {1997return viewColumnIndex;1998}1999return cm.getColumn(viewColumnIndex).getModelIndex();2000}20012002/**2003* Maps the index of the column in the {@code cm} at2004* {@code modelColumnIndex} to the index of the column2005* in the view. Returns the index of the2006* corresponding column in the view; returns {@code -1} if this column2007* is not being displayed. If {@code modelColumnIndex} is less than zero,2008* returns {@code modelColumnIndex}.2009*2010* @param cm the table model2011* @param modelColumnIndex the index of the column in the model2012* @return the index of the corresponding column in the view2013*2014* @see JTable#convertColumnIndexToView(int)2015* @see javax.swing.plaf.basic.BasicTableHeaderUI2016*/2017public static int convertColumnIndexToView(TableColumnModel cm,2018int modelColumnIndex) {2019if (modelColumnIndex < 0) {2020return modelColumnIndex;2021}2022for (int column = 0; column < cm.getColumnCount(); column++) {2023if (cm.getColumn(column).getModelIndex() == modelColumnIndex) {2024return column;2025}2026}2027return -1;2028}20292030public static int getSystemMnemonicKeyMask() {2031Toolkit toolkit = Toolkit.getDefaultToolkit();2032if (toolkit instanceof SunToolkit) {2033return ((SunToolkit) toolkit).getFocusAcceleratorKeyMask();2034}2035return InputEvent.ALT_MASK;2036}20372038/**2039* Returns the {@link TreePath} that identifies the changed nodes.2040*2041* @param event changes in a tree model2042* @param model corresponing tree model2043* @return the path to the changed nodes2044*/2045public static TreePath getTreePath(TreeModelEvent event, TreeModel model) {2046TreePath path = event.getTreePath();2047if ((path == null) && (model != null)) {2048Object root = model.getRoot();2049if (root != null) {2050path = new TreePath(root);2051}2052}2053return path;2054}20552056/**2057* Used to listen to "blit" repaints in RepaintManager.2058*/2059public interface RepaintListener {2060void repaintPerformed(JComponent c, int x, int y, int w, int h);2061}2062}206320642065