Package org.eclipse.jst.pagedesigner.viewer

Source Code of org.eclipse.jst.pagedesigner.viewer.EditPartPositionHelper

/*******************************************************************************
* 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.viewer;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.jst.pagedesigner.IHTMLConstants;
import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
import org.eclipse.jst.pagedesigner.css2.layout.CSSTextFigure;
import org.eclipse.jst.pagedesigner.css2.layout.FlowBox;
import org.eclipse.jst.pagedesigner.dom.DOMPosition;
import org.eclipse.jst.pagedesigner.dom.DOMPositionHelper;
import org.eclipse.jst.pagedesigner.dom.DOMRefPosition;
import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
import org.eclipse.jst.pagedesigner.parts.NodeEditPart;
import org.eclipse.jst.pagedesigner.parts.TextEditPart;
import org.eclipse.jst.pagedesigner.validation.caret.IMovementMediator;
import org.eclipse.jst.pagedesigner.validation.caret.IPositionMediator;
import org.eclipse.jst.pagedesigner.validation.caret.Target;
import org.w3c.dom.Node;

/**
* @author mengbo
*/
public class EditPartPositionHelper {
//  private final static Logger _log = PDPlugin
//      .getLogger(EditPartPositionHelper.class);

  /**
   * Add something to current
   *
   * @param lineBox
   * @param host
   * @param point
   * @param validator
   */
  private static void addToCurrentLine(FlowBoxLine lineBox, EditPart host,
      Point point, IPositionMediator validator) {
    Node node = Target.resolveNode(host);
    if (!(node == null || EditModelQuery.isDocument(node))) {
      // Either it is referencable or is editable.
      if (validator.isValidPosition(new DOMRefPosition(node, true))
          || //
          validator
              .isValidPosition((new DOMRefPosition(node, false)))
          || //
          validator.isValidPosition(new DOMPosition(node, 0))) {
        lineBox.addLayoutPart(host, point);
      }
    }
  }

  /**
   * @param position
   * @return null means failed to convert to rect.
   */
  public static Rectangle convertToAbsoluteCaretRect(DesignPosition position) {
    Rectangle ret = null;
    try {
      final int CARET_OFFSET = 1;
      if (position == null || !position.isValid()) {
        return null;
      }
      EditPart containerEditPart = position.getContainerPart();
      if (containerEditPart instanceof TextEditPart) {
        CSSTextFigure figure = (CSSTextFigure) ((TextEditPart) containerEditPart)
            .getFigure();
        ret = figure.calculateCaretPosition(position.getOffset());
        figure.translateToAbsolute(ret);
        ret.width = CaretUpdater.CARET_WIDTH;
      } else {
        int offset = position.getOffset();
        // there is no child
        if (containerEditPart.getChildren().isEmpty()
            || LayoutPart.getConcretePart(containerEditPart) == null) {
          IFigure figure = ((GraphicalEditPart) containerEditPart)
              .getFigure();
          Rectangle bounds = figure.getBounds();
          if (figure instanceof CSSFigure) {
            List fragments = ((CSSFigure) figure)
                .getFragmentsForRead();
            if (fragments.size() > 0) {
              FlowBox box = (FlowBox) fragments.get(fragments
                  .size() - 1);
              bounds = LayoutPart.getBounds(box);
            }
          }

          ret = new Rectangle(bounds.x + CARET_OFFSET, bounds.y,
              CaretUpdater.CARET_WIDTH, bounds.height);

          figure.translateToAbsolute(ret);
        } else if (offset >= 0
            && offset <= containerEditPart.getChildren().size()) {
          ret = getRefRect(position);
        }
      }
    } catch (Exception e) {
      // This should never happen, we catch here for later analysis.
      // _log.debug("Error in caret rect resolving", e);
      ret = new Rectangle(0, 0, 0, 0);
    }
    if (ret == null) {
      ret = new Rectangle(0, 0, 0, 0);
    }
    return ret;
  }

  /**
   * This method will create FlowBoxLine to calculate the accurate parts.
   *
   * @param host
   * @param p
   * @param validator
   * @return the design position
   */
  public static DesignPosition findEditPartPosition(EditPart host, Point p,
      IPositionMediator validator) {
    try {
      host = validator.getEditableContainer(new Target(host));
      FlowBoxLine boxLine = new FlowBoxLine(
          new Rectangle(p.x, p.y, 0, 0), validator, p);
      DesignPosition position = innerFindEditPartPosition(host, host, p,
          boxLine, validator);
      if (position == null) {
        position = innerFindEditPartPosition(host, host, p, boxLine,
            validator);
        if (position == null) {
          EditPart part = boxLine.getClosestPart();
          if (part != null) {
            LayoutPart layoutPart = new LayoutPart(part, p);
            position = layoutPart.resolvePosition(validator);
          }
        }
      }
      return position;
    } catch (Exception e) {
      return null;
    }

  }

  /**
   * This function finds the position, if there is one which is widget or text
   * and it contains p, or there is not such widget, then boxLine will return
   * the widget that are in a same line which contains p;
   * @param rootHost
   * @param host
   *
   * @param p
   * @param boxLine
   * @param validator
   * @return the design position
   */
    //TODO: needs refactoring
  public static DesignPosition innerFindEditPartPosition(EditPart rootHost,
      EditPart host, Point p, FlowBoxLine boxLine,
      IPositionMediator validator) {
    Target target = new Target(host);
    LayoutPart lPart = new LayoutPart(host, p);
    // text
    if (host instanceof TextEditPart) {
      if (lPart.contains(p)) {
        DesignPosition position = null;
        // see if the point is within string.
        position = findTextEditPartPosition((TextEditPart) host, p);
        if (position == null) {
          addToCurrentLine(boxLine, host, p, validator);
        }
        // found?!!
        return position;
      }
            addToCurrentLine(boxLine, host, p, validator);
            return null;
    }
    // widget
    else if (isWidget(host)) {
      if (lPart.contains(p)
          && (validator.isValidPosition(new DOMRefPosition(target
              .getNode(), true)) || //
          validator.isValidPosition((new DOMRefPosition(target
              .getNode(), false))))) {
        if (IHTMLConstants.TAG_BR.equalsIgnoreCase(Target.resolveNode(
            host).getNodeName())) {
          return new DesignRefPosition(host, lPart.isBeforePoint(p));
        }
                return new DesignRefPosition(host, lPart.isBeforePoint(p)
                    || !lPart.atLeftPart(p));
      }
            addToCurrentLine(boxLine, host, p, validator);
    } else {
      // root host. we always support it has editable area.
      if (host == rootHost) {
        if (host.getChildren().size() > 0) {
          List children = host.getChildren();
          for (int i = 0, size = children.size(); i < size; i++) {
            GraphicalEditPart child = (GraphicalEditPart) children
                .get(i);
            DesignPosition position = innerFindEditPartPosition(
                rootHost, child, p, boxLine, validator);
            if (position != null) {
              return position;
            }
          }
        }
        if (boxLine.getPartsList().size() == 0) {
          if (lPart.contains(p)) {
            // found!!!
            return new DesignPosition(host, 0);
          }
          addToCurrentLine(boxLine, host, p, validator);
        }
      }
      // container
      else {
        // can't edit it.
        if (!validator.hasEditableArea(target)) {
          if (lPart.contains(p) && //
              (validator.isValidPosition(new DesignRefPosition(
                  target.getPart(), true)) || //
              validator.isValidPosition(new DesignRefPosition(
                  target.getPart(), false)))) {
            return new DesignRefPosition(host, lPart
                .isBeforePoint(p)
                || !lPart.atLeftPart(p));
          }
                    addToCurrentLine(boxLine, host, p, validator);
        }
        // can edit
        else {
          // contains p
          if (lPart.contains(p) || //
              (!validator.isValidPosition(new DesignRefPosition(
                  target.getPart(), true)) && //
              !validator.isValidPosition(new DesignRefPosition(
                  target.getPart(), false)))) {
            if (host.getChildren().size() > 0) {
              List children = host.getChildren();
              for (int i = 0, size = children.size(); i < size; i++) {
                GraphicalEditPart child = (GraphicalEditPart) children
                    .get(i);
                DesignPosition position = innerFindEditPartPosition(
                    rootHost, child, p, boxLine, validator);
                if (position != null) {
                  return position;
                }
              }
            } else {
              // we put the container which is empty here.
              if (lPart.contains(p)) {
                // found!!!
                return new DesignPosition(host, 0);
              }
                            addToCurrentLine(boxLine, host, p, validator);
            }
          }
          // not contains p
          else {
            addToCurrentLine(boxLine, host, p, validator);
          }
        }
      }
    }
    return null;
  }

  /**
   * Similar to findEditPartPositionConstrained, this method is used to
   * vertically move caret.
   *
   * @param host
   * @param p
   * @param validator
   * @return the design position
   */
  public static DesignPosition findEditPartPositionConstrained(EditPart host,
      Point p, IMovementMediator validator) {
    try {
      FlowBoxLine boxLine = new FlowBoxLine(
          new Rectangle(p.x, p.y, 0, 0), validator, p);
      DesignPosition position = innerFindEditPartPositionConstrained(
          host, host, p, boxLine, validator);
      if (position == null) {
        position = innerFindEditPartPositionConstrained(host, host, p,
            boxLine, validator);
        if (position == null) {
          EditPart part = boxLine.getClosestPart();
          if (part != null) {
            LayoutPart layoutPart = new LayoutPart(part, p);
            position = layoutPart.resolvePosition(validator);
          }
        }
      }
      return position;
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * This method is used for move up/down, except for using tactics to deal
   * with container, this method is similar to findEditPartPosition.
   *
   * @param rootHost
   * @param host
   * @param p
   * @param boxLine
   * @param validator
   * @return the design position
   */
    // TODO: needs refactoring
  public static DesignPosition innerFindEditPartPositionConstrained(
      EditPart rootHost, EditPart host, Point p, FlowBoxLine boxLine,
      IMovementMediator validator) {
    Target target = new Target(host);
    LayoutPart lPart = new LayoutPart(host, p);
    // text
    if (host instanceof TextEditPart) {
      if (lPart.contains(p)) {
        DesignPosition position = null;
        // see if the point is within string.
        position = findTextEditPartPosition((TextEditPart) host, p);
        if (position == null) {
          addToCurrentLine(boxLine, host, p, validator);
        }
        // found?!!
        return position;
      }
            addToCurrentLine(boxLine, host, p, validator);
            return null;
    }
    // widget
    else if (isWidget(host)) {
      if (lPart.contains(p)) {
        // found!!!
        if (IHTMLConstants.TAG_BR.equalsIgnoreCase(Target.resolveNode(
            host).getNodeName())) {
          return new DesignRefPosition(host, lPart.isBeforePoint(p));
        }
                return new DesignRefPosition(host, lPart.isBeforePoint(p)
                    || !lPart.atLeftPart(p));
      }
            addToCurrentLine(boxLine, host, p, validator);
    } else {
      // root host. we always support it has editable area.
      if (host == rootHost) {
        if (host.getChildren().size() > 0) {
          List children = host.getChildren();
          for (int i = 0, size = children.size(); i < size; i++) {
            GraphicalEditPart child = (GraphicalEditPart) children
                .get(i);
            DesignPosition position = innerFindEditPartPositionConstrained(
                rootHost, child, p, boxLine, validator);
            if (position != null) {
              return position;
            }
          }
        } else {
          if (lPart.contains(p)) {
            // found!!!
            return new DesignPosition(host, 0);
          }
          addToCurrentLine(boxLine, host, p, validator);
        }
      }
      // container
      else {
        // can't edit it.
        if (!validator.hasEditableArea(target)
            || !validator.allowsMoveIn(target)) {
          if (validator.canReference(target, true)
              || validator.canReference(target, false)) {
            if (lPart.contains(p)) {
              return new DesignRefPosition(host, lPart
                  .isBeforePoint(p)
                  || !lPart.atLeftPart(p));
            }
                        addToCurrentLine(boxLine, host, p, validator);
          }
        }
        // can edit
        else {
          // contains p
          if (lPart.contains(p)) {
            if (host.getChildren().size() > 0) {
              List children = host.getChildren();
              for (int i = 0, size = children.size(); i < size; i++) {
                GraphicalEditPart child = (GraphicalEditPart) children
                    .get(i);
                DesignPosition position = innerFindEditPartPositionConstrained(
                    rootHost, child, p, boxLine, validator);
                if (position != null) {
                  return position;
                }
              }
            } else {
              // we put the container which is empty here.
              if (lPart.contains(p)) {
                // found!!!
                return new DesignPosition(host, 0);
              }
                            addToCurrentLine(boxLine, host, p, validator);
            }
          }
          // not contains p
          else {
            addToCurrentLine(boxLine, host, p, validator);
          }
        }
      }
    }
    return null;

  }

  // /**
  // * @param host
  // * @param p
  // * @return
  // */
  // private static DesignPosition
  // findTextEditPartPositionAdjacent(TextEditPart host, Point p)
  // {
  // if (host.getFigure() instanceof CSSTextFigure)
  // {
  // CSSTextFigure figure = (CSSTextFigure) host.getFigure();
  // // make a copy to not destroy the original o
  // p = p.getCopy();
  // figure.translateToRelative(p);
  // int offset = figure.getNewInsertionOffset(p);
  // if (offset >= 0)
  // {
  // return new DesignPosition(host, offset);
  // }
  // else
  // {
  // return null;
  // }
  // }
  // else
  // {
  // // should not happen.
  // return new DesignPosition(host, 0);
  // }
  // }

  /**
   * @param host
   * @param p
   * @return
   */
  private static DesignPosition findTextEditPartPosition(TextEditPart host,
      Point p) {
    if (host.getFigure() instanceof CSSTextFigure) {
      CSSTextFigure figure = (CSSTextFigure) host.getFigure();
      // make a copy to not destroy the original o
      p = p.getCopy();
      figure.translateToRelative(p);
      int offset = figure.getInsertionOffset(p);
      if (offset >= 0) {
        return new DesignPosition(host, offset);
      }
            return null;
    }
        // should not happen.
        return new DesignPosition(host, 0);
  }

  /**
   * @param figure
   * @param box
   * @return
   */
//  public static Rectangle getBoxBounds(IFigure figure, FlowBox box) {
//    Rectangle r = new Rectangle(box._x, box._y, box.getWidth(), box
//        .getHeight());
//    figure.translateToAbsolute(r);
//    return r;
//  }

  /**
   * If child is a GraphicalEditPart, a new copy of its bounding rectangle
   * will be returned translated to absolute bounds. If child is not a GraphicalEditPart
   * then the empty rectangle (0,0,0,0) is returned.
   *
   * @param child
   * @return the bounding rectangle or (0,0,0,0) if none.
   */
  public static Rectangle getAbsoluteBounds(EditPart child) {
    if (child instanceof GraphicalEditPart) {
      Rectangle bounds = ((GraphicalEditPart) child).getFigure()
          .getBounds().getCopy();
      ((GraphicalEditPart) child).getFigure().translateToAbsolute(bounds);
      return bounds;
    }
        return new Rectangle(0, 0, 0, 0);
  }

  /**
   * @param host
   * @param tagName
   * @return
   */
  private static boolean isWidget(EditPart host) {
    if (host instanceof NodeEditPart) {
      return ((NodeEditPart) host).isWidget();
    }
        return false;
  }

  /**
   * Is Caret at right?
   *
   * @param position
   * @param caretRefResult
   * @return
   */
  private static EditPart tryTwoWays(DesignPosition position,
      List<Boolean> caretRefResult) {
    EditPart result = null;
    // Sibling first:
    Node node = EditModelQuery.getInstance().getSibling(
        DOMPositionHelper.toDOMPosition(position), true);
    if (node != null && !EditModelQuery.isTransparentText(node)) {
      result = Target.resolvePart(node);
      caretRefResult.add(Boolean.FALSE);
    } else {
      node = EditModelQuery.getInstance().getSibling(
          DOMPositionHelper.toDOMPosition(position), false);
      if (node != null && !EditModelQuery.isTransparentText(node)) {
        result = Target.resolvePart(node);
        caretRefResult.add(Boolean.TRUE);
      }
    }
    if (result == null) {
      if (getConcretePart(position, false) != null) {
        result = getConcretePart(position, false);
        caretRefResult.add(Boolean.TRUE);
      } else if (getConcretePart(position, true) != null) {
        result = getConcretePart(position, true);
        caretRefResult.add(Boolean.FALSE);
      }
    }
    return result;
  }

  /*
   * Here we are doing something to avoid reference whitespace tag. Since we
   * still need to improve whitespace tags's layout further more.
   */
  private static EditPart getNextConcretPart(DesignPosition position,
      List<Boolean> caretIsAtRightTest) {
    EditPart result = null;
    boolean caretIsAtRight = true;
    if (position instanceof DesignRefPosition) {
      caretIsAtRight = ((DesignRefPosition) position).caretIsAtRight();
      result = ((DesignRefPosition) position).getRefPart();
      caretIsAtRightTest.add(Boolean.valueOf(caretIsAtRight));
    }
    if (result == null
        || EditModelQuery.isTransparentText(Target.resolveNode(result))) {
      caretIsAtRightTest.clear();
      result = tryTwoWays(position, caretIsAtRightTest);
    }
    return result;
  }

  /**
   * Avoid whitespaces
   *
   * @param position
   * @param forward
   * @return the edit part at position which is non-whitespace ? TODO:
   */
  public static EditPart getConcretePart(DesignPosition position,
      boolean forward) {
    EditPart result = null;
    Node node = EditModelQuery.getInstance().getSibling(
        DOMPositionHelper.toDOMPosition(position), forward);
    while (node != null && EditModelQuery.isTransparentText(node)) {
      node = EditModelQuery.getInstance().getSibling(node, forward);
    }
    if (node != null) {
      result = Target.resolvePart(node);
    }
    return result;
  }

  /**
   * @param position
   * @param forward
   * @return the next concrete part.
   */
  public static EditPart getNextConcretPart(DesignPosition position,
      boolean forward) {
    Node node;
    EditPart result = null;
    node = EditModelQuery.getInstance().getSibling(
        DOMPositionHelper.toDOMPosition(position), forward);
    if (node != null) {
      if (forward) {
        while (node != null) {
          if (!EditModelQuery.isTransparentText(node)
              && (result = Target.resolvePart(node)) != null) {
            result = Target.resolvePart(node);
            break;
          }
          node = node.getNextSibling();
        }
      } else {
        while (node != null) {
          if (!EditModelQuery.isTransparentText(node)
              && (result = Target.resolvePart(node)) != null) {
            result = Target.resolvePart(node);
            break;
          }
          node = node.getPreviousSibling();
        }
      }
    }
    return result;
  }

  private static Rectangle getRefRect(DesignPosition position) {
    List<Boolean> caretLocation = new ArrayList<Boolean>();
    EditPart part = getNextConcretPart(position, caretLocation);
    LayoutPart layoutPart;
    Rectangle rect = null;
    if (part != null) {
      layoutPart = new LayoutPart(part, null);
      boolean caretIsAtRight = caretLocation.get(0)
          .booleanValue();
      final int CARET_OFFSET = 1;
      Rectangle bounds = null;
      IFigure figure = ((GraphicalEditPart) part).getFigure();
      if (!caretIsAtRight) {
        FlowBox box;
        if ((box = layoutPart.getLine(0)) != null) {
          bounds = LayoutPart.getBounds(box);
        }
      } else {
        FlowBox box;
        if ((box = layoutPart.getLastLine()) != null) {
          bounds = LayoutPart.getBounds(box);
        }
      }
      if (bounds == null) {
        bounds = figure.getBounds();
      }
      if (!caretIsAtRight) {
        rect = new Rectangle(bounds.x - CARET_OFFSET, bounds.y,
            CaretUpdater.CARET_WIDTH, bounds.height);// new
      } else {
        rect = new Rectangle(bounds.getRight().x + CARET_OFFSET,
            bounds.y, CaretUpdater.CARET_WIDTH, bounds.height);// new
      }
      figure.translateToAbsolute(rect);
    } else {
      System.out.println("No concrete part?"); //$NON-NLS-1$
    }
    return rect;
  }
}
TOP

Related Classes of org.eclipse.jst.pagedesigner.viewer.EditPartPositionHelper

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.