/* * @(#)SwingUtilities2.java 1.28 05/08/08 * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.java.swing; import java.security.*; import java.lang.reflect.*; import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.geom.*; import java.awt.print.PrinterGraphics; import java.text.AttributedCharacterIterator; import javax.swing.*; import javax.swing.plaf.*; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.DefaultHighlighter; import javax.swing.table.TableCellRenderer; import sun.swing.PrintColorUIResource; import sun.print.ProxyPrintGraphics; import sun.awt.AppContext; import sun.font.FontDesignMetrics; import sun.java2d.SunGraphics2D; import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; import java.io.*; /** * A collection of utility methods for Swing. *
* WARNING: While this class is public, it should not be treated as
* public API and its API may change in incompatable ways between dot dot
* releases and even patch releases. You should not rely on this class even
* existing.
*
* @version 1.28 08/08/05
*/
public class SwingUtilities2 {
// Maintain a cache of CACHE_SIZE fonts and the left side bearing
// of the characters falling into the range MIN_CHAR_INDEX to
// MAX_CHAR_INDEX. The values in fontCache are created as needed.
private static LSBCacheEntry[] fontCache;
// Windows defines 6 font desktop properties, we will therefore only
// cache the metrics for 6 fonts.
private static final int CACHE_SIZE = 6;
// nextIndex in fontCache to insert a font into.
private static int nextIndex;
// LSBCacheEntry used to search in fontCache to see if we already
// have an entry for a particular font
private static LSBCacheEntry searchKey;
// getLeftSideBearing will consult all characters that fall in the
// range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
private static final int MIN_CHAR_INDEX = (int)'W';
private static final int MAX_CHAR_INDEX = (int)'W' + 1;
private static final FontRenderContext DEFAULT_FRC = new FontRenderContext(
null, false, false);
/**
* FontRenderContext with antialiased turned on.
*/
public static final FontRenderContext AA_FRC;
//
// To determine if a JComponent should use AA text the following is
// used:
// 1. Is the system property 'swing.aatext' defined, return the value of
// the system property.
// 2. Use the JComponent client property AA_TEXT_PROPERTY_KEY. To
// avoid having this property persist between look and feels changes
// the value of this property is set to false in JComponent.setUI
//
/**
* Whether or not text is drawn anti-aliased. This is only used if
* AA_TEXT_DEFINED
is true.
*/
private static final boolean AA_TEXT;
/**
* Whether or not the system property 'swing.aatext' is defined.
*/
private static final boolean AA_TEXT_DEFINED;
/**
* Key used in client properties to indicate whether or not the component
* should use aa text.
*/
public static final Object AA_TEXT_PROPERTY_KEY =
new StringBuffer("AATextPropertyKey");
/**
* Whether or not the system proprety 'sun.swing.enableImprovedDragGesture'
* is defined, indicating that we should enable the fix for 4521075
* and start drag recognition on the first press without requiring a
* selection.
*/
public static final boolean DRAG_FIX;
// security stuff
private static Field inputEvent_CanAccessSystemClipboard_Field = null;
private static final String UntrustedClipboardAccess =
"UNTRUSTED_CLIPBOARD_ACCESS_KEY";
static {
fontCache = new LSBCacheEntry[CACHE_SIZE];
Object aa = java.security.AccessController.doPrivileged(
new GetPropertyAction("swing.aatext"));
AA_TEXT_DEFINED = (aa != null);
AA_TEXT = "true".equals(aa);
AA_FRC = new FontRenderContext(null, true, false);
Object dragFix = java.security.AccessController.doPrivileged(
new GetPropertyAction("sun.swing.enableImprovedDragGesture"));
DRAG_FIX = (dragFix != null);
}
//
// WARNING WARNING WARNING WARNING WARNING WARNING
// Many of the following methods are invoked from older API.
// As this older API was not passed a Component, a null Component may
// now be passsed in. For example, SwingUtilities.computeStringWidth
// is implemented to call SwingUtilities2.stringWidth, the
// SwingUtilities variant does not take a JComponent, as such
// SwingUtilities2.stringWidth can be passed a null Component.
// In other words, if you add new functionality to these methods you
// need to gracefully handle null.
//
/**
* Returns whether or not text should be drawn antialiased.
*
* @param c JComponent to test.
* @return Whether or not text should be drawn antialiased for the
* specified component.
*/
private static boolean drawTextAntialiased(JComponent c) {
if (!AA_TEXT_DEFINED) {
if (c != null) {
// Check if the component wants aa text
return ((Boolean)c.getClientProperty(
AA_TEXT_PROPERTY_KEY)).booleanValue();
}
// No component, assume aa is off
return false;
}
// 'swing.aatext' was defined, use its value.
return AA_TEXT;
}
/**
* Returns whether or not text should be drawn antialiased.
*
* @param aaText Whether or not aa text has been turned on for the
* component.
* @return Whether or not text should be drawn antialiased.
*/
public static boolean drawTextAntialiased(boolean aaText) {
if (!AA_TEXT_DEFINED) {
// 'swing.aatext' wasn't defined, use the components aa text value.
return aaText;
}
// 'swing.aatext' was defined, use its value.
return AA_TEXT;
}
/**
* Returns the left side bearing of the first character of string. The
* left side bearing is calculated from the passed in
* FontMetrics. If the passed in String is less than one
* character, this will throw a StringIndexOutOfBoundsException exception.
*
* @param c JComponent that will display the string
* @param fm FontMetrics used to measure the String width
* @param string String to get the left side bearing for.
*/
public static int getLeftSideBearing(JComponent c, FontMetrics fm,
String string) {
return getLeftSideBearing(c, fm, string.charAt(0));
}
/**
* Returns the left side bearing of the first character of string. The
* left side bearing is calculated from the passed in FontMetrics.
*
* @param c JComponent that will display the string
* @param fm FontMetrics used to measure the String width
* @param char Character to get the left side bearing for.
*/
public static int getLeftSideBearing(JComponent c, FontMetrics fm,
char firstChar) {
int charIndex = (int)firstChar;
if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {
byte[] lsbs = null;
FontRenderContext frc = getFRC(c, fm);
Font font = fm.getFont();
synchronized(SwingUtilities2.class) {
LSBCacheEntry entry = null;
if (searchKey == null) {
searchKey = new LSBCacheEntry(frc, font);
}
else {
searchKey.reset(frc, font);
}
// See if we already have an entry for this pair
for (LSBCacheEntry cacheEntry : fontCache) {
if (searchKey.equals(cacheEntry)) {
entry = cacheEntry;
break;
}
}
if (entry == null) {
// No entry for this pair, add it.
entry = searchKey;
fontCache[nextIndex] = searchKey;
searchKey = null;
nextIndex = (nextIndex + 1) % CACHE_SIZE;
}
return entry.getLeftSideBearing(firstChar);
}
}
return 0;
}
/**
* Returns the FontMetrics for the current Font of the passed
* in Graphics. This method is used when a Graphics
* is available, typically when painting. If a Graphics is not
* available the JComponent method of the same name should be used.
*
* Callers should pass in a non-null JComponent, the exception * to this is if a JComponent is not readily available at the time of * painting. *
* This does not necessarily return the FontMetrics from the * Graphics. * * @param c JComponent requesting FontMetrics, may be null * @param g Graphics Graphics */ public static FontMetrics getFontMetrics(JComponent c, Graphics g) { return getFontMetrics(c, g, g.getFont()); } /** * Returns the FontMetrics for the specified Font. * This method is used when a Graphics is available, typically when * painting. If a Graphics is not available the JComponent method of * the same name should be used. *
* Callers should pass in a non-null JComonent, the exception * to this is if a JComponent is not readily available at the time of * painting. *
* This does not necessarily return the FontMetrics from the
* Graphics.
*
* @param c JComponent requesting FontMetrics, may be null
* @param c Graphics Graphics
* @param font Font to get FontMetrics for
*/
public static FontMetrics getFontMetrics(JComponent c, Graphics g,
Font font) {
if (c != null) {
// Note: We assume that we're using the FontMetrics
// from the widget to layout out text, otherwise we can get
// mismatches when printing.
return c.getFontMetrics(font);
}
return Toolkit.getDefaultToolkit().getFontMetrics(font);
}
/**
* Returns the width of the passed in String.
*
* @param c JComponent that will display the string, may be null
* @param fm FontMetrics used to measure the String width
* @param string String to get the width of
*/
public static int stringWidth(JComponent c, FontMetrics fm, String string){
return fm.stringWidth(string);
}
/**
* Clips the passed in String to the space provided.
*
* @param c JComponent that will display the string, may be null
* @param fm FontMetrics used to measure the String width
* @param string String to display
* @param availTextWidth Amount of space that the string can be drawn in
* @return Clipped string that can fit in the provided space.
*/
public static String clipStringIfNecessary(JComponent c, FontMetrics fm,
String string,
int availTextWidth) {
if ((string == null) || (string.equals(""))) {
return "";
}
int textWidth = SwingUtilities2.stringWidth(c, fm, string);
if (textWidth > availTextWidth) {
return SwingUtilities2.clipString(c, fm, string, availTextWidth);
}
return string;
}
/**
* Clips the passed in String to the space provided. NOTE: this assumes
* the string does not fit in the available space.
*
* @param c JComponent that will display the string, may be null
* @param fm FontMetrics used to measure the String width
* @param string String to display
* @param availTextWidth Amount of space that the string can be drawn in
* @return Clipped string that can fit in the provided space.
*/
public static String clipString(JComponent c, FontMetrics fm,
String string, int availTextWidth) {
// c may be null here.
String clipString = "...";
int width = SwingUtilities2.stringWidth(c, fm, clipString);
// NOTE: This does NOT work for surrogate pairs and other fun
// stuff
int nChars = 0;
for(int max = string.length(); nChars < max; nChars++) {
width += fm.charWidth(string.charAt(nChars));
if (width > availTextWidth) {
break;
}
}
string = string.substring(0, nChars) + clipString;
return string;
}
/**
* Returns the FontRenderContext for the passed in FontMetrics or
* for the passed in JComponent if FontMetrics is null
*/
private static FontRenderContext getFRC(JComponent c, FontMetrics fm) {
// c may be null.
if (fm instanceof FontDesignMetrics) {
return ((FontDesignMetrics)fm).getFRC();
}
if (fm == null && c != null) {
//we do it this way because we need first case to
//work as fast as possible
return getFRC(c, c.getFontMetrics(c.getFont()));
}
// PENDING: This shouldn't really happen, but if it does we
// should try and handle AA as necessary.
assert false;
return DEFAULT_FRC;
}
/**
* Draws the string at the specified location.
*
* @param c JComponent that will display the string, may be null
* @param g Graphics to draw the text to
* @param text String to display
* @param x X coordinate to draw the text at
* @param y Y coordinate to draw the text at
*/
public static void drawString(JComponent c, Graphics g, String text,
int x, int y) {
// c may be null
// All non-editable widgets that draw strings call into this
// methods. By non-editable that means widgets like JLabel, JButton
// but NOT JTextComponents.
if ( text == null || text.length() <= 0 ) { //no need to paint empty strings
return;
}
if (isPrinting(g)) {
Graphics2D g2d = getGraphics2D(g);
if (g2d != null) {
TextLayout layout = new TextLayout(text, g2d.getFont(),
DEFAULT_FRC);
/* Use alternate print color if specified */
Color col = g2d.getColor();
if (col instanceof PrintColorUIResource) {
g2d.setColor(((PrintColorUIResource)col).getPrintColor());
}
layout.draw(g2d, x, y);
g2d.setColor(col);
return;
}
}
// If we get here we're not printing
if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
Graphics2D g2 = (Graphics2D)g;
Object oldAAValue = g2.getRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString(text, x, y);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
oldAAValue);
}
else {
g.drawString(text, x, y);
}
}
/**
* Draws the string at the specified location underlining the specified
* character.
*
* @param c JComponent that will display the string, may be null
* @param g Graphics to draw the text to
* @param text String to display
* @param underlinedIndex Index of a character in the string to underline
* @param x X coordinate to draw the text at
* @param y Y coordinate to draw the text at
*/
public static void drawStringUnderlineCharAt(JComponent c,Graphics g,
String text, int underlinedIndex, int x,int y) {
SwingUtilities2.drawString(c, g, text, x, y);
if (underlinedIndex >= 0 && underlinedIndex < text.length() ) {
// PENDING: this needs to change.
FontMetrics fm = g.getFontMetrics();
int underlineRectX = x + SwingUtilities2.stringWidth(c,
fm, text.substring(0,underlinedIndex));
int underlineRectY = y;
int underlineRectWidth = fm.charWidth(text.
charAt(underlinedIndex));
int underlineRectHeight = 1;
g.fillRect(underlineRectX, underlineRectY + 1,
underlineRectWidth, underlineRectHeight);
}
}
/**
* A variation of locationToIndex() which only returns an index if the
* Point is within the actual bounds of a list item (not just in the cell)
* and if the JList has the "List.isFileList" client property set.
* Otherwise, this method returns -1.
* This is used to make WindowsL&F JFileChooser act like native dialogs.
*/
public static int loc2IndexFileList(JList list, Point point) {
int index = list.locationToIndex(point);
if (index != -1) {
Object bySize = list.getClientProperty("List.isFileList");
if (bySize instanceof Boolean && ((Boolean)bySize).booleanValue() &&
!pointIsInActualBounds(list, index, point)) {
index = -1;
}
}
return index;
}
/**
* Returns true if the given point is within the actual bounds of the
* JList item at index (not just inside the cell).
*/
private static boolean pointIsInActualBounds(JList list, int index,
Point point) {
ListCellRenderer renderer = list.getCellRenderer();
ListModel dataModel = list.getModel();
Object value = dataModel.getElementAt(index);
Component item = renderer.getListCellRendererComponent(list,
value, index, false, false);
Dimension itemSize = item.getPreferredSize();
Rectangle cellBounds = list.getCellBounds(index, index);
if (!item.getComponentOrientation().isLeftToRight()) {
cellBounds.x += (cellBounds.width - itemSize.width);
}
cellBounds.width = itemSize.width;
cellBounds.height = itemSize.height;
return cellBounds.contains(point);
}
/**
* Returns true if the given point is outside the preferredSize of the
* item at the given row of the table. (Column must be 0).
* Does not check the "Table.isFileList" property. That should be checked
* before calling this method.
* This is used to make WindowsL&F JFileChooser act like native dialogs.
*/
public static boolean pointOutsidePrefSize(JTable table, int row, int column, Point p) {
if (table.convertColumnIndexToModel(column) != 0 || row == -1) {
return true;
}
TableCellRenderer tcr = table.getCellRenderer(row, column);
Object value = table.getValueAt(row, column);
Component cell = tcr.getTableCellRendererComponent(table, value, false,
false, row, column);
Dimension itemSize = cell.getPreferredSize();
Rectangle cellBounds = table.getCellRect(row, column, false);
cellBounds.width = itemSize.width;
cellBounds.height = itemSize.height;
// See if coords are inside
// ASSUME: mouse x,y will never be < cell's x,y
assert (p.x >= cellBounds.x && p.y >= cellBounds.y);
if (p.x > cellBounds.x + cellBounds.width ||
p.y > cellBounds.y + cellBounds.height) {
return true;
}
return false;
}
/**
* Ignore mouse events if the component is null, not enabled, or the event
* is not associated with the left mouse button.
*/
public static boolean shouldIgnore(MouseEvent me, JComponent c) {
return c == null || !c.isEnabled()
|| !SwingUtilities.isLeftMouseButton(me);
}
/**
* Request focus on the given component if it doesn't already have it
* and isRequestFocusEnabled()
returns true.
*/
public static void adjustFocus(JComponent c) {
if (!c.hasFocus() && c.isRequestFocusEnabled()) {
c.requestFocus();
}
}
/**
* The following draw functions have the same semantic as the
* Graphics methods with the same names.
*
* this is used for printing
*/
public static int drawChars(JComponent c, Graphics g,
char[] data,
int offset,
int length,
int x,
int y) {
if ( length <= 0 ) { //no need to paint empty strings
return x;
}
int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
if (isPrinting(g)) {
Graphics2D g2d = getGraphics2D(g);
if (g2d != null) {
FontRenderContext deviceFontRenderContext = g2d.
getFontRenderContext();
FontRenderContext frc = getFRC(c, null);
if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
frc = new FontRenderContext(frc.getTransform(), false, false);
}
if (frc != null
&& ! isFontRenderContextCompatible(deviceFontRenderContext,
frc)) {
TextLayout layout =
new TextLayout(new String(data,offset,length),
g2d.getFont(),
frc);
/* Use alternate print color if specified */
Color col = g2d.getColor();
if (col instanceof PrintColorUIResource) {
g2d.setColor(((PrintColorUIResource)col).getPrintColor());
}
layout.draw(g2d,x,y);
g2d.setColor(col);
return nextX;
}
}
}
// Assume we're not printing if we get here.
if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
Graphics2D g2 = (Graphics2D)g;
Object oldAAValue = g2.getRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawChars(data, offset, length, x, y);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
oldAAValue);
}
else {
g.drawChars(data, offset, length, x, y);
}
return nextX;
}
/*
* see documentation for drawChars
* returns the advance
*/
public static float drawString(JComponent c, Graphics g,
AttributedCharacterIterator iterator,
int x,
int y) {
float retVal;
boolean isPrinting = isPrinting(g);
Color col = g.getColor();
if (isPrinting) {
/* Use alternate print color if specified */
if (col instanceof PrintColorUIResource) {
g.setColor(((PrintColorUIResource)col).getPrintColor());
}
}
Graphics2D g2d = getGraphics2D(g);
if (g2d == null) {
g.drawString(iterator,x,y); //for the cases where advance
//matters it should not happen
retVal = x;
} else {
FontRenderContext frc;
if (isPrinting) {
frc = getFRC(c, null);
if (frc.isAntiAliased() || frc.usesFractionalMetrics()) {
frc = new FontRenderContext(frc.getTransform(), false, false);
}
} else if (drawTextAntialiased(c)) {
frc = AA_FRC;
} else {
frc = g2d.getFontRenderContext();
}
TextLayout layout = new TextLayout(iterator, frc);
layout.draw(g2d, x, y);
retVal = layout.getAdvance();
}
if (isPrinting) {
g.setColor(col);
}
return retVal;
}
/*
* Checks if two given FontRenderContexts are compatible.
* Compatible means no special handling needed for text painting
*/
public static boolean isFontRenderContextCompatible(FontRenderContext frc1,
FontRenderContext frc2) {
return (frc1 != null) ? frc1.equals(frc2) : frc2 == null;
}
/*
* Tries it best to get Graphics2D out of the given Graphics
* returns null if can not derive it.
*/
public static Graphics2D getGraphics2D(Graphics g) {
if (g instanceof Graphics2D) {
return (Graphics2D) g;
} else if (g instanceof ProxyPrintGraphics) {
return (Graphics2D)(((ProxyPrintGraphics)g).getGraphics());
} else {
return null;
}
}
/*
* Returns FontRendedrContext associated with JComponent
* see JComponent.getFontMetrics
*/
public static FontRenderContext getFontRenderContext(Component c) {
if (c == null) {
return DEFAULT_FRC;
} else {
return getFRC(null, c.getFontMetrics(c.getFont()));
}
}
/*
* returns true if the Graphics is print Graphics
* false otherwise
*/
static boolean isPrinting(Graphics g) {
return (g instanceof PrinterGraphics || g instanceof PrintGraphics);
}
/**
* Determines whether the SelectedTextColor should be used for painting text
* foreground for the specified highlight.
*
* Returns true only if the highlight painter for the specified highlight
* is the swing painter (whether inner class of javax.swing.text.DefaultHighlighter
* or com.sun.java.swing.plaf.windows.WindowsTextUI) and its background color
* is null or equals to the selection color of the text component.
*
* This is a hack for fixing both bugs 4761990 and 5003294
*/
public static boolean useSelectedTextColor(Highlighter.Highlight h, JTextComponent c) {
Highlighter.HighlightPainter painter = h.getPainter();
String painterClass = painter.getClass().getName();
if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
return false;
}
try {
DefaultHighlighter.DefaultHighlightPainter defPainter =
(DefaultHighlighter.DefaultHighlightPainter) painter;
if (defPainter.getColor() != null &&
!defPainter.getColor().equals(c.getSelectionColor())) {
return false;
}
} catch (ClassCastException e) {
return false;
}
return true;
}
/**
* LSBCacheEntry is used to cache the left side bearing (lsb) for
* a particular Font
and FontRenderContext
.
* This only caches characters that fall in the range
* MIN_CHAR_INDEX
to MAX_CHAR_INDEX
.
*/
private static class LSBCacheEntry {
// Used to indicate a particular entry in lsb has not been set.
private static final byte UNSET = Byte.MAX_VALUE;
// Used in creating a GlyphVector to get the lsb
private static final char[] oneChar = new char[1];
private byte[] lsbCache;
private Font font;
private FontRenderContext frc;
public LSBCacheEntry(FontRenderContext frc, Font font) {
lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
reset(frc, font);
}
public void reset(FontRenderContext frc, Font font) {
this.font = font;
this.frc = frc;
for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
lsbCache[counter] = UNSET;
}
}
public int getLeftSideBearing(char aChar) {
int index = aChar - MIN_CHAR_INDEX;
assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
byte lsb = lsbCache[index];
if (lsb == UNSET) {
oneChar[0] = aChar;
GlyphVector gv = font.createGlyphVector(frc, oneChar);
lsb = (byte)gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
lsbCache[index] = lsb;
}
return lsb;
}
public boolean equals(Object entry) {
if (entry == this) {
return true;
}
if (!(entry instanceof LSBCacheEntry)) {
return false;
}
LSBCacheEntry oEntry = (LSBCacheEntry)entry;
return (font.equals(oEntry.font) &&
frc.equals(oEntry.frc));
}
public int hashCode() {
int result = 17;
if (font != null) {
result = 37 * result + font.hashCode();
}
if (frc != null) {
result = 37 * result + frc.hashCode();
}
return result;
}
}
/*
* here goes the fix for 4856343 [Problem with applet interaction
* with system selection clipboard]
*
* NOTE. In case isTrustedContext() no checking
* are to be performed
*/
/**
* checks the security permissions for accessing system clipboard
*
* for untrusted context (see isTrustedContext) checks the
* permissions for the current event being handled
*
*/
public static boolean canAccessSystemClipboard() {
boolean canAccess = false;
if (!GraphicsEnvironment.isHeadless()) {
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
canAccess = true;
} else {
try {
sm.checkSystemClipboardAccess();
canAccess = true;
} catch (SecurityException e) {
}
if (canAccess && ! isTrustedContext()) {
canAccess = canCurrentEventAccessSystemClipboard(true);
}
}
}
return canAccess;
}
/**
* Returns true if EventQueue.getCurrentEvent() has the permissions to
* access the system clipboard
*/
public static boolean canCurrentEventAccessSystemClipboard() {
return isTrustedContext()
|| canCurrentEventAccessSystemClipboard(false);
}
/**
* Returns true if the given event has permissions to access the
* system clipboard
*
* @param e AWTEvent to check
*/
public static boolean canEventAccessSystemClipboard(AWTEvent e) {
return isTrustedContext()
|| canEventAccessSystemClipboard(e, false);
}
/**
* returns canAccessSystemClipboard field from InputEvent
*
* @param ie InputEvent to get the field from
*/
private static synchronized boolean inputEvent_canAccessSystemClipboard(InputEvent ie) {
if (inputEvent_CanAccessSystemClipboard_Field == null) {
inputEvent_CanAccessSystemClipboard_Field =
(Field)AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
Field field = null;
try {
field = InputEvent.class.
getDeclaredField("canAccessSystemClipboard");
field.setAccessible(true);
return field;
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
}
return null;
}
});
}
if (inputEvent_CanAccessSystemClipboard_Field == null) {
return false;
}
boolean ret = false;
try {
ret = inputEvent_CanAccessSystemClipboard_Field.
getBoolean(ie);
} catch(IllegalAccessException e) {
}
return ret;
}
/**
* Returns true if the given event is corrent gesture for
* accessing clipboard
*
* @param ie InputEvent to check
*/
private static boolean isAccessClipboardGesture(InputEvent ie) {
boolean allowedGesture = false;
if (ie instanceof KeyEvent) { //we can validate only keyboard gestures
KeyEvent ke = (KeyEvent)ie;
int keyCode = ke.getKeyCode();
int keyModifiers = ke.getModifiers();
switch(keyCode) {
case KeyEvent.VK_C:
case KeyEvent.VK_V:
case KeyEvent.VK_X:
allowedGesture = (keyModifiers == InputEvent.CTRL_MASK);
break;
case KeyEvent.VK_INSERT:
allowedGesture = (keyModifiers == InputEvent.CTRL_MASK ||
keyModifiers == InputEvent.SHIFT_MASK);
break;
case KeyEvent.VK_COPY:
case KeyEvent.VK_PASTE:
case KeyEvent.VK_CUT:
allowedGesture = true;
break;
case KeyEvent.VK_DELETE:
allowedGesture = ( keyModifiers == InputEvent.SHIFT_MASK);
break;
}
}
return allowedGesture;
}
/**
* Returns true if e has the permissions to
* access the system clipboard and if it is allowed gesture (if
* checkGesture is true)
*
* @param e AWTEvent to check
* @param checkGesture boolean
*/
private static boolean canEventAccessSystemClipboard(AWTEvent e,
boolean checkGesture) {
if (EventQueue.isDispatchThread()) {
/*
* Checking event permissions makes sense only for event
* dispathing thread
*/
if (e instanceof InputEvent
&& (! checkGesture || isAccessClipboardGesture((InputEvent)e))) {
return inputEvent_canAccessSystemClipboard((InputEvent)e);
} else {
return false;
}
} else {
return true;
}
}
/**
* Returns true if EventQueue.getCurrentEvent() has the permissions to
* access the system clipboard and if it is allowed gesture (if
* checkGesture true)
*
* @param checkGesture boolean
*/
private static boolean canCurrentEventAccessSystemClipboard(boolean
checkGesture) {
AWTEvent event = EventQueue.getCurrentEvent();
return canEventAccessSystemClipboard(event, checkGesture);
}
/**
* see RFE 5012841 [Per AppContect security permissions] for the
* details
*
*/
private static boolean isTrustedContext() {
return (System.getSecurityManager() == null)
|| (AppContext.getAppContext().
get(UntrustedClipboardAccess) == null);
}
public static String displayPropertiesToCSS(Font font, Color fg) {
StringBuffer rule = new StringBuffer("body {");
if (font != null) {
rule.append(" font-family: ");
rule.append(font.getFamily());
rule.append(" ; ");
rule.append(" font-size: ");
rule.append(font.getSize());
rule.append("pt ;");
if (font.isBold()) {
rule.append(" font-weight: 700 ; ");
}
if (font.isItalic()) {
rule.append(" font-style: italic ; ");
}
}
if (fg != null) {
rule.append(" color: #");
if (fg.getRed() < 16) {
rule.append('0');
}
rule.append(Integer.toHexString(fg.getRed()));
if (fg.getGreen() < 16) {
rule.append('0');
}
rule.append(Integer.toHexString(fg.getGreen()));
if (fg.getBlue() < 16) {
rule.append('0');
}
rule.append(Integer.toHexString(fg.getBlue()));
rule.append(" ; ");
}
rule.append(" }");
return rule.toString();
}
/**
* Utility method that creates a UIDefaults.LazyValue
that
* creates an ImageIcon
UIResource
for the
* specified image file name. The image is loaded using
* getResourceAsStream
, starting with a call to that method
* on the base class parameter. If it cannot be found, searching will
* continue through the base class' inheritance hierarchy, up to and
* including rootClass
.
*
* @param baseClass the first class to use in searching for the resource
* @param rootClass an ancestor of baseClass
to finish the
* search at
* @param imageFile the name of the file to be found
* @return a lazy value that creates the ImageIcon
* UIResource
for the image,
* or null if it cannot be found
*/
public static Object makeIcon(final Class> baseClass,
final Class> rootClass,
final String imageFile) {
return new UIDefaults.LazyValue() {
public Object createValue(UIDefaults table) {
/* Copy resource into a byte array. This is
* necessary because several browsers consider
* Class.getResource a security risk because it
* can be used to load additional classes.
* Class.getResourceAsStream just returns raw
* bytes, which we can convert to an image.
*/
byte[] buffer = (byte[])
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
try {
InputStream resource = null;
Class> srchClass = baseClass;
while (srchClass != null) {
resource = srchClass.getResourceAsStream(imageFile);
if (resource != null || srchClass == rootClass) {
break;
}
srchClass = srchClass.getSuperclass();
}
if (resource == null) {
return null;
}
BufferedInputStream in =
new BufferedInputStream(resource);
ByteArrayOutputStream out =
new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
in.close();
out.flush();
return out.toByteArray();
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
return null;
}
});
if (buffer == null) {
return null;
}
if (buffer.length == 0) {
System.err.println("warning: " + imageFile +
" is zero-length");
return null;
}
return new IconUIResource(new ImageIcon(buffer));
}
};
}
}