001 /*
002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.swing.text.html;
026
027 import java.awt.*;
028 import java.util.*;
029 import java.net.*;
030 import java.io.*;
031 import javax.swing.*;
032 import javax.swing.text.*;
033 import javax.swing.event.*;
034
035 import sun.swing.text.html.FrameEditorPaneTag;
036
037 /**
038 * Implements a FrameView, intended to support the HTML
039 * <FRAME> tag. Supports the frameborder, scrolling,
040 * marginwidth and marginheight attributes.
041 *
042 * @author Sunita Mani
043 * @version 1.37, 05/05/07
044 */
045
046 class FrameView extends ComponentView implements HyperlinkListener {
047
048 JEditorPane htmlPane;
049 JScrollPane scroller;
050 boolean editable;
051 float width;
052 float height;
053 URL src;
054 /** Set to true when the component has been created. */
055 private boolean createdComponent;
056
057 /**
058 * Creates a new Frame.
059 *
060 * @param elem the element to represent.
061 */
062 public FrameView(Element elem) {
063 super (elem);
064 }
065
066 protected Component createComponent() {
067
068 Element elem = getElement();
069 AttributeSet attributes = elem.getAttributes();
070 String srcAtt = (String) attributes
071 .getAttribute(HTML.Attribute.SRC);
072
073 if ((srcAtt != null) && (!srcAtt.equals(""))) {
074 try {
075 URL base = ((HTMLDocument) elem.getDocument())
076 .getBase();
077 src = new URL(base, srcAtt);
078 htmlPane = new FrameEditorPane();
079 htmlPane.addHyperlinkListener(this );
080 JEditorPane host = getHostPane();
081 boolean isAutoFormSubmission = true;
082 if (host != null) {
083 htmlPane.setEditable(host.isEditable());
084 String charset = (String) host
085 .getClientProperty("charset");
086 if (charset != null) {
087 htmlPane.putClientProperty("charset", charset);
088 }
089 HTMLEditorKit hostKit = (HTMLEditorKit) host
090 .getEditorKit();
091 if (hostKit != null) {
092 isAutoFormSubmission = hostKit
093 .isAutoFormSubmission();
094 }
095 }
096 htmlPane.setPage(src);
097 HTMLEditorKit kit = (HTMLEditorKit) htmlPane
098 .getEditorKit();
099 if (kit != null) {
100 kit.setAutoFormSubmission(isAutoFormSubmission);
101 }
102
103 Document doc = htmlPane.getDocument();
104 if (doc instanceof HTMLDocument) {
105 ((HTMLDocument) doc).setFrameDocumentState(true);
106 }
107 setMargin();
108 createScrollPane();
109 setBorder();
110 } catch (MalformedURLException e) {
111 e.printStackTrace();
112 } catch (IOException e1) {
113 e1.printStackTrace();
114 }
115 }
116 createdComponent = true;
117 return scroller;
118 }
119
120 JEditorPane getHostPane() {
121 Container c = getContainer();
122 while ((c != null) && !(c instanceof JEditorPane)) {
123 c = c.getParent();
124 }
125 return (JEditorPane) c;
126 }
127
128 /**
129 * Sets the parent view for the FrameView.
130 * Also determines if the FrameView should be editable
131 * or not based on whether the JTextComponent that
132 * contains it is editable.
133 *
134 * @param parent View
135 */
136 public void setParent(View parent) {
137 if (parent != null) {
138 JTextComponent t = (JTextComponent) parent.getContainer();
139 editable = t.isEditable();
140 }
141 super .setParent(parent);
142 }
143
144 /**
145 * Also determines if the FrameView should be editable
146 * or not based on whether the JTextComponent that
147 * contains it is editable. And then proceeds to call
148 * the superclass to do the paint().
149 *
150 * @param parent View
151 * @see text.ComponentView#paint
152 */
153 public void paint(Graphics g, Shape allocation) {
154
155 Container host = getContainer();
156 if (host != null
157 && htmlPane != null
158 && htmlPane.isEditable() != ((JTextComponent) host)
159 .isEditable()) {
160 editable = ((JTextComponent) host).isEditable();
161 htmlPane.setEditable(editable);
162 }
163 super .paint(g, allocation);
164 }
165
166 /**
167 * If the marginwidth or marginheight attributes have been specified,
168 * then the JEditorPane's margin's are set to the new values.
169 */
170 private void setMargin() {
171 int margin = 0;
172 Insets in = htmlPane.getMargin();
173 Insets newInsets;
174 boolean modified = false;
175 AttributeSet attributes = getElement().getAttributes();
176 String marginStr = (String) attributes
177 .getAttribute(HTML.Attribute.MARGINWIDTH);
178 if (in != null) {
179 newInsets = new Insets(in.top, in.left, in.right, in.bottom);
180 } else {
181 newInsets = new Insets(0, 0, 0, 0);
182 }
183 if (marginStr != null) {
184 margin = Integer.parseInt(marginStr);
185 if (margin > 0) {
186 newInsets.left = margin;
187 newInsets.right = margin;
188 modified = true;
189 }
190 }
191 marginStr = (String) attributes
192 .getAttribute(HTML.Attribute.MARGINHEIGHT);
193 if (marginStr != null) {
194 margin = Integer.parseInt(marginStr);
195 if (margin > 0) {
196 newInsets.top = margin;
197 newInsets.bottom = margin;
198 modified = true;
199 }
200 }
201 if (modified) {
202 htmlPane.setMargin(newInsets);
203 }
204 }
205
206 /**
207 * If the frameborder attribute has been specified, either in the frame,
208 * or by the frames enclosing frameset, the JScrollPane's setBorder()
209 * method is invoked to achieve the desired look.
210 */
211 private void setBorder() {
212
213 AttributeSet attributes = getElement().getAttributes();
214 String frameBorder = (String) attributes
215 .getAttribute(HTML.Attribute.FRAMEBORDER);
216 if ((frameBorder != null)
217 && (frameBorder.equals("no") || frameBorder.equals("0"))) {
218 // make invisible borders.
219 scroller.setBorder(null);
220 }
221 }
222
223 /**
224 * This method creates the JScrollPane. The scrollbar policy is determined by
225 * the scrolling attribute. If not defined, the default is "auto" which
226 * maps to the scrollbar's being displayed as needed.
227 */
228 private void createScrollPane() {
229 AttributeSet attributes = getElement().getAttributes();
230 String scrolling = (String) attributes
231 .getAttribute(HTML.Attribute.SCROLLING);
232 if (scrolling == null) {
233 scrolling = "auto";
234 }
235
236 if (!scrolling.equals("no")) {
237 if (scrolling.equals("yes")) {
238 scroller = new JScrollPane(
239 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
240 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
241 } else {
242 // scrollbars will be displayed if needed
243 //
244 scroller = new JScrollPane();
245 }
246 } else {
247 scroller = new JScrollPane(
248 JScrollPane.VERTICAL_SCROLLBAR_NEVER,
249 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
250 }
251
252 JViewport vp = scroller.getViewport();
253 vp.add(htmlPane);
254 vp.setBackingStoreEnabled(true);
255 scroller.setMinimumSize(new Dimension(5, 5));
256 scroller.setMaximumSize(new Dimension(Integer.MAX_VALUE,
257 Integer.MAX_VALUE));
258 }
259
260 /**
261 * Finds the outermost FrameSetView. It then
262 * returns that FrameSetView's container.
263 */
264 JEditorPane getOutermostJEditorPane() {
265
266 View parent = getParent();
267 FrameSetView frameSetView = null;
268 while (parent != null) {
269 if (parent instanceof FrameSetView) {
270 frameSetView = (FrameSetView) parent;
271 }
272 parent = parent.getParent();
273 }
274 if (frameSetView != null) {
275 return (JEditorPane) frameSetView.getContainer();
276 }
277 return null;
278 }
279
280 /**
281 * Returns true if this frame is contained within
282 * a nested frameset.
283 */
284 private boolean inNestedFrameSet() {
285 FrameSetView parent = (FrameSetView) getParent();
286 return (parent.getParent() instanceof FrameSetView);
287 }
288
289 /**
290 * Notification of a change relative to a
291 * hyperlink. This method searches for the outermost
292 * JEditorPane, and then fires an HTMLFrameHyperlinkEvent
293 * to that frame. In addition, if the target is _parent,
294 * and there is not nested framesets then the target is
295 * reset to _top. If the target is _top, in addition to
296 * firing the event to the outermost JEditorPane, this
297 * method also invokes the setPage() method and explicitly
298 * replaces the current document with the destination url.
299 *
300 * @param HyperlinkEvent
301 */
302 public void hyperlinkUpdate(HyperlinkEvent evt) {
303
304 JEditorPane c = getOutermostJEditorPane();
305 if (c == null) {
306 return;
307 }
308
309 if (!(evt instanceof HTMLFrameHyperlinkEvent)) {
310 c.fireHyperlinkUpdate(evt);
311 return;
312 }
313
314 HTMLFrameHyperlinkEvent e = (HTMLFrameHyperlinkEvent) evt;
315
316 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
317 String target = e.getTarget();
318 String postTarget = target;
319
320 if (target.equals("_parent") && !inNestedFrameSet()) {
321 target = "_top";
322 }
323
324 if (evt instanceof FormSubmitEvent) {
325 HTMLEditorKit kit = (HTMLEditorKit) c.getEditorKit();
326 if (kit != null && kit.isAutoFormSubmission()) {
327 if (target.equals("_top")) {
328 try {
329 movePostData(c, postTarget);
330 c.setPage(e.getURL());
331 } catch (IOException ex) {
332 // Need a way to handle exceptions
333 }
334 } else {
335 HTMLDocument doc = (HTMLDocument) c
336 .getDocument();
337 doc.processHTMLFrameHyperlinkEvent(e);
338 }
339 } else {
340 c.fireHyperlinkUpdate(evt);
341 }
342 return;
343 }
344
345 if (target.equals("_top")) {
346 try {
347 c.setPage(e.getURL());
348 } catch (IOException ex) {
349 // Need a way to handle exceptions
350 // ex.printStackTrace();
351 }
352 }
353 if (!c.isEditable()) {
354 c.fireHyperlinkUpdate(new HTMLFrameHyperlinkEvent(c, e
355 .getEventType(), e.getURL(),
356 e.getDescription(), getElement(), target));
357 }
358 }
359 }
360
361 /**
362 * Gives notification from the document that attributes were changed
363 * in a location that this view is responsible for. Currently this view
364 * handles changes to its SRC attribute.
365 *
366 * @param e the change information from the associated document
367 * @param a the current allocation of the view
368 * @param f the factory to use to rebuild if the view has children
369 *
370 */
371 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
372
373 Element elem = getElement();
374 AttributeSet attributes = elem.getAttributes();
375
376 URL oldPage = src;
377
378 String srcAtt = (String) attributes
379 .getAttribute(HTML.Attribute.SRC);
380 URL base = ((HTMLDocument) elem.getDocument()).getBase();
381 try {
382 if (!createdComponent) {
383 return;
384 }
385
386 Object postData = movePostData(htmlPane, null);
387 src = new URL(base, srcAtt);
388 if (oldPage.equals(src) && (src.getRef() == null)
389 && (postData == null)) {
390 return;
391 }
392
393 htmlPane.setPage(src);
394 Document newDoc = htmlPane.getDocument();
395 if (newDoc instanceof HTMLDocument) {
396 ((HTMLDocument) newDoc).setFrameDocumentState(true);
397 }
398 } catch (MalformedURLException e1) {
399 // Need a way to handle exceptions
400 //e1.printStackTrace();
401 } catch (IOException e2) {
402 // Need a way to handle exceptions
403 //e2.printStackTrace();
404 }
405 }
406
407 /**
408 * Move POST data from temporary storage into the target document property.
409 *
410 * @return the POST data or null if no data found
411 */
412 private Object movePostData(JEditorPane targetPane, String frameName) {
413 Object postData = null;
414 JEditorPane p = getOutermostJEditorPane();
415 if (p != null) {
416 if (frameName == null) {
417 frameName = (String) getElement().getAttributes()
418 .getAttribute(HTML.Attribute.NAME);
419 }
420 if (frameName != null) {
421 String propName = FormView.PostDataProperty + "."
422 + frameName;
423 Document d = p.getDocument();
424 postData = d.getProperty(propName);
425 if (postData != null) {
426 targetPane.getDocument().putProperty(
427 FormView.PostDataProperty, postData);
428 d.putProperty(propName, null);
429 }
430 }
431 }
432
433 return postData;
434 }
435
436 /**
437 * Determines the minimum span for this view along an
438 * axis.
439 *
440 * @param axis may be either <code>View.X_AXIS</code> or
441 * <code>View.Y_AXIS</code>
442 * @return the preferred span; given that we do not
443 * support resizing of frames, the minimum span returned
444 * is the same as the preferred span
445 *
446 */
447 public float getMinimumSpan(int axis) {
448 return 5;
449 }
450
451 /**
452 * Determines the maximum span for this view along an
453 * axis.
454 *
455 * @param axis may be either <code>View.X_AXIS</code> or
456 * <code>View.Y_AXIS</code>
457 * @return the preferred span; given that we do not
458 * support resizing of frames, the maximum span returned
459 * is the same as the preferred span
460 *
461 */
462 public float getMaximumSpan(int axis) {
463 return Integer.MAX_VALUE;
464 }
465
466 /** Editor pane rendering frame of HTML document
467 * It uses the same editor kits classes as outermost JEditorPane
468 */
469 class FrameEditorPane extends JEditorPane implements
470 FrameEditorPaneTag {
471 public EditorKit getEditorKitForContentType(String type) {
472 EditorKit editorKit = super
473 .getEditorKitForContentType(type);
474 JEditorPane outerMostJEditorPane = null;
475 if ((outerMostJEditorPane = getOutermostJEditorPane()) != null) {
476 EditorKit inheritedEditorKit = outerMostJEditorPane
477 .getEditorKitForContentType(type);
478 if (!editorKit.getClass().equals(
479 inheritedEditorKit.getClass())) {
480 editorKit = (EditorKit) inheritedEditorKit.clone();
481 setEditorKitForContentType(type, editorKit);
482 }
483 }
484 return editorKit;
485 }
486
487 FrameView getFrameView() {
488 return FrameView.this;
489 }
490 }
491 }
|