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