History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/swing/SwingUtilities2.java (1 of 18352 files). Show all

Unified · Split

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