6557223: Resize cursor stays after fast outline-resize of JInternalFrame with JScrollPane
Reviewed-by: peterz
/*
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package javax.swing.plaf.basic;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.net.URL;
import java.net.MalformedURLException;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.plaf.*;
import javax.swing.border.*;
/**
* Provides the look and feel for a JEditorPane.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans<sup><font size="-2">TM</font></sup>
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Timothy Prinzing
*/
public class BasicEditorPaneUI extends BasicTextUI {
/**
* Creates a UI for the JTextPane.
*
* @param c the JTextPane component
* @return the UI
*/
public static ComponentUI createUI(JComponent c) {
return new BasicEditorPaneUI();
}
/**
* Creates a new BasicEditorPaneUI.
*/
public BasicEditorPaneUI() {
super();
}
/**
* Fetches the name used as a key to lookup properties through the
* UIManager. This is used as a prefix to all the standard
* text properties.
*
* @return the name ("EditorPane")
*/
protected String getPropertyPrefix() {
return "EditorPane";
}
/**
*{@inheritDoc}
*
* @since 1.5
*/
public void installUI(JComponent c) {
super.installUI(c);
updateDisplayProperties(c.getFont(),
c.getForeground());
}
/**
*{@inheritDoc}
*
* @since 1.5
*/
public void uninstallUI(JComponent c) {
cleanDisplayProperties();
super.uninstallUI(c);
}
/**
* Fetches the EditorKit for the UI. This is whatever is
* currently set in the associated JEditorPane.
*
* @return the editor capabilities
* @see TextUI#getEditorKit
*/
public EditorKit getEditorKit(JTextComponent tc) {
JEditorPane pane = (JEditorPane) getComponent();
return pane.getEditorKit();
}
/**
* Fetch an action map to use. The map for a JEditorPane
* is not shared because it changes with the EditorKit.
*/
ActionMap getActionMap() {
ActionMap am = new ActionMapUIResource();
am.put("requestFocus", new FocusAction());
EditorKit editorKit = getEditorKit(getComponent());
if (editorKit != null) {
Action[] actions = editorKit.getActions();
if (actions != null) {
addActions(am, actions);
}
}
am.put(TransferHandler.getCutAction().getValue(Action.NAME),
TransferHandler.getCutAction());
am.put(TransferHandler.getCopyAction().getValue(Action.NAME),
TransferHandler.getCopyAction());
am.put(TransferHandler.getPasteAction().getValue(Action.NAME),
TransferHandler.getPasteAction());
return am;
}
/**
* This method gets called when a bound property is changed
* on the associated JTextComponent. This is a hook
* which UI implementations may change to reflect how the
* UI displays bound properties of JTextComponent subclasses.
* This is implemented to rebuild the ActionMap based upon an
* EditorKit change.
*
* @param evt the property change event
*/
protected void propertyChange(PropertyChangeEvent evt) {
super.propertyChange(evt);
String name = evt.getPropertyName();
if ("editorKit".equals(name)) {
ActionMap map = SwingUtilities.getUIActionMap(getComponent());
if (map != null) {
Object oldValue = evt.getOldValue();
if (oldValue instanceof EditorKit) {
Action[] actions = ((EditorKit)oldValue).getActions();
if (actions != null) {
removeActions(map, actions);
}
}
Object newValue = evt.getNewValue();
if (newValue instanceof EditorKit) {
Action[] actions = ((EditorKit)newValue).getActions();
if (actions != null) {
addActions(map, actions);
}
}
}
updateFocusTraversalKeys();
} else if ("editable".equals(name)) {
updateFocusTraversalKeys();
} else if ("foreground".equals(name)
|| "font".equals(name)
|| "document".equals(name)
|| JEditorPane.W3C_LENGTH_UNITS.equals(name)
|| JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name)
) {
JComponent c = getComponent();
updateDisplayProperties(c.getFont(), c.getForeground());
if ( JEditorPane.W3C_LENGTH_UNITS.equals(name)
|| JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name) ) {
modelChanged();
}
if ("foreground".equals(name)) {
Object honorDisplayPropertiesObject = c.
getClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES);
boolean honorDisplayProperties = false;
if (honorDisplayPropertiesObject instanceof Boolean) {
honorDisplayProperties =
((Boolean)honorDisplayPropertiesObject).booleanValue();
}
if (honorDisplayProperties) {
modelChanged();
}
}
}
}
void removeActions(ActionMap map, Action[] actions) {
int n = actions.length;
for (int i = 0; i < n; i++) {
Action a = actions[i];
map.remove(a.getValue(Action.NAME));
}
}
void addActions(ActionMap map, Action[] actions) {
int n = actions.length;
for (int i = 0; i < n; i++) {
Action a = actions[i];
map.put(a.getValue(Action.NAME), a);
}
}
void updateDisplayProperties(Font font, Color fg) {
JComponent c = getComponent();
Object honorDisplayPropertiesObject = c.
getClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES);
boolean honorDisplayProperties = false;
Object w3cLengthUnitsObject = c.getClientProperty(JEditorPane.
W3C_LENGTH_UNITS);
boolean w3cLengthUnits = false;
if (honorDisplayPropertiesObject instanceof Boolean) {
honorDisplayProperties =
((Boolean)honorDisplayPropertiesObject).booleanValue();
}
if (w3cLengthUnitsObject instanceof Boolean) {
w3cLengthUnits = ((Boolean)w3cLengthUnitsObject).booleanValue();
}
if (this instanceof BasicTextPaneUI
|| honorDisplayProperties) {
//using equals because can not use UIResource for Boolean
Document doc = getComponent().getDocument();
if (doc instanceof StyledDocument) {
if (doc instanceof HTMLDocument
&& honorDisplayProperties) {
updateCSS(font, fg);
} else {
updateStyle(font, fg);
}
}
} else {
cleanDisplayProperties();
}
if ( w3cLengthUnits ) {
Document doc = getComponent().getDocument();
if (doc instanceof HTMLDocument) {
StyleSheet documentStyleSheet =
((HTMLDocument)doc).getStyleSheet();
documentStyleSheet.addRule("W3C_LENGTH_UNITS_ENABLE");
}
} else {
Document doc = getComponent().getDocument();
if (doc instanceof HTMLDocument) {
StyleSheet documentStyleSheet =
((HTMLDocument)doc).getStyleSheet();
documentStyleSheet.addRule("W3C_LENGTH_UNITS_DISABLE");
}
}
}
/**
* Attribute key to reference the default font.
* used in javax.swing.text.StyleContext.getFont
* to resolve the default font.
*/
private static final String FONT_ATTRIBUTE_KEY = "FONT_ATTRIBUTE_KEY";
void cleanDisplayProperties() {
Document document = getComponent().getDocument();
if (document instanceof HTMLDocument) {
StyleSheet documentStyleSheet =
((HTMLDocument)document).getStyleSheet();
StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets();
if (styleSheets != null) {
for (StyleSheet s : styleSheets) {
if (s instanceof StyleSheetUIResource) {
documentStyleSheet.removeStyleSheet(s);
documentStyleSheet.addRule("BASE_SIZE_DISABLE");
break;
}
}
}
Style style = ((StyledDocument) document).getStyle(StyleContext.DEFAULT_STYLE);
if (style.getAttribute(FONT_ATTRIBUTE_KEY) != null) {
style.removeAttribute(FONT_ATTRIBUTE_KEY);
}
}
}
static class StyleSheetUIResource extends StyleSheet implements UIResource {
}
private void updateCSS(Font font, Color fg) {
JTextComponent component = getComponent();
Document document = component.getDocument();
if (document instanceof HTMLDocument) {
StyleSheet styleSheet = new StyleSheetUIResource();
StyleSheet documentStyleSheet =
((HTMLDocument)document).getStyleSheet();
StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets();
if (styleSheets != null) {
for (StyleSheet s : styleSheets) {
if (s instanceof StyleSheetUIResource) {
documentStyleSheet.removeStyleSheet(s);
}
}
}
String cssRule = sun.swing.
SwingUtilities2.displayPropertiesToCSS(font,
fg);
styleSheet.addRule(cssRule);
documentStyleSheet.addStyleSheet(styleSheet);
documentStyleSheet.addRule("BASE_SIZE " +
component.getFont().getSize());
Style style = ((StyledDocument) document).getStyle(StyleContext.DEFAULT_STYLE);
if (! font.equals(style.getAttribute(FONT_ATTRIBUTE_KEY))) {
style.addAttribute(FONT_ATTRIBUTE_KEY, font);
}
}
}
private void updateStyle(Font font, Color fg) {
updateFont(font);
updateForeground(fg);
}
/**
* Update the color in the default style of the document.
*
* @param color the new color to use or null to remove the color attribute
* from the document's style
*/
private void updateForeground(Color color) {
StyledDocument doc = (StyledDocument)getComponent().getDocument();
Style style = doc.getStyle(StyleContext.DEFAULT_STYLE);
if (style == null) {
return;
}
if (color == null) {
if (style.getAttribute(StyleConstants.Foreground) != null) {
style.removeAttribute(StyleConstants.Foreground);
}
} else {
if (! color.equals(StyleConstants.getForeground(style))) {
StyleConstants.setForeground(style, color);
}
}
}
/**
* Update the font in the default style of the document.
*
* @param font the new font to use or null to remove the font attribute
* from the document's style
*/
private void updateFont(Font font) {
StyledDocument doc = (StyledDocument)getComponent().getDocument();
Style style = doc.getStyle(StyleContext.DEFAULT_STYLE);
if (style == null) {
return;
}
String fontFamily = (String) style.getAttribute(StyleConstants.FontFamily);
Integer fontSize = (Integer) style.getAttribute(StyleConstants.FontSize);
Boolean isBold = (Boolean) style.getAttribute(StyleConstants.Bold);
Boolean isItalic = (Boolean) style.getAttribute(StyleConstants.Italic);
Font fontAttribute = (Font) style.getAttribute(FONT_ATTRIBUTE_KEY);
if (font == null) {
if (fontFamily != null) {
style.removeAttribute(StyleConstants.FontFamily);
}
if (fontSize != null) {
style.removeAttribute(StyleConstants.FontSize);
}
if (isBold != null) {
style.removeAttribute(StyleConstants.Bold);
}
if (isItalic != null) {
style.removeAttribute(StyleConstants.Italic);
}
if (fontAttribute != null) {
style.removeAttribute(FONT_ATTRIBUTE_KEY);
}
} else {
if (! font.getName().equals(fontFamily)) {
StyleConstants.setFontFamily(style, font.getName());
}
if (fontSize == null
|| fontSize.intValue() != font.getSize()) {
StyleConstants.setFontSize(style, font.getSize());
}
if (isBold == null
|| isBold.booleanValue() != font.isBold()) {
StyleConstants.setBold(style, font.isBold());
}
if (isItalic == null
|| isItalic.booleanValue() != font.isItalic()) {
StyleConstants.setItalic(style, font.isItalic());
}
if (! font.equals(fontAttribute)) {
style.addAttribute(FONT_ATTRIBUTE_KEY, font);
}
}
}
}