1 /*******************************************************************************
\r
2 * Copyright (c) 2006 Sybase, Inc. and others.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Sybase, Inc. - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.eclipse.jst.pagedesigner.dom;
\r
14 import org.eclipse.jst.jsf.common.ui.internal.logging.Logger;
\r
15 import org.eclipse.jst.pagedesigner.IHTMLConstants;
\r
16 import org.eclipse.jst.pagedesigner.PDPlugin;
\r
17 import org.eclipse.jst.pagedesigner.utils.HTMLUtil;
\r
18 import org.eclipse.jst.pagedesigner.validation.caret.IMovementMediator;
\r
19 import org.eclipse.jst.pagedesigner.validation.caret.Target;
\r
20 import org.w3c.dom.Node;
\r
21 import org.w3c.dom.Text;
\r
22 import org.w3c.dom.traversal.NodeIterator;
\r
27 public class CaretMoveIterator {
\r
28 private final static Logger _log = PDPlugin
\r
29 .getLogger(CaretMoveIterator.class);
\r
31 private final boolean INNER_DEBUG = false;
\r
33 private NodeIterator _nodeIterator;
\r
35 private IMovementMediator _validator;
\r
37 private IDOMPosition _currentPosition;
\r
39 private boolean _forward;
\r
42 * @param nodeIterator
\r
47 public CaretMoveIterator(NodeIterator nodeIterator,
\r
48 IMovementMediator validator, IDOMPosition position, boolean forward) {
\r
50 _nodeIterator = nodeIterator;
\r
51 _validator = validator;
\r
52 _currentPosition = position;
\r
57 * @return the node iterator
\r
59 public NodeIterator getNodeIterator() {
\r
60 return _nodeIterator;
\r
64 * @return Returns the _currentPosition.
\r
66 public IDOMPosition getCurrentPosition() {
\r
67 return _currentPosition;
\r
72 * The _currentPosition to set.
\r
74 public void setCurrentPosition(IDOMPosition position) {
\r
75 _currentPosition = position;
\r
78 // assume the currentPosition is invalid
\r
79 private IDOMPosition moveOut(Node container) {
\r
80 IDOMPosition result = new DOMRefPosition(container, _forward);
\r
81 String name = container.getNodeName();
\r
83 && EditModelQuery.HTML_STYLE_NODES.contains(name.toLowerCase())) {
\r
84 result = moveToNextPosition(result, _validator);
\r
91 * @return the dom position
\r
93 public IDOMPosition moveIn(Node node) {
\r
94 IDOMPosition result = null;
\r
96 _log.info("- Move into: " + node.getLocalName()); //$NON-NLS-1$
\r
98 if (_validator.isEditable(new Target(node))) {
\r
100 // Transparent text is not editable, so this is not transparent.
\r
101 if (EditModelQuery.isText(node)) {
\r
102 index = (_forward) ? 0 : ((Text) node).getData().length();
\r
103 result = new DOMPosition(node, index);
\r
104 // move ahead one pos.
\r
105 IDOMPosition pos = getNextTextPosition(result);
\r
110 if (node.hasChildNodes()) {
\r
111 index = _forward ? 0 : node.getChildNodes().getLength();
\r
112 result = new DOMPosition(node, index); // DOMRefPosition(next,
\r
115 result = new DOMPosition(node, 0);
\r
119 if (node.hasChildNodes()) {
\r
120 Node child = _forward ? node.getFirstChild() : node
\r
122 result = new DOMRefPosition(child, _forward);
\r
123 while (child != null) {
\r
124 if (_validator.allowsMoveIn(new Target(child))) {
\r
125 result = moveIn(child);
\r
128 child = _forward ? child.getNextSibling() : child
\r
129 .getPreviousSibling();
\r
132 // Should be impposible to reach here.
\r
133 result = new DOMPosition(node, 0);
\r
139 private IDOMPosition getNextTextPosition(IDOMPosition position) {
\r
140 IDOMPosition result = null;
\r
141 String value = position.getContainerNode().getNodeValue();
\r
142 int i = position.getOffset();
\r
144 if (i < value.length()) {
\r
145 if (HTMLUtil.isHTMLWhitespace(value.charAt(i))) {
\r
146 while (i < value.length()
\r
147 && HTMLUtil.isHTMLWhitespace(value.charAt(i))) {
\r
150 result = new DOMPosition(position.getContainerNode(), i);
\r
151 } else if (i < value.length()) {
\r
152 result = new DOMPosition(position.getContainerNode(), i + 1);
\r
157 if (HTMLUtil.isHTMLWhitespace(value.charAt(i - 1))) {
\r
159 && HTMLUtil.isHTMLWhitespace(value.charAt(i - 1))) {
\r
162 result = new DOMPosition(position.getContainerNode(), i);
\r
163 } else if (i > 0) {
\r
164 result = new DOMPosition(position.getContainerNode(), i - 1);
\r
172 * Assume the original position are valid.
\r
177 * @param referenceImediatly
\r
180 private IDOMPosition moveToNextPosition(IDOMPosition position,
\r
181 IMovementMediator validator) {
\r
182 IDOMPosition currentPosition = null;
\r
183 if (validator.isValidPosition(position) && position.isText()) {
\r
184 currentPosition = getNextTextPosition(position);
\r
186 if (currentPosition == null) {
\r
187 Node nextNode = EditModelQuery.getInstance().getSibling(position,
\r
189 while (EditModelQuery.isText(nextNode)
\r
190 && ((Text) nextNode).getData().length() == 0) {
\r
191 nextNode = EditModelQuery.getInstance().getSibling(nextNode,
\r
194 if (nextNode != null) {
\r
196 if (validator.allowsMoveIn(new Target(nextNode))) {
\r
197 currentPosition = moveIn(nextNode);
\r
198 // Stop when it is in table. For others we continue search
\r
200 if (!canStopHere(nextNode) && //
\r
201 EditModelQuery.getInstance().getSibling(
\r
202 currentPosition, _forward) != null) {
\r
203 currentPosition = moveToNextPosition(currentPosition,
\r
207 // not allowed to move in. e.g. it's empty string.
\r
209 currentPosition = new DOMRefPosition(nextNode, _forward);// skip(position);
\r
212 if (validator.allowsMoveOut(new Target(
\r
213 getNaviContainer(position)))) {
\r
214 currentPosition = moveOut(getNaviContainer(position));
\r
218 currentPosition = EditHelper.ensureDOMPosition(currentPosition);
\r
219 if (currentPosition != null
\r
220 && !validator.isValidPosition(currentPosition)) {
\r
221 currentPosition = moveToNextPosition(currentPosition, validator);
\r
223 return currentPosition;
\r
227 * When the tag starts from new line, or in table, then caret can be put at
\r
233 private boolean canStopHere(Node node) {
\r
234 boolean result = false;
\r
235 if (EditModelQuery.isText(node)) {
\r
237 } else if (node != null && node.getNodeName() != null) {
\r
238 result |= node.getNodeName().equals(IHTMLConstants.TAG_TD);
\r
239 result |= EditModelQuery.isBlockNode(node);
\r
245 * Move operation position to next edit position. We may need rule to valid
\r
246 * it based on operation ID and direction. We need to pack transparent
\r
249 * @param currentPosition
\r
252 * @return the dom position
\r
254 public IDOMPosition moveToNextEditPosition(IDOMPosition currentPosition,
\r
255 boolean forward, IMovementMediator validator) {
\r
256 IDOMPosition result = null;
\r
257 if ((currentPosition = moveToNextPosition(currentPosition, validator)) != null) {
\r
258 result = currentPosition;
\r
260 result = _currentPosition;
\r
265 private Node getNaviContainer(IDOMPosition position) {
\r
266 if (position.isText()) {
\r
267 return position.getContainerNode().getParentNode();
\r
269 return position.getContainerNode();
\r