001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.css2;
043:
044: import java.awt.EventQueue;
045: import java.net.URL;
046: import javax.swing.ImageIcon;
047: import javax.swing.JViewport;
048:
049: import org.netbeans.modules.visualweb.api.designer.Designer.ExternalBox;
050: import org.netbeans.modules.visualweb.api.designer.DomProvider;
051: import org.netbeans.modules.visualweb.api.designer.cssengine.CssListValue;
052: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
053: import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
054: import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
055: import org.netbeans.modules.visualweb.designer.CssUtilities;
056: import org.netbeans.modules.visualweb.designer.DesignerPane;
057: import org.netbeans.modules.visualweb.designer.DesignerUtils;
058: import org.netbeans.modules.visualweb.designer.ImageCache;
059: import org.netbeans.modules.visualweb.designer.WebForm;
060:
061: import org.openide.util.NbBundle;
062:
063: import org.w3c.dom.Element;
064: import org.w3c.dom.Node;
065: import org.w3c.dom.NodeList;
066:
067: /**
068: * ExternalDocumentBox is an abstract class used by FrameBox,
069: * JspIncludeBox etc. -- boxes that represent content rendered from
070: * external documents / separate files.
071: *
072: * @author Tor Norbye
073: *
074: */
075: public abstract class ExternalDocumentBox extends DocumentBox implements
076: ExternalBox {
077: /** Flag which indicates that this page wants to load the resource
078: * via a url, and that we don't support it*/
079: // protected boolean external;
080: private boolean haveCreatedChildren;
081: private WebForm frameForm;
082:
083: /** Flag which indicates whether or not this box is the root of a layout hierarchy.
084: * If it is, computing absolute positions for example should terminate at this box
085: * even if the parent pointer points further.
086: */
087: private boolean layoutRoot;
088:
089: protected ExternalDocumentBox(DesignerPane pane, /*WebForm frameForm,*/
090: WebForm webform, Element element, /*URL url,*/
091: BoxType boxType, boolean inline, boolean replaced) {
092: super (pane, webform, element, boxType, inline, replaced);
093: // this.frameForm = frameForm;
094: this .frameForm = findExternalForm(webform, element);
095: }
096:
097: // XXX Moved to designer/jsf/../JsfForm.
098: // protected final static WebForm findForm(WebForm webform, URL url) {
099: //// DocumentCache cache = webform.getDocument().getFrameBoxCache();
100: // DocumentCache cache = webform.getFrameBoxCache();
101: // WebForm frameForm = cache.get(url);
102: //
103: // if (frameForm != null) {
104: // return frameForm;
105: // }
106: //
107: // // According to HTML4.01 section 16.5: "The contents of the
108: // // IFRAME element, on the other hand, should only be displayed
109: // // by user agents that do not support frames or are configured
110: // // not to display frames."
111: // // Thus, we don't walk the children array; instead, we
112: // // fetch the url document and display that instead
113: // if (url == null) {
114: // return null;
115: // }
116: //
117: // FileObject fo = URLMapper.findFileObject(url);
118: //
119: // if (fo != null) {
120: // frameForm = loadPage(fo);
121: // }
122: //
123: // if (frameForm == null) {
124: // frameForm = loadPage(url);
125: // }
126: //
127: // if ((frameForm != null) && (frameForm != WebForm.EXTERNAL)) {
128: // cache.put(url, frameForm);
129: // }
130: //
131: //// // Set the cell renderer pane if necessary
132: //// if ((frameForm != null) && (frameForm.getRenderPane() == null)) {
133: //// frameForm.setRenderPane(webform.getRenderPane());
134: //// }
135: //
136: // return frameForm;
137: // }
138:
139: protected abstract String getUrlString();
140:
141: // private static WebForm loadPage(URL url) {
142: // //Log.err.log("URL box loading not yet implemented");
143: // return WebForm.EXTERNAL;
144: //
145: //// /*
146: //// // Compute document base for the other document
147: //// // try {
148: //// // url = new URL(getBase(), href);
149: //// // } catch (MalformedURLException mfe) {
150: //// // try {
151: //// // ErrorManager.getDefault().notify(mfe);
152: //// // url = new URL(href);
153: //// // } catch (MalformedURLException mfe2) {
154: //// // ErrorManager.getDefault().notify(mfe);
155: //// // url = null;
156: //// // }
157: //// // }
158: //// // if (url != null) {
159: //// StringBuffer sb = new StringBuffer();
160: //// try {
161: //// InputStream uis = url.openStream();
162: //// Reader r = new BufferedReader(new InputStreamReader(uis));
163: //// int c;
164: //// while ((c = r.read()) != -1) {
165: //// sb.append((char)c);
166: //// }
167: //// } catch (IOException ioe) {
168: //// ErrorManager.getDefault().notify(ioe);
169: //// return false;
170: //// }
171: //// String str = sb.toString();
172: ////
173: //// // Construct a document containing the string buffer
174: //// StringContent content = new StringContent(str.length()+5);
175: //// try {
176: //// content.insertString(0, str);
177: //// } catch (Exception e) {
178: //// ErrorManager.getDefault().notify(e);
179: //// return false;
180: //// }
181: //// AbstractDocument adoc = new PlainDocument(content);
182: //// DataObject dobj = null;
183: //// String filename = url.toString(); // only used for diagnostic messages, right?
184: ////
185: //// MarkupUnit markup = new MarkupUnit(dobj, adoc, filename, MarkupUnit.ALLOW_XML);
186: //// markup.sync();
187: //// //if (!markup.getState().equals(markup.getState().CLEAN)) {
188: //// if (!markup.getState().equals(Unit.State.CLEAN)) {
189: //// return false;
190: //// }
191: ////
192: //// CellRendererPane renderPane = webform.getPane().getRenderPane();
193: //// Log.err.log("FrameBox initialization for external urls not yet done");
194: //// */
195: //// /* XXX Not yet implemented
196: //// frameForm = new WebForm(markup, renderPane);
197: //// DesignerPane pane = null;
198: //// Document document = new Document(frameForm);
199: //// frameForm.setDocument(document);
200: //// return success;
201: //// */
202: // }
203: //
204: // private static WebForm loadPage(FileObject fobj) {
205: // DataObject dobj = null;
206: //
207: // try {
208: // dobj = DataObject.find(fobj);
209: // } catch (DataObjectNotFoundException ex) {
210: // return null;
211: // }
212: //
213: // /*
214: // // Wrapper which handles errors
215: // LiveFacesCookie c = LiveFacesCookie.getInstanceFor(dobj);
216: // if (c == null) {
217: // ErrorManager.getDefault().log("Data object " + dobj + " ain't got no insync cookie!");
218: // return false;
219: // }
220: // FacesModel model = getDocument().getWebForm().getModel();
221: // model.syncFromDoc();
222: // if (model.getMarkup().getState().isInvalid()) {
223: // return false;
224: // }
225: // markup = model.getMarkup();
226: // */
227: //
228: // // XXX Does this work for a form which is not yet open?
229: //// WebForm frameForm = WebForm.findWebForm(dobj);
230: // WebForm frameForm = WebForm.getWebFormForDataObject(dobj);
231: //
232: //// if ((frameForm != null) && (frameForm.getModel() != null)) {
233: //// frameForm.getModel().sync();
234: // if (frameForm != null) {
235: // frameForm.syncModel();
236: //
237: // return frameForm;
238: // } else {
239: // return null;
240: // }
241: // }
242:
243: protected void initializeBackgroundColor() {
244: WebForm frameForm = getExternalForm();
245: // if ((frameForm != null) && !frameForm.getModel().isBusted()) {
246: // XXX The model validity should be checked here.
247: // if (frameForm != null && !frameForm.isModelBusted()) {
248: if (frameForm != null) {
249: // Use the pointed-to document's background colors
250: // etc.
251: // Element frameFormElement = frameForm.getDocument().getWebForm().getHtmlBody();
252: Element frameFormElement = frameForm.getHtmlBody();
253: // bg = CssLookup.getColor(frameFormElement, XhtmlCss.BACKGROUND_COLOR_INDEX);
254: bg = CssProvider.getValueService().getColorForElement(
255: frameFormElement, XhtmlCss.BACKGROUND_COLOR_INDEX);
256: } else {
257: super .initializeBackgroundColor();
258: }
259: }
260:
261: protected void initializeBackgroundImage() {
262: WebForm frameForm = getExternalForm();
263: // if ((frameForm != null) && !frameForm.getModel().isBusted()) {
264: // if (frameForm != null && !frameForm.isModelBusted()) {
265: // XXX The model validity shouldn't be checked here.
266: if (frameForm != null) {
267: // Use the pointed-to document's background colors
268: // etc.
269: // Element frameFormElement = frameForm.getDocument().getWebForm().getHtmlBody();
270: Element frameFormElement = frameForm.getHtmlBody();
271: // ImageIcon bgImage = BackgroundImagePainter.getBackgroundImage(webform, frameFormElement);
272: // URL imageUrl = CssBoxUtilities.getBackgroundImageUrl(frameFormElement, webform.getMarkup().getBase());
273: // URL imageUrl = CssProvider.getEngineService().getBackgroundImageUrlForElement(frameFormElement, webform.getMarkup().getBase());
274: URL imageUrl = CssProvider.getEngineService()
275: .getBackgroundImageUrlForElement(frameFormElement,
276: webform.getBaseUrl());
277: ImageIcon bgImage;
278: if (imageUrl != null) {
279: // XXX Revise this caching impl.
280: // ImageCache imageCache = webform.getDocument().getImageCache();
281: ImageCache imageCache = webform.getImageCache();
282: bgImage = imageCache.get(imageUrl);
283: if (bgImage == null) {
284: bgImage = new ImageIcon(imageUrl);
285: imageCache.put(imageUrl, bgImage);
286: }
287: } else {
288: bgImage = null;
289: }
290:
291: if (bgImage != null) {
292: // Value repeatValue = CssLookup.getValue(frameFormElement, XhtmlCss.BACKGROUND_REPEAT_INDEX);
293: CssValue cssRepeatValue = CssProvider
294: .getEngineService().getComputedValueForElement(
295: frameFormElement,
296: XhtmlCss.BACKGROUND_REPEAT_INDEX);
297: // ListValue positionValue =
298: // CssLookup.getListValue(CssLookup.getValue(frameFormElement, XhtmlCss.BACKGROUND_POSITION_INDEX));
299: CssListValue cssPositionValue = CssProvider
300: .getValueService()
301: .getComputedCssListValue(
302: CssProvider
303: .getEngineService()
304: .getComputedValueForElement(
305: frameFormElement,
306: XhtmlCss.BACKGROUND_POSITION_INDEX));
307: // bgPainter = new BackgroundImagePainter(bgImage, repeatValue, positionValue);
308: bgPainter = new BackgroundImagePainter(bgImage,
309: cssRepeatValue, cssPositionValue,
310: frameFormElement, frameForm
311: .getDefaultFontSize());
312: }
313: } else {
314: super .initializeBackgroundImage();
315: }
316: }
317:
318: /** When building the box hierarchy, instead of adding content
319: * for children, add the string attribute content
320: */
321: protected void createChildren(CreateContext context) {
322: // Since frameboxes are cached, make sure we only do this once.
323: // LAYOUT on the other hand should NOT be suppressed, since it
324: // may have to be done again if the parent box changes, etc.
325: if (haveCreatedChildren) {
326: return;
327: }
328:
329: haveCreatedChildren = true;
330:
331: Element element = getElement();
332: WebForm frameForm = getExternalForm();
333: // if (external) {
334: if (frameForm == null) {
335: String desc = NbBundle.getMessage(
336: ExternalDocumentBox.class, "UrlNotSupported", // NOI18N
337: getUrlString());
338: LineBoxGroup old = context.lineBox;
339: context.lineBox = null;
340: addText(context, null, element, desc);
341: finishLineBox(context);
342: context.lineBox = old;
343:
344: // Clip the overflow of the text in case it spills outside the
345: // requested size of the frame/fragment
346: clipOverflow = true;
347:
348: return;
349: }
350:
351: // if (frameForm == null) {
352: // return;
353: // }
354:
355: // This shouldn't be here, the model should be always valid.
356: // // We allow invalid forms to be shown when included in say <iframes>
357: // // But should I include some note about parsing errors???
358: //// if (frameForm.getModel().isBusted()) {
359: // if (frameForm.isModelBusted()) {
360: // return;
361: // }
362:
363: // Element body = frameForm.getDocument().getWebForm().getHtmlBody();
364: Element body = frameForm.getHtmlBody();
365:
366: if (body == null) {
367: return;
368: }
369:
370: // Make sure styles inherit right into the included content
371: // RaveElement.setStyleParent(body, element);
372: CssProvider.getEngineService().setStyleParentForElement(body,
373: element);
374: // ((RaveDocument)frameForm.getDom()).setCssEngine(webform.getDom().getCssEngine());
375: // CssProvider.getEngineService().reuseCssEngineForDocument(frameForm.getJspDom(), webform.getJspDom());
376: // XXX Reusing the jsp dom, shouldn't be here (it seem it didn't work anyway).
377: // frameForm.reuseCssStyle(webform);
378: CssProvider.getEngineService().reuseCssEngineForDocument(
379: frameForm.getHtmlDom(), webform.getHtmlDom());
380:
381: // XhtmlCssEngine engine = CssLookup.getCssEngine(body);
382: // if (engine != null) {
383: // engine.clearTransientStyleSheetNodes();
384: // }
385: CssProvider.getEngineService()
386: .clearTransientStyleSheetNodesForDocument(
387: body.getOwnerDocument());
388:
389: // We need to have our own create context here, so fixed boxes
390: // doesn't bleed into the parent document fixed box list, etc.
391: CreateContext cc = new CreateContext(context);
392: cc.pushPage(frameForm);
393:
394: try {
395: // Font font = CssLookup.getFont(body, DesignerSettings.getInstance().getDefaultFontSize());
396: // Font font = CssProvider.getValueService().getFontForElement(body, DesignerSettings.getInstance().getDefaultFontSize(), Font.PLAIN);
397: // cc.metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
398: // XXX Missing text.
399: cc.metrics = CssUtilities.getDesignerFontMetricsForElement(
400: body, null, frameForm.getDefaultFontSize());
401:
402: NodeList list = body.getChildNodes();
403: int len = list.getLength();
404: setProbableChildCount(len);
405:
406: for (int i = 0; i < len; i++) {
407: org.w3c.dom.Node child = (org.w3c.dom.Node) list
408: .item(i);
409:
410: if ((child.getNodeType() == Node.TEXT_NODE)
411: && COLLAPSE
412: && DesignerUtils.onlyWhitespace(child
413: .getNodeValue())) {
414: continue;
415: }
416:
417: addNode(cc, child, null, null, null);
418: }
419:
420: fixedBoxes = cc.getFixedBoxes();
421: } finally {
422: WebForm page = cc.popPage();
423:
424: assert page == frameForm;
425: }
426: }
427:
428: // Override standard methods to give frames special treatment, since
429: // they are "black boxes" as far as the box hierarchy is concerned
430: protected CssBox findCssBox(int x, int y, int px, int py, int depth) {
431: // Don't expose any of the boxes within the frame
432: // See if this match is okay.
433: // This is necesary because we investigate children whose
434: // extents include absolutely positioned views
435: boolean match = (x >= getExtentX()) && (x <= getExtentX2())
436: && (y >= getExtentY()) && (y <= getExtentY2());
437:
438: if (match) {
439: return this ;
440: } else {
441: return null;
442: }
443: }
444:
445: // // XXX Get rid of this. Replace with #findCssBoxForComponentRootElement.
446: // protected CssBox findCssBox(DesignBean bean) {
447: //// if (bean == getDesignBean()) {
448: //// if (bean == CssBox.getMarkupDesignBeanForCssBox(this)) {
449: //// return this;
450: //// }
451: // Element componentRootElement = WebForm.getDomProviderService().getRenderedElement(bean);
452: // if (componentRootElement != null && componentRootElement == CssBox.getElementForComponentRootCssBox(this)) {
453: // return this;
454: // }
455: //
456: // // XXX Why not?
457: // // Don't search among the children
458: // return null;
459: // }
460:
461: protected CssBox findCssBoxForComponentRootElement(
462: Element componentRootElement) {
463: if (componentRootElement != null
464: && componentRootElement == CssBox
465: .getElementForComponentRootCssBox(this )) {
466: return this ;
467: }
468:
469: // XXX Why not?
470: // Don't search among the children
471: return null;
472: }
473:
474: /** What should the default intrinsic width be? Mozilla 1.6 seems
475: * to use 300x150.
476: */
477: public int getIntrinsicWidth() {
478: return 300;
479: }
480:
481: /** What should the default intrinsic height be? Mozilla 1.6 seems
482: * to use 300x150.
483: */
484: public int getIntrinsicHeight() {
485: return 150;
486: }
487:
488: // /** Open the given page source in the editor */
489: // public void open() {
490: // if (frameForm == null) {
491: // java.awt.Toolkit.getDefaultToolkit().beep();
492: //
493: // return;
494: // }
495: //
496: // DataObject dobj = frameForm.getDataObject();
497: // OpenCookie oc = (OpenCookie)dobj.getCookie(OpenCookie.class);
498: //
499: // if (oc != null) {
500: // oc.open();
501: // }
502: // }
503:
504: protected void updateSizeInfo() {
505: // Unlike the main page box, we don't want the extents of the
506: // view box to include the initial viewport
507: width = 0;
508: height = 0;
509: super .updateSizeInfo();
510: }
511:
512: public int getAbsoluteX() {
513: ContainerBox parent = getParent();
514: if (positionedBy != parent) {
515: return positionedBy.getAbsoluteX() + getX() + leftMargin;
516: }
517:
518: if (!layoutRoot && (parent != null)) {
519: return parent.getAbsoluteX() + x + leftMargin;
520: } else {
521: return x + leftMargin;
522: }
523: }
524:
525: public int getAbsoluteY() {
526: ContainerBox parent = getParent();
527: if (positionedBy != parent) {
528: return positionedBy.getAbsoluteY() + getY()
529: + effectiveTopMargin;
530: }
531:
532: if (!layoutRoot && (parent != null)) {
533: return parent.getAbsoluteY() + y + effectiveTopMargin;
534: } else {
535: return y + effectiveTopMargin;
536: }
537: }
538:
539: public void relayout(JViewport viewport, int initialWidth,
540: int initialHeight, int wrapWidth) {
541: try {
542: layoutRoot = true;
543: super .relayout(viewport, initialWidth, initialHeight,
544: wrapWidth);
545: } finally {
546: layoutRoot = false;
547: }
548: }
549:
550: /** Return the webform associated with this box, containing the
551: * model for the included/referenced external document. May be null.
552: */
553: public WebForm getExternalForm() {
554: // XXX Model validity shouldn't be checked here.
555: // if (frameForm == null || !frameForm.isModelValid()) {
556: if (frameForm == null) {
557: frameForm = findExternalForm(super .getWebForm(),
558: getElement());
559: }
560: return frameForm;
561: }
562:
563: // XXX #118167 This hack seems to be causing more troubles (see the issue), commenting out.
564: // If you need to access the external form, use getExternalForm() method.
565: // /** Redefine to return the <code>WebForm</code> for the content being shown
566: // * in the external document. That way JSF rendering etc. will use
567: // * the correct form.
568: // * XXX This looks suspicious.
569: // */
570: // @Override
571: // public WebForm getWebForm() {
572: // WebForm frameForm = getExternalForm();
573: // if (frameForm != null) {
574: // return frameForm;
575: // }
576: //
577: // return super.getWebForm();
578: // }
579:
580: public DomProvider getExternalDomProvider() {
581: WebForm externalForm = getExternalForm();
582: return externalForm == null ? null : externalForm
583: .getDomProvider();
584: }
585:
586: protected WebForm findExternalForm(WebForm webform, Element element) {
587: URL src = getContentURL(webform, element); // TODO - check for null here!
588: return webform.findExternalForm(src);
589: }
590:
591: protected abstract URL getContentURL(WebForm webform,
592: Element element);
593: }
|