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: package org.netbeans.modules.visualweb.designer.markup;
042:
043: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
044: import org.apache.batik.css.engine.CSSEngine;
045: import org.apache.batik.css.engine.CSSStylableElement;
046: import org.apache.batik.css.engine.StyleMap;
047: import org.apache.xerces.dom.CoreDocumentImpl;
048: import org.w3c.dom.DOMException;
049: import org.w3c.dom.Element;
050: import org.w3c.dom.Node;
051:
052: /**
053: * XXX Originally in insync.
054: *
055: * <p>
056: * Element for <table> elements. We need some extra state here to
057: * be able to automatically handle CSS styling of tables missing tbody
058: * elements.
059: * The problem is that a html document like this:
060: * <pre>
061: * <style>tbody {background: red}</style>
062: * <table><tr><td>Hello</td></tr></table>
063: * </pre>
064: * should have a red background. That's because a <tbody> element should
065: * "automatically" be inserted in the table. I first tried an approach
066: * where I actually inserted <tbody> elements during the parse, but
067: * this didn't work right -- doing insertBefore calls during Xerces parse
068: * caused the structure of the document to be wrong because it doesn't
069: * seem to look at the return value from insertBefore. So I then changed
070: * the code to try to "patch up" the table during the box creation phase;
071: * this had the problem that the screen would refresh multiple times since
072: * layout would be invalidated while rendering the page (table has changed)
073: * and besides, I would have to acquire a write lock since I was modifying
074: * the source dom (except for JSF-rendered tables in DocumentFragments);
075: * and each write unlock would cause a flush, so documents with multiple
076: * tables would cause multiple flushes. I then switched to a write lock
077: * for the entire phase -- but this was getting to be a big ugly solution.
078: * </p>
079: * <p>
080: * So I instead went for the following scheme:
081: * When a <table> element is created, create a special subclass of
082: * RaveElement for it. This subclass tracks the "tbody" child, if any.
083: * On insert, any <tr> elements inserted directly on the table are put
084: * in a "secret" tbody element. The tbody element is secret in that it
085: * is not added to the DOM itself, but it is however linked stylewise
086: * via the setStyleParent, such that my modified Batik CSS parser will
087: * follow the style parent link for the <tr> to jump to the <tbody> first,
088: * then the <table>, instead of directly to the <table>. This will cause
089: * the (unconnected) <tbody> element to be styled too, and as a result,
090: * the proper CSS inheritance and treatment of the <tbody> tag works.
091: * </p>
092: *
093: * @author Tor Norbye
094: */
095: class RaveTableElement extends RaveElement {
096:
097: /**
098: *
099: */
100: private static final long serialVersionUID = 3257003272006154552L;
101:
102: // private RaveElement tbody;
103: // private RaveSourceElement tbody;
104: private Element tbody;
105:
106: public RaveTableElement(CoreDocumentImpl ownerDocument,
107: String namespaceURI, String qualifiedName)
108: throws DOMException {
109: super (ownerDocument, namespaceURI, qualifiedName);
110: }
111:
112: public Node insertBefore(Node newChild, Node refChild) {
113: if (newChild.getNodeType() == Node.ELEMENT_NODE) {
114: // The table spec requires us to insert a tbody between
115: // a table and a tr
116: // RaveElement xel = (RaveElement)newChild;
117: // RaveSourceElement xel = (RaveSourceElement)newChild;
118: Element xel = (Element) newChild;
119: String tag = xel.getTagName();
120: // TODO -- should be using CSS instead here....
121: // Css.getComputedStyle(element, XhtmlCss.DISPLAY_INDEX) == CssValueConstants.TABLE_ROW_GROUP_VALUE) {
122: if (tag.equals(HtmlTag.TBODY.name)) {
123: tbody = xel;
124: } else if (!(tag.equals(HtmlTag.TFOOT.name)
125: || tag.equals(HtmlTag.THEAD.name) || tag
126: .equals(HtmlTag.CAPTION.name))) {
127: if (tbody == null) {
128: // Let's say the user has a table with multiple rows
129: // that aren't inside a tbody, but also contains a tbody
130: // further down. It would be nice if we could associate
131: // these tr's with the "existing" tbody instead; afterall,
132: // it could have custom-styles applied to it.
133: // However, we can't do that here, since insertBefore
134: // is called during the parse, and the tbody hasn't been
135: // seen yet. I'm going to punt on this issue for now.
136: // But I'm stashing the tbody element away when I see
137: // it such that I can at least associate later tr's with
138: // it.
139: // tbody = (RaveElement)getOwnerDocument().createElement(HtmlTag.TBODY.name);
140: tbody = getOwnerDocument().createElement(
141: HtmlTag.TBODY.name);
142: ((CSSEngine.StyleElementLink) tbody)
143: .setStyleParent(this );
144: }
145: ((CSSEngine.StyleElementLink) xel)
146: .setStyleParent((CSSStylableElement) tbody);
147: }
148: }
149: return super .insertBefore(newChild, refChild);
150: }
151:
152: /** Return the tbody element for the table. This may be null
153: * if the table has no rows. It may also be an element that is
154: * not actually in the DOM, if the table didn't actually include a
155: * tbody element.
156: */
157: // public RaveSourceElement getTbody() {
158: public Element getTbody() {
159: return tbody;
160: }
161:
162: // XXX Batik
163: @Override
164: public void setComputedStyleMap(String pseudoElement, StyleMap sm) {
165: super .setComputedStyleMap(pseudoElement, sm);
166:
167: if (sm == null && tbody instanceof CSSStylableElement) {
168: // XXX #115932 Also clear the tbody element.
169: // The issue is that the tbody might not be a child of the table element(!??)
170: // See above insertBefore hack.
171: ((CSSStylableElement) tbody).setComputedStyleMap(
172: pseudoElement, sm);
173: }
174: }
175:
176: }
|