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