Package org.eclipse.jst.pagedesigner.viewer

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

/*******************************************************************************
* 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.core.runtime.Assert;
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.css2.layout.FlowUtilities;
import org.eclipse.jst.pagedesigner.css2.layout.TextFragmentBox;
import org.eclipse.jst.pagedesigner.css2.layout.TextLayoutSupport;
import org.eclipse.jst.pagedesigner.dom.DOMRefPosition;
import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
import org.eclipse.jst.pagedesigner.parts.SubNodeEditPart;
import org.eclipse.jst.pagedesigner.parts.TextEditPart;
import org.eclipse.jst.pagedesigner.validation.caret.IPositionMediator;
import org.eclipse.jst.pagedesigner.validation.caret.Target;
import org.w3c.dom.Node;

/**
* @author mengbo
*/
public final  class LayoutPart {
  private final static int MAX_OFFSET_TO_EDGE = 10;

  private EditPart _part;

  private FlowBox _box;

  private final Point EMPTY_POINT = new Point(0, 0);

  private Point _point = EMPTY_POINT;

  /**
   * If caller didn't resolve FlowBox, call this.
   *
   * @param part
   * @param point
   */
  public LayoutPart(EditPart part, Point point) {
    Assert.isTrue(part != null);
    _part = part;
    _point = point;
  }

  /**
   * @return Returns the _box, when it is null, generate box with part and
   *         point.
   */
  public FlowBox getBox() {
    if (_box == null) {
      _box = getClosestBox();
    }
    return _box;
  }

  /**
   * @return Returns the _part.
   */
  public EditPart getPart() {
    return _part;
  }

  /**
   * Get closest box's bounds.
   *
   * @param point
   * @return
   */
  private Rectangle getClosestBoxAbsoluteBounds() {
    Rectangle rect = null;
    if (getBox() != null) {
      rect = getAbsoluteBounds(getBox());
    }
    return rect;
  }

  /**
   * Try to get the closest flowbox absolute bounds.
   *
   * @return the bounding rectangle
   */
  public Rectangle getAbsoluteBounds() {
    Rectangle bounds = null;
    if ((bounds = getClosestBoxAbsoluteBounds()) == null) {
      // This should never happens.
      bounds = EditPartPositionHelper.getAbsoluteBounds(_part);
    }
    return bounds;
  }

  /**
   * Get box's absolute bounds.
   *
   * @param box
   * @return the box's bounding rectangle
   */
  public Rectangle getAbsoluteBounds(FlowBox box) {
    if (box != null) {
      IFigure figure = ((GraphicalEditPart) _part).getFigure();
      Rectangle rect = new Rectangle(box.getX(), box.getY(), box.getWidth(), box
          .getHeight());
      figure.translateToAbsolute(rect);
      return rect;
    }
    return null;
  }

  /**
   * Closest box is the part's FlowBox which y coordinate is closest to point,
   * and then its x coordinate is more close to point than other boxs of the
   * same line.
   *
   * @param part
   * @param point
   * @return
   */
  private FlowBox getClosestBox() {
    FlowBox closestBox = null;
    List fragments = getLines(_part);

    // if there is one which are at the same line with relative,
    // calculate that line first;
    for (int i = 0; i < fragments.size(); i++) {
      FlowBox box = (FlowBox) fragments.get(i);
      Rectangle boxRect = getAbsoluteBounds(box);
      if (boxRect.contains(_point.x, _point.y)) {
        closestBox = box;
        break;
      }
            if (closestBox == null) {
              closestBox = box;
            } else {
              // compare y.
              int offset1 = Math.abs(CaretPositionResolver.getYDistance(
                  boxRect, _point));
              Rectangle closestRect = getAbsoluteBounds(closestBox);
              int offset2 = Math.abs(CaretPositionResolver.getYDistance(
                  closestRect, _point));
              if (offset1 < offset2) {
                closestBox = box;
              }
            }
            // at the same line
            if (closestBox != box && boxRect.contains(boxRect.x, _point.y)) {
              // compare x.
              int offset1 = Math.abs(CaretPositionResolver.getXDistance(
                  boxRect, _point));
              Rectangle closestRect = getAbsoluteBounds(closestBox);
              int offset2 = Math.abs(CaretPositionResolver.getXDistance(
                  closestRect, _point));
              if (offset1 < offset2) {
                closestBox = box;
              }
            }
    }
    return closestBox;
  }

  /**
   * The point is whitin the bounds of the figure.
   *
   * @param point
   * @return true if point is the absolute bounds of this
   */
  public boolean contains(Point point) {
    return getAbsoluteBounds().contains(point);
  }

  /**
   * @return the design position
   */
  public DesignPosition resolveTextPosition() {
    DesignPosition result = null;
    if (_part instanceof TextEditPart
        && !EditModelQuery.isTransparentText(Target.resolveNode(_part))) {
      FlowBox flowBox = getBox();
      if (flowBox instanceof TextFragmentBox) {
        TextFragmentBox box = (TextFragmentBox) flowBox;
        if (((TextEditPart) _part).getFigure() instanceof CSSTextFigure) {
          CSSTextFigure figure = (CSSTextFigure) ((TextEditPart) _part)
              .getFigure();
          Rectangle boxRect = getAbsoluteBounds(box);
          int index = FlowUtilities.getTextInWidth(box.getTextData(),
              figure.getCSSStyle().getCSSFont().getSwtFont(),
              _point.x - boxRect.x, TextLayoutSupport
                  .getAverageCharWidth(box));
          result = new DesignPosition(_part, box._offset + index);
        }
      }
    }
    return result;
  }

  /**
   * @param validator
   * @return resolve the design position using validator
   */
  public DesignPosition resolvePosition(IPositionMediator validator) {
    DesignPosition result;
    if ((result = resolveTextPosition()) == null) {
      boolean atPointLeft = isBeforePoint(_point);
//      boolean atPointRight = isAfterPoint(_point);
//      if (atPointLeft == atPointRight) {
//          // TODO: and...?
//      }
      Target target = new Target(getPart());
      if (validator.isValidPosition(new DOMRefPosition(target.getNode(),
          atPointLeft))) {
        result = new DesignRefPosition(_part, atPointLeft);
      } else if (validator.isValidPosition(new DOMRefPosition(target
          .getNode(), !atPointLeft))) {
        result = new DesignRefPosition(_part, !atPointLeft);
      } else if (validator.isEditable(target)) {
        if (atPointLeft) {
          result = new DesignPosition(_part, 0);
        } else {
          result = new DesignPosition(_part, _part.getChildren()
              .size());
        }
      }
    }
    return result;
  }

    // TODO: dead?
//  private IFigure getFigure() {
//    return ((GraphicalEditPart) _part).getFigure();
//  }

  private boolean isAfterPoint(Point point) {
    boolean result = false;
    FlowBox flowBox = getLine(0);
    if (IHTMLConstants.TAG_BR.equalsIgnoreCase(Target.resolveNode(_part)
        .getNodeName())) {
      if (flowBox != null) {
        Rectangle boxRect = getAbsoluteBounds(flowBox);
        result = CaretPositionResolver.getYDistance(boxRect, point) == 0;
      }
    } else {

      if (flowBox != null) {
        Rectangle boxRect = getAbsoluteBounds(flowBox);
        if (CaretPositionResolver.getXDistance(boxRect, point) != 0) {
          result = CaretPositionResolver.getXDistance(boxRect, point) < 0
              && //
              CaretPositionResolver.getYDistance(boxRect, point) == 0;
        }
      }
    }
    result |= isUnderCaret();
    // if (isWidget() && flowBox != null)
    // {
    // result |= contains(point) &&
    // CaretPositionResolver.toXMiddle(getAbsoluteBounds(flowBox), point) <
    // 0;
    // }
    return result;

  }

  /*package*/ boolean isBeforePoint(Point point) {
    boolean result = false;
    FlowBox flowBox = getLastLine();
    if (flowBox != null) {
      Rectangle boxRect = getAbsoluteBounds(flowBox);
      if (IHTMLConstants.TAG_BR.equalsIgnoreCase(Target
          .resolveNode(_part).getNodeName())) {
        return CaretPositionResolver.getYDistance(boxRect, point) == 0;
      } else if (CaretPositionResolver.getXDistance(boxRect, point) != 0) {
        result = CaretPositionResolver.getXDistance(boxRect, point) > 0
            && //
            CaretPositionResolver.getYDistance(boxRect, point) == 0;
      }
    }
    result |= isAboveCaret();
    // if (isWidget() && flowBox != null)
    // {
    // result |= contains(point) &&
    // CaretPositionResolver.toXMiddle(getAbsoluteBounds(flowBox), point) >
    // 0;
    // }
    return result;
    // return !isAfterPoint(point);
  }

  /*package*/ boolean isBeforePoint() {
    return isBeforePoint(_point);
  }

  /*package*/ boolean atLeftPart(Point point) {
    FlowBox flowBox = getBox();
    if (flowBox != null) {
      Rectangle boxRect = getAbsoluteBounds(flowBox);
      return CaretPositionResolver.toXMiddle(boxRect, point) < 0;
    }
    return true;
  }

  /*package*/ boolean isAfterPoint() {
    return isAfterPoint(_point);
  }

  // TODO: dead but possibly useful?
//  private boolean atSameLine(Point point) {
//    Rectangle bounds = getAbsoluteBounds();
//    return bounds.contains(bounds.getTop().x, point.y);
//  }

  /*package*/ boolean atSameRow(Point point) {
    Rectangle bounds = getAbsoluteBounds();
    return bounds.contains(point.x, bounds.getRight().y);
  }

  /*package*/ static Rectangle getBounds(FlowBox box) {
    return new Rectangle(box.getX(), box.getY(), box.getWidth(), box.getHeight());
  }

  /**
   * @return Returns the _point.
   */
  public Point getPoint() {
    return _point;
  }

  FlowBox getLine(int index) {
    FlowBox result = null;
    List lines = getLines(_part);
    if (lines.size() > 0 && index >= 0 && index <= lines.size() - 1) {
      result = (FlowBox) lines.get(index);
    }
    return result;
  }

  FlowBox getLastLine() {
    FlowBox result = null;
    List lines = getLines(_part);
    if (lines.size() > 0) {
      result = (FlowBox) lines.get(lines.size() - 1);
    }
    return result;
  }

  /**
   * @param part
   * @return
   */
  List getLines(EditPart part) {
    List fragments = new ArrayList();
    if (part instanceof SubNodeEditPart) {
      IFigure figure = ((GraphicalEditPart) part).getFigure();

      if (figure instanceof CSSTextFigure) {
        fragments = ((CSSTextFigure) figure).getFragments();
        ((CSSTextFigure) figure).getCSSStyle();
      } else if (figure instanceof CSSFigure) {
        fragments = ((CSSFigure) figure).getFragmentsForRead();
        ((CSSFigure) figure).getCSSStyle();
      }
    }
    return fragments;
  }

  /**
   * To search for none empty string, this is not final.
   * @param part
   * @return the edit part
   *
   */
  /*package*/ static EditPart getConcretePart(EditPart part) {
    if (part != null) {
      Node node = Target.resolveNode(part);
      Node child = node.getFirstChild();
      EditPart result;
      while (child != null) {
        if (!EditModelQuery.isTransparentText(child)
            && (result = Target.resolvePart(child)) != null) {
          return result;
        }
        child = child.getNextSibling();
      }
    }
    return null;
  }

  /**
   * To search for none empty string, this is not final.
   * Equivalent to getConcretePart(getPart())
   *
   * @return the edit part
   *
   */
  public EditPart getConcretePart() {
    return getConcretePart(_part);
  }

  /**
   * @param node
   * @return the node
   */
  public static Node getConcreteNode(Node node) {
    if (node != null) {
      Node child = node.getFirstChild();
      while (child != null) {
        if (!EditModelQuery.isTransparentText(child)) {
          return node;
        }
        child = child.getNextSibling();
      }
    }
    return null;
  }

  /**
   * @return true if is close to edge
   */
  public boolean isCloseToEdgeFromOutSide() {
    boolean result = false;
    if (EditModelQuery.isBlockNode(Target.resolveNode(_part))) {
      result = Math.abs(getAbsoluteBounds().getLeft().x - _point.x) <= MAX_OFFSET_TO_EDGE;
      if (!result) {
        result = Math.abs(getAbsoluteBounds().getRight().x - _point.x) <= MAX_OFFSET_TO_EDGE;
      }
    }
    return result;
  }

  private boolean isAboveCaret() {
    return getAbsoluteBounds().getBottom().y <= _point.y;
  }

  private boolean isUnderCaret() {
    return getAbsoluteBounds().getTop().y >= _point.y;
  }

  /**
   * @return tru if getPart() is considered inline
   */
  /*package*/ boolean isInline() {
    return EditModelQuery.isInline(Target.resolveNode(_part));
  }

    // TODO: dead?
//  private boolean isWidget() {
//    return EditModelQuery.isWidget(_part);
//  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#toString()
   */
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("editPart:" + _part + ", --- box: " + getBox()); //$NON-NLS-1$ //$NON-NLS-2$
    return sb.toString();
  }
}
TOP

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

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.