/* * @(#)HiddenTagView.java 1.15 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing.text.html; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.MalformedURLException; import java.net.URL; import javax.swing.text.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; import java.util.*; /** * HiddenTagView subclasses EditableView to contain a JTextField showing * the element name. When the textfield is edited the element name is * reset. As this inherits from EditableView if the JTextComponent is * not editable, the textfield will not be visible. * * @author Scott Violet * @version 1.15, 12/19/03 */ class HiddenTagView extends EditableView implements DocumentListener { HiddenTagView(Element e) { super(e); yAlign = 1; } protected Component createComponent() { JTextField tf = new JTextField(getElement().getName()); Document doc = getDocument(); Font font; if (doc instanceof StyledDocument) { font = ((StyledDocument)doc).getFont(getAttributes()); tf.setFont(font); } else { font = tf.getFont(); } tf.getDocument().addDocumentListener(this); updateYAlign(font); // Create a panel to wrap the textfield so that the textfields // laf border shows through. JPanel panel = new JPanel(new BorderLayout()); panel.setBackground(null); if (isEndTag()) { panel.setBorder(EndBorder); } else { panel.setBorder(StartBorder); } panel.add(tf); return panel; } public float getAlignment(int axis) { if (axis == View.Y_AXIS) { return yAlign; } return 0.5f; } public float getMinimumSpan(int axis) { if (axis == View.X_AXIS && isVisible()) { // Default to preferred. return Math.max(30, super.getPreferredSpan(axis)); } return super.getMinimumSpan(axis); } public float getPreferredSpan(int axis) { if (axis == View.X_AXIS && isVisible()) { return Math.max(30, super.getPreferredSpan(axis)); } return super.getPreferredSpan(axis); } public float getMaximumSpan(int axis) { if (axis == View.X_AXIS && isVisible()) { // Default to preferred. return Math.max(30, super.getMaximumSpan(axis)); } return super.getMaximumSpan(axis); } // DocumentListener methods public void insertUpdate(DocumentEvent e) { updateModelFromText(); } public void removeUpdate(DocumentEvent e) { updateModelFromText(); } public void changedUpdate(DocumentEvent e) { updateModelFromText(); } // View method public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { if (!isSettingAttributes) { setTextFromModel(); } } // local methods void updateYAlign(Font font) { Container c = getContainer(); FontMetrics fm = (c != null) ? c.getFontMetrics(font) : Toolkit.getDefaultToolkit().getFontMetrics(font); float h = fm.getHeight(); float d = fm.getDescent(); yAlign = (h - d) / h; } void resetBorder() { Component comp = getComponent(); if (comp != null) { if (isEndTag()) { ((JPanel)comp).setBorder(EndBorder); } else { ((JPanel)comp).setBorder(StartBorder); } } } /** * This resets the text on the text component we created to match * that of the AttributeSet for the Element we represent. *
If this is invoked on the event dispatching thread, this
* directly invokes _setTextFromModel
, otherwise
* SwingUtilities.invokeLater
is used to schedule execution
* of _setTextFromModel
.
*/
void setTextFromModel() {
if (SwingUtilities.isEventDispatchThread()) {
_setTextFromModel();
}
else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_setTextFromModel();
}
});
}
}
/**
* This resets the text on the text component we created to match
* that of the AttributeSet for the Element we represent.
*/
void _setTextFromModel() {
Document doc = getDocument();
try {
isSettingAttributes = true;
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).readLock();
}
JTextComponent text = getTextComponent();
if (text != null) {
text.setText(getRepresentedText());
resetBorder();
Container host = getContainer();
if (host != null) {
preferenceChanged(this, true, true);
host.repaint();
}
}
}
finally {
isSettingAttributes = false;
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).readUnlock();
}
}
}
/**
* This copies the text from the text component we've created
* to the Element's AttributeSet we represent.
*
If this is invoked on the event dispatching thread, this
* directly invokes _updateModelFromText
, otherwise
* SwingUtilities.invokeLater
is used to schedule execution
* of _updateModelFromText
.
*/
void updateModelFromText() {
if (!isSettingAttributes) {
if (SwingUtilities.isEventDispatchThread()) {
_updateModelFromText();
}
else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_updateModelFromText();
}
});
}
}
}
/**
* This copies the text from the text component we've created
* to the Element's AttributeSet we represent.
*/
void _updateModelFromText() {
Document doc = getDocument();
Object name = getElement().getAttributes().getAttribute
(StyleConstants.NameAttribute);
if ((name instanceof HTML.UnknownTag) &&
(doc instanceof StyledDocument)) {
SimpleAttributeSet sas = new SimpleAttributeSet();
JTextComponent textComponent = getTextComponent();
if (textComponent != null) {
String text = textComponent.getText();
isSettingAttributes = true;
try {
sas.addAttribute(StyleConstants.NameAttribute,
new HTML.UnknownTag(text));
((StyledDocument)doc).setCharacterAttributes
(getStartOffset(), getEndOffset() -
getStartOffset(), sas, false);
}
finally {
isSettingAttributes = false;
}
}
}
}
JTextComponent getTextComponent() {
Component comp = getComponent();
return (comp == null) ? null : (JTextComponent)((Container)comp).
getComponent(0);
}
String getRepresentedText() {
String retValue = getElement().getName();
return (retValue == null) ? "" : retValue;
}
boolean isEndTag() {
AttributeSet as = getElement().getAttributes();
if (as != null) {
Object end = as.getAttribute(HTML.Attribute.ENDTAG);
if (end != null && (end instanceof String) &&
((String)end).equals("true")) {
return true;
}
}
return false;
}
/** Alignment along the y axis, based on the font of the textfield. */
float yAlign;
/** Set to true when setting attributes. */
boolean isSettingAttributes;
// Following are for Borders that used for Unknown tags and comments.
//
// Border defines
static final int circleR = 3;
static final int circleD = circleR * 2;
static final int tagSize = 6;
static final int padding = 3;
static final Color UnknownTagBorderColor = Color.black;
static final Border StartBorder = new StartTagBorder();
static final Border EndBorder = new EndTagBorder();
static class StartTagBorder implements Border, Serializable {
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
g.setColor(UnknownTagBorderColor);
x += padding;
width -= (padding * 2);
g.drawLine(x, y + circleR,
x, y + height - circleR);
g.drawArc(x, y + height - circleD - 1,
circleD, circleD, 180, 90);
g.drawArc(x, y, circleD, circleD, 90, 90);
g.drawLine(x + circleR, y, x + width - tagSize, y);
g.drawLine(x + circleR, y + height - 1,
x + width - tagSize, y + height - 1);
g.drawLine(x + width - tagSize, y,
x + width - 1, y + height / 2);
g.drawLine(x + width - tagSize, y + height,
x + width - 1, y + height / 2);
}
public Insets getBorderInsets(Component c) {
return new Insets(2, 2 + padding, 2, tagSize + 2 + padding);
}
public boolean isBorderOpaque() {
return false;
}
} // End of class HiddenTagView.StartTagBorder
static class EndTagBorder implements Border, Serializable {
public void paintBorder(Component c, Graphics g, int x, int y,
int width, int height) {
g.setColor(UnknownTagBorderColor);
x += padding;
width -= (padding * 2);
g.drawLine(x + width - 1, y + circleR,
x + width - 1, y + height - circleR);
g.drawArc(x + width - circleD - 1, y + height - circleD - 1,
circleD, circleD, 270, 90);
g.drawArc(x + width - circleD - 1, y, circleD, circleD, 0, 90);
g.drawLine(x + tagSize, y, x + width - circleR, y);
g.drawLine(x + tagSize, y + height - 1,
x + width - circleR, y + height - 1);
g.drawLine(x + tagSize, y,
x, y + height / 2);
g.drawLine(x + tagSize, y + height,
x, y + height / 2);
}
public Insets getBorderInsets(Component c) {
return new Insets(2, tagSize + 2 + padding, 2, 2 + padding);
}
public boolean isBorderOpaque() {
return false;
}
} // End of class HiddenTagView.EndTagBorder
} // End of HiddenTagView