Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/utils/BodyHelper.java')
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/utils/BodyHelper.java327
1 files changed, 327 insertions, 0 deletions
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/utils/BodyHelper.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/utils/BodyHelper.java
new file mode 100644
index 000000000..ba0cf0a65
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/utils/BodyHelper.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Sybase, Inc. and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sybase, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jst.pagedesigner.utils;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import javax.xml.namespace.QName;
+
+import org.eclipse.jst.pagedesigner.IJMTConstants;
+import org.eclipse.jst.pagedesigner.adapters.IBodyInfo;
+import org.eclipse.jst.pagedesigner.adapters.internal.BodyInfo;
+import org.eclipse.jst.pagedesigner.dom.DOMPosition;
+import org.eclipse.jst.pagedesigner.dom.DOMRefPosition;
+import org.eclipse.jst.pagedesigner.dom.DOMRefPosition2;
+import org.eclipse.jst.pagedesigner.dom.IDOMPosition;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMText;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * This class helps location insertion position to inside correct body or doc
+ * prefix. NOTE: this class only doing limited support on doc level position
+ * validation. Element specific position validation will be done in other
+ * places.
+ *
+ * @author mengbo
+ */
+public class BodyHelper {
+ // bit flags used for child skipping.
+ public static final int EMPTY_TEXT = 1;
+
+ public static final int COMMENT = 2;
+
+ public static final int HEADER = 3;
+
+ /**
+ *
+ * @param child
+ * @return
+ */
+ private static boolean isSkippableChild(Node parent, Node child, int flag) {
+ if ((flag & COMMENT) != 0 && child.getNodeType() == Node.COMMENT_NODE)
+ return true;
+ if ((flag & EMPTY_TEXT) != 0 && child instanceof IDOMText
+ && ((IDOMText) child).isElementContentWhitespace())
+ return true;
+
+ if ((flag & HEADER) != 0 && child.getNodeType() == Node.ELEMENT_NODE) {
+ String uri = CMUtil.getElementNamespaceURI((Element) child);
+ IBodyInfo parentInfo = getBodyInfo((IDOMNode) parent);
+ if (parentInfo != null
+ && parentInfo.isBodyHeader((IDOMNode) parent, uri,
+ ((Element) child).getLocalName()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * check whether uri/tag should be header of any body container that is
+ * ancester of the start node.
+ *
+ * @param start
+ * @param uri
+ * @param tag
+ * @return
+ */
+ public static IDOMNode findHeaderContainer(IDOMNode start, String uri,
+ String tag) {
+ while (start != null) {
+ IBodyInfo designInfo = getBodyInfo(start);
+ if (designInfo != null && designInfo.isBodyContainer(start)) {
+ if (designInfo.isBodyHeader(start, uri, tag))
+ return start;
+ }
+ start = (IDOMNode) start.getParentNode();
+ }
+ return null;
+ }
+
+ /**
+ * find the closest body insertion point, to make it as deep as possible.
+ * (Move into as more body as possible)
+ *
+ * @param parent
+ * @param start
+ */
+ public static IDOMPosition findBodyInsertLocation(IDOMPosition position) {
+ // forward first.
+ Node reference = position.getNextSiblingNode();
+ Node container = position.getContainerNode();
+ while (reference != null) {
+ IBodyInfo info = getBodyInfo((IDOMNode) reference);
+ if (info != null && info.isBodyContainer((IDOMNode) reference)) {
+ // good, we find a body!
+ position = new DOMPosition(reference, 0);
+ return findBodyInsertLocation(position);
+ }
+ if (isSkippableChild(container, reference, EMPTY_TEXT | COMMENT
+ | HEADER)) {
+ reference = reference.getNextSibling();
+ continue;
+ } else
+ break;
+ }
+
+ // backward
+ reference = position.getPreviousSiblingNode();
+ while (reference != null) {
+ IBodyInfo info = getBodyInfo((IDOMNode) reference);
+ if (info != null && info.isBodyContainer((IDOMNode) reference)) {
+ // good, we find a body!
+ position = new DOMPosition(reference, reference.getChildNodes()
+ .getLength());
+ return findBodyInsertLocation(position);
+ }
+ // XXX: not skip header here. So if there is some header with wrong
+ // location, we will respect user.
+ if (isSkippableChild(container, reference, EMPTY_TEXT | COMMENT)) {
+ reference = reference.getPreviousSibling();
+ continue;
+ } else
+ break;
+ }
+
+ // not find any body at same level as the insertion point.
+ return position;
+ }
+
+ /**
+ * The element type identifiered by "uri" and "tag" is going to be inserted
+ * into the document. This method is used to adjust the insert position so
+ * it can be put into correct body or header section.
+ *
+ * @param parent
+ * @param reference
+ */
+ public static IDOMPosition adjustInsertPosition(String uri, String tag,
+ IDOMPosition position) {
+ IDOMNode parent = (IDOMNode) position.getContainerNode();
+ IBodyInfo designInfo = getBodyInfo(parent);
+ if (designInfo == null) {
+ return position; // should not happen.
+ }
+
+ IDOMNode headerContainer = findHeaderContainer(parent, uri, tag);
+
+ if (headerContainer == null) {
+ // the new node is not header.
+ if (shouldIgnoreAdjust(uri, tag)) {
+ return position;
+ }
+
+ // new node is not body header. So should inside the inner most
+ // body.
+ if (!designInfo.isBodyContainer(parent)) {
+ return position; // it's parent is not body, so we suggest
+ // it's parent already correctly located, and respect user's
+ // choice.
+ }
+
+ // ok, we are inside some body, but we don't know whether we are in
+ // the inner most body.
+ // try to find a body container at same level and see whether we can
+ // move into that body.
+ return findBodyInsertLocation(position);
+ } else {
+ // good, we find a body container and the new node should be header
+ // of it.
+ Node child = headerContainer.getFirstChild();
+ Node refNode = position.getNextSiblingNode();
+ // if parent is different from headerContainer, then
+ // child!=referenceHolder[0] will always be true
+ while (child != null) // && child != refNode)
+ {
+ Comparator comp = NodeLocationComparator.getInstance();
+ // Currently the comparator deels with tags like taglib and
+ // loadbundle particularly, comparasion result 0
+ // means it didn't compare the tags.
+ if (comp.compare(child, tag) < 0
+ || (comp.compare(child, tag) == 0 && isSkippableChild(
+ headerContainer, child, COMMENT | EMPTY_TEXT
+ | HEADER))) {
+ child = child.getNextSibling();
+ } else {
+ break;
+ }
+ }
+ if (child != null) {
+ return new DOMRefPosition(child, false);
+ } else {
+ return new DOMPosition(parent, parent.getChildNodes()
+ .getLength());
+ }
+ // parentHolder[0] = headerContainer;
+ // referenceHolder[0] = child;
+ // return;
+ }
+ }
+
+ /**
+ * Find the position to insert a header element into the specified parent.
+ *
+ * @param uri
+ * @param tag
+ * @param parent
+ */
+ public static void findHeaderInsertPosition(String uri, String tag,
+ Node parent, Node[] ref) {
+ Node child = parent.getFirstChild();
+ while (child != null) {
+ Comparator comp = NodeLocationComparator.getInstance();
+ if (comp.compare(child, tag) < 0
+ || (comp.compare(child, tag) == 0 && isSkippableChild(
+ parent, child, COMMENT | EMPTY_TEXT | HEADER))) {
+ child = child.getNextSibling();
+ } else {
+ break;
+ }
+ }
+ ref[0] = child;
+ return;
+ }
+
+ public static IDOMPosition insertBody(IDOMPosition position, QName body,
+ String defaultPrefix) {
+ IBodyInfo bodyInfo = getBodyInfo((IDOMNode) position.getContainerNode());
+
+ Node node = position.getContainerNode();
+ Node originalContainer = node;
+ Node nextSibling = position.getNextSiblingNode();
+
+ // create the body element first.
+ Document ownerDoc;
+ if (node instanceof Document) {
+ ownerDoc = (Document) node;
+ } else {
+ ownerDoc = node.getOwnerDocument();
+ }
+ if (ownerDoc == null) {
+ return null; // should not happen
+ }
+
+ String prefix = JSPUtil.getOrCreatePrefix(((IDOMNode) node).getModel(),
+ body.getNamespaceURI(), defaultPrefix);
+ Element ele = ownerDoc.createElement((prefix == null ? ""
+ : (prefix + ":"))
+ + body.getLocalPart());
+
+ // need to find out the insertion point
+ while (node instanceof IDOMNode) {
+ if (bodyInfo.isBodyContainer((IDOMNode) node)) {
+ // ok, node is a body container.
+ // we could create the new node as child of node and move all
+ // node's none header children
+ // as children of the new node.
+
+ NodeList nl = node.getChildNodes();
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node child = (Node) nl.item(i);
+ if (isSkippableChild(node, child, HEADER | COMMENT
+ | EMPTY_TEXT)) {
+ continue;
+ }
+ list.add(nl.item(i));
+ }
+ for (int i = 0; i < list.size(); i++) {
+ ele.appendChild((Node) list.get(i));
+ }
+ node.appendChild(ele);
+
+ if (node == originalContainer) {
+ if (nextSibling == null) {
+ return new DOMRefPosition2(ele, true);
+ } else if (nextSibling.getParentNode() == ele) {
+ // next sibling is not in header part
+ return new DOMRefPosition(nextSibling, false);
+ } else {
+ return new DOMPosition(ele, 0);
+ }
+ } else {
+ return position;
+ }
+ }
+ node = node.getParentNode();
+ }
+ // should not happen, because document and documentfragment node will
+ // always be body node
+ // so if reach here, means the position is not in document.
+ return null;
+ }
+
+ /**
+ * For certain special tags, do not following the "header"/"body" separation
+ * and can't fit into the relocation process.
+ *
+ * @param uri
+ * @param tag
+ * @return
+ */
+ public static boolean shouldIgnoreAdjust(String uri, String tag) {
+ // FIXME:
+ return (IJMTConstants.URI_HTML.equals(uri) && "script"
+ .equalsIgnoreCase(tag))
+ || (IJMTConstants.URI_JSP.equals(uri));
+ }
+
+ public static IBodyInfo getBodyInfo(IDOMNode node) {
+ // TODO: in the future, when bodyinfo is no longer singleton, we'll use
+ // adapter mechanism.
+ return BodyInfo.getInstance();
+ }
+}

Back to the top