blob: d0e77f82b2d4543b2311619273a470badcb0664c [file] [log] [blame]
/*******************************************************************************
* 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.dom;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.gef.EditPart;
import org.eclipse.jst.pagedesigner.parts.NodeEditPart;
import org.eclipse.jst.pagedesigner.parts.TextEditPart;
import org.eclipse.jst.pagedesigner.utils.HTMLUtil;
import org.eclipse.jst.pagedesigner.viewer.DesignPosition;
import org.eclipse.jst.pagedesigner.viewer.DesignRefPosition;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
/**
* @author mengbo
*/
public class DOMPositionHelper {
/**
* @param position
* @return the design position
*/
public static DesignPosition toDesignRefPosition(DOMRefPosition position) {
Node node = position.getReferenceNode();
do {
IDOMNode container = (IDOMNode) node.getParentNode();
EditPart part = (EditPart) container.getAdapterFor(EditPart.class);
if (part != null) {
// XXX: what if the node has not corresponding part?
EditPart child = DOMPositionHelper.findEditPart(part, node);
if (child != null) {
return new DesignRefPosition(child, position.isForward());
}
return DesignPosition.INVALID;
}
node = node.getParentNode();
} while (true);
}
/**
*
* @param position
* if it is null, then will return null
* @return null if position is null or invalid.
*/
public static DesignPosition toDesignPosition(IDOMPosition position) {
if (position == null) {
return null;
}
if (position instanceof DOMRefPosition) {
return toDesignRefPosition((DOMRefPosition) position);
}
do {
IDOMNode container = (IDOMNode) position.getContainerNode();
EditPart part = (EditPart) container.getAdapterFor(EditPart.class);
if (part != null) {
if (container instanceof Text) {
String textData = ((Text) container).getData();
String displayData = ((TextEditPart) part).getTextData();
return new DesignPosition(part,
textDataOffsetToDisplayOffset(textData,
displayData, position.getOffset()));
}
Node pre = position.getPreviousSiblingNode();
while (pre != null) {
int index = findChildEditPartIndex(part, pre);
if (index != -1) {
return new DesignPosition(part, index + 1);
}
pre = pre.getPreviousSibling();
}
return new DesignPosition(part, 0);
}
position = new DOMRefPosition(position.getContainerNode(),
false);
} while (true);
}
/**
* Here is the position is not currect, currently it will returns invalid
* pos.
*
* @param position
* @return the design position
*/
public static DesignPosition toDesignPosition1(IDOMPosition position) {
if (position instanceof DOMRefPosition) {
return toDesignRefPosition((DOMRefPosition) position);
}
do {
IDOMNode container = (IDOMNode) position.getContainerNode();
EditPart part = (EditPart) container.getAdapterFor(EditPart.class);
if (part != null) {
if (container instanceof Text) {
String textData = ((Text) container).getData();
String displayData = ((TextEditPart) part).getTextData();
return new DesignPosition(part,
textDataOffsetToDisplayOffset(textData,
displayData, position.getOffset()));
}
Node pre = position.getPreviousSiblingNode();
while (pre != null) {
int index = findChildEditPartIndex(part, pre);
if (index != -1) {
return new DesignPosition(part, index + 1);
}
pre = pre.getPreviousSibling();
}
return new DesignPosition(part, 0);
}
return DesignPosition.INVALID;
} while (true);
}
static int findChildEditPartIndex(EditPart parent, Node node) {
List children = parent.getChildren();
for (int i = 0; i < children.size(); i++) {
if (((EditPart) children.get(i)).getModel() == node) {
return i;
}
}
return -1;
}
static EditPart findEditPart(EditPart parent, Node node) {
List children = parent.getChildren();
EditPart part;
for (int i = 0; i < children.size(); i++) {
if ((part = (EditPart) children.get(i)).getModel() == node) {
return part;
}
}
return null;
}
/**
* convert a DesignPosition into DOMPosition.
*
* @param position
* @return the dom position
*/
public static IDOMPosition toDOMRefPosition(DesignRefPosition position) {
// ok, it is not text.
EditPart sibling = position.getRefPart();
if (sibling != null) {
return new DOMRefPosition((Node) sibling.getModel(), position
.caretIsAtRight());
}
// should never happens
Assert.isTrue(false);
return null;
}
/**
* convert a DesignPosition into DOMPosition.
*
* @param position
* @return the dom position
*/
public static IDOMPosition toDOMPosition(DesignPosition position) {
if (!EditValidateUtil.validPosition(position)) {
return null;
} else if (position instanceof DesignRefPosition) {
return toDOMRefPosition((DesignRefPosition) position);
}
EditPart part = position.getContainerPart();
if (part instanceof TextEditPart) {
Text text = (Text) ((TextEditPart) part).getIDOMNode();
int offset = position.getOffset();
if (offset == 0) {
return new DOMPosition(text, 0);
}
String displayData = ((TextEditPart) part).getTextData();
String nodeData = text.getData();
if (offset >= displayData.length()) {
// point to end of the text node.
return new DOMPosition(text, nodeData.length());
}
// we need to calculate it out.
int index = displayOffsetToTextDataOffset(displayData,
nodeData, offset);
return new DOMPosition(text, index);
}
// ok, it is not text.
EditPart sibling = position.getSiblingEditPart(true);
if (sibling instanceof NodeEditPart) {
return new DOMRefPosition(((NodeEditPart) sibling).getDOMNode(), false);
}
sibling = position.getSiblingEditPart(false);
if (sibling instanceof NodeEditPart) {
return new DOMRefPosition(((NodeEditPart) sibling).getDOMNode(), true);
}
// no previous sibling, no next sibling, the parent node must be
// empty
return new DOMPosition(((NodeEditPart) part).getDOMNode(), 0);
}
/**
* if "position" is inside a text node, then split the text node and return
* a new IDOMPosition semantically equal to the position in the two
* splitted text. If the "position" is not a text position, then no action
* will be taken and will return the original position.
*
* @param position
* @return IDOMPosition
*/
public static IDOMPosition splitText(IDOMPosition position) {
Node container = position.getContainerNode();
if (container instanceof Text) {
int offset = position.getOffset();
if (offset <= 0) {
// at beginning of text node. no need to split
return new DOMRefPosition(container, false);
}
String textData = ((Text) container).getData();
if (offset >= textData.length()) {
// at end of text node. no need to split
return new DOMRefPosition(container, true);
}
// ok, we need split
((Text) container).splitText(offset);
return new DOMRefPosition(container, true);
}
return position;
}
/**
* Remove all the content in the range. And return the new position.
*
* @param range
* @return the dom position
*/
public static IDOMPosition removeRange(DOMRange range) {
boolean ordered = range.isOrdered();
// IDOMPosition start = ordered ? range.getStartPosition() : range
// .getEndPosition();
IDOMPosition end = ordered ? range.getEndPosition() : range
.getStartPosition();
// FIXME: Not DONE:
return end;
}
/**
* try to merge the position in adjacent text node (if it is not already in)
*
* @param position
* @return the dom position
*/
public static IDOMPosition mergeIntoText(IDOMPosition position) {
if (position.getContainerNode() instanceof Text)
return position;
Node pre = position.getPreviousSiblingNode();
if (pre instanceof Text) {
return new DOMPosition(pre, ((Text) pre).getData().length());
}
Node after = position.getNextSiblingNode();
if (after instanceof Text) {
return new DOMPosition(after, 0);
}
return position;
}
/**
* @param displayData
* @param nodeData
* @param offset
* @return the offset
*/
// FIXME: this method is still buggy
public static int displayOffsetToTextDataOffset(String displayData,
String nodeData, int offset) {
char[] display = displayData.toCharArray();
if (offset >= display.length) {
// offset is already at end
return nodeData.length();
}
char[] node = nodeData.toCharArray();
int nodeDataLength = node.length;
int displayIndex = 0;
int nodeIndex = 0;
while (displayIndex < offset && nodeIndex < nodeDataLength) {
if (display[displayIndex] == node[nodeIndex]) {
displayIndex++;
nodeIndex++;
continue;
}
if (HTMLUtil.isHTMLWhitespace(node[nodeIndex])) {
if (HTMLUtil.isHTMLWhitespace(display[displayIndex])) {
displayIndex++;
nodeIndex++;
} else {
nodeIndex++;
}
continue;
}
// should not happen!
displayIndex++;
nodeIndex++;
}
if (nodeIndex >= nodeDataLength)
return nodeDataLength;
// else means displayIndex == offset
// since we already checked that offset < displayLength, so we can get
// the next char
if (display[offset] != ' ') {
// we may need to skip whitespaces after nodeIndex
while (nodeIndex < nodeDataLength
&& HTMLUtil.isHTMLWhitespace(node[nodeIndex])) {
nodeIndex++;
}
}
return nodeIndex;
}
/**
* @param nodeData
* @param displayData
* @param offset
* @return the offset
*/
// FIXME: this method is still buggy
public static int textDataOffsetToDisplayOffset(String nodeData,
String displayData, int offset) {
if (offset >= nodeData.length()) {
return displayData.length();
}
char[] node = nodeData.toCharArray();
char[] display = displayData.toCharArray();
int displayIndex = 0;
int nodeIndex = 0;
int displayDataLength = display.length;
while (nodeIndex < offset && displayIndex < displayDataLength) {
if (display[displayIndex] == node[nodeIndex]) {
displayIndex++;
nodeIndex++;
continue;
}
if (HTMLUtil.isHTMLWhitespace(node[nodeIndex])) {
if (HTMLUtil.isHTMLWhitespace(display[displayIndex])) {
displayIndex++;
nodeIndex++;
} else {
nodeIndex++;
}
continue;
}
// should not happen!
displayIndex++;
nodeIndex++;
}
return displayIndex;
}
/**
* Convert a IDOMPosition to IDOMRefPosition. If can't convert to
* IDOMRefPosition, will return the original one.
*
* @param position
* @return IDOMPosition
*/
public static IDOMPosition toDOMRefPosition(IDOMPosition position) {
if (position.isText()) {
return position; // can't convert Text node.
}
if (position instanceof IDOMRefPosition) {
return position;
}
if (position.getNextSiblingNode() != null) {
return new DOMRefPosition(position.getNextSiblingNode(), false);
}
if (position.getPreviousSiblingNode() != null) {
return new DOMRefPosition(position.getPreviousSiblingNode(), true);
}
return new DOMRefPosition2(position.getContainerNode(), true);
}
}