1. /*
  2. * @(#)HiddenTagView.java 1.12 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text.html;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.io.*;
  11. import java.net.MalformedURLException;
  12. import java.net.URL;
  13. import javax.swing.text.*;
  14. import javax.swing.*;
  15. import javax.swing.border.*;
  16. import javax.swing.event.*;
  17. import java.util.*;
  18. /**
  19. * HiddenTagView subclasses EditableView to contain a JTextField showing
  20. * the element name. When the textfield is edited the element name is
  21. * reset. As this inherits from EditableView if the JTextComponent is
  22. * not editable, the textfield will not be visible.
  23. *
  24. * @author Scott Violet
  25. * @version 1.12, 01/23/03
  26. */
  27. class HiddenTagView extends EditableView implements DocumentListener {
  28. HiddenTagView(Element e) {
  29. super(e);
  30. yAlign = 1;
  31. }
  32. protected Component createComponent() {
  33. JTextField tf = new JTextField(getElement().getName());
  34. Document doc = getDocument();
  35. Font font;
  36. if (doc instanceof StyledDocument) {
  37. font = ((StyledDocument)doc).getFont(getAttributes());
  38. tf.setFont(font);
  39. }
  40. else {
  41. font = tf.getFont();
  42. }
  43. tf.getDocument().addDocumentListener(this);
  44. updateYAlign(font);
  45. // Create a panel to wrap the textfield so that the textfields
  46. // laf border shows through.
  47. JPanel panel = new JPanel(new BorderLayout());
  48. panel.setBackground(null);
  49. if (isEndTag()) {
  50. panel.setBorder(EndBorder);
  51. }
  52. else {
  53. panel.setBorder(StartBorder);
  54. }
  55. panel.add(tf);
  56. return panel;
  57. }
  58. public float getAlignment(int axis) {
  59. if (axis == View.Y_AXIS) {
  60. return yAlign;
  61. }
  62. return 0.5f;
  63. }
  64. public float getMinimumSpan(int axis) {
  65. if (axis == View.X_AXIS && isVisible()) {
  66. // Default to preferred.
  67. return Math.max(30, super.getPreferredSpan(axis));
  68. }
  69. return super.getMinimumSpan(axis);
  70. }
  71. public float getPreferredSpan(int axis) {
  72. if (axis == View.X_AXIS && isVisible()) {
  73. return Math.max(30, super.getPreferredSpan(axis));
  74. }
  75. return super.getPreferredSpan(axis);
  76. }
  77. public float getMaximumSpan(int axis) {
  78. if (axis == View.X_AXIS && isVisible()) {
  79. // Default to preferred.
  80. return Math.max(30, super.getMaximumSpan(axis));
  81. }
  82. return super.getMaximumSpan(axis);
  83. }
  84. // DocumentListener methods
  85. public void insertUpdate(DocumentEvent e) {
  86. updateModelFromText();
  87. }
  88. public void removeUpdate(DocumentEvent e) {
  89. updateModelFromText();
  90. }
  91. public void changedUpdate(DocumentEvent e) {
  92. updateModelFromText();
  93. }
  94. // View method
  95. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  96. if (!isSettingAttributes) {
  97. setTextFromModel();
  98. }
  99. }
  100. // local methods
  101. void updateYAlign(Font font) {
  102. FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
  103. float h = fm.getHeight();
  104. float d = fm.getDescent();
  105. yAlign = (h - d) / h;
  106. }
  107. void resetBorder() {
  108. Component comp = getComponent();
  109. if (comp != null) {
  110. if (isEndTag()) {
  111. ((JPanel)comp).setBorder(EndBorder);
  112. }
  113. else {
  114. ((JPanel)comp).setBorder(StartBorder);
  115. }
  116. }
  117. }
  118. /**
  119. * This resets the text on the text component we created to match
  120. * that of the AttributeSet for the Element we represent.
  121. * <p>If this is invoked on the event dispatching thread, this
  122. * directly invokes <code>_setTextFromModel</code>, otherwise
  123. * <code>SwingUtilities.invokeLater</code> is used to schedule execution
  124. * of <code>_setTextFromModel</code>.
  125. */
  126. void setTextFromModel() {
  127. if (SwingUtilities.isEventDispatchThread()) {
  128. _setTextFromModel();
  129. }
  130. else {
  131. SwingUtilities.invokeLater(new Runnable() {
  132. public void run() {
  133. _setTextFromModel();
  134. }
  135. });
  136. }
  137. }
  138. /**
  139. * This resets the text on the text component we created to match
  140. * that of the AttributeSet for the Element we represent.
  141. */
  142. void _setTextFromModel() {
  143. Document doc = getDocument();
  144. try {
  145. isSettingAttributes = true;
  146. if (doc instanceof AbstractDocument) {
  147. ((AbstractDocument)doc).readLock();
  148. }
  149. JTextComponent text = getTextComponent();
  150. if (text != null) {
  151. text.setText(getRepresentedText());
  152. resetBorder();
  153. Container host = getContainer();
  154. if (host != null) {
  155. preferenceChanged(this, true, true);
  156. host.repaint();
  157. }
  158. }
  159. }
  160. finally {
  161. isSettingAttributes = false;
  162. if (doc instanceof AbstractDocument) {
  163. ((AbstractDocument)doc).readUnlock();
  164. }
  165. }
  166. }
  167. /**
  168. * This copies the text from the text component we've created
  169. * to the Element's AttributeSet we represent.
  170. * <p>If this is invoked on the event dispatching thread, this
  171. * directly invokes <code>_updateModelFromText</code>, otherwise
  172. * <code>SwingUtilities.invokeLater</code> is used to schedule execution
  173. * of <code>_updateModelFromText</code>.
  174. */
  175. void updateModelFromText() {
  176. if (!isSettingAttributes) {
  177. if (SwingUtilities.isEventDispatchThread()) {
  178. _updateModelFromText();
  179. }
  180. else {
  181. SwingUtilities.invokeLater(new Runnable() {
  182. public void run() {
  183. _updateModelFromText();
  184. }
  185. });
  186. }
  187. }
  188. }
  189. /**
  190. * This copies the text from the text component we've created
  191. * to the Element's AttributeSet we represent.
  192. */
  193. void _updateModelFromText() {
  194. Document doc = getDocument();
  195. Object name = getElement().getAttributes().getAttribute
  196. (StyleConstants.NameAttribute);
  197. if ((name instanceof HTML.UnknownTag) &&
  198. (doc instanceof StyledDocument)) {
  199. SimpleAttributeSet sas = new SimpleAttributeSet();
  200. JTextComponent textComponent = getTextComponent();
  201. if (textComponent != null) {
  202. String text = textComponent.getText();
  203. isSettingAttributes = true;
  204. try {
  205. sas.addAttribute(StyleConstants.NameAttribute,
  206. new HTML.UnknownTag(text));
  207. ((StyledDocument)doc).setCharacterAttributes
  208. (getStartOffset(), getEndOffset() -
  209. getStartOffset(), sas, false);
  210. }
  211. finally {
  212. isSettingAttributes = false;
  213. }
  214. }
  215. }
  216. }
  217. JTextComponent getTextComponent() {
  218. Component comp = getComponent();
  219. return (comp == null) ? null : (JTextComponent)((Container)comp).
  220. getComponent(0);
  221. }
  222. String getRepresentedText() {
  223. String retValue = getElement().getName();
  224. return (retValue == null) ? "" : retValue;
  225. }
  226. boolean isEndTag() {
  227. AttributeSet as = getElement().getAttributes();
  228. if (as != null) {
  229. Object end = as.getAttribute(HTML.Attribute.ENDTAG);
  230. if (end != null && (end instanceof String) &&
  231. ((String)end).equals("true")) {
  232. return true;
  233. }
  234. }
  235. return false;
  236. }
  237. /** Alignment along the y axis, based on the font of the textfield. */
  238. float yAlign;
  239. /** Set to true when setting attributes. */
  240. boolean isSettingAttributes;
  241. // Following are for Borders that used for Unknown tags and comments.
  242. //
  243. // Border defines
  244. static final int circleR = 3;
  245. static final int circleD = circleR * 2;
  246. static final int tagSize = 6;
  247. static final int padding = 3;
  248. static final Color UnknownTagBorderColor = Color.black;
  249. static final Border StartBorder = new StartTagBorder();
  250. static final Border EndBorder = new EndTagBorder();
  251. static class StartTagBorder implements Border, Serializable {
  252. public void paintBorder(Component c, Graphics g, int x, int y,
  253. int width, int height) {
  254. g.setColor(UnknownTagBorderColor);
  255. x += padding;
  256. width -= (padding * 2);
  257. g.drawLine(x, y + circleR,
  258. x, y + height - circleR);
  259. g.drawArc(x, y + height - circleD - 1,
  260. circleD, circleD, 180, 90);
  261. g.drawArc(x, y, circleD, circleD, 90, 90);
  262. g.drawLine(x + circleR, y, x + width - tagSize, y);
  263. g.drawLine(x + circleR, y + height - 1,
  264. x + width - tagSize, y + height - 1);
  265. g.drawLine(x + width - tagSize, y,
  266. x + width - 1, y + height / 2);
  267. g.drawLine(x + width - tagSize, y + height,
  268. x + width - 1, y + height / 2);
  269. }
  270. public Insets getBorderInsets(Component c) {
  271. return new Insets(2, 2 + padding, 2, tagSize + 2 + padding);
  272. }
  273. public boolean isBorderOpaque() {
  274. return false;
  275. }
  276. } // End of class HiddenTagView.StartTagBorder
  277. static class EndTagBorder implements Border, Serializable {
  278. public void paintBorder(Component c, Graphics g, int x, int y,
  279. int width, int height) {
  280. g.setColor(UnknownTagBorderColor);
  281. x += padding;
  282. width -= (padding * 2);
  283. g.drawLine(x + width - 1, y + circleR,
  284. x + width - 1, y + height - circleR);
  285. g.drawArc(x + width - circleD - 1, y + height - circleD - 1,
  286. circleD, circleD, 270, 90);
  287. g.drawArc(x + width - circleD - 1, y, circleD, circleD, 0, 90);
  288. g.drawLine(x + tagSize, y, x + width - circleR, y);
  289. g.drawLine(x + tagSize, y + height - 1,
  290. x + width - circleR, y + height - 1);
  291. g.drawLine(x + tagSize, y,
  292. x, y + height / 2);
  293. g.drawLine(x + tagSize, y + height,
  294. x, y + height / 2);
  295. }
  296. public Insets getBorderInsets(Component c) {
  297. return new Insets(2, tagSize + 2 + padding, 2, 2 + padding);
  298. }
  299. public boolean isBorderOpaque() {
  300. return false;
  301. }
  302. } // End of class HiddenTagView.EndTagBorder
  303. } // End of HiddenTagView