Package org.eclipse.jst.pagedesigner.css2.layout

Source Code of org.eclipse.jst.pagedesigner.css2.layout.CSSLayout

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

import java.util.List;

import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
import org.eclipse.jst.pagedesigner.css2.property.PositionMeta;
import org.eclipse.jst.pagedesigner.css2.property.VerticalAlignMeta;
import org.eclipse.jst.pagedesigner.css2.value.Length;
import org.eclipse.jst.pagedesigner.ui.preferences.PDPreferences;

/**
* CSSLayout is the base layout manager for different CSS layouts, such as block
* layout, inline layout (possible in the future table layout, etc)
*
* @author mengbo
*/
public abstract class CSSLayout extends FlowFigureLayout implements FlowContext {
  private BlockFlowContext _absoluteContext;

  // when doing absolute layout, and if top/left are both "auto", it will be
  // relating to the normaly flow position. The following two fields try to
  // catch normal flow layout position.
  // int _xForAbsolute;
  // int _yForAbsolute;
  private FlowBox _boxForAbsolute;

  /**
   * the current line
   */
  protected LineBox _currentLine;

  private boolean _calculatingMaxWidth = false;

  /**
   * @param flowFigure
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#FlowFigureLayout(FlowFigure)
   */
  protected CSSLayout(CSSFigure flowFigure) {
    super(flowFigure);
  }

  /**
   * a shortcut method to get the style associated with the figure.
   *
   * @return the css style
   */
  public ICSSStyle getCSSStyle() {
    return getCSSFigure().getCSSStyle();
  }

  /**
   * @return the absolute context
   */
  protected final BlockFlowContext getAbsoluteContext() {
        return _absoluteContext;
    }

    /**
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#addToCurrentLine(FlowBox)
   */
  public void addToCurrentLine(FlowBox block) {
    getCurrentLine().add(block);
  }

  /**
   * Used by getCurrentLine().
   */
  protected abstract void createNewLine();

  /**
   * Used by getCurrentLine(int topmargin)
   *
   * @param topMargin
   */
  protected void createNewLine(int topMargin) {
    createNewLine();
  }

  /**
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentLine()
   */
  public LineBox getCurrentLine() {
    if (_currentLine == null) {
      createNewLine();
    }
    return _currentLine;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentLine(int)
   */
  public LineBox getCurrentLine(int topMargin) {
    if (_currentLine == null) {
      createNewLine(topMargin);
    }
    // if the current line only contains an empty string, reset the current
    // line using the given margin.
    else if (_currentLine.isEmptyStringLine()) {
      List list = _currentLine.getFragments();
      createNewLine(topMargin);
      _currentLine._fragments.addAll(list);
    }
    return _currentLine;
  }

  /**
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#isCurrentLineOccupied
   */
  public boolean isCurrentLineOccupied() {
    return _currentLine != null && _currentLine.isOccupied();
  }

  /**
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#layout()
   */
  protected void layout() {
    preLayout();
    layoutChildren();
    flush();
    cleanup();
  }

  /**
   * @return true if is absolute position
   */
  protected final boolean isAbsolutePosition() {
    ICSSStyle style = getCSSStyle();

    // FIXME: Some layout don't support absolute, need check here
    if (style != null) {
      Object obj = style.getStyleProperty(ICSSPropertyID.ATTR_POSITION);
      if (PositionMeta.ABSOLUTE.equals(obj)
          || PositionMeta.FIXED.equals(obj))
      {
          PDPreferences prefs = new PDPreferences();
          return prefs.isCssAbsolutePositioningEnabled();
      }
    }
    return false;
  }

  /**
   * Child class could override this method.
   *
   * @return true if supports absolute position 
   */
  protected boolean supportAbsolutePosition() {
    if (findContainingPositionedFigure() == null) {
      return false;
    }
    return true;
  }

  /**
   * Perform a prelayout
   */
  protected void preLayout() {
    ICSSStyle style = this.getCSSStyle();
    if (style != null) {
      style.processCounters();
    }

    if (isAbsolutePosition()) {
      FlowContext parentFigureContext = getParentFigureContext();
      _absoluteContext = new BlockFlowContext(parentFigureContext, style);
      _boxForAbsolute = new FlowBox();// size is 0. Just as a flag, so
      // later we
      // could figure out where will this figure be
      // be put in case of not absolute
      _boxForAbsolute.setVerticalAlignData(VerticalAlignMeta.TOP);
      parentFigureContext.addToCurrentLine(_boxForAbsolute);
    } else {
      _absoluteContext = null;
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#getFlowContext()
   */
  public FlowContext getFlowContext() {
    if (_absoluteContext != null) {
      return _absoluteContext;
    }
        return getOriginalFlowContext();
  }

  /**
   * @return the flow context
   */
  private FlowContext getParentFigureContext() {
    return super.getFlowContext();
  }

  final void postValidateForAbsolute() {
    if (_absoluteContext != null) {
      ICSSStyle style = this.getCSSStyle();

      _absoluteContext.endBlock();

      int xOffset;
      int yOffset;

      ICSSFigure containingPositionedFigure = findContainingPositionedFigure();
      IFigure parentFigure = this.getCSSFigure().getParent();

      xOffset = calculatePositionRelativeToParent(style,
          containingPositionedFigure, parentFigure, true);
      yOffset = calculatePositionRelativeToParent(style,
          containingPositionedFigure, parentFigure, false);
      move(_absoluteContext._blockBox, xOffset, yOffset);
    }
  }

  /**
   * @param style
   * @param containingPositionedFigure
   * @param parentFigure
   * @return
   */
  private int calculatePositionRelativeToParent(ICSSStyle style,
      ICSSFigure containingPositionedFigure, IFigure parentFigure,
      boolean horizontal) {
    int xOffset;
    Object left = horizontal ? style
        .getStyleProperty(ICSSPropertyID.ATTR_LEFT) : style
        .getStyleProperty(ICSSPropertyID.ATTR_TOP);
    Object right = horizontal ? style
        .getStyleProperty(ICSSPropertyID.ATTR_RIGHT) : style
        .getStyleProperty(ICSSPropertyID.ATTR_BOTTOM);

    if (!(left instanceof Length) && !(right instanceof Length)) {
      // _boxForAbsolute partipated the layout of the parent figure, and
      // is already relative to parent.
      return horizontal ? _boxForAbsolute._x : _boxForAbsolute._y;
    }

    // ok, user specified left or right. let's calculate the left
    int leftValue;
    if (left instanceof Length) {
      Length leftLength = (Length) left;
      leftValue = leftLength.getValue();
      if (leftLength.isPercentage()) {
        leftValue = (horizontal ? containingPositionedFigure
            .getBounds().width : containingPositionedFigure
            .getBounds().height)
            * leftValue / 100;
      }
    } else {
      Length rightLength = (Length) right;
      int lengthValue = rightLength.getValue();
      if (rightLength.isPercentage()) {
        lengthValue = (horizontal ? containingPositionedFigure
            .getBounds().width : containingPositionedFigure
            .getBounds().height)
            * lengthValue / 100;
      }

      if (horizontal) {
        leftValue = containingPositionedFigure.getBounds().width
            - _absoluteContext._blockBox.getWidth() - lengthValue;
      } else {
        leftValue = containingPositionedFigure.getBounds().height
            - _absoluteContext._blockBox.getHeight() - lengthValue;
      }

    }

    // xOffset is relative to the first box of the containing figure
    List fragments = containingPositionedFigure
        .getFragmentsForRead();
    if (fragments.size() > 0) {
      FlowBox box = (FlowBox) fragments.get(0);
      // box._x is the x location relative to containingPositionedFigure's
      // parent.
      // so now xOffset is relative to containingPositionedFigure's
      // parent.
      xOffset = (horizontal ? box._x : box._y) + leftValue;
    } else {
      xOffset = leftValue; // should not happen.
    }
    Point p;
    if (horizontal) {
      p = new Point(xOffset, 0);
    } else {
      p = new Point(0, xOffset);
    }
    containingPositionedFigure.translateFromParent(p);
    containingPositionedFigure.translateToAbsolute(p);
    parentFigure.translateToRelative(p);
    return horizontal ? p.x : p.y;
  }

  /**
   * @return
   */
  private ICSSFigure findContainingPositionedFigure() {
    IFigure figure = this.getCSSFigure().getParent();
    while (figure instanceof ICSSFigure) {
      return (ICSSFigure) figure;
      // ICSSStyle style = ((ICSSFigure) figure).getCSSStyle();
      // if (DisplayToLayout.isPositioned(style))
      // {
      // return (ICSSFigure) figure;
      // }
      // figure = figure.getParent();
    }
    return null;

  }

  /**
   * @param resultBox
   * @param x
   * @param y
   */
  private void move(CompositeBox compBox, int x, int y) {
    compBox._x += x;
    compBox._y += y;
    List list = compBox.getFragments();
    for (int i = 0; i < list.size(); i++) {
      FlowBox box = (FlowBox) list.get(i);

      if (box instanceof CompositeBox && !(box instanceof BlockBox)) {
        move((CompositeBox) box, x, y);
      } else {
        box._x += x;
        box._y += y;
      }
    }
  }

  /**
   * Layout all children.
   */
  protected void layoutChildren() {
    List children = getFlowFigure().getChildren();
    for (int i = 0; i < children.size(); i++) {
      Figure f = (Figure) children.get(i);
      f.invalidate();
      f.validate();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getLastMarginRight()
   */
  public int getLastMarginRight() {
    if (_currentLine == null || !_currentLine.isOccupied()) {
      return 0;
    }
    FlowBox box = (FlowBox) _currentLine.getFragments().get(
        _currentLine.getFragments().size() - 1);
    if (box != null) {
      return box.getMarginInsets().right;
    }
        return 0;
  }

  /**
   * @param c
   */
  public void setCalculatingMaxWidth(boolean c) {
    _calculatingMaxWidth = c;
  }

  /**
   * @return the calculated maximum width
   */
  public boolean getCalcuatingMaxWidth() {
    return _calculatingMaxWidth;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#isCalculatingMaxWidth()
   */
  public boolean isCalculatingMaxWidth() {
    if (_calculatingMaxWidth) {
      return true;
    } else if (this.getFlowContext() == null) {
      return false;
    } else {
      return this.getFlowContext().isCalculatingMaxWidth();
    }
  }

  /**
   * Called after {@link #layoutChildren()}when all children have been laid
   * out. This method exists to flush the last line.
   */
  protected abstract void flush();

  /**
   * Flush anything pending and free all temporary data used during layout.
   */
  protected abstract void cleanup();

  // ------------------------------------------------------------------------------------

  /**
   * @return the css figure
   */
  protected final CSSFigure getCSSFigure() {
    return (CSSFigure) getFlowFigure();
  }

  /**
   *
   * @return the fragments for read
   */
  public abstract List getFragmentsForRead();

  /**
   * postValidate the child figures of this CSSFigure. Normally layout fall
   * into the first category need implement this method.
   */
  public abstract void postValidate();

  /**
   * setBounds is called on the CSSFigure. Normally layout fall into the
   * second category need implement this method.
   *
   * @param rect
   * @param invalidate
   */
  public void setBoundsCalled(Rectangle rect, boolean invalidate) {
        // TODO: dead?
  }

  /**
   * Child class can override this. Normally block figure will return true.
   *
   * @return true if should use local coordinates
   */
  protected boolean useLocalCoordinates() {
    return false;
  }

  /**
   * If CSSLayout will call paint rountine to draw Border for its box, this
   * method will return true, else return false, for example,the input file
   * will return false.
   *
   * @return true if handling border block
   */
  protected boolean handlingBorderForBlock() {
    return true;
  }

  /**
   * This method is called when the corresponding figure is revalidated.
   *
   */
  protected void figureRevalidate() {
    // child class can override.
  }
}
TOP

Related Classes of org.eclipse.jst.pagedesigner.css2.layout.CSSLayout

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.