Package org.eclipse.jst.pagedesigner.dom

Source Code of org.eclipse.jst.pagedesigner.dom.EditHelper

/*******************************************************************************
* 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 java.util.Stack;

import org.eclipse.core.runtime.Assert;
import org.eclipse.gef.EditPart;
import org.eclipse.jst.pagedesigner.IHTMLConstants;
import org.eclipse.jst.pagedesigner.commands.range.WorkNode;
import org.eclipse.jst.pagedesigner.parts.TextEditPart;
import org.eclipse.jst.pagedesigner.utils.HTMLUtil;
import org.eclipse.jst.pagedesigner.validation.caret.ActionData;
import org.eclipse.jst.pagedesigner.validation.caret.IMovementMediator;
import org.eclipse.jst.pagedesigner.validation.caret.InlineEditingNavigationMediator;
import org.eclipse.jst.pagedesigner.viewer.DesignPosition;
import org.eclipse.jst.pagedesigner.viewer.DesignRefPosition;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
* @author mengbo
*/
public class EditHelper {
//  public final static boolean INNER_DEBUG = false;

  private final static int OUT_OF_LEFT = 1;

  private final static int LEFT_NAME = 2;

  /**
   * indicates a position in the middle
   */
  public final static int IN_MIDDLE = 3;

  private final static int RIGHT_NAME = 4;

  private final static int OUT_OF_RIGHT = 5;

  private static final EditHelper _instance = new EditHelper();

  //private static Logger _log = PDPlugin.getLogger(EditHelper.class);

  private EditHelper() {
        //  no external instantiation
  }

  /**
   * Move operation position in front of next non-blank and non-transparent
   * char. The caller should ensure position's container node is not
   * transparent text node.
   *
   * @param position
   * @param forward
   * @param forEmpty
   * @return the offset
   */
  public int getTextNextOffset(IDOMPosition position, boolean forward,
      boolean forEmpty) {
    EditValidateUtil.validPosition(position);
    Assert.isTrue(!EditModelQuery.isTransparentText(position
        .getContainerNode()));
    Text text = (Text) position.getContainerNode();
    int offset = position.getOffset();
    String data = text.getNodeValue();
    if (forward) {
      while (offset < data.length()
          && HTMLUtil.isHTMLWhitespace(data.charAt(offset))) {
        offset++;
      }
    } else {
      while (offset > 0
          && HTMLUtil.isHTMLWhitespace(data.charAt(offset - 1))) {
        offset--;
      }
    }
    return offset;

  }

  /**
   * @return the singleton instance
   */
  public static EditHelper getInstance() {
    return _instance;
  }

  /**
   * This caret from current operation position to next position, this method
   * will convert DesignPosition in to DOMPosition, then call dom function to
   * move dom position. Here we might insert some complex rules to see whether
   * move is valid.
   *
   * @param action
   * @param currentPosition
   * @param forward
   * @return the dom position
   */
  public static DesignPosition moveToNextEditPosition(int action,
      DesignPosition currentPosition, boolean forward) {
    IDOMPosition position;
    position = DOMPositionHelper.toDOMPosition(currentPosition);
    position = moveToNextEditPosition(position, forward,
        new InlineEditingNavigationMediator(
            new ActionData(action, null)));
    if (position == null) {
      return currentPosition;
    }

    EditValidateUtil.validPosition(position);
    return DOMPositionHelper.toDesignPosition(position);
  }

  /**
   * Move operation position to next edit position. We may need rule to valid
   * it based on operation ID and direction. We need to pack transparent
   * string.
   *
   * @param currentPosition
   * @param forward
   * @param validator
   * @return the dom position
   */
  public static IDOMPosition moveToNextEditPosition(
      IDOMPosition currentPosition, boolean forward,
      IMovementMediator validator) {
    IDOMPosition result = null;
    CaretMoveIterator moveIterator = new CaretMoveIterator(null, validator,
        currentPosition, forward);
    if ((result = moveIterator.moveToNextEditPosition(currentPosition,
        forward, validator)) == null) {
      result = currentPosition;
    }
    return result;
  }

  /**
   * Delete a node, in case it is 'body' or 'html', it won't perform delete.
   *
   * @param node
   * @return the node
   */
  public static Node deleteNode(Node node) {
    if (node == null || node.getNodeName() == null) {
      return null;
    }
    String name = node.getLocalName();

    if (name != null
        && (name.equalsIgnoreCase(IHTMLConstants.TAG_BODY)
            || name.equalsIgnoreCase(IHTMLConstants.TAG_HEAD)
            || name.equalsIgnoreCase(IHTMLConstants.TAG_HTML))) {
      return null;
    }
    Node parent = node.getParentNode();
    name = parent.getNodeName();
    if (parent != null
        && name != null
        && parent.getNodeName().equalsIgnoreCase(
            IHTMLConstants.TAG_HEAD)) {
      return null;
    }
    return parent.removeChild(node);
  }

  /**
   * Order the IDOMPositions in a range in ascending order.
   *
   * @param range
   * @return the dom range
   */
  public static DOMRange normal(DOMRange range) {
    EditValidateUtil.validRange(range);
    IDOMPosition p1 = range.getStartPosition();
    IDOMPosition p2 = range.getEndPosition();
    if (EditModelQuery.getIndexedRegionLocation(p1) > EditModelQuery
        .getIndexedRegionLocation(p2)) {
      return new DOMRange(p2, p1);
    }
        return range;
  }

  /**
   * Move position in to node from its outside, the node should be breakble.
   *
   * @param node
   * @param validator
   * @param forward
   * @return the dom position
   */
  public static IDOMPosition moveInto(Node node, IMovementMediator validator,
      boolean forward) {
    CaretMoveIterator moveIterator = new CaretMoveIterator(null, validator,
        new DOMRefPosition(node, !forward), forward);
    return moveIterator.moveIn(node);
  }

  /**
   * Convert a DomRefPosition into DOMPosition.
   *
   * @param position
   * @return the dom position
   */
  public static IDOMPosition ensureDOMPosition(IDOMPosition position) {
    if (position instanceof DOMRefPosition) {
      return new DOMPosition(position.getContainerNode(), position
          .getOffset());
    }
    return position;
  }

  /**
   * @param currentNode
   * @param pos1
   * @param pos2
   * @param top
   * @param workNode
   */
  public void processText(Text currentNode, final int pos1, final int pos2,
      Node top, Stack workNode) {
    // the text could be tranparent, or 0 length.
    Assert.isTrue(pos1 <= pos2);
    if (pos1 == pos2) {
      return;
    }
    // int left = EditModelQuery.getNodeStartIndex(currentNode);
    // int right = EditModelQuery.getNodeEndIndex(currentNode);
    int location1 = getLocation(currentNode, pos1, false);
    int location2 = getLocation(currentNode, pos2, false);
    if (location1 <= IN_MIDDLE && location2 >= IN_MIDDLE) {
      workNode.push(new WorkNode(currentNode, pos1, pos2));
    }
  }

  /**
   * @param currentNode
   * @param pos1
   * @param pos2
   * @param top
   * @param result
   */
  public void collectNodes(Node currentNode, final int pos1, final int pos2,
      Node top, Stack result) {
    Assert.isTrue(pos1 <= pos2);
    if (pos1 == pos2) {
      return;
    }
    if (EditModelQuery.isText(currentNode)) {
      processText((Text) currentNode, pos1, pos2, top, result);
    } else {
      int location1 = getLocation(currentNode, pos1, false);
      int location2 = getLocation(currentNode, pos2, false);
      if (location1 < IN_MIDDLE && location2 > IN_MIDDLE) {
        // TODO: push the node into result.--
        result.push(new WorkNode(currentNode, pos1, pos2));
      } else if (location1 <= IN_MIDDLE && location2 >= IN_MIDDLE) {
        if (currentNode.hasChildNodes()) {
          Node child = currentNode.getFirstChild();
          Stack myResult = new Stack();
          while (child != null) {
            collectNodes(child, pos1, pos2, top, myResult);
            child = child.getNextSibling();
          }
          if (location1 < IN_MIDDLE && location2 >= IN_MIDDLE
              || location1 <= IN_MIDDLE && location2 > IN_MIDDLE) {
            WorkNode workNode = new WorkNode(currentNode, pos1,
                pos2);
            while (myResult.size() > 0) {
              WorkNode w = (WorkNode) myResult.remove(0);
              if (w.getNode().getParentNode() == workNode
                  .getNode()) {
                w.setParent(workNode);
              }
              result.push(w);
            }
            // TODO: push parent into result.--
            result.push(workNode);
          }
        } else {
          if (!(location1 == IN_MIDDLE && location2 == IN_MIDDLE)) {
            // TODO: push this node into result.
            result.push(new WorkNode(currentNode, pos1, pos2));
          }
        }
      }
    }
  }

  /**
   * @param currentNode
   * @param pos
   * @param isOffset
   * @return the location
   */
  public int getLocation(Node currentNode, int pos, boolean isOffset) {
    if (EditModelQuery.getInstance().isSingleRegionNode(currentNode)) {
      // if (EditModelQuery.isText(currentNode))
      {

        int left = EditModelQuery.getNodeStartIndex(currentNode);
        int right = EditModelQuery.getNodeEndIndex(currentNode);
        if (isOffset) {
          pos += left;
        }
        if (pos <= left) {
          return OUT_OF_LEFT;
        } else if (left < pos && pos < right) {
          return IN_MIDDLE;
        } else {
          return OUT_OF_RIGHT;
        }
      }
    }
        int left = EditModelQuery.getNodeStartIndex(currentNode);
        int left1 = EditModelQuery.getNodeStartNameEndIndex(currentNode);
        int right = EditModelQuery.getNodeEndNameStartIndex(currentNode);
        int right1 = EditModelQuery.getNodeEndIndex(currentNode);
        if (isOffset) {
          pos += left;
        }
        if (pos <= left) {
          return OUT_OF_LEFT;
        } else if (left < pos && pos < left1) {
          return LEFT_NAME;
        } else if (left1 <= pos && pos <= right) {
          return IN_MIDDLE;
        } else if (right < pos && pos < right1) {
          return RIGHT_NAME;
        } else {
          return OUT_OF_RIGHT;
        }

  }

    // TODO: dead?
//  private Node cutCurrentNode(int pos[], Node currentNode,
//      IDOMPosition position) {
//    // at right edge
//    int curpos = EditModelQuery.getIndexedRegionLocation(position);
//    if (pos[0] <= curpos) {
//      pos[1] = EditModelQuery.getNodeStartIndex(currentNode);
//      currentNode = deleteNode(currentNode);
//      if (INNER_DEBUG) {
//        _log.info("cut:" + currentNode);
//      }
//      return currentNode;
//    } else if (pos[1] >= curpos) {
//      pos[0] = EditModelQuery.getNodeEndIndex(currentNode);
//      currentNode = deleteNode(currentNode);
//      if (INNER_DEBUG) {
//        _log.info("cut:" + currentNode);
//      }
//      return currentNode;
//    }
//    return null;
//  }

    //TODO: dead?
//  private int getPos(DOMRange range, boolean forStart) {
//    if (forStart) {
//      return EditModelQuery.getIndexedRegionLocation(range
//          .getStartPosition());
//    } else {
//      return EditModelQuery.getIndexedRegionLocation(range
//          .getEndPosition());
//    }
//  }

  /**
   * @param position
   * @param forward
   * @return the edit part for position
   */
  public EditPart getEditPart(DesignPosition position, boolean forward) {
    if (position instanceof DesignRefPosition) {
      return ((DesignRefPosition) position).getRefPart();
    }
    EditPart container = position.getContainerPart();
    if (container instanceof TextEditPart) {
      return container;
    }
    if (container != null) {
      List children = container.getChildren();
      for (int i = 0, n = children.size(); i < n; i++) {
        if (i == position.getOffset()) {
          int index = (forward) ? i - 1 : i + 1;
          if (index < 0) {
            index = 0;
          }
          if (index >= children.size()) {
            index = children.size() - 1;
          }

          return (EditPart) children.get(index);
        }
      }
    }
    return null;
  }

  /**
   * @param position
   * @return the resulting dom position
   */
  public static IDOMPosition splitNode(IDOMPosition position) {
    if (EditValidateUtil.validPosition(position)) {
      Node container = null;
      // Avoid to split tag at its edge
      if (position.getOffset() > 0) {
        if (position.isText()) {
          container = position.getContainerNode();
          if (position.getOffset() < ((Text) container).getLength()) {
            position = DOMPositionHelper.splitText(position);
          } else {
            // position = new
            // DOMRefPosition(position.getContainerNode(), true);
          }
        } else {
          if (position.getNextSiblingNode() != null) {
            container = position.getContainerNode();
            Node parent = container.getParentNode();

            Document document = EditModelQuery
                .getDocumentNode(container);
            Node newContainer = document.createElement(container
                .getNodeName());
            Node node = position.getPreviousSiblingNode();
            Node refNode = null;
            while (node != null) {
              Node prev = node.getPreviousSibling();
              node = node.getParentNode().removeChild(node);

              newContainer.insertBefore(node, refNode);
              refNode = node;
              node = prev;
            }
            parent.insertBefore(newContainer, container);
            // set the newContainer node align attribute to the
            // original align attribue
            // copy nodes under container node to container node's
            // parent node
            if (container.getNodeName().equalsIgnoreCase(
                IHTMLConstants.TAG_P)) {
              Element pNode = (Element) container;
              String align = pNode
                  .getAttribute(IHTMLConstants.ATTR_ALIGN);
              if (align != null && !"".equalsIgnoreCase(align)) { //$NON-NLS-1$
                ((Element) newContainer).setAttribute(
                    IHTMLConstants.ATTR_ALIGN, align);
              }
              NodeList nodeList = pNode.getChildNodes();
              for (int i = 0, size = nodeList.getLength(); i < size; i++) {
                Node tempNode = nodeList.item(i);
                parent.insertBefore(tempNode, container);
              }
            }
            return new DOMRefPosition(newContainer, true);
          }
//                    position = new
//                    DOMRefPosition(position.getContainerNode(), true);
        }
      } else {
        // container = position.getContainerNode();
        // position = new DOMRefPosition(container, false);
      }
    }
    return position;
  }

  /**
   * @param position
   * @return the position of this 'position' in relative to it's container.
   */
  public static int getLocation(IDOMPosition position) {
    if (position.getOffset() == 0) {
      return -1;
    }
        if (position.isText()) {
          if (position.getOffset() == ((Text) position.getContainerNode())
              .getLength()) {
            return 1;
          }
            return 0;
        }
        if (position.getOffset() == position.getContainerNode()
            .getChildNodes().getLength()) {
          return 1;
        }
        return 0;
  }
}
TOP

Related Classes of org.eclipse.jst.pagedesigner.dom.EditHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.