1. /*
  2. * @(#)FrameView.java 1.12 01/11/29
  3. *
  4. * Copyright 2002 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.util.*;
  10. import java.net.*;
  11. import java.io.*;
  12. import javax.swing.*;
  13. import javax.swing.text.*;
  14. import javax.swing.event.*;
  15. /**
  16. * Implements a FrameView, intended to support the HTML
  17. * <FRAME> tag. Supports the frameborder, scrolling,
  18. * marginwidth and marginheight attributes.
  19. *
  20. * @author Sunita Mani
  21. * @version 1.12, 11/29/01
  22. */
  23. class FrameView extends ComponentView implements HyperlinkListener {
  24. JEditorPane htmlPane;
  25. JScrollPane scroller;
  26. boolean editable;
  27. float width;
  28. float height;
  29. URL src;
  30. /**
  31. * Creates a new Frame.
  32. *
  33. * @param elem the element to represent.
  34. */
  35. public FrameView(Element elem) {
  36. super(elem);
  37. }
  38. protected Component createComponent() {
  39. Element elem = getElement();
  40. AttributeSet attributes = elem.getAttributes();
  41. String srcAtt = (String)attributes.getAttribute(HTML.Attribute.SRC);
  42. if ((srcAtt != null) && (!srcAtt.equals(""))) {
  43. try {
  44. URL base = ((HTMLDocument)elem.getDocument()).getBase();
  45. src = new URL(base, srcAtt);
  46. htmlPane = new JEditorPane(src);
  47. htmlPane.addHyperlinkListener(this);
  48. htmlPane.setEditable(editable);
  49. HTMLDocument doc = (HTMLDocument)htmlPane.getDocument();
  50. doc.setFrameDocumentState(true);
  51. setMargin();
  52. createScrollPane();
  53. setBorder();
  54. } catch (MalformedURLException e) {
  55. e.printStackTrace();
  56. } catch (IOException e1) {
  57. e1.printStackTrace();
  58. }
  59. }
  60. return scroller;
  61. }
  62. /**
  63. * Sets the parent view for the FrameView.
  64. * Also determines if the FrameView should be editable
  65. * or not based on whether the JTextComponent that
  66. * contains it is editable.
  67. *
  68. * @param parent View
  69. */
  70. public void setParent(View parent) {
  71. if (parent != null) {
  72. JTextComponent t = (JTextComponent)parent.getContainer();
  73. editable = t.isEditable();
  74. }
  75. super.setParent(parent);
  76. }
  77. /**
  78. * Also determines if the FrameView should be editable
  79. * or not based on whether the JTextComponent that
  80. * contains it is editable. And then proceeds to call
  81. * the superclass to do the paint().
  82. *
  83. * @param parent View
  84. * @see text.ComponentView#paint
  85. */
  86. public void paint(Graphics g, Shape allocation) {
  87. Container host = getContainer();
  88. if (host != null && htmlPane != null &&
  89. htmlPane.isEditable() != ((JTextComponent)host).isEditable()) {
  90. editable = ((JTextComponent)host).isEditable();
  91. htmlPane.setEditable(editable);
  92. }
  93. super.paint(g, allocation);
  94. }
  95. /**
  96. * If the marginwidth or marginheight attributes have been specified,
  97. * then the JEditorPane's margin's are set to the new values.
  98. */
  99. private void setMargin() {
  100. int margin = 0;
  101. Insets in = htmlPane.getMargin();
  102. Insets newInsets = new Insets(in.top, in.left, in.right, in.bottom);
  103. boolean modified = false;
  104. AttributeSet attributes = getElement().getAttributes();
  105. String marginStr = (String)attributes.getAttribute(HTML.Attribute.MARGINWIDTH);
  106. if (marginStr != null) {
  107. margin = Integer.parseInt(marginStr);
  108. if (margin > 0) {
  109. newInsets.left = margin;
  110. newInsets.right = margin;
  111. modified = true;
  112. }
  113. }
  114. marginStr = (String)attributes.getAttribute(HTML.Attribute.MARGINHEIGHT);
  115. if (marginStr != null) {
  116. margin = Integer.parseInt(marginStr);
  117. if (margin > 0) {
  118. newInsets.top = margin;
  119. newInsets.bottom = margin;
  120. modified = true;
  121. }
  122. }
  123. if (modified) {
  124. htmlPane.setMargin(newInsets);
  125. }
  126. }
  127. /**
  128. * If the frameborder attribute has been specified, either in the frame,
  129. * or by the frames enclosing frameset, the JScrollPane's setBorder()
  130. * method is invoked to achieve the desired look.
  131. */
  132. private void setBorder() {
  133. AttributeSet attributes = getElement().getAttributes();
  134. String frameBorder = (String)attributes.getAttribute(HTML.Attribute.FRAMEBORDER);
  135. if ((frameBorder != null) &&
  136. (frameBorder.equals("no") || frameBorder.equals("0"))) {
  137. // make invisible borders.
  138. scroller.setBorder(null);
  139. }
  140. }
  141. /**
  142. * This method creates the JScrollPane. The scrollbar policy is determined by
  143. * the scrolling attribute. If not defined, the default is "auto" which
  144. * maps to the scrollbar's being displayed as needed.
  145. */
  146. private void createScrollPane() {
  147. AttributeSet attributes = getElement().getAttributes();
  148. String scrolling = (String)attributes.getAttribute(HTML.Attribute.SCROLLING);
  149. if (scrolling == null) {
  150. scrolling = "auto";
  151. }
  152. if (!scrolling.equals("no")) {
  153. if (scrolling.equals("yes")) {
  154. scroller = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  155. JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
  156. } else {
  157. // scrollbars will be displayed if needed
  158. //
  159. scroller = new JScrollPane();
  160. }
  161. } else {
  162. scroller = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_NEVER,
  163. JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  164. }
  165. JViewport vp = scroller.getViewport();
  166. vp.add(htmlPane);
  167. vp.setBackingStoreEnabled(true);
  168. scroller.setVisible(false);
  169. scroller.setMinimumSize(new Dimension(5,5));
  170. scroller.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
  171. }
  172. /**
  173. * Finds the outermost FrameSetView. It then
  174. * returns that FrameSetView's container.
  175. */
  176. private JEditorPane getOutermostJEditorPane() {
  177. View parent = getParent();
  178. FrameSetView frameSetView = null;
  179. while (parent != null) {
  180. if (parent instanceof FrameSetView) {
  181. frameSetView = (FrameSetView)parent;
  182. }
  183. parent = parent.getParent();
  184. }
  185. if (frameSetView != null) {
  186. return (JEditorPane)frameSetView.getContainer();
  187. }
  188. return null;
  189. }
  190. /**
  191. * Returns true if this frame is contained within
  192. * a nested frameset.
  193. */
  194. private boolean inNestedFrameSet() {
  195. FrameSetView parent = (FrameSetView)getParent();
  196. return (parent.getParent() instanceof FrameSetView);
  197. }
  198. /**
  199. * Notification of a change relative to a
  200. * hyperlink. This method searches for the outermost
  201. * JEditorPane, and then fires an HTMLFrameHyperlinkEvent
  202. * to that frame. In addition, if the target is _parent,
  203. * and there is not nested framesets then the target is
  204. * reset to _top. If the target is _top, in addition to
  205. * firing the event to the outermost JEditorPane, this
  206. * method also invokes the setPage() method and explicitly
  207. * replaces the current document with the destination url.
  208. *
  209. * @param HyperlinkEvent
  210. */
  211. public void hyperlinkUpdate(HyperlinkEvent evt) {
  212. if (!(evt instanceof HTMLFrameHyperlinkEvent)) {
  213. return;
  214. }
  215. HTMLFrameHyperlinkEvent e = (HTMLFrameHyperlinkEvent)evt;
  216. if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
  217. JEditorPane c = getOutermostJEditorPane();
  218. String target = e.getTarget();
  219. if (e.getTarget().equals("_parent") && !inNestedFrameSet()){
  220. target = "_top";
  221. }
  222. if (c != null && !c.isEditable()) {
  223. c.fireHyperlinkUpdate(new HTMLFrameHyperlinkEvent(c,
  224. e.getEventType(),
  225. e.getURL(),
  226. e.getDescription(),
  227. getElement(),
  228. target));
  229. if (target.equals("_top")) {
  230. try {
  231. c.setPage(e.getURL());
  232. } catch (IOException ex) {
  233. // Need a way to handle exceptions
  234. // ex.printStackTrace();
  235. }
  236. }
  237. }
  238. }
  239. }
  240. /**
  241. * Gives notification from the document that attributes were changed
  242. * in a location that this view is responsible for. Currently this view
  243. * handles changes to its SRC attribute.
  244. *
  245. * @param e the change information from the associated document
  246. * @param a the current allocation of the view
  247. * @param f the factory to use to rebuild if the view has children
  248. *
  249. */
  250. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  251. Element elem = getElement();
  252. AttributeSet attributes = elem.getAttributes();
  253. URL oldPage = src;
  254. String srcAtt = (String)attributes.getAttribute(HTML.Attribute.SRC);
  255. URL base = ((HTMLDocument)elem.getDocument()).getBase();
  256. try {
  257. src = new URL(base, srcAtt);
  258. if (oldPage.equals(src)) {
  259. return;
  260. }
  261. htmlPane.setPage(src);
  262. HTMLDocument newDoc = (HTMLDocument)htmlPane.getDocument();
  263. newDoc.setFrameDocumentState(true);
  264. } catch (MalformedURLException e1) {
  265. // Need a way to handle exceptions
  266. //e1.printStackTrace();
  267. } catch (IOException e2) {
  268. // Need a way to handle exceptions
  269. //e2.printStackTrace();
  270. }
  271. }
  272. /**
  273. * Determines the minimum span for this view along an
  274. * axis.
  275. *
  276. * @param axis may be either View.X_AXIS or View.Y_AXIS
  277. * @returns the preferred span. Given that we do not
  278. * support resizing of frames, the minimum span returned
  279. * is the same as the preferred span.
  280. *
  281. */
  282. public float getMinimumSpan(int axis) {
  283. return 5;
  284. }
  285. /**
  286. * Determines the maximum span for this view along an
  287. * axis.
  288. *
  289. * @param axis may be either View.X_AXIS or View.Y_AXIS
  290. * @returns the preferred span. Given that we do not
  291. * support resizing of frames, the maximum span returned
  292. * is the same as the preferred span.
  293. *
  294. */
  295. public float getMaximumSpan(int axis) {
  296. return Integer.MAX_VALUE;
  297. }
  298. }