Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout')
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockBox.java101
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlow.java112
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowContext.java284
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowLayout.java251
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BoxUtil.java66
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBlockFlowLayout.java723
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBrFlowLayout.java62
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSFigure.java518
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSInlineFlowLayout.java319
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSLayout.java457
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSListItemLayout.java185
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSPageFlowLayout.java186
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextFigure.java302
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextLayout.java176
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSWidgetLayout.java220
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CompositeBox.java148
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/Debug.java28
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/DisplayToLayout.java100
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FigureUtil.java42
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowBox.java161
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContainerLayout.java180
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContext.java90
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigure.java190
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigureLayout.java116
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowPage.java160
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowUtilities.java260
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSFigure.java38
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSLayout.java55
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter.java29
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter2.java34
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/LineBox.java414
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/MultiLineLabel.java126
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/PageFlowLayout.java72
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextFragmentBox.java85
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextLayoutSupport.java386
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/WidgetBox.java41
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRGroupLayout.java179
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRLayout.java193
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCaptionLayout.java110
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCellLayout.java199
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableLayout2.java628
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CachedTableCellLayout.java251
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCaptionInfo.java63
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCellInfo.java216
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfo.java368
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfoContext.java112
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableItemInfo.java38
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowGroupInfo.java103
-rw-r--r--jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowInfo.java136
49 files changed, 9313 insertions, 0 deletions
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockBox.java
new file mode 100644
index 000000000..7c635a59c
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockBox.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * A CompositeBox suitable for containing multiple LineBox fragments. Based on
+ * BlockBox of draw2d.
+ *
+ * @author mengbo
+ */
+public class BlockBox extends CompositeBox {
+ // internalContent dimension is for the closure of the FlowBox(es) added
+ // into the BlockBox.
+ private int _internalContentWidth = -1;
+
+ private int _internalContentHeight = -1;
+
+ Rectangle toRectangle() {
+ return new Rectangle(_x, _y, Math.max(_width, _recommendedWidth),
+ _height);
+ }
+
+ /**
+ * Sets the height.
+ *
+ * @param h
+ * The height
+ */
+ public void setHeight(int h) {
+ _height = h;
+ }
+
+ /**
+ * Unions the dimensions of this with the dimensions of the passed FlowBox.
+ * For BlockBox, each time unionInfo is called, the passed in object
+ * represents a line.
+ *
+ * @param box
+ * The FlowBox to union this with
+ */
+ protected void unionInfo(FlowBox box) {
+ _width = Math.max(_width, box._width + this.getBorderPaddingWidth());
+ _height = Math.max(_height, box._y + box._height
+ + this.getBorderPaddingHeight());
+
+ _internalContentWidth = Math.max(_internalContentWidth, box._width);
+ _internalContentHeight = Math.max(_internalContentHeight, box._y
+ + box._height);
+ }
+
+ public int getInternalContentWidth() {
+ return _internalContentWidth;
+ }
+
+ public int getInternalContentHeight() {
+ return _internalContentHeight;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowBox#getAscent()
+ */
+ public int getAscent() {
+ // XXX: some hard coded things here. If the blockbox is only for a
+ // single widget, and if that widget support ascent, then we'll
+ // delegate to that widget for ascent support.
+ // if (_fragments.size()==1)
+ // {
+ // FlowBox box = (FlowBox) _fragments.get(0);
+ // if (box instanceof LineBox)
+ // {
+ // List linecomponents = ((LineBox) box).getFragments();
+ // if (linecomponents != null && linecomponents.size() == 1)
+ // {
+ // FlowBox box2 = (FlowBox) linecomponents.get(0);
+ // if (box2 instanceof WidgetBox)
+ // {
+ // WidgetBox widgetBox = (WidgetBox) box2;
+ // if (widgetBox.supportAscent())
+ // {
+ // return widgetBox.getAscent() + this.getBorderPaddingInsets().top;
+ // }
+ // }
+ // }
+ // }
+ // }
+ return super.getAscent();
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlow.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlow.java
new file mode 100644
index 000000000..35eb4c7c2
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlow.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * 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.PositionConstants;
+
+/**
+ * A <code>FlowFigure</code> represented by a single {@link BlockBox}fragment
+ * containing one or more lines. A BlockFlow is a creator of LineBoxes, which
+ * its children require during layout. A BlockFlow can be thought of as a
+ * paragraph.
+ * <P>
+ * BlockFlows should be nested inside other BlockFlows, but it is also valid to
+ * place them in InlineFlows. {@link FlowPage}can be used as a "root" block and
+ * can be added to normal draw2d Figures.
+ * <P>
+ * Only {@link FlowFigure}s can be added to a BlockFlow.
+ */
+public class BlockFlow extends FlowFigure {
+
+ final BlockBox _blockBox;
+
+ private int _aligment;
+
+ /**
+ * Constructs a new BlockFlow.
+ */
+ public BlockFlow() {
+ setLayoutManager(createDefaultFlowLayout());
+ _blockBox = createBlockBox();
+ }
+
+ BlockBox createBlockBox() {
+ return new BlockBox();
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigure#createDefaultFlowLayout()
+ */
+ protected FlowFigureLayout createDefaultFlowLayout() {
+ return new BlockFlowLayout(this);
+ }
+
+ /**
+ * Returns the BlockBox associated with this.
+ *
+ * @return This BlockFlow's BlockBox
+ */
+ protected BlockBox getBlockBox() {
+ return _blockBox;
+ }
+
+ /**
+ * Returns the horizontal aligment.
+ *
+ * @return the hotizontal aligment
+ */
+ public int getHorizontalAligment() {
+ return _aligment & PositionConstants.LEFT_CENTER_RIGHT;
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigure#postValidate()
+ */
+ public void postValidate() {
+ setBounds(getBlockBox().toRectangle().expand(getInsets()));
+ List v = getChildren();
+ for (int i = 0, n = v.size(); i < n; i++) {
+ ((FlowFigure) v.get(i)).postValidate();
+ }
+ }
+
+ /**
+ * Sets the horitontal aligment of the block. Valid values are:
+ * <UL>
+ * <LI>{@link org.eclipse.draw2d.PositionConstants#LEFT}
+ * <LI>{@link org.eclipse.draw2d.PositionConstants#RIGHT}
+ * <LI>{@link org.eclipse.draw2d.PositionConstants#CENTER}
+ *
+ * @param value
+ * the aligment
+ */
+ public void setHorizontalAligment(int value) {
+ if (!(value == PositionConstants.LEFT
+ || value == PositionConstants.RIGHT || value == PositionConstants.CENTER)) {
+ throw new IllegalArgumentException(
+ "Horizontal Aligment must be one of: LEFT, CENTER, RIGHT");
+ }
+ this._aligment &= ~PositionConstants.LEFT_CENTER_RIGHT;
+ this._aligment |= value;
+ revalidate();
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowContext.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowContext.java
new file mode 100644
index 000000000..55faec578
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowContext.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * 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 org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.value.Length;
+
+/**
+ * When doing absolute positioning, we need to create a block. But that block
+ * don't have a corresponding figure. So we need a block without corresponding
+ * figure.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class BlockFlowContext implements FlowContext {
+ protected LineBox _currentLine;
+
+ private LineBox _previousLine = null;
+
+ protected BlockBox _blockBox;
+
+ protected FlowContext _originalContext;
+
+ protected ICSSStyle _style;
+
+ /**
+ *
+ */
+ public BlockFlowContext(FlowContext originalContext, ICSSStyle style) {
+ this._originalContext = originalContext;
+ this._style = style;
+ setup();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()
+ */
+ public int getContainerWidth() {
+
+ return _originalContext.getContainerWidth();
+ }
+
+ public void setup() {
+ _blockBox = new BlockBox();
+ _blockBox.setRecommendedWidth(getRecommendedWidth());
+ _currentLine = this.getCurrentLine();
+ _previousLine = null;
+ }
+
+ private int getRecommendedWidth() {
+ int containerWidth = getContainerWidth();
+ Object leftObj = _style.getStyleProperty(ICSSPropertyID.ATTR_LEFT);
+ if (leftObj != null && leftObj instanceof Length) {
+ Length left = (Length) leftObj;
+ int intLeft = left.getValue();
+ if (left.isPercentage()) {
+ intLeft = containerWidth * intLeft / 100;
+ }
+ if (intLeft < containerWidth) {
+ return containerWidth - intLeft;
+ }
+ }
+ return containerWidth;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#addToCurrentLine(org.eclipse.jst.pagedesigner.css2.layout.FlowBox)
+ */
+ public void addToCurrentLine(FlowBox block) {
+ getCurrentLine().add(block);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#endLine()
+ */
+ public void endLine() {
+ // this is called from child layouts.
+ // If there is no current line, state is equivalent to new line
+ if (_currentLine == null)
+ return;
+ if (_currentLine.isOccupied())
+ layoutLine(); // finalize the current line layout
+ else
+ return;
+
+ LineBox box = _currentLine;
+ // _currentLine = _previousLine; //XXX: ???? why (yang)
+ _previousLine = box;
+
+ _currentLine = null;
+ // setupLine(getCurrentLine());
+
+ }
+
+ /**
+ * @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);
+ return _currentLine;
+ }
+
+ /**
+ * @param topMargin
+ */
+ private void createNewLine(int topMargin) {
+ createNewLine();
+ }
+
+ protected void createNewLine() {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, Integer.MIN_VALUE);
+ }
+
+ /**
+ * Override to setup the line's x, remaining, and available width.
+ *
+ * @param line
+ * the LineBox to set up
+ */
+ protected void setupLine(LineBox line, int topMargin) {
+ line.clear();
+
+ // the caller of getCurrentLine() may add leftMargin and leftPadding and
+ // leftBorder to line.x
+ line._x = _blockBox._borderInsets.left + _blockBox._paddingInsets.left;
+
+ // FIXME: here should check the floating boxes, and minus the width of
+ // them from
+ // current line.
+ // XXX: the RecommendedContentWidth is related with the RecommendedWidth
+ // of container that
+ // usually larger than it needed.here we do not set the RecommendedWidth
+ // for the sake of
+ // layouting right absolute position.
+ // /shortcoming:the box will break into multi-line after every white
+ // space.
+ // line.setRecommendedWidth(_blockBox.getRecommendedContentWidth());
+ if (_previousLine == null) {
+ line._y = _blockBox._borderInsets.top
+ + _blockBox._paddingInsets.top;
+ if (topMargin != Integer.MIN_VALUE)
+ line._y += topMargin;
+ } else {
+ if (topMargin == Integer.MIN_VALUE)
+ line._y = _previousLine._y + _previousLine.getHeight()
+ + getLinePadding() + _previousLine._marginInsets.bottom; // XXX:
+ // should
+ // add
+ // previous
+ // margin
+ // bottom?
+ else
+ line._y = _previousLine._y
+ + _previousLine.getHeight()
+ + Math.max(topMargin,
+ _previousLine._marginInsets.bottom);
+ }
+ // line.validate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()
+ */
+ public int getCurrentY() {
+ return getCurrentLine()._y; // FIXME: margin of previous block?
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#isCurrentLineOccupied()
+ */
+ public boolean isCurrentLineOccupied() {
+ return _currentLine != null && _currentLine.isOccupied();
+ }
+
+ /*
+ * (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._marginInsets.right;
+ } else {
+ return 0;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#isCalculatingMaxWidth()
+ */
+ public boolean isCalculatingMaxWidth() {
+ return false;
+ }
+
+ /**
+ * Adjust all fragments in the current line to have the same baseline. Do
+ * any additional adjustments, such as horizontal alignment.
+ */
+ protected void layoutLine() {
+ // currentLine.x = 0; //XXX: comment out, don't understand why set to 0,
+ // because it has already
+ // been set when setupLine(). And if do need, should
+ // set to getBorderPaddingInsets().left
+ // if (!isInlineBlock() && shouldExpand())
+ // {
+ // // FIXME: currently we are using getRecommendedContentWidth,
+ // // what happen if after adding the new line, the new width is bigger
+ // than
+ // // recommendedContentWidth? should we use getWidth() instead of
+ // // recommendedcontentWidth?
+ //
+ // Object textalign =
+ // (getCSSStyle().getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));
+ // if (textalign == ICSSPropertyID.VAL_RIGHT)
+ // {
+ // _currentLine._x = _blockBox.getRecommendedContentWidth() +
+ // _blockBox.getBorderPaddingInsets().left - _currentLine.getWidth();
+ // }
+ // else if (textalign == ICSSPropertyID.VAL_CENTER)
+ // {
+ //
+ // _currentLine._x = _blockBox.getBorderPaddingInsets().left +
+ // (_blockBox.getRecommendedContentWidth() - _currentLine.getWidth()) /
+ // 2;
+ // }
+ // if (_currentLine._x < 0)
+ // _currentLine._x = 0;
+ // }
+
+ // FIXME: should check vertical alignment here?
+ _currentLine.commit();
+ _blockBox.add(_currentLine);
+ }
+
+ public void endBlock() {
+ endLine();
+ }
+
+ int getLinePadding() {
+ return 0;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowLayout.java
new file mode 100644
index 000000000..8647f293c
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BlockFlowLayout.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Insets;
+
+/**
+ * The layout for {@link BlockFlow}figures.
+ * <P>
+ * WARNING: This class is not intended to be subclassed by clients.
+ *
+ * @author mengbo
+ * @since 2.1
+ */
+public class BlockFlowLayout extends FlowContainerLayout {
+ private LineBox _previousLine = null;
+
+ BlockBox _blockBox;
+
+ /**
+ * Creates a new BlockFlowLayout with the given BlockFlow.
+ *
+ * @param blockFlow
+ * the BlockFlow
+ */
+ public BlockFlowLayout(BlockFlow blockFlow) {
+ super(blockFlow);
+ }
+
+ /**
+ * @see FlowContainerLayout#cleanup()
+ */
+ protected void cleanup() {
+ _currentLine = _previousLine = null;
+ }
+
+ /**
+ * @see FlowContainerLayout#createNewLine()
+ */
+ protected void createNewLine() {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, Integer.MIN_VALUE);
+ }
+
+ protected void createNewLine(int topmargin) {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, topmargin);
+ }
+
+ /**
+ * Override to setup the line's x, remaining, and available width.
+ *
+ * @param line
+ * the LineBox to set up
+ */
+ protected void setupLine(LineBox line, int topMargin) {
+ line.clear();
+
+ // the caller of getCurrentLine() may add leftMargin and leftPadding and
+ // leftBorder to line.x
+ line._x = 0;
+
+ // FIXME: here should check the floating boxes, and minus the width of
+ // them from
+ // current line.
+ line.setRecommendedWidth(_blockBox.getRecommendedContentWidth());
+ if (_previousLine == null) {
+ line._y = 0;
+ if (topMargin != Integer.MIN_VALUE) {
+ line._y += topMargin;
+ }
+ } else {
+ if (topMargin == Integer.MIN_VALUE) {
+ line._y = _previousLine._y + _previousLine.getHeight()
+ + getLinePadding() + _previousLine._marginInsets.bottom; // XXX:
+ // should
+ // add
+ // previous
+ // margin
+ // bottom?
+ } else {
+ line._y = _previousLine._y
+ + _previousLine.getHeight()
+ + Math.max(topMargin,
+ _previousLine._marginInsets.bottom);
+ }
+ }
+ // line.validate();
+ }
+
+ /**
+ * Called by flush(), adds the BlockBox associated with this BlockFlowLayout
+ * to the current line and then ends the line.
+ */
+ protected void endBlock() {
+ getFlowContext().addToCurrentLine(_blockBox);
+
+ // FIXME: here should tell the context the bottom margin.
+ getFlowContext().endLine();
+ }
+
+ /**
+ * @see FlowContext#endLine()
+ */
+ public void endLine() {
+ // this is called from child layouts.
+ // If there is no current line, state is equivalent to new line
+ if (_currentLine == null) {
+ return;
+ }
+ if (_currentLine.isOccupied()) {
+ layoutLine(); // finalize the current line layout
+ } else {
+ _currentLine = null;
+ return;
+ }
+ LineBox box = _currentLine;
+ _previousLine = box;
+ _currentLine = null;// _previousLine; //XXX: ???? why (yang)
+
+ // setupLine(getCurrentLine());
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()
+ */
+ public int getCurrentY() {
+ return getCurrentLine()._y; // FIXME: margin of previous block?
+ }
+
+ /**
+ * Returns the BlockFlow associated with this BlockFlowLayout
+ *
+ * @return the BlockFlow
+ */
+ protected final BlockFlow getBlockFlow() {
+ return (BlockFlow) getFlowFigure();
+ }
+
+ /**
+ * Adjust all fragments in the current line to have the same baseline. Do
+ * any additional adjustments, such as horizontal alignment.
+ */
+ protected void layoutLine() {
+ // currentLine.x = 0; //XXX: comment out, don't understand why set to 0,
+ // because it has already
+ // been set when setupLine(). And if do need, should
+ // set to getBorderPaddingInsets().left
+ switch (getBlockFlow().getHorizontalAligment()) {
+ case PositionConstants.RIGHT:
+ _currentLine._x = _blockBox.getContentWidth()
+ - getBorderPaddingInsets().right - _currentLine.getWidth();
+ break;
+ case PositionConstants.CENTER:
+ _currentLine._x = (_blockBox.getContentWidth()
+ + getBorderPaddingInsets().left
+ - getBorderPaddingInsets().right - _currentLine.getWidth()) / 2;
+ break;
+ }
+ // FIXME: should check vertical alignment here?
+ _currentLine.commit();
+ _blockBox.add(_currentLine);
+ }
+
+ /**
+ * @see FlowContainerLayout#flush()
+ */
+ protected void flush() {
+ if (_currentLine != null)
+ layoutLine();
+ endBlock();
+ }
+
+ /**
+ * @see FlowContainerLayout#preLayout()
+ */
+ protected void preLayout() {
+ _blockBox = getBlockFlow().getBlockBox();
+ setupBlock();
+ // Probably could setup current and previous line here, or just previous
+ }
+
+ /**
+ * sets up the single block that contains all of the lines.
+ */
+ protected void setupBlock() {
+ // Ask for a new line, in case we are in the middle of a line
+
+ // FIXME: the endLine() should tell context the top margin of this
+ // block.
+ getFlowContext().endLine();
+
+ LineBox line = getFlowContext().getCurrentLine();
+ // int recommended = line.getAvailableWidth();
+ // if (recommended != previousRecommendedWidth)
+ // Remove all current Fragments
+ _blockBox.clear();
+
+ // Setup the one fragment for this Block with the correct X and
+ // available width
+
+ // FIXME: here should check whether the CSS already set recommended
+ // width for this
+ // block.
+ _blockBox.setRecommendedWidth(line.getAvailableWidth());
+
+ _blockBox._y = getFlowContext().getCurrentY();
+
+ // FIXME: blockBox.x should be context.getBorderPaddingInsets().left
+ // or just line.x ?
+ _blockBox._x = 0;
+ }
+
+ Insets getBorderPaddingInsets() {
+ // FIXME:
+ return new Insets();
+ }
+
+ int getLinePadding() {
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()
+ */
+ public void dispose() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()
+ */
+ public int getContainerWidth() {
+ int width = Math.max(0, Math.max(_blockBox.getWidth(), _blockBox
+ .getRecommendedWidth()));
+ return width;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BoxUtil.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BoxUtil.java
new file mode 100644
index 000000000..54978d145
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/BoxUtil.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.swt.graphics.Color;
+
+/**
+ * @author mengbo
+ */
+public class BoxUtil {
+ /**
+ * @param box
+ * @param style
+ */
+ public static void setupBorderPaddingMargin(FlowBox box, ICSSStyle style) {
+ box._marginInsets = new Insets(style.getMarginInsets());
+ box._borderInsets = new Insets(style.getBorderInsets());
+ box._paddingInsets = new Insets(style.getPaddingInsets());
+
+ if (box.getBorderPaddingHeight() > box.getHeight()) {
+ box.setHeight(box.getBorderPaddingHeight());
+ }
+ if (box.getBorderPaddingWidth() > box.getWidth()) {
+ box.setWidth(box.getBorderPaddingWidth());
+ }
+ }
+
+ /**
+ * Debug code.
+ *
+ * @param g
+ * @param box
+ */
+ public static void drawBox(Graphics g, FlowBox box) {
+ Color color = null;
+ if (box instanceof BlockBox) {
+ // color = ColorConstants.red;
+ } else if (box instanceof LineBox) {
+ color = ColorConstants.blue;
+ } else if (box instanceof TextFragmentBox) {
+ color = ColorConstants.green;
+ } else {
+ color = ColorConstants.darkGreen;
+ }
+ if (color != null) {
+ g.setForegroundColor(color);
+ g.setLineStyle(Graphics.LINE_DASH);
+ g.setLineWidth(1);
+ g.drawRectangle(box._x, box._y, box.getWidth(), box.getHeight());
+ }
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBlockFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBlockFlowLayout.java
new file mode 100644
index 000000000..6460f5ffd
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBlockFlowLayout.java
@@ -0,0 +1,723 @@
+/*******************************************************************************
+ * 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.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Insets;
+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.ICSSPropertyMeta;
+import org.eclipse.jst.pagedesigner.css2.style.ITagEditInfo;
+import org.eclipse.jst.pagedesigner.css2.value.Length;
+import org.eclipse.jst.pagedesigner.css2.widget.BorderUtil;
+import org.eclipse.swt.graphics.FontMetrics;
+
+/**
+ * The block layout for {@link CSSFigure}figures. Basic code structure is from
+ * BlockFlowLayout.
+ *
+ * @author mengbo
+ */
+public class CSSBlockFlowLayout extends CSSLayout implements ICSSPainter2 {
+ private LineBox _previousLine = null;
+
+ protected BlockBox _blockBox = null;
+
+ protected FontMetrics _fontMetrices;
+
+ int _userSpecifiedWidth;
+
+ int _userSpecifiedHeight;
+
+ /*
+ * whether we need HScroll and VScroll when overflow is set to "scroll".
+ * will be updated in "endBlock" and used in "paintFigurePostClientArea"
+ */
+ boolean _needHScroll = false;
+
+ boolean _needVScroll = false;
+
+ /**
+ * Creates a new CSSBlockFlowLayout with the given BlockFlow.
+ */
+ public CSSBlockFlowLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ protected boolean hasMoreThanOneLine() {
+ return _previousLine != null;
+ }
+
+ public boolean isInlineBlock() {
+ String obj = getCSSStyle().getDisplay();
+ return ICSSPropertyID.VAL_INLINE_BLOCK.equals(obj)
+ || ICSSPropertyID.VAL_INLINE_TABLE.equals(obj);
+ }
+
+ /**
+ * whether should expand the width to all available width.
+ *
+ * @return
+ */
+ public boolean shouldExpand() {
+ ICSSStyle style = getCSSStyle();
+ if (style == null) {
+ return false;
+ } else {
+ return "block".equalsIgnoreCase(style.getDisplay())
+ || "list-item".equalsIgnoreCase(style.getDisplay());
+ }
+ }
+
+ // ---------------------------------------------------------------------------------------------------
+ // preLayout stage. Major job is get the top-left corner information of the
+ // new block.
+
+ /**
+ * sets up the single block that contains all of the lines.
+ */
+ protected void setupBlock() {
+ // int recommended = line.getAvailableWidth();
+ // if (recommended != previousRecommendedWidth)
+ // Remove all current Fragments
+ _blockBox.clear();
+ // Ask for a new line, in case we are in the middle of a line
+
+ if (!isInlineBlock()) {
+ LineBox lineBox = getFlowContext().getCurrentLine();
+ if (lineBox != null && !lineBox.isEmptyStringLine()) {
+ getFlowContext().endLine();
+ }
+ }
+
+ ICSSStyle style = getCSSStyle();
+
+ // endLine will result in context create a new line, so we are in the
+ // new line now.
+ // passing in the top margin, and context will consider that when create
+ // the new line.
+ int marginTop = style.getMarginInsets().top;
+ LineBox line = getFlowContext().getCurrentLine(marginTop);
+
+ // Setup the one fragment for this Block with the correct X and
+ // available width
+
+ // FIXME: according to spec, when using percentage width/height, should
+ // percentage to
+ // the "containing block". But we don't have very good "containing
+ // block" resolution
+ // implementation yet.
+
+ // calculate the min size
+ // int minWidth = 0;
+ // int minHeight = 0;
+ // if (style != null)
+ // {
+ // // try to see whether there is any designer specified min size
+ // ITagEditInfo info = (ITagEditInfo)
+ // style.getAdapter(ITagEditInfo.class);
+ // if (info != null)
+ // {
+ // minWidth = info.getMinWidth();
+ // minHeight = info.getMinHeight();
+ // }
+ //
+ // // CSS also has the min-width/min-height property. We should also get
+ // that,
+ // // and using the max of the "min-width" css property and the designer
+ // specified min size.
+ // int height = getLengthValue(style,ICSSPropertyID.ATTR_MIN_HEIGHT);
+ // if(height > minHeight)
+ // {
+ // minHeight = height;
+ // }
+ // int width = getLengthValue(style,ICSSPropertyID.ATTR_MIN_WIDTH);
+ // if(width > minWidth)
+ // {
+ // minWidth = width;
+ // }
+ // }
+
+ // keep track of user specified size, this will be used when handling
+ // the "overflow" CSS property.
+ _userSpecifiedWidth = 0;
+ _userSpecifiedHeight = 0;
+
+ {
+ int width = getLengthValue(style, ICSSPropertyID.ATTR_WIDTH);
+
+ int availableWidth = line.getAvailableWidth()
+ - style.getMarginInsets().getWidth();
+ if (width <= 0) {
+ // no width setting
+ if (isCalculatingMaxWidth()) {
+ _blockBox.setRecommendedWidth(Integer.MAX_VALUE);
+ // _blockBox.setWidth( (minWidth>0?minWidth:0));
+ } else {
+ _blockBox.setRecommendedWidth(availableWidth);
+ if (shouldExpand()) {
+ _blockBox.setWidth(availableWidth);
+ } else {
+ // _blockBox.setWidth( (minWidth>0?minWidth:0));
+ }
+ }
+ } else {
+ int w = width;
+ if (!style.isSizeIncludeBorderPadding()) {
+ w += style.getBorderInsets().getWidth()
+ + style.getPaddingInsets().getWidth();
+ }
+ // XXX: should we use minWidth or follow user's choice?
+ // if (w < minWidth)
+ // {
+ // w = minWidth;
+ // }
+ _userSpecifiedWidth = w;
+ _blockBox.setWidth(w);
+ _blockBox.setRecommendedWidth(w);
+ }
+ }
+
+ {
+ int height = getLengthValue(style, ICSSPropertyID.ATTR_HEIGHT);
+ // Object height =
+ // style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);
+ // Length heightLength = (height instanceof Length) ? (Length)
+ // height : null;
+
+ if (height <= 0) {
+ // if (minHeight > 0)
+ // {
+ // // _blockBox.setHeight(minHeight);
+ // _blockBox.setRecommendedHeight(minHeight);
+ // }
+ // else
+ {
+ _blockBox.setHeight(0);
+ _blockBox.setRecommendedHeight(0);
+ }
+ } else {
+ int h = height;
+ if (handlingBorderForBlock()
+ && !style.isSizeIncludeBorderPadding()) {
+ h += style.getBorderInsets().getHeight()
+ + style.getPaddingInsets().getHeight();
+ }
+ // XXX: should we follow minHeight or user's choice?
+ // if (minHeight > h)
+ // {
+ // h = minHeight;
+ // }
+ _userSpecifiedHeight = h;
+ _blockBox.setHeight(h);
+ _blockBox.setRecommendedHeight(h);
+ }
+ }
+ _blockBox._marginInsets = new Insets(style.getMarginInsets());
+ if (handlingBorderForBlock()) {
+ BoxUtil.setupBorderPaddingMargin(_blockBox, getCSSStyle());
+ }
+
+ // as in designer, we don't want to the element to have zero size, so
+ // set a minimun size here.
+ // _blockBox.setWidth(Math.max(20, _blockBox.getWidth()));
+ // int minHeight = getCSSStyle().getCSSFont().getFontSize() +
+ // _blockBox.getBorderPaddingHeight();
+ // _blockBox.setHeight(Math.max(minHeight, _blockBox.getHeight()));
+
+ _blockBox._y = line._y;
+ _blockBox._x = line._x;
+
+ setBlockVerticalAlign(_blockBox);
+ }
+
+ protected int getLengthValue(ICSSStyle style, String property) {
+ int lengthValue = 0;
+ if (style != null) {
+ Object object = style.getStyleProperty(property);
+ Length lengthObj = (object instanceof Length) ? (Length) object
+ : null;
+
+ if (lengthObj != null) {
+ lengthValue = lengthObj.getValue();
+ if (lengthObj.isPercentage()) {
+ if (ICSSPropertyID.ATTR_WIDTH.equalsIgnoreCase(property)
+ || ICSSPropertyID.ATTR_MIN_WIDTH
+ .equalsIgnoreCase(property)) {
+ lengthValue = this.getFlowContext().getContainerWidth()
+ * lengthValue / 100;
+ } else if (ICSSPropertyID.ATTR_HEIGHT
+ .equalsIgnoreCase(property)
+ || ICSSPropertyID.ATTR_MIN_HEIGHT
+ .equalsIgnoreCase(property)) {
+ // XXX: we should omit it because we don't support
+ // percentage height now.
+ lengthValue = 0;
+ }
+ }
+ }
+ }
+ return lengthValue;
+ }
+
+ private void setBlockVerticalAlign(BlockBox box) {
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ box.setVerticalAlignData(style
+ .getStyleProperty(ICSSPropertyID.ATTR_VERTICAL_ALIGN));
+ }
+ }
+
+ /**
+ * @see FlowContainerLayout#preLayout()
+ */
+ protected void preLayout() {
+ super.preLayout();
+ _blockBox = new BlockBox();
+ setupBlock();
+ // Probably could setup current and previous line here, or just previous
+ }
+
+ // -------------------------------------------------------------------------------------------------------
+ protected void layoutLines() {
+ List lines = _blockBox.getFragments();
+ if (lines != null) {
+ for (int i = 0; i < lines.size(); i++) {
+ if (lines.get(i) instanceof LineBox) {
+ layoutLine((LineBox) lines.get(i));
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by flush(), adds the BlockBox associated with this BlockFlowLayout
+ * to the current line and then ends the line.
+ */
+ protected void endBlock() {
+ layoutLines();
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ int minWidth = 0;
+ int minHeight = 0;
+ // try to see whether there is any designer specified min size
+ ITagEditInfo info = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (info != null) {
+ minWidth = info.getMinWidth();
+ minHeight = info.getMinHeight();
+ }
+
+ // CSS also has the min-width/min-height property. We should also
+ // get that,
+ // and using the max of the "min-width" css property and the
+ // designer specified min size.
+ int height = getLengthValue(style, ICSSPropertyID.ATTR_MIN_HEIGHT);
+ if (height > minHeight) {
+ minHeight = height;
+ }
+ int width = getLengthValue(style, ICSSPropertyID.ATTR_MIN_WIDTH);
+ if (width > minWidth) {
+ minWidth = width;
+ }
+ if (minHeight > _blockBox.getHeight()) {
+ _blockBox.setHeight(minHeight);
+ }
+ if (minWidth > _blockBox.getWidth()) {
+ _blockBox.setWidth(minWidth);
+ }
+ }
+
+ // reset scroll information.
+ this._needHScroll = this._needVScroll = false;
+
+ // ok, now we need to adjust the _blockBox's size according to the
+ // "overflow" setting.
+ // depends on different "overflow" style of this block, different sizing
+ // policy may apply.
+ // ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ Object overflow = style
+ .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);
+ if (ICSSPropertyID.VAL_HIDDEN.equals(overflow)) {
+ if (_userSpecifiedWidth > 0) {
+ _blockBox.setWidth(_userSpecifiedWidth);
+ }
+ if (_userSpecifiedHeight > 0) {
+ _blockBox.setHeight(_userSpecifiedHeight);
+ }
+ } else if (ICSSPropertyID.VAL_SCROLL.equals(overflow)
+ || ICSSPropertyID.VAL_AUTO.equals(overflow)) {
+ // adjust _needHScroll and _needVScroll
+ if (_userSpecifiedWidth > 0
+ && _userSpecifiedWidth < _blockBox.getWidth()) {
+ _needHScroll = true;
+ }
+ if (_userSpecifiedHeight > 0
+ && _userSpecifiedHeight < _blockBox.getHeight()) {
+ _needVScroll = true;
+ }
+ if (_needHScroll && !_needVScroll) {
+ if (_userSpecifiedHeight > 0
+ && _blockBox.getInternalContentHeight() >= 0
+ && _userSpecifiedHeight < _blockBox
+ .getInternalContentHeight()
+ + _blockBox._paddingInsets.getHeight()
+ + BorderUtil.SCROLL_WIDTH) {
+ _needVScroll = true;
+ }
+ }
+ if (!_needHScroll && _needVScroll) {
+ if (_userSpecifiedWidth > 0
+ && _blockBox.getInternalContentWidth() >= 0
+ && _userSpecifiedWidth < _blockBox
+ .getInternalContentWidth()
+ + _blockBox._paddingInsets.getWidth()
+ + BorderUtil.SCROLL_WIDTH) {
+ _needHScroll = true;
+ }
+ }
+
+ if (_userSpecifiedWidth > 0) {
+ _blockBox.setWidth(_userSpecifiedWidth);
+ }
+ if (_userSpecifiedHeight > 0) {
+ _blockBox.setHeight(_userSpecifiedHeight);
+ }
+ }
+ }
+
+ if (getFlowContext().isCurrentLineOccupied()
+ && getFlowContext().getCurrentLine().getAvailableWidth() < _blockBox._width
+ + _blockBox._marginInsets.getWidth()) {
+ getFlowContext().endLine();
+ }
+ if (!isInlineBlock()) {
+ LineBox line = getFlowContext().getCurrentLine();
+ line.setHorizonalData(getCSSStyle().getStyleProperty(
+ ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));
+ line.setHtmlInitData(getCSSStyle().getHTMLelementInitValue(
+ ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));
+ line.add(_blockBox);
+ // getFlowContext().addToCurrentLine(_blockBox);
+ } else {
+ getFlowContext().addToCurrentLine(_blockBox);
+ }
+ getFlowContext().getCurrentLine()._marginInsets.bottom = getCSSStyle()
+ .getMarginInsets().bottom;
+
+ if (!isInlineBlock()) {
+ getFlowContext().endLine();
+ }
+ }
+
+ protected void layoutLine(LineBox line) {
+ // currentLine.x = 0; //XXX: comment out, don't understand why set to 0,
+ // because it has already
+ // been set when setupLine(). And if do need, should
+ // set to getBorderPaddingInsets().left
+ // if (!isInlineBlock() && shouldExpand())
+ // {
+ // FIXME: currently we are using getRecommendedContentWidth,
+ // what happen if after adding the new line, the new width is bigger
+ // than
+ // recommendedContentWidth? should we use getWidth() instead of
+ // recommendedcontentWidth?
+ Object textalign = line.getHorizonalData();
+ if (textalign == null
+ || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {
+ textalign = (getCSSStyle()
+ .getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));
+ }
+ if (textalign == null
+ || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {
+ textalign = line.getHtmlInitData();
+ }
+ if (ICSSPropertyID.VAL_RIGHT.equals(textalign)) {
+ line._x = _blockBox.getContentWidth() - line.getWidth();
+ } else if (ICSSPropertyID.VAL_CENTER.equals(textalign)) {
+ line._x = (_blockBox.getContentWidth() - line.getWidth()) / 2;
+ }
+
+ if (line._x < 0) {
+ line._x = 0;
+ }
+ line.commit();
+ }
+
+ /**
+ * Adjust all fragments in the current line to have the same baseline. Do
+ * any additional adjustments, such as horizontal alignment.
+ */
+ protected void addCurrentLine() {
+ // The follow code is commented out, and moved into layoutLine(line)
+ // called by endBlock().
+ // since only when endBlock is called we really know how big is this
+ // block box, and then can
+ // do horizontal alignment.
+ // // currentLine.x = 0; //XXX: comment out, don't understand why set to
+ // 0, because it has already
+ // // been set when setupLine(). And if do need, should
+ // // set to getBorderPaddingInsets().left
+ // if (!isInlineBlock() && shouldExpand())
+ // {
+ // // FIXME: currently we are using getRecommendedContentWidth,
+ // // what happen if after adding the new line, the new width is bigger
+ // than
+ // // recommendedContentWidth? should we use getWidth() instead of
+ // // recommendedcontentWidth?
+ //
+ // Object textalign =
+ // (getCSSStyle().getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));
+ // if (textalign == ICSSPropertyID.VAL_RIGHT)
+ // {
+ // _currentLine._x = _blockBox.getContentWidth() +
+ // _blockBox.getBorderPaddingInsets().left - _currentLine.getWidth();
+ // }
+ // else if (textalign == ICSSPropertyID.VAL_CENTER)
+ // {
+ //
+ // _currentLine._x = _blockBox.getBorderPaddingInsets().left +
+ // (_blockBox.getContentWidth() - _currentLine.getWidth()) / 2;
+ // }
+ // if (_currentLine._x < 0)
+ // _currentLine._x = 0;
+ // }
+ //
+ // // FIXME: should check vertical alignment here?
+ // _currentLine.commit();
+
+ // layoutLine(_currentLine);
+ _blockBox.add(_currentLine);
+ }
+
+ /**
+ * @see FlowContainerLayout#flush()
+ */
+ protected void flush() {
+ if (_currentLine != null && _currentLine.isOccupied()) {
+ addCurrentLine();
+ }
+ endBlock();
+ }
+
+ /**
+ * @see FlowContainerLayout#cleanup()
+ */
+ protected void cleanup() {
+ _currentLine = _previousLine = null;
+ _fontMetrices = null;
+ }
+
+ // ----------------------------------------------------------------------------------
+
+ /**
+ * Override to setup the line's x, remaining, and available width.
+ *
+ * @param line
+ * the LineBox to set up
+ */
+ protected void setupLine(LineBox line, int topMargin) {
+ line.clear();
+
+ // the caller of getCurrentLine() may add leftMargin and leftPadding and
+ // leftBorder to line.x
+ line._x = 0;
+
+ // FIXME: here should check the floating boxes, and minus the width of
+ // them from
+ // current line.
+ line.setRecommendedWidth(_blockBox.getRecommendedContentWidth());
+ if (_previousLine == null) {
+ line._y = 0;
+ if (topMargin != Integer.MIN_VALUE) {
+ line._y += topMargin;
+ }
+ } else {
+ if (topMargin == Integer.MIN_VALUE) {
+ line._y = _previousLine._y + _previousLine.getHeight()
+ + getLinePadding() + _previousLine._marginInsets.bottom; // XXX:
+ // should
+ // add
+ // previous
+ // margin
+ // bottom?
+ } else {
+ line._y = _previousLine._y
+ + _previousLine.getHeight()
+ + Math.max(topMargin,
+ _previousLine._marginInsets.bottom);
+ }
+ }
+ setFontinfoForLine(line);
+ // line.validate();
+ }
+
+ private void setFontinfoForLine(LineBox line) {
+
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ if (_fontMetrices == null) {
+ // as getSwtFont is resource consuming, so we cache the
+ // _fontMetrics.
+ _fontMetrices = FigureUtilities.getFontMetrics(style
+ .getCSSFont().getSwtFont());
+ }
+ line.setFontMetrics(_fontMetrices);
+ }
+ }
+
+ /**
+ * @see FlowContainerLayout#createNewLine()
+ */
+ protected void createNewLine() {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, Integer.MIN_VALUE);
+ }
+
+ protected void createNewLine(int topmargin) {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, topmargin);
+ }
+
+ /**
+ * @see FlowContext#endLine()
+ */
+ public void endLine() {
+ // this is called from child layouts.
+ // If there is no current line, state is equivalent to new line
+ if (_currentLine == null) {
+ return;
+ }
+ if (_currentLine.isOccupied()) {
+ addCurrentLine(); // finalize the current line layout
+ } else {
+ _currentLine = null;
+ return;
+ }
+
+ LineBox box = _currentLine;
+ // _currentLine = _previousLine; //XXX: ???? why (yang)
+ _previousLine = box;
+
+ _currentLine = null;
+ // setupLine(getCurrentLine());
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()
+ */
+ public int getCurrentY() {
+ return getCurrentLine()._y; // FIXME: margin of previous block?
+ }
+
+ int getLinePadding() {
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#useLocalCoordinates()
+ */
+ public boolean useLocalCoordinates() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()
+ */
+ public void dispose() {
+ //
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#getFragmentsForRead()
+ */
+ public List getFragmentsForRead() {
+ List r = new ArrayList(1);
+ r.add(_blockBox);
+ return r;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#postValidate()
+ */
+ public void postValidate() {
+
+ Rectangle r = new Rectangle(_blockBox._x, _blockBox._y, _blockBox
+ .getWidth(), _blockBox.getHeight());
+ getCSSFigure().setBounds(r);
+ List list = getCSSFigure().getChildren();
+ for (int i = 0; i < list.size(); i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()
+ */
+ public int getContainerWidth() {
+ int width = Math.max(0, Math.max(_blockBox.getWidth(), _blockBox
+ .getRecommendedWidth()));
+ return width;
+ }
+
+ /**
+ * when the "overflow" is "scroll", we need to paint the scrollbar
+ */
+ public void paintFigurePostClientArea(Graphics g) {
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ Object overflow = style
+ .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);
+ if (ICSSPropertyID.VAL_SCROLL.equals(overflow)
+ || ICSSPropertyID.VAL_AUTO.equals(overflow)) {
+ if (this._needHScroll || this._needVScroll) {
+ // as this is using localCoordinate, so translate to
+ // relative to left/up corder of whole
+ // blockbox.
+ g.translate(-_blockBox.getBorderPaddingInsets().left,
+ -_blockBox.getBorderPaddingInsets().top);
+
+ Rectangle rect = new Rectangle(0, 0, _blockBox.getWidth(),
+ _blockBox.getHeight());
+ rect.crop(_blockBox._borderInsets);
+
+ if (this._needHScroll && this._needVScroll) {
+ BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
+ rect, BorderUtil.BOTH);
+ } else if (this._needHScroll) {
+ BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
+ rect, BorderUtil.HORIZONTAL_BAR);
+ } else if (this._needVScroll) {
+ BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,
+ rect, BorderUtil.VERTICAL_BAR);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBrFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBrFlowLayout.java
new file mode 100644
index 000000000..b343aaea9
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSBrFlowLayout.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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.Graphics;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.jst.pagedesigner.PDPlugin;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * @author mengbo
+ */
+public class CSSBrFlowLayout extends CSSInlineFlowLayout implements ICSSPainter {
+ /**
+ * @param flow
+ */
+ public CSSBrFlowLayout(CSSFigure flow) {
+ super(flow);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSInlineFlowLayout#flush()
+ */
+ protected void flush() {
+ FlowBox forcedBox = new FlowBox();
+ forcedBox.setWidth(16);
+ forcedBox.setHeight(getCSSStyle().getCSSFont().getXHeight());
+ addToCurrentLine(forcedBox);
+ endLine();
+
+ FlowBox flowbox = new FlowBox();
+ flowbox.setHeight(getCSSStyle().getCSSFont().getFontSize());
+ getCurrentLine().add(flowbox);
+
+ super.flush();
+ }
+
+ public void paintFigure(Graphics g) {
+ List fragments = getFragmentsForRead();
+ if (!fragments.isEmpty()) {
+ FlowBox box = (FlowBox) fragments.get(0);
+ g.drawImage(getSharedHTMLImage(), new Point(box._x, box._y));
+ }
+ }
+
+ private static Image getSharedHTMLImage() {
+ return PDPlugin.getDefault().getImage("palette/HTML/small/HTML_BR.gif");
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSFigure.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSFigure.java
new file mode 100644
index 000000000..60580d2bb
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSFigure.java
@@ -0,0 +1,518 @@
+/*******************************************************************************
+ * 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.Border;
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.PDPlugin;
+import org.eclipse.jst.pagedesigner.common.logging.Logger;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.border.CSSBorder;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.property.VisibilityMeta;
+import org.eclipse.jst.pagedesigner.css2.style.DefaultStyle;
+import org.eclipse.jst.pagedesigner.css2.style.ITagEditInfo;
+import org.eclipse.jst.pagedesigner.css2.widget.BorderUtil;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Normally a CSSFigure is a container. It's layout will be driven by different
+ * display type information from the style.
+ *
+ * Each CSSFigure will be driven by ICSSStyle, the display type of the ICSSStyle
+ * will decide the layout to be used for the figure.
+ *
+ * @author mengbo
+ */
+public class CSSFigure extends FlowFigure implements ICSSFigure {
+ private static Logger _log = PDPlugin.getLogger(CSSFigure.class);
+
+ private static final Rectangle PRIVATE_RECT = new Rectangle();
+
+ ICSSStyle _style;
+
+ // NOTE: here keep the element is only for debug use. CSSFigure shouldn't
+ // require an element.
+ // Element _element;
+
+ // if this field is set, then regetLayout() will still return this layout,
+ // without going through the CSS resolution
+ CSSLayout _fixedLayout;
+
+ public CSSFigure() {
+ _style = DefaultStyle.getInstance();
+ invalidateCSS();
+ }
+
+ public CSSFigure(ICSSStyle style) {
+ _style = style;
+ // _element = element;
+ invalidateCSS();
+ }
+
+ public ICSSStyle getCSSStyle() {
+ return _style;
+ }
+
+ public void setCSSStyle(ICSSStyle style) {
+ _style = style;
+ invalidateCSS();
+ }
+
+ public void revalidate() {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ layout.figureRevalidate();
+ super.revalidate();
+ }
+
+ /**
+ * this method is called when the css source noticed style change. So tell
+ * the figure should invalidate its cached data.
+ */
+ public void invalidateCSS() {
+ // maybe we changed from inline to block or block to inline
+ // XXX: or even to table?
+ CSSLayout layout = regetLayout(getLayoutManager());
+ this.setLayoutManager(layout);
+ }
+
+ public void setFixedLayoutManager(CSSLayout layout) {
+ this._fixedLayout = layout;
+ this.setLayoutManager(regetLayout(getLayoutManager()));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#setLayoutManager(org.eclipse.draw2d.LayoutManager)
+ */
+ public void setLayoutManager(LayoutManager manager) {
+ LayoutManager old = getLayoutManager();
+ if (old != manager) {
+ FlowContext context = null;
+ if (old instanceof FlowFigureLayout) {
+ context = ((FlowFigureLayout) old).getOriginalFlowContext();
+ }
+ if (manager instanceof FlowFigureLayout) {
+ ((FlowFigureLayout) manager).setOriginalFlowContext(context);
+ }
+
+ if (manager instanceof FlowContext) {
+ List list = getChildren();
+ for (int i = 0, size = list.size(); i < size; i++) {
+ try {
+ ((FlowFigure) list.get(i))
+ .setOriginalFlowContext((FlowContext) manager);
+ } catch (ClassCastException classcastexception) {
+ // Error in flowContext setting.
+ _log.error("Error.CSSFigure.0", classcastexception); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ super.setLayoutManager(manager);
+ }
+
+ protected CSSLayout regetLayout(LayoutManager old) {
+ if (_fixedLayout != null) {
+ return _fixedLayout;
+ }
+ CSSLayout layout = DisplayToLayout.displayToLayout(this, getCSSStyle()
+ .getDisplay(), old);
+ if (layout != null) {
+ return layout;
+ } else {
+ return new CSSInlineFlowLayout(this);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#containsPoint(int, int)
+ */
+ public boolean containsPoint(int x, int y) {
+ // check whether any float figure contains it.
+ // FIXME: need check floating figure here!!!
+ if (!super.containsPoint(x, y)) {
+ return false;
+ }
+ List frags = getFragmentsForRead();
+ // Here we should not get void pointer.
+ if (frags != null) {
+ for (int i = 0; i < frags.size(); i++) {
+ FlowBox box = (FlowBox) frags.get(i);
+ if (box != null && box.containsPoint(x, y)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure#getFragmentsForRead()
+ */
+ public List getFragmentsForRead() {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ return layout.getFragmentsForRead();
+ }
+
+ /**
+ * this method is a shortcut to getFragmentsForRead
+ *
+ * @return
+ */
+ public Rectangle[] getFragmentsBounds() {
+ List list = getFragmentsForRead();
+ if (list == null || list.size() == 0) {
+ // should not happen. but still handle it.
+ return new Rectangle[] { getBounds() };
+ } else {
+ Rectangle[] ret = new Rectangle[list.size()];
+ for (int i = 0, size = list.size(); i < size; i++) {
+ FlowBox box = (FlowBox) list.get(i);
+ ret[i] = new Rectangle(box._x, box._y, box.getWidth(), box
+ .getHeight());
+ }
+ return ret;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ public void setBounds(Rectangle r) {
+ if (getBounds().equals(r)) {
+ return;
+ }
+ boolean invalidate = getBounds().width != r.width
+ || getBounds().height != r.height;
+ super.setBounds(r);
+
+ CSSLayout layout = (CSSLayout) this.getLayoutManager();
+ layout.setBoundsCalled(r, invalidate);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigure#postValidate()
+ */
+ public void postValidate() {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ layout.postValidateForAbsolute();
+ layout.postValidate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#validate()
+ */
+ public void validate() {
+ super.validate();
+ // should not call this.postValidate() here. PostValidate() should
+ // only be started from the FlowPage. Otherwise it will be called
+ // multiple times on a figure.
+ // this.postValidate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ protected boolean useLocalCoordinates() {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ if (layout == null) {
+ return false;
+ } else {
+ return layout.useLocalCoordinates();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#paint(org.eclipse.draw2d.Graphics)
+ */
+ public void paint(Graphics graphics) {
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ Object visibility = style
+ .getStyleProperty(ICSSPropertyID.ATTR_VISIBILITY);
+ // handle visibility: hidden here.
+ // TODO: "collapse" is not supported yet!
+ if (VisibilityMeta.HIDDEN.equals(visibility)) {
+ return;
+ }
+ }
+
+ CSSLayout layout = (CSSLayout) this.getLayoutManager();
+ graphics.pushState();
+ try {
+ paintFigure(graphics);
+ graphics.restoreState();
+ paintClientArea(graphics);
+ if (layout instanceof ICSSPainter2) {
+ if (useLocalCoordinates()) {
+ graphics.translate(getBounds().x + getInsets().left,
+ getBounds().y + getInsets().top);
+ ((ICSSPainter2) layout).paintFigurePostClientArea(graphics);
+ graphics.restoreState();
+ } else {
+ ((ICSSPainter2) layout).paintFigurePostClientArea(graphics);
+ }
+ }
+ paintBorder(graphics);
+ } finally {
+ graphics.popState();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ protected void paintFigure(Graphics g) {
+ Color rgbColor = null;
+ boolean fillArea = false;
+ Object bg = getCSSStyle().getBackgroundColor();
+ if (bg instanceof RGB) {
+ rgbColor = new Color(null, (RGB) bg);
+ g.setBackgroundColor(rgbColor);
+ fillArea = true;
+ } else if (bg instanceof Color) {
+ g.setBackgroundColor((Color) bg);
+ fillArea = true;
+ }
+ if (fillArea) {
+ List fragments = getFragmentsForRead();
+
+ for (int i = 0, n = fragments.size(); i < n; i++) {
+ Object obj = fragments.get(i);
+ if (obj instanceof FlowBox) {
+ FlowBox box = (FlowBox) obj;
+ g.fillRectangle(box._x, box._y, box.getWidth(), box
+ .getHeight());
+ }
+ }
+ }
+ if (rgbColor != null) {
+ rgbColor.dispose();
+ }
+ g.restoreState();
+
+ LayoutManager layout = getLayoutManager();
+ if (layout instanceof ICSSPainter) {
+ if (useLocalCoordinates()) {
+ g.translate(getBounds().x + getInsets().left, getBounds().y
+ + getInsets().top);
+ ((ICSSPainter) layout).paintFigure(g);
+ g.restoreState();
+ } else {
+ ((ICSSPainter) layout).paintFigure(g);
+ }
+ }
+
+ // paint selected mode here.
+ paintSelection(g);
+
+ if (Debug.DEBUG_BOX) {
+ // draw two levels of boxes. Since normally each figure will only
+ // have two levels of boxes.
+ List fragments = this.getFragmentsForRead();
+ for (int i = 0, size = fragments.size(); i < size; i++) {
+ FlowBox box = (FlowBox) fragments.get(i);
+ BoxUtil.drawBox(g, box);
+ if (box instanceof BlockBox) {
+ BlockBox compositeBox = (BlockBox) box;
+ List list = compositeBox.getFragments();
+ for (int j = 0; j < list.size(); j++) {
+ g.translate(this.getInsets().left,
+ this.getInsets().right);
+ BoxUtil.drawBox(g, (FlowBox) list.get(j));
+ g.restoreState();
+ }
+ }
+ }
+ }
+ if (Debug.DEBUG_BASELINE) {
+ List fragments = this.getFragmentsForRead();
+ for (int i = 0, size = fragments.size(); i < size; i++) {
+ Object obj = fragments.get(i);
+ if (obj instanceof LineBox) {
+ LineBox linebox = (LineBox) obj;
+ g.setForegroundColor(ColorConstants.red);
+ g.drawLine(linebox._x, linebox._y + linebox.getAscent(),
+ linebox._x + linebox.getWidth(), linebox._y
+ + linebox.getAscent());
+ }
+ }
+ }
+
+ if (Debug.DEBUG_BORDERPADDING) {
+ if (this.getLayoutManager() instanceof CSSBlockFlowLayout) {
+ g.setLineWidth(1);
+ Rectangle rect = getBounds().getCopy().crop(getInsets());
+ g.setForegroundColor(ColorConstants.green);
+ g.drawRectangle(rect);
+ g.setForegroundColor(ColorConstants.red);
+ g.drawRectangle(getBounds());
+ }
+ }
+
+ if (Debug.DEBUG_BOX) {
+ CSSLayout csslayout = (CSSLayout) this.getLayoutManager();
+ if (csslayout._absoluteContext != null) {
+ BlockBox blockbox = csslayout._absoluteContext._blockBox;
+ g.setLineWidth(1);
+ g.setForegroundColor(ColorConstants.green);
+ g.drawRectangle(blockbox._x, blockbox._y, blockbox.getWidth(),
+ blockbox.getHeight());
+ }
+ }
+ }
+
+ /**
+ * Paints this Figure's client area. The client area is typically defined as
+ * the anything inside the Figure's {@link Border} or {@link Insets}, and
+ * by default includes the children of this Figure. On return, this method
+ * must leave the given Graphics in its initial state.
+ *
+ * @param graphics
+ * The Graphics used to paint
+ * @since 2.0
+ */
+ protected void paintClientArea(Graphics graphics) {
+ if (this.getChildren().isEmpty()) {
+ return;
+ }
+
+ Object overflow = ICSSPropertyID.VAL_VISIBLE;
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ overflow = style.getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);
+ }
+
+ boolean optimizeClip = ICSSPropertyID.VAL_VISIBLE.equals(overflow);
+
+ if (useLocalCoordinates()) {
+ graphics.translate(getBounds().x + getInsets().left, getBounds().y
+ + getInsets().top);
+ if (!optimizeClip) {
+ graphics.clipRect(getClientArea(PRIVATE_RECT));
+ }
+ graphics.pushState();
+ paintChildren(graphics);
+ graphics.popState();
+ graphics.restoreState();
+ } else {
+ if (optimizeClip) {
+ paintChildren(graphics);
+ } else {
+ graphics.clipRect(getClientArea(PRIVATE_RECT));
+ graphics.pushState();
+ paintChildren(graphics);
+ graphics.popState();
+ graphics.restoreState();
+ }
+ }
+ }
+
+ /**
+ * @param g
+ */
+ protected void paintSelection(Graphics g) {
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ if (style.isInSelection()) {
+ ITagEditInfo editInfo = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (editInfo != null && editInfo.isWidget()) {
+ BorderUtil.maskFigure(this, g);
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics)
+ */
+ protected void paintBorder(Graphics graphics) {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ if (layout != null && !layout.handlingBorderForBlock()) {
+ return;
+ }
+
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ CSSBorder border = new CSSBorder(this.getCSSStyle());
+ border.paint(this, graphics, NO_INSETS);
+
+ // draw a border for those special elements like <h:form>, etc.
+ ITagEditInfo editInfo = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (editInfo != null && editInfo.needBorderDecorator()) {
+ BorderUtil.drawBorderDecorator(this, graphics);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#getInsets()
+ */
+ public Insets getInsets() {
+ CSSLayout layout = (CSSLayout) getLayoutManager();
+ if (layout != null && !layout.handlingBorderForBlock()) {
+ return new Insets();
+ }
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ return style.getBorderInsets().getAdded(style.getPaddingInsets());
+ }
+ return new Insets();
+ }
+
+ /**
+ * FIXME: need trace the implementation of Figure.invalidate() We want to
+ * just mark this figure as invalid, but don't want to the layout get
+ * invalidated.
+ *
+ */
+ public void invalidate2() {
+ if (!isValid())
+ return;
+ // if (getLayoutManager() != null)
+ // getLayoutManager().invalidate();
+ setValid(false);
+
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSInlineFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSInlineFlowLayout.java
new file mode 100644
index 000000000..97f4571c0
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSInlineFlowLayout.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * 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.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.FigureUtilities;
+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.style.ITagEditInfo;
+
+/**
+ * The layout manager for {@link CSSFigure}figures. This class is based on
+ * InlineFlowLayout of draw2d.
+ *
+ * @author mengbo
+ */
+public class CSSInlineFlowLayout extends CSSLayout {
+ List _fragments = new ArrayList();
+
+ /**
+ * Creates a new InlineFlowLayout with the given FlowFigure.
+ *
+ * @param flow
+ * The FlowFigure
+ */
+ public CSSInlineFlowLayout(CSSFigure flow) {
+ super(flow);
+ }
+
+ /**
+ * Clears out all fragments prior to the call to layoutChildren().
+ */
+ public void preLayout() {
+ super.preLayout();
+ _fragments.clear();
+ // force creating of the first line. avoid empty element don't have
+ // fragments.
+ // createFirstLine();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#layoutChildren()
+ */
+ protected void layoutChildren() {
+ // For designer, to make it to have some size. otherwise can't
+ // be found on screen.
+ // List children = getCSSFigure().getChildren();
+ // if (children.size() == 0)
+ // {
+ // FlowBox box = new FlowBox();
+ // box._height = getCSSStyle().getCSSFont().getFontSize();
+ // box._width = 2;
+ // addToCurrentLine(box);
+ //
+ // }
+ super.layoutChildren();
+ }
+
+ /**
+ * Adds the given FlowBox to the current line of this InlineFlowLayout.
+ *
+ * @param block
+ * the FlowBox to add to the current line
+ */
+ public void addToCurrentLine(FlowBox block) {
+ getCurrentLine().add(block);
+ // XXX: ???: will currentLine be added multiple times to fragments?
+ // (yang)
+ // _fragments.add(_currentLine);
+ }
+
+ private void createFirstLine() {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, true);
+ _fragments.add(_currentLine);
+ }
+
+ /**
+ * @see FlowContainerLayout#createNewLine()
+ */
+ protected void createNewLine() {
+ _currentLine = new LineBox();
+ setupLine(_currentLine, false);
+ _fragments.add(_currentLine);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#createNewLine(int)
+ */
+ protected void createNewLine(int topMargin) {
+ // inline flow don't support vertical margin.
+ createNewLine();
+ }
+
+ /**
+ * @see FlowContainerLayout#cleanup()
+ */
+ protected void cleanup() {
+ _currentLine = null;
+ }
+
+ /**
+ * @see FlowContainerLayout#flush()
+ */
+ protected void flush() {
+ if (_fragments.isEmpty()) {
+ createFirstLine();
+ } else if (_fragments.size() == 1) {
+
+ ICSSStyle style = getCSSStyle();
+ int minWidth = 0, minHeight = 0;
+ // try to see whether there is any designer specified min size
+ ITagEditInfo info = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (info != null) {
+ minWidth = info.getMinWidth();
+ minHeight = info.getMinHeight();
+ }
+ FlowBox box = (FlowBox) _fragments.get(0);
+ if (minWidth > box._width) {
+ box._width = minWidth;
+ }
+ if (minHeight > box._height) {
+ box._height = minHeight;
+ }
+ }
+
+ if (_currentLine != null /* && _currentLine.isOccupied() */) {
+ _currentLine._marginInsets.right = getCSSStyle().getMarginInsets().right;
+ getFlowContext().addToCurrentLine(_currentLine);
+ }
+
+ }
+
+ /**
+ * @see FlowContext#endLine()
+ */
+ public void endLine() {
+ if (_currentLine == null) {
+ getFlowContext().endLine();
+ return;
+ }
+ // If nothing was ever placed in the line, ignore it. and if the line is
+ // the first line, just remove it.
+ if (_currentLine.isOccupied()) {
+ getFlowContext().addToCurrentLine(_currentLine);
+ } else if (_fragments.size() == 1) {
+ _fragments.remove(0);
+ }
+ getFlowContext().endLine();
+ _currentLine = null;
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()
+ */
+ public int getCurrentY() {
+ return getCurrentLine()._y;
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#isCurrentLineOccupied()
+ */
+ public boolean isCurrentLineOccupied() {
+ if (_currentLine == null) {
+ return getFlowContext().isCurrentLineOccupied();
+ } else if (_currentLine.getFragments().isEmpty()) {
+ return getFlowContext().isCurrentLineOccupied();
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Initializes the given LineBox. Called by createNewLine().
+ *
+ * @param line
+ * The LineBox to initialize.
+ */
+ protected void setupLine(LineBox line, boolean firstline) {
+ LineBox parent = getFlowContext().getCurrentLine();
+ line._x = 0;
+ line._y = getFlowContext().getCurrentY();
+
+ line.setRecommendedWidth(parent.getAvailableWidth());
+
+ setLineVerticalAlign(line);
+ setFontinfoForLine(line);
+
+ if (firstline && getCSSStyle() != null) {
+ ICSSStyle style = getCSSStyle();
+ int minWidth = 0, minHeight = 0;
+ // try to see whether there is any designer specified min size
+ ITagEditInfo info = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (info != null) {
+ minWidth = info.getMinWidth();
+ minHeight = info.getMinHeight();
+ }
+
+ // // CSS also has the min-width/min-height property. We should also
+ // get that,
+ // // and using the max of the "min-width" css property and the
+ // designer specified min size.
+ // int height =
+ // getLengthValue(style,ICSSPropertyID.ATTR_MIN_HEIGHT);
+ // if(height > minHeight)
+ // {
+ // minHeight = height;
+ // }
+ // int width = getLengthValue(style,ICSSPropertyID.ATTR_MIN_WIDTH);
+ // if(width > minWidth)
+ // {
+ // minWidth = width;
+ // }
+ if (minWidth > 0) {
+ line.setWidth(minWidth);
+ }
+ int fontHeight = this.getCSSStyle().getCSSFont().getXHeight();
+ if (minHeight > 0 && minHeight > fontHeight) {
+ line.setHeight(minHeight);
+ } else {
+ line.setHeight(fontHeight);
+ }
+ }
+ }
+
+ private void setLineVerticalAlign(LineBox box) {
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ box.setVerticalAlignData(style
+ .getStyleProperty(ICSSPropertyID.ATTR_VERTICAL_ALIGN));
+ }
+ }
+
+ private void setFontinfoForLine(LineBox line) {
+
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ line.setFontMetrics(FigureUtilities.getFontMetrics(style
+ .getCSSFont().getSwtFont()));
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()
+ */
+ public void dispose() {
+ //
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#getFragmentsForRead()
+ */
+ public List getFragmentsForRead() {
+ return _fragments;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#postValidate()
+ */
+ public void postValidate() {
+ List list = _fragments;
+
+ FlowBox box;
+ int left = Integer.MAX_VALUE, top = left;
+ int right = Integer.MIN_VALUE, bottom = right;
+ for (int i = 0; i < list.size(); i++) {
+ box = (FlowBox) list.get(i);
+ // if (box instanceof LineBox && !((LineBox) box).isOccupied())
+ // {
+ // continue; // skip unoccupied line
+ // }
+ left = Math.min(left, box._x);
+ right = Math.max(right, box._x + box._width);
+ top = Math.min(top, box._y);
+ bottom = Math.max(bottom, box._y + box._height);
+ }
+ getCSSFigure().setBounds(
+ new Rectangle(left, top, right - left, bottom - top));
+ list = getCSSFigure().getChildren();
+ for (int i = 0; i < list.size(); i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()
+ */
+ public int getContainerWidth() {
+ // FIXME: don't really understand what means for inline
+ return this.getFlowContext().getContainerWidth();
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSLayout.java
new file mode 100644
index 000000000..c38052946
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSLayout.java
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * 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 {
+ protected 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;
+
+ /**
+ * @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
+ */
+ public ICSSStyle getCSSStyle() {
+ return getCSSFigure().getCSSStyle();
+ }
+
+ /**
+ * @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();
+ }
+
+ protected 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)) {
+ return supportAbsolutePosition();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Child class could override this method.
+ *
+ * @return
+ */
+ protected boolean supportAbsolutePosition() {
+ if (findContainingPositionedFigure() == null) {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#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;
+ } else {
+ return getOriginalFlowContext();
+ }
+ }
+
+ public FlowContext getParentFigureContext() {
+ return super.getFlowContext();
+ }
+
+ public 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 = ((ICSSFigure) 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._marginInsets.right;
+ } else {
+ return 0;
+ }
+ }
+
+ public void setCalculatingMaxWidth(boolean c) {
+ _calculatingMaxWidth = c;
+ }
+
+ 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();
+
+ // ------------------------------------------------------------------------------------
+
+ public CSSFigure getCSSFigure() {
+ return (CSSFigure) getFlowFigure();
+ }
+
+ /**
+ *
+ * @return
+ */
+ 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) {
+ }
+
+ /**
+ * Child class can override this. Normally block figure will return true.
+ *
+ * @return
+ */
+ public 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
+ */
+ public boolean handlingBorderForBlock() {
+ return true;
+ }
+
+ /**
+ * This method is called when the corresponding figure is revalidated.
+ *
+ */
+ public void figureRevalidate() {
+ // child class can override.
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSListItemLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSListItemLayout.java
new file mode 100644
index 000000000..a3608ddad
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSListItemLayout.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * 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.FigureUtilities;
+import org.eclipse.draw2d.Graphics;
+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.list.CounterHelper;
+import org.eclipse.jst.pagedesigner.css2.list.ICounterValueGenerator;
+import org.eclipse.jst.pagedesigner.css2.marker.CounterUtil;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.style.DefaultStyle;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * @author mengbo
+ */
+public class CSSListItemLayout extends CSSBlockFlowLayout implements
+ ICSSPainter {
+ private static final String DEFAULT_LIST_COUNTER = "_anonymous";
+
+ private static final int CIRCLE_DIAMETER = 6;
+
+ private static final int DISC_DIAMETER = 5;
+
+ private static final int ROUNDRECT_ARC = 2;
+
+ private static final int TEXT_PADDING = 16;
+
+ private int _count;
+
+ /**
+ * @param cssfigure
+ */
+ public CSSListItemLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSPainter#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics g) {
+ ICSSStyle style = this.getCSSStyle();
+ if (style == null) {
+ style = DefaultStyle.getInstance();
+ }
+
+ Rectangle drawArea = null;
+ Font font = getCSSStyle().getCSSFont().getSwtFont();
+
+ // draw the marker box
+ Object styleType = style
+ .getStyleProperty(ICSSPropertyID.ATTR_LIST_STYLE_TYPE);
+
+ g.pushState();
+
+ Color newColor = null;
+ Object color = style.getColor();
+ if (color instanceof Color) {
+ g.setForegroundColor((Color) color);
+ g.setBackgroundColor((Color) color);
+ } else if (color instanceof RGB) {
+ newColor = new Color(Display.getCurrent(), (RGB) color);
+ g.setForegroundColor(newColor);
+ g.setBackgroundColor(newColor);
+ }
+
+ if (styleType instanceof String) {
+ int type = CounterHelper.toTypeInt((String) styleType);
+ switch (type) {
+ case CounterHelper.LIST_T_UPPER_ALPHA:
+ case CounterHelper.LIST_T_LOWER_ALPHA:
+ case CounterHelper.LIST_T_LOWER_ROMAN:
+ case CounterHelper.LIST_T_UPPER_ROMAN:
+ case CounterHelper.LIST_T_DECIMAL:
+ g.setFont(font);
+ String displayString = CounterUtil.convertCount(_count, type);
+ Point point = getDrawPointForText(displayString);
+ g.drawString(displayString, point);
+ break;
+ case CounterHelper.LIST_T_CIRCLE:
+ drawArea = getDrawAreaForGraph(CIRCLE_DIAMETER, CIRCLE_DIAMETER);
+ g.drawArc(drawArea, 0, 360);
+ break;
+ case CounterHelper.LIST_T_SQUARE:
+ drawArea = getDrawAreaForGraph(DISC_DIAMETER, DISC_DIAMETER);
+ g.fillRectangle(drawArea);
+ case CounterHelper.LIST_T_DECIMAL_LEADING_ZERO:
+ case CounterHelper.LIST_T_LOWER_GREEK:
+ case CounterHelper.LIST_T_ARMENIAN:
+ case CounterHelper.LIST_T_GEORGIAN:
+ case CounterHelper.LIST_T_IMAGE:
+ case CounterHelper.LIST_T_NONE:
+ default:
+ drawArea = getDrawAreaForGraph(DISC_DIAMETER, DISC_DIAMETER);
+ g.fillRoundRectangle(drawArea, ROUNDRECT_ARC, ROUNDRECT_ARC);
+ break;
+ }
+ }
+ g.popState();
+
+ if (newColor != null) {
+ newColor.dispose();
+ }
+ }
+
+ /**
+ * @param g
+ * @return
+ */
+ private Rectangle getDrawAreaForGraph(int width, int height) {
+ Rectangle drawArea;
+
+ int x = 0;
+ int y = 0;
+
+ List list = _blockBox.getFragments();
+ Rectangle box = _blockBox.toRectangle().getCopy().expand(
+ _blockBox.getBorderPaddingInsets().getAdded(
+ _blockBox._marginInsets));
+ if (list != null && !list.isEmpty()) {
+ LineBox line = (LineBox) list.get(0);
+ y = line.getBaseline() - CIRCLE_DIAMETER;
+ x = box.x;
+ } else {
+ x = box.x;
+ y = box.height / 2 - CIRCLE_DIAMETER;
+ }
+ drawArea = new Rectangle(x - CIRCLE_DIAMETER * 5 / 2, y, width, height);
+ return drawArea;
+ }
+
+ private Point getDrawPointForText(String displayString) {
+ Font font = getCSSStyle().getCSSFont().getSwtFont();
+
+ int x = 0;
+ int y = 0;
+
+ Rectangle box = _blockBox.toRectangle().getCopy().expand(
+ _blockBox.getBorderPaddingInsets().getAdded(
+ _blockBox._marginInsets));
+
+ x = box.x - FigureUtilities.getTextWidth(displayString, font);
+ x = x
+ - (TEXT_PADDING - FigureUtilities.getFontMetrics(font)
+ .getDescent());
+
+ return new Point(x, y);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#layoutChildren()
+ */
+ protected void layoutChildren() {
+ ICounterValueGenerator counter = this.getCSSStyle().findCounter(
+ DEFAULT_LIST_COUNTER, true);
+ if (counter != null) {
+ _count = counter.getCurrentCount();
+ } else {
+ // should not happen.
+ _count = 1; // use 1 as the default value
+ }
+ super.layoutChildren();
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSPageFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSPageFlowLayout.java
new file mode 100644
index 000000000..c74963a58
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSPageFlowLayout.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * 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.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * This layout if for those thigns that it's parent will decide its size. Such
+ * as table cell.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSPageFlowLayout extends CSSBlockFlowLayout {
+ private Dimension _pageSize = new Dimension();
+
+ private int _recommendedWidth;
+
+ private int _pageSizeCacheKeys[] = new int[4];
+
+ private Dimension _pageSizeCacheValues[] = new Dimension[4];
+
+ private Dimension _cacheMaxWidthSize = null;
+
+ /**
+ * @param cssfigure
+ */
+ public CSSPageFlowLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#invalidate()
+ */
+ public void invalidate() {
+ super.invalidate();
+ _pageSizeCacheKeys = new int[4];
+ _pageSizeCacheValues = new Dimension[4];
+ _pageSize = new Dimension();
+ _recommendedWidth = 0;
+ _cacheMaxWidthSize = null;
+ }
+
+ protected void endBlock() {
+ layoutLines();
+ }
+
+ /**
+ * TODO: This method is not being called.
+ */
+ public void postValidate() {
+ Rectangle r = new Rectangle(_blockBox._x, _blockBox._y, _blockBox
+ .getWidth(), _blockBox.getHeight());
+ r = r.expand(getCSSFigure().getInsets());
+ _pageSize.width = r.width;
+ _pageSize.height = r.height;
+
+ List list = getCSSFigure().getChildren();
+ for (int i = 0; i < list.size(); i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+
+ }
+
+ /**
+ * Setup blockBox to the initial bounds of the Page
+ */
+ protected void setupBlock() {
+ // Remove all current Fragments
+ _blockBox.clear();
+
+ // Setup the one fragment for this Block with the correct X and
+ // available width
+ int recommendedWidth = getRecommendedWidth();
+ _blockBox.setRecommendedWidth(recommendedWidth);
+
+ if (recommendedWidth > 0 && recommendedWidth != Integer.MAX_VALUE) {
+ _blockBox.setWidth(recommendedWidth);
+ }
+
+ _blockBox._x = 0;
+ }
+
+ public int getRecommendedWidth() {
+ return _recommendedWidth;
+ }
+
+ private void setRecommendedWidth(int width) {
+ if (_recommendedWidth == width) {
+ return;
+ }
+ _recommendedWidth = width;
+ getCSSFigure().invalidate2();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#setBoundsCalled(org.eclipse.jst.pagedesigner.css2.layout.CSSFigure,
+ * org.eclipse.draw2d.geometry.Rectangle, boolean)
+ */
+ public void setBoundsCalled(Rectangle r, boolean invalidate) {
+ super.setBoundsCalled(r, invalidate);
+ CSSFigure figure = getCSSFigure();
+ int newWidth = r.width - figure.getInsets().getWidth();
+ if (invalidate || getRecommendedWidth() != newWidth) {
+ setRecommendedWidth(newWidth);
+ figure.getUpdateManager().addInvalidFigure(figure);
+ }
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int)
+ */
+ public Dimension getPreferredSize(IFigure container, int width, int h) {
+ if (width >= 0) {
+ width = Math.max(0, width - container.getInsets().getWidth());
+ }
+
+ for (int i = 0; i < 4; i++) {
+ if (_pageSizeCacheKeys[i] == width
+ && _pageSizeCacheValues[i] != null) {
+ return _pageSizeCacheValues[i];
+ }
+ }
+
+ _pageSizeCacheKeys[3] = _pageSizeCacheKeys[2];
+ _pageSizeCacheKeys[2] = _pageSizeCacheKeys[1];
+ _pageSizeCacheKeys[1] = _pageSizeCacheKeys[0];
+ _pageSizeCacheKeys[0] = width;
+
+ _pageSizeCacheValues[3] = _pageSizeCacheValues[2];
+ _pageSizeCacheValues[2] = _pageSizeCacheValues[1];
+ _pageSizeCacheValues[1] = _pageSizeCacheValues[0];
+
+ // Flowpage must temporarily layout to determine its preferred size
+ int oldWidth = getRecommendedWidth();
+ setRecommendedWidth(width);
+ container.validate();
+ _pageSizeCacheValues[0] = _pageSize.getExpanded(container.getInsets()
+ .getWidth(), container.getInsets().getHeight());
+
+ if (width != oldWidth) {
+ setRecommendedWidth(oldWidth);
+ container.getUpdateManager().addInvalidFigure(container);
+ }
+ return _pageSizeCacheValues[0];
+ }
+
+ public Dimension getMaxContentWidthSize(IFigure container) {
+ if (this._cacheMaxWidthSize == null) {
+ boolean b = getCalcuatingMaxWidth();
+ setCalculatingMaxWidth(true);
+
+ // Flowpage must temporarily layout to determine its preferred size
+ int oldWidth = getRecommendedWidth();
+ setRecommendedWidth(Integer.MAX_VALUE);
+ container.validate();
+ _cacheMaxWidthSize = _pageSize.getExpanded(container.getInsets()
+ .getWidth(), container.getInsets().getHeight());
+
+ if (0 != oldWidth) {
+ setRecommendedWidth(oldWidth);
+ container.getUpdateManager().addInvalidFigure(container);
+ }
+
+ setCalculatingMaxWidth(b);
+ }
+ return _cacheMaxWidthSize;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextFigure.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextFigure.java
new file mode 100644
index 000000000..a5a2871d1
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextFigure.java
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * 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.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Graphics;
+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.provider.ICSSTextProvider;
+import org.eclipse.jst.pagedesigner.css2.style.DefaultStyle;
+import org.eclipse.jst.pagedesigner.css2.style.StyleUtil;
+import org.eclipse.jst.pagedesigner.viewer.CaretPositionResolver;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * @author mengbo
+ */
+public class CSSTextFigure extends FlowFigure implements ICSSFigure {
+ private ICSSTextProvider _provider;
+
+ private List _fragments = new ArrayList(1);
+
+ public CSSTextFigure(ICSSTextProvider provider) {
+ _provider = provider;
+ this.setLayoutManager(createDefaultFlowLayout());
+ }
+
+ public ICSSStyle getCSSStyle() {
+ IFigure parentFigure = this.getParent();
+ if (parentFigure instanceof ICSSFigure) {
+ ICSSStyle style = ((ICSSFigure) parentFigure).getCSSStyle();
+ if (style != null) {
+ return style;
+ }
+ }
+ return DefaultStyle.getInstance();
+ }
+
+ /**
+ * @see org.eclipse.draw2d.IFigure#containsPoint(int, int)
+ */
+ public boolean containsPoint(int x, int y) {
+ if (!super.containsPoint(x, y)) {
+ return false;
+ }
+ List frags = getFragments();
+ for (int i = 0, n = frags.size(); i < n; i++) {
+ if (((FlowBox) frags.get(i)).containsPoint(x, y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see FlowFigure#createDefaultFlowLayout()
+ */
+ protected FlowFigureLayout createDefaultFlowLayout() {
+ return new CSSTextLayout(this);
+ }
+
+ /**
+ * Returns the <code>LineBox</code> fragments contained in this InlineFlow
+ *
+ * @return The fragments
+ */
+ public List getFragments() {
+ return _fragments;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure#getFragmentsForRead()
+ */
+ public List getFragmentsForRead() {
+ return getFragments();
+ }
+
+ public String getText() {
+ return _provider.getTextData();
+ }
+
+ /**
+ * @see FlowFigure#postValidate()
+ */
+ public void postValidate() {
+ List list = getFragments();
+ FlowBox box;
+ int left = Integer.MAX_VALUE, top = left;
+ int right = Integer.MIN_VALUE, bottom = right;
+ for (int i = 0, n = list.size(); i < n; i++) {
+ box = (FlowBox) list.get(i);
+ left = Math.min(left, box._x);
+ right = Math.max(right, box._x + box._width);
+ top = Math.min(top, box._y);
+ bottom = Math.max(bottom, box._y + box._height);
+ }
+ setBounds(new Rectangle(left, top, right - left, bottom - top));
+ list = getChildren();
+ for (int i = 0, n = list.size(); i < n; i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics)
+ */
+ protected void paintBorder(Graphics graphics) {
+ if (Debug.DEBUG_TEXTBORDER) {
+ if (_fragments != null) {
+ graphics.setForegroundColor(ColorConstants.darkBlue);
+ for (int i = 0, size = _fragments.size(); i < size; i++) {
+ FlowBox box = (FlowBox) _fragments.get(i);
+ BoxUtil.drawBox(graphics, box);
+ }
+ graphics.restoreState();
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#paintFigure(Graphics)
+ */
+ protected void paintFigure(Graphics g) {
+ Object result = this.getCSSStyle().getColor();
+ Color color;
+ if (result instanceof Color) {
+ color = (Color) result;
+ } else if (result instanceof RGB) {
+ color = new Color(null, (RGB) result);
+ } else {
+ color = null;
+ }
+ int[] range = null;
+ if (!StyleUtil.isInWidget(this.getCSSStyle())) {
+ range = _provider.getSelectedRange();
+ }
+ if (range == null || range[0] == range[1]) {
+ // we are not in selection
+ TextLayoutSupport.paintTextFigure(g, _fragments, getCSSStyle()
+ .getCSSFont().getSwtFont(), color, ((Integer) getCSSStyle()
+ .getStyleProperty(ICSSPropertyID.ATTR_TEXTDECORATION))
+ .intValue());
+ } else {
+ TextLayoutSupport.paintTextFigureWithSelection(g, _fragments,
+ _provider.getTextData(), getCSSStyle().getCSSFont()
+ .getSwtFont(), color, ((Integer) getCSSStyle()
+ .getStyleProperty(
+ ICSSPropertyID.ATTR_TEXTDECORATION))
+ .intValue(), range[0], range[1],
+ ColorConstants.white, ColorConstants.blue);
+ }
+ if (color != result && color != null) {
+ color.dispose();
+ }
+ }
+
+ /**
+ * Find out lines which has closer y coordinate to point, and then line
+ * which has closer x coordinate.
+ *
+ * @param relative
+ * @return
+ */
+ public int getNewInsertionOffset(Point relative) {
+ TextFragmentBox closestBox = null;
+ // if there is one which are at the same line with relative, calculate
+ // that line first;
+ for (int i = 0, n = _fragments.size(); i < n; i++) {
+ TextFragmentBox box = (TextFragmentBox) _fragments.get(i);
+ if (box.containsPoint(relative.x, relative.y)) {
+ int index = FlowUtilities.getTextInWidth(box.getTextData(),
+ getCSSStyle().getCSSFont().getSwtFont(), relative.x
+ - box._x, TextLayoutSupport
+ .getAverageCharWidth(box));
+ return box._offset + index;
+ } else {
+ if (closestBox == null) {
+ closestBox = box;
+ } else {
+ // box is above point
+ TextFragmentBox tempBox = box;
+ int offset1 = Math
+ .abs(CaretPositionResolver.getYDistance(
+ new Rectangle(tempBox._x, tempBox._y,
+ tempBox._width, tempBox._height),
+ relative));
+ tempBox = closestBox;
+ int offset2 = Math
+ .abs(CaretPositionResolver.getYDistance(
+ new Rectangle(tempBox._x, tempBox._y,
+ tempBox._width, tempBox._height),
+ relative));
+ if (offset1 < offset2) {
+ closestBox = box;
+ }
+ }
+ // at the same line
+ if (box.containsPoint(box._x, relative.y)) {
+ TextFragmentBox tempBox = box;
+ int offset1 = Math
+ .abs(CaretPositionResolver.getXDistance(
+ new Rectangle(tempBox._x, tempBox._y,
+ tempBox._width, tempBox._height),
+ relative));
+ tempBox = closestBox;
+ int offset2 = Math
+ .abs(CaretPositionResolver.getXDistance(
+ new Rectangle(tempBox._x, tempBox._y,
+ tempBox._width, tempBox._height),
+ relative));
+ if (offset1 < offset2) {
+ closestBox = box;
+ }
+ }
+ }
+ }
+
+ if (closestBox.containsPoint(closestBox._x, relative.y)
+ || closestBox.containsPoint(relative.x, closestBox._y)) {
+ int offset = relative.x - closestBox._x;
+ int index = FlowUtilities.getTextInWidth(closestBox.getTextData(),
+ getCSSStyle().getCSSFont().getSwtFont(), offset,
+ TextLayoutSupport.getAverageCharWidth(closestBox));
+ return closestBox._offset + index;
+ } else {
+ return -1;
+ }
+ }
+
+ public int getInsertionOffset(Point relative) {
+ for (int i = 0, n = _fragments.size(); i < n; i++) {
+ TextFragmentBox box = (TextFragmentBox) _fragments.get(i);
+ if (box.containsPoint(relative.x, relative.y)) {
+ int index = FlowUtilities.getTextInWidth(box.getTextData(),
+ getCSSStyle().getCSSFont().getSwtFont(), relative.x
+ - box._x, TextLayoutSupport
+ .getAverageCharWidth(box));
+ return box._offset + index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * the returned rectangle will be relative to this text figure.
+ *
+ * @param offset
+ * @return
+ */
+ public Rectangle calculateCaretPosition(int offset) {
+ // search reverse order, find the latest box that has _offset small than
+ // the specified one
+ if (offset > 0) {
+ for (int i = _fragments.size() - 1; i >= 0; i--) {
+ TextFragmentBox box = (TextFragmentBox) _fragments.get(i);
+ if (box._offset <= offset) {
+ // ok, we find the box.
+ if (box._offset + box._length < offset) {
+ return new Rectangle(box._x + box._width, box._y, 1,
+ box._height);
+ } else {
+ String s = box.getTextData().substring(0,
+ offset - box._offset);
+ int width = FlowUtilities.getTextExtents(s,
+ getCSSStyle().getCSSFont().getSwtFont()).width;
+ return new Rectangle(box._x + width, box._y, 1,
+ box._height);
+ }
+ }
+ }
+ } else {
+ if (_fragments.size() > 0) {
+ TextFragmentBox box = (TextFragmentBox) _fragments.get(0);
+ return new Rectangle(box._x, box._y, 1, box._height);
+ }
+ }
+ // should only reach here when there is no fragments.
+ Rectangle bounds = this.getBounds();
+ return new Rectangle(bounds.x, bounds.y, 1, bounds.height);
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextLayout.java
new file mode 100644
index 000000000..b61a37a94
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSTextLayout.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * 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.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.swt.graphics.Font;
+
+/**
+ * @author mengbo
+ */
+// NOTE: CSSTextLayout does not extends CSSFlowLayout. Since text is a little
+// special,
+// we don't want to do things like "preLayout()" as in CSSFlowLayout.
+public class CSSTextLayout extends FlowFigureLayout {
+ /**
+ * Wrapping will ONLY occur at valid line breaks
+ */
+ public static final int WORD_WRAP_HARD = 0;
+
+ /**
+ * Wrapping will always occur at the end of the available space, breaking in
+ * the middle of a word.
+ */
+ public static final int WORD_WRAP_SOFT = 1;
+
+ /**
+ * Wrapping will always occur at the end of available space, truncating a
+ * word if it doesn't fit.
+ */
+ // don't support this flag
+ // public static final int WORD_WRAP_TRUNCATE = 2;
+ private int _wrappingStyle = WORD_WRAP_HARD;
+
+ public CSSTextLayout(CSSTextFigure textfigure) {
+ super(textfigure);
+ }
+
+ // --------------------------------------------------------------------------------------------------
+ FlowBox findLastNonLineBox(LineBox box) {
+ List fragments = box.getFragments();
+ for (int i = fragments.size() - 1; i >= 0; i--) {
+ FlowBox item = (FlowBox) fragments.get(i);
+ if (item instanceof LineBox) {
+ FlowBox found = findLastNonLineBox((LineBox) item);
+ if (found != null) {
+ return found;
+ }
+ } else {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ // boolean isElementContentWhitespaceEnding()
+ // {
+ // if (!this._context.isCurrentLineOccupied())
+ // return true;
+ // LineBox line = this._context.getCurrentLine();
+ // FlowBox lastNoneLinebox = findLastNonLineBox(line);
+ // if (lastNoneLinebox instanceof TextFragmentBox)
+ // return ((TextFragmentBox) lastNoneLinebox)._isLastCharWhitespace;
+ // else
+ // return true;
+ // }
+ //
+ // String normalize(String text)
+ // {
+ // text = EntityMap.translateAndCompact(text);
+ // if (text.length() > 0 &&
+ // Character.isElementContentWhitespace(text.charAt(0)) &&
+ // isElementContentWhitespaceEnding())
+ // return text.substring(1);
+ // else
+ // return text;
+ // }
+
+ private void layoutEmptyString(List fragments, Font font) {
+ // empty node! we want to create a fake fragment, so things can be
+ // consistent
+ // that all the CSSTextFigure will have something inside, also in this
+ // way, even
+ // empty text node will have a position, thus we can support showing
+ // caret associated
+ // with this text figure.
+ fragments.clear();
+ TextFragmentBox box = TextLayoutSupport.getFragment(0, fragments);
+ box._length = 0;
+ box._offset = 0;
+ box._height = 0;
+ box._width = 0;
+ box.setTextData("");
+
+ // {following comments deprecated XXX: If is empty string, we only want
+ // to this figure to have a size, but don't
+ // want to it to be added into current line. Otherwise, a line with only
+ // a empty string
+ // will also take a line's space.}
+
+ // please reference LineBox.isOccupied()
+ // now we treat a line with only an empty text as not occupied.
+ getFlowContext().getCurrentLine().add(box);
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#layout()
+ */
+ protected void layout() {
+ CSSTextFigure flowFigure = (CSSTextFigure) getFlowFigure();
+
+ List fragments = flowFigure.getFragments();// Reuse the previous List
+ // of fragments
+ String text = flowFigure.getText();
+ Font font = flowFigure.getCSSStyle().getCSSFont().getSwtFont();
+ Object whitespace = flowFigure.getCSSStyle().getStyleProperty(
+ ICSSPropertyID.ATTR_WHITESPACE);
+
+ if (whitespace == ICSSPropertyID.VAL_PRE) {
+ if (text == null || text.length() == 0)
+ layoutEmptyString(fragments, font);
+ else
+ TextLayoutSupport.layoutNoWrap(getFlowContext(), text,
+ fragments, font);
+ } else if (whitespace == ICSSPropertyID.VAL_NOWRAP) {
+ if (text == null || text.length() == 0)
+ layoutEmptyString(fragments, font);
+ else
+ TextLayoutSupport.layoutNoWrap(getFlowContext(), text,
+ fragments, font);
+ } else {
+ if (text == null || text.length() == 0)
+ layoutEmptyString(fragments, font);
+ else {
+ boolean trimLeadingChar = (text.charAt(0) == ' ' && shouldTrimLeadingWhitespace(getFlowContext()));
+ TextLayoutSupport.layoutNormal(getFlowContext(), text,
+ fragments, font, _wrappingStyle, trimLeadingChar);
+ }
+ }
+ }
+
+ // XXX: maybe should move to TextSupport later.
+ public boolean shouldTrimLeadingWhitespace(FlowContext context) {
+ if (!context.isCurrentLineOccupied()) {
+ return true;
+ }
+ while (context instanceof CSSInlineFlowLayout) {
+ context = ((CSSInlineFlowLayout) context).getFlowContext();
+ }
+ LineBox line = context.getCurrentLine();
+ if (line == null || !line.isOccupied()) {
+ return true;
+ }
+ FlowBox lastNoneLinebox = findLastNonLineBox(line);
+ if (lastNoneLinebox == null || lastNoneLinebox.getWidth() == 0) {
+ return true;
+ } else if (lastNoneLinebox instanceof TextFragmentBox) {
+ return ((TextFragmentBox) lastNoneLinebox)._isLastCharWhitespace;
+ } else {
+ return false;
+ }
+ }
+
+ public void dispose() {
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSWidgetLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSWidgetLayout.java
new file mode 100644
index 000000000..1c83653d2
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CSSWidgetLayout.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.provider.DimensionInfo;
+import org.eclipse.jst.pagedesigner.css2.provider.ICSSWidgetProvider;
+
+/**
+ * @author mengbo
+ */
+public class CSSWidgetLayout extends CSSBlockFlowLayout implements ICSSPainter {
+ private WidgetBox _widgetBox;
+
+ private ICSSWidgetProvider _provider;
+
+ /**
+ * @param flowfigure
+ */
+ public CSSWidgetLayout(CSSFigure flowfigure, ICSSWidgetProvider provider) {
+ super(flowfigure);
+ _provider = provider;
+ }
+
+ /**
+ * normally this method is called directly after constructor
+ *
+ * @param provider
+ */
+ public void setProvider(ICSSWidgetProvider provider) {
+ _provider = provider;
+ }
+
+ public ICSSWidgetProvider getProvider() {
+ // return ((CSSWidgetFigure)this.getFlowFigure()).getProvider();
+ return _provider;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#isInlineBlock()
+ */
+ public boolean isInlineBlock() {
+ ICSSWidgetProvider provider = getProvider();
+ return provider.isInline();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#layout()
+ */
+ protected void layoutChildren() {
+ ICSSWidgetProvider provider = getProvider();
+
+ // if we did endLine, then will result in context create a new line, so
+ // we may in the new line now.
+ // passing in the top margin, and context will consider that when
+ // creating the new line.
+
+ int suggestedWith = _blockBox.getContentWidth();
+ int suggestedHeight = _blockBox.getContentHeight();
+ // int suggestedWith = getSuggestedWidth(line, style, provider);
+ // int suggestedHeight = getSuggestedHeight(line, style, provider);
+
+ DimensionInfo resultInfo = provider.getPreferredDimension(
+ suggestedWith, suggestedHeight);
+ Dimension resultSize = resultInfo.getDimension();
+
+ _widgetBox = new WidgetBox(); // ((CSSWidgetFigure)getFlowFigure()).getWidgetBox();
+ // if (provider.isHandlingBorder() || style == null)
+ // {
+ _widgetBox.setWidth(resultSize.width);
+ _widgetBox.setHeight(resultSize.height);
+ _widgetBox.setAscent(resultInfo.getAscent());
+ // }
+ // else
+ // {
+ // widgetBox.setWidth(resultSize.width +
+ // style.getBorderInsets().getWidth());
+ // widgetBox.setHeight(resultSize.height +
+ // style.getBorderInsets().getHeight());
+ // widgetBox.setAscent(resultInfo.getAscent()+style.getBorderInsets().top);
+ // }
+ this.addToCurrentLine(_widgetBox);
+ // if (!provider.isInline())
+ // {
+ // context.endLine();
+ // }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()
+ */
+ public void dispose() {
+ }
+
+ // public int getSuggestedWidth(LineBox line, ICSSStyle style,
+ // ICSSWidgetProvider provider)
+ // {
+ // if (style == null) return -1;
+ //
+ // Object width = style.getStyleProperty(ICSSPropertyID.ATTR_WIDTH);
+ // Length recommendedWidth = (width instanceof Length) ? (Length) width :
+ // null;
+ //
+ // int rw = 0;
+ // if (recommendedWidth == null || recommendedWidth.getValue() <= 0)
+ // {
+ // return -1;
+ // }
+ // else
+ // {
+ // if (recommendedWidth.isPercentage())
+ // {
+ // rw = line.getAvailableWidth() * recommendedWidth.getValue() / 100;
+ // }
+ // else
+ // {
+ // rw = recommendedWidth.getValue();
+ // }
+ //
+ // if (!style.isSizeIncludeBorderPadding() && provider.isHandlingBorder())
+ // {
+ // rw += style.getBorderInsets().getWidth() +
+ // style.getPaddingInsets().getWidth();
+ // }
+ // else if (style.isSizeIncludeBorderPadding() &&
+ // !provider.isHandlingBorder())
+ // {
+ // rw -= style.getBorderInsets().getWidth() +
+ // style.getPaddingInsets().getWidth();
+ // }
+ // }
+ //
+ // return rw;
+ // }
+ //
+ // public int getSuggestedHeight(LineBox line, ICSSStyle style,
+ // ICSSWidgetProvider provider)
+ // {
+ // if (style == null) return -1;
+ //
+ // Object height = style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);
+ // Length recommendedHeight = (height instanceof Length) ? (Length) height :
+ // null;
+ //
+ // int rh = 0;
+ // if (recommendedHeight == null || recommendedHeight.getValue() <= 0)
+ // {
+ // return -1;
+ // }
+ // else
+ // {
+ // if (recommendedHeight.isPercentage())
+ // {
+ // // we don't support percentage height for this version, ignore
+ // return -1;
+ // }
+ // else
+ // {
+ // rh = recommendedHeight.getValue();
+ // }
+ //
+ // if (!style.isSizeIncludeBorderPadding() && provider.isHandlingBorder())
+ // {
+ // rh += style.getBorderInsets().getHeight() +
+ // style.getPaddingInsets().getHeight();
+ // }
+ // else if (style.isSizeIncludeBorderPadding() &&
+ // !provider.isHandlingBorder())
+ // {
+ // rh -= style.getBorderInsets().getHeight() +
+ // style.getPaddingInsets().getHeight();
+ // }
+ // }
+ //
+ // return rh;
+ // }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSPainter#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics g) {
+ ICSSWidgetProvider provider = this.getProvider();
+ if (provider != null && _widgetBox != null) {
+ provider.paintFigure(g, new Rectangle(_widgetBox._x, _widgetBox._y,
+ _widgetBox.getWidth(), _widgetBox.getHeight()));
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#handlingBorderForBlock()
+ */
+ public boolean handlingBorderForBlock() {
+ ICSSWidgetProvider provider = this.getProvider();
+ if (provider != null) {
+ return provider.isHandlingBorder();
+ }
+ return super.handlingBorderForBlock();
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CompositeBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CompositeBox.java
new file mode 100644
index 000000000..6cce9545a
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/CompositeBox.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * 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.ArrayList;
+import java.util.List;
+
+/**
+ * A FlowBox that can contain other BlockInfos. The contained BlockInfos are
+ * called <i>fragments </i>.
+ *
+ * @author mengbo
+ * @since 2.1
+ */
+public abstract class CompositeBox extends FlowBox {
+
+ /**
+ * The contained fragments.
+ */
+ protected List _fragments = new ArrayList();
+
+ int _recommendedWidth;
+
+ int _recommendedHeight;
+
+ /**
+ * Adds the specified FlowBox. Updates the width, height, and ascent
+ * properties.
+ *
+ * @param block
+ * the FlowBox being added
+ */
+ public void add(FlowBox block) {
+ // The order is critical.see the first "if" block in the unionInfo()
+ // method.
+ unionInfo(block);
+ _fragments.add(block);
+ }
+
+ /**
+ * Removes all owned fragments and invalidates this CompositeBox.
+ */
+ public void clear() {
+ _fragments.clear();
+ resetInfo();
+ }
+
+ /**
+ * Overridden to ensure that the CompositeBox is valid.
+ *
+ * @see FlowBox#getBounds()
+ */
+ // public Rectangle getBounds() {
+ // validate();
+ // return this;
+ // }
+ /**
+ * @return the List of fragments
+ */
+ public List getFragments() {
+ return _fragments;
+ }
+
+ /**
+ * Returns the recommended width for this CompositeBox.
+ *
+ * @return the recommended width
+ */
+ public int getRecommendedWidth() {
+ return _recommendedWidth;
+ }
+
+ /**
+ * Returns the recommended height for this compositebox.
+ *
+ * @return
+ */
+ public int getRecommendedHeight() {
+ return _recommendedHeight;
+ }
+
+ // public int getInnerTop() {
+ // validate();
+ // return y;
+ // }
+
+ /**
+ * resets fields before unioning the data from the fragments.
+ */
+ protected void resetInfo() {
+ _width = _height = 0;
+ }
+
+ /**
+ * Sets the recommended width for this CompositeBox.
+ *
+ * @param w
+ * the width
+ */
+ public void setRecommendedWidth(int w) {
+ _recommendedWidth = w;
+ }
+
+ public void setRecommendedHeight(int h) {
+ _recommendedHeight = h;
+ }
+
+ /**
+ * unions the fragment's width, height, and ascent into this composite.
+ *
+ * @param box
+ * the fragment
+ */
+ protected void unionInfo(FlowBox box) {
+ int right = Math.max(_x + _width, box._x + box._width);
+ int bottom = Math.max(_y + _height, box._y + box._height);
+ _x = Math.min(_x, box._x);
+ _y = Math.min(_y, box._y);
+ _width = right - _x;
+ _height = bottom - _y;
+ }
+
+ public int getContentWidth() {
+ return getWidth() - getBorderPaddingWidth();
+ }
+
+ public int getContentHeight() {
+ return getHeight() - getBorderPaddingHeight();
+ }
+
+ public int getRecommendedContentWidth() {
+ return Math.max(0, getRecommendedWidth() - getBorderPaddingWidth());
+ }
+ //
+ // public int getRecommendedContentHeight()
+ // {
+ // return Math.max(0, getRecommendedHeight() - getBorderPaddingHeight());
+ // }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/Debug.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/Debug.java
new file mode 100644
index 000000000..c15f21da0
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/Debug.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * Debug constants.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class Debug {
+ public static final boolean DEBUG_BASELINE = false;
+
+ public static final boolean DEBUG_BOX = false;
+
+ public static final boolean DEBUG_BORDERPADDING = false;
+
+ public static final boolean DEBUG_TEXTBORDER = false;
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/DisplayToLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/DisplayToLayout.java
new file mode 100644
index 000000000..de2eaa8d9
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/DisplayToLayout.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.LayoutManager;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.table.CSSTRGroupLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.table.CSSTRLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.table.CSSTableCaptionLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.table.CSSTableCellLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.table.CSSTableLayout2;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.property.PositionMeta;
+
+/**
+ * @author mengbo
+ */
+public class DisplayToLayout {
+ /**
+ * @param figure
+ * @param display
+ * @param old
+ * @return
+ */
+ public static CSSLayout displayToLayout(CSSFigure figure, String display,
+ LayoutManager old) {
+ if ("block".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSBlockFlowLayout(figure);
+ } else if ("inline".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSInlineFlowLayout(figure);
+ } else if ("table".equalsIgnoreCase(display) || "inline-table".equalsIgnoreCase(display)) //$NON-NLS-1$ $NON-NLS-2$
+ {
+ return new CSSTableLayout2(figure);
+ } else if ("table-row".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSTRLayout(figure);
+ } else if ("table-row-group".equalsIgnoreCase(display) //$NON-NLS-1$
+ || "table-header-group".equalsIgnoreCase(display) //$NON-NLS-1$
+ || "table-footer-group".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSTRGroupLayout(figure);
+ } else if ("table-cell".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSTableCellLayout(figure);
+ } else if (display.equalsIgnoreCase("table-caption")) //$NON-NLS-1$
+ {
+ return new CSSTableCaptionLayout(figure);
+ } else if ("inline-block".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ return new CSSBlockFlowLayout(figure) {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#isInlineBlock()
+ */
+ public boolean isInlineBlock() {
+ return true;
+ }
+ };
+ } else if (ICSSPropertyID.VAL_LIST_ITEM.equalsIgnoreCase(display)) {
+ return new CSSListItemLayout(figure);
+ }
+ return null;
+ }
+
+ /**
+ * @param figure
+ * @param display
+ * @param old
+ * @return
+ */
+ public static boolean isInline(String display) {
+ return "inline".equalsIgnoreCase(display) //$NON-NLS-1$
+ || "inline-block".equalsIgnoreCase(display); //$NON-NLS-1$
+ }
+
+ /**
+ * @param style
+ * @return
+ */
+ public static boolean isPositioned(ICSSStyle style) {
+ Object position = style.getStyleProperty(ICSSPropertyID.ATTR_POSITION);
+ if (PositionMeta.STATIC.equalsIgnoreCase((String) position)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FigureUtil.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FigureUtil.java
new file mode 100644
index 000000000..60e3f6fcb
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FigureUtil.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Translatable;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class FigureUtil {
+ // XXX:
+ // seemed Figure.translateToRelative is bug?
+ public static final void translateToRelative(IFigure figure, Translatable t) {
+ if (figure.getParent() != null) {
+ translateToRelative(figure.getParent(), t);
+ // figure.getParent().translateToRelative(t);
+ figure.translateFromParent(t);
+ }
+ }
+
+ // XXX:
+ // seemed Figure.translateToAbsolute is bug?
+ public static final void translateToAbsolute(IFigure figure, Translatable t) {
+ if (figure.getParent() != null) {
+ figure.translateToParent(t);
+ translateToAbsolute(figure.getParent(), t);
+ // figure.getParent().translateToAbsolute(t);
+ }
+
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowBox.java
new file mode 100644
index 000000000..149fbd9a4
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowBox.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * This class represents the CSS box model. See chapter 8 of CSS2 spec.
+ *
+ * @see http://www.w3.org/TR/REC-CSS2/box.html
+ */
+public class FlowBox {
+ private Object _verticalAlignData = null;
+
+ /**
+ * The x location
+ */
+ public int _x;
+
+ /**
+ * The y location
+ */
+ public int _y;
+
+ int _width;
+
+ int _height;
+
+ public Insets _marginInsets = new Insets();
+
+ public Insets _borderInsets = new Insets();
+
+ public Insets _paddingInsets = new Insets();
+
+ /**
+ * This method must be called on a block that is completely positioned and
+ * committed.
+ *
+ * @param x
+ * X
+ * @param y
+ * Y
+ * @return <code>true</code> if the FlowBox contains the point
+ */
+ public boolean containsPoint(int x, int y) {
+ return x >= this._x && y >= this._y && x < this._x + this._width
+ && y < this._y + this._height;
+ }
+
+ /**
+ * By default, a FlowBox is all ascent, and no descent, so the height is
+ * returned.
+ *
+ * @return the <i>ascent </i> in pixels above the baseline
+ */
+ public int getAscent() {
+ return getHeight();
+ }
+
+ /**
+ * By default, a simple FlowBox is all ascent, and no descent. Zero is
+ * returned.
+ *
+ * @return the <i>descent </i> in pixels below the baseline
+ */
+ public final int getDescent() {
+ return getHeight() - getAscent();
+ }
+
+ /**
+ * Returns the height
+ *
+ * @return height
+ */
+ public int getHeight() {
+ return _height;
+ }
+
+ /**
+ * Returns the width
+ *
+ * @return width
+ */
+ public int getWidth() {
+ return _width;
+ }
+
+ public void setWidth(int w) {
+ _width = w;
+ }
+
+ public void setHeight(int h) {
+ _height = h;
+ }
+
+ /**
+ * Used to set the baseline of this FlowBox to the specified value.
+ *
+ * @param value
+ * the new baseline
+ */
+ public void makeBaseline(int value) {
+ _y = (value - getAscent());
+ }
+
+ public int getBorderPaddingWidth() {
+ return _borderInsets.getWidth() + _paddingInsets.getWidth();
+ }
+
+ /**
+ * @return
+ */
+ public int getBorderPaddingHeight() {
+ return _borderInsets.getHeight() + _paddingInsets.getHeight();
+ }
+
+ /**
+ * @return
+ */
+ public Insets getBorderPaddingInsets() {
+ Insets temp = new Insets(_borderInsets);
+ return temp.add(_paddingInsets);
+ }
+
+ public void setXYWidthHeight(Rectangle rect) {
+ this._x = rect.x;
+ this._y = rect.y;
+ this.setWidth(rect.width);
+ this.setHeight(rect.height);
+ }
+
+ /**
+ * @return Returns the _verticalAlignData.
+ */
+ public Object getVerticalAlignData() {
+ return _verticalAlignData;
+ }
+
+ /**
+ * @param alignData
+ * The _verticalAlignData to set.
+ */
+ public void setVerticalAlignData(Object alignData) {
+ _verticalAlignData = alignData;
+ }
+
+ public Rectangle getRectangle() {
+ return new Rectangle(this._x, this._y, this.getWidth(), this
+ .getHeight());
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContainerLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContainerLayout.java
new file mode 100644
index 000000000..b53cf7f2c
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContainerLayout.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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.jst.pagedesigner.PDPlugin;
+import org.eclipse.jst.pagedesigner.common.logging.Logger;
+
+/**
+ * A layout for FlowFigures with children.
+ * <P>
+ * WARNING: This class is not intended to be subclassed by clients.
+ *
+ * @author mengbo
+ * @since 2.1
+ */
+public abstract class FlowContainerLayout extends FlowFigureLayout implements
+ FlowContext {
+ private static Logger _log = PDPlugin.getLogger(FlowContainerLayout.class);
+
+ /**
+ * the current line
+ */
+ protected LineBox _currentLine;
+
+ private boolean _calculatingMaxWidth = false;
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#FlowFigureLayout(FlowFigure)
+ */
+ protected FlowContainerLayout(FlowFigure flowFigure) {
+ super(flowFigure);
+ }
+
+ /**
+ * @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();
+ }
+
+ /**
+ * 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._marginInsets.right;
+ } else {
+ return 0;
+ }
+ }
+
+ public void setCalculatingMaxWidth(boolean c) {
+ _calculatingMaxWidth = c;
+ }
+
+ 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 before layoutChildren() to setup any necessary state.
+ */
+ protected abstract void preLayout();
+
+ /**
+ * 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();
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContext.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContext.java
new file mode 100644
index 000000000..dbca0dd53
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowContext.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * Copied from draw2d. Enhanced to meet page designer's needs. The context that
+ * a {@link FlowFigureLayout}uses to perform its layout.
+ * <P>
+ * WARNING: This interface is not intended to be implemented by clients. It
+ * exists to define the API between the layout and its context.
+ */
+public interface FlowContext {
+
+ /**
+ * Adds the given box into the current line.
+ *
+ * @param box
+ * the FlowBox to add
+ */
+ void addToCurrentLine(FlowBox box);
+
+ /**
+ * The current line should be committed if it is occupied, and then set to
+ * <code>null</code>. Otherwise, do nothing.
+ */
+ void endLine();
+
+ /**
+ * Obtains the current line, creating a new line if there is no current
+ * line. if create a new line, the new line's x will be set correctly
+ * without considering the new element's left margin. Also, if create new
+ * line, it will treat as the new line's top margin is 0.
+ *
+ * @return the current line
+ */
+ LineBox getCurrentLine();
+
+ /**
+ * if create a new line, the new line's x will be set correctly without
+ * considering the new element's left margin.
+ *
+ * @param topMargin
+ * @return
+ */
+ LineBox getCurrentLine(int topMargin);
+
+ /**
+ * Returns the current Y value.
+ *
+ * @return the current Y value
+ */
+ int getCurrentY();
+
+ /**
+ * @return <code>true</code> if the current line contains any fragments
+ */
+ boolean isCurrentLineOccupied();
+
+ /**
+ * @return
+ */
+ int getLastMarginRight();
+
+ /**
+ * when layout table, we need to calculate max width of a cell. This is done
+ * by don't break line (other than explicit required). Currently, the
+ * solution is to make the recommended width to be very big, and when create
+ * block element we don't set the block element's size to be recommended
+ * width. Please see CSSBlockFlowLayout
+ *
+ * @return
+ */
+ boolean isCalculatingMaxWidth();
+
+ /**
+ * when calculating percentage width, we need the container width
+ *
+ * @return
+ */
+ int getContainerWidth();
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigure.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigure.java
new file mode 100644
index 000000000..7c15e1278
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigure.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * 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.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * The base implementation for text flow figures. A flow figure is used to
+ * render a document in which elements are laid out horizontally within a "line"
+ * until that line is filled. Layout continues on the next line.
+ * <p>
+ * WARNING: This class is not intended to be subclassed by clients. Future
+ * versions may contain additional abstract methods.
+ *
+ * @author mengbo
+ * @since 2.1
+ */
+public abstract class FlowFigure extends Figure {
+
+ // static final boolean SHOW_BASELINE = true;
+
+ /**
+ * Constructs a new FlowFigure.
+ */
+ public FlowFigure() {
+ // setLayoutManager(createDefaultFlowLayout());
+ }
+
+ /**
+ * If the child is a <code>FlowFigure</code>, its FlowContext is passed
+ * to it.
+ *
+ * @see org.eclipse.draw2d.IFigure#add(IFigure, Object, int)
+ */
+ public void add(IFigure child, Object constraint, int index) {
+ super.add(child, constraint, index);
+ if (child instanceof FlowFigure) {
+ FlowFigure ff = (FlowFigure) child;
+ if (getLayoutManager() instanceof FlowContext) {
+ ff.setOriginalFlowContext((FlowContext) getLayoutManager());
+ } else {
+ // should not happen
+ // FIXME: logging
+ System.err.println("layout is not FlowContext");
+ }
+ }
+ }
+
+ /**
+ * Creates the default layout manager
+ *
+ * @return The default layout
+ */
+ // protected abstract FlowFigureLayout createDefaultFlowLayout();
+ /**
+ * @see Figure#paintFigure(Graphics)
+ */
+ protected void paintFigure(Graphics g) {
+ super.paintFigure(g);
+ // g.drawRectangle(getBounds().getResized(-1,-1));
+ }
+
+ /**
+ * Called after validate has occurred. This is used to update the bounds of
+ * the FlowFigure to encompass its new flow boxed created during validate.
+ */
+ public abstract void postValidate();
+
+ /**
+ * FlowFigures override setBounds() to prevent translation of children.
+ * "bounds" is a derived property for FlowFigures, calculated from the
+ * fragments that make up the FlowFigure.
+ *
+ * @see Figure#setBounds(Rectangle)
+ */
+ public void setBounds(Rectangle r) {
+ if (getBounds().equals(r))
+ return;
+ erase();
+ bounds.x = r.x;
+ bounds.y = r.y;
+ bounds.width = r.width;
+ bounds.height = r.height;
+ fireFigureMoved();
+ repaint();
+ }
+
+ /**
+ * Sets the flow context.
+ *
+ * @param flowContext
+ * the flow context for this flow figure
+ */
+ public void setOriginalFlowContext(FlowContext flowContext) {
+ ((FlowFigureLayout) getLayoutManager())
+ .setOriginalFlowContext(flowContext);
+ }
+
+ public void setDisplayString(String s) {
+ _displayString = s;
+ }
+
+ public String toString() {
+ if (_displayString == null)
+ return super.toString();
+ else
+ return _displayString + " " + getClass().getName();
+ }
+
+ String _displayString; // for debug
+
+ /**
+ * @return
+ */
+ public FlowContext getFlowContext() {
+ return ((FlowFigureLayout) getLayoutManager()).getFlowContext();
+ }
+
+ // ----------------------------------------------------------------------
+ // as absolute positioning and relative positioning may have children
+ // out-side
+ // of parent bounds, so we want to disable clipping when drawing figures
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#paintChildren(org.eclipse.draw2d.Graphics)
+ */
+ protected void paintChildren(Graphics graphics) {
+ IFigure child;
+
+ Rectangle clip = Rectangle.SINGLETON;
+ List children = this.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ child = (IFigure) children.get(i);
+ if (child.isVisible() && child.intersects(graphics.getClip(clip))) {
+ // graphics.clipRect(child.getBounds());
+ child.paint(graphics);
+ graphics.restoreState();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#paintClientArea(org.eclipse.draw2d.Graphics)
+ */
+ protected void paintClientArea(Graphics graphics) {
+ if (this.getChildren().isEmpty())
+ return;
+
+ // boolean optimizeClip = getBorder() == null || getBorder().isOpaque();
+
+ if (useLocalCoordinates()) {
+ graphics.translate(getBounds().x + getInsets().left, getBounds().y
+ + getInsets().top);
+ // if (!optimizeClip)
+ // graphics.clipRect(getClientArea(PRIVATE_RECT));
+ graphics.pushState();
+ paintChildren(graphics);
+ graphics.popState();
+ graphics.restoreState();
+ } else {
+ // if (optimizeClip)
+ paintChildren(graphics);
+ // else {
+ // graphics.clipRect(getClientArea(PRIVATE_RECT));
+ // graphics.pushState();
+ // paintChildren(graphics);
+ // graphics.popState();
+ // graphics.restoreState();
+ // }
+ }
+
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigureLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigureLayout.java
new file mode 100644
index 000000000..3f80478cf
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowFigureLayout.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.AbstractLayout;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+
+public abstract class FlowFigureLayout extends AbstractLayout {
+
+ /**
+ * <code>true</code> if the context has changed, and a layout is needed.
+ */
+ protected boolean _invalid = true;
+
+ /**
+ * The flow context in which this LayoutManager exists.
+ */
+ private FlowContext _context;
+
+ /**
+ * The figure passed by layout(Figure) is held for convenience.
+ */
+ private final FlowFigure _flowFigure;
+
+ /**
+ * Constructs a new FlowFigureLayout with the given FlowFigure.
+ *
+ * @param flowfigure
+ * the FlowFigure
+ */
+ protected FlowFigureLayout(FlowFigure flowfigure) {
+ this._flowFigure = flowfigure;
+ }
+
+ /**
+ * TextFlowLayouts do not calculate a preferred size because it is too
+ * expensive. {@link FlowPage}will actually layout itself in order to
+ * calculate preferredSize.
+ *
+ * @see AbstractLayout#calculatePreferredSize(IFigure)
+ */
+ public Dimension calculatePreferredSize(IFigure f, int w, int h) {
+ return null;
+ }
+
+ /**
+ * @return the FlowFigure
+ */
+ protected FlowFigure getFlowFigure() {
+ return _flowFigure;
+ }
+
+ /**
+ * Marks this layout as invalid.
+ *
+ * @see org.eclipse.draw2d.LayoutManager#invalidate()
+ */
+ public void invalidate() {
+ _invalid = true;
+ super.invalidate();
+ }
+
+ /**
+ * @see org.eclipse.draw2d.LayoutManager#layout(IFigure)
+ */
+ public final void layout(IFigure figure) {
+ layout();
+ _invalid = false;
+ }
+
+ /**
+ * Called during {@link #layout(IFigure)}. The {@link #_invalid}flag is
+ * reset after this method is called.
+ */
+ protected abstract void layout();
+
+ /**
+ * Sets the context for this layout manager.
+ *
+ * @param flowContext
+ * the context of this layout
+ */
+ public void setOriginalFlowContext(FlowContext flowContext) {
+ _context = flowContext;
+ }
+
+ public FlowContext getOriginalFlowContext() {
+ return _context;
+ }
+
+ /**
+ * get flow context.
+ *
+ * @return
+ */
+ public FlowContext getFlowContext() {
+ return _context;
+ }
+
+ public String toString() {
+ // for debug purpose.
+ return _flowFigure.toString();
+ }
+
+ abstract public void dispose();
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowPage.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowPage.java
new file mode 100644
index 000000000..31d44de44
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowPage.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * 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.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * The root of a Flow hierarchy. A flow page can be treated as a normal figure,
+ * but contains FlowFigures.
+ * <P>
+ * A FlowPage will not have a defined width unless it is inside a figure whose
+ * layout provides width hints when calling
+ * {@link org.eclipse.draw2d.IFigure#getPreferredSize(int, int)}.
+ * <P>
+ * WARNING: This class is not intended to be subclassed by clients.
+ */
+public class FlowPage extends BlockFlow {
+
+ private Dimension _pageSize = new Dimension();
+
+ private int _recommendedWidth;
+
+ private int _pageSizeCacheKeys[] = new int[4];
+
+ private Dimension _pageSizeCacheValues[] = new Dimension[4];
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.BlockFlow#createDefaultFlowLayout()
+ */
+ protected FlowFigureLayout createDefaultFlowLayout() {
+ return new PageFlowLayout(this);
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#getMinimumSize()
+ */
+ public Dimension getMinimumSize(int w, int h) {
+ return getPreferredSize(w, h);
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#invalidate()
+ */
+ public void invalidate() {
+ _pageSizeCacheValues = new Dimension[4];
+ super.invalidate();
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int)
+ */
+ public Dimension getPreferredSize(int width, int h) {
+ if (width >= 0)
+ width = Math.max(0, width - getInsets().getWidth());
+
+ for (int i = 0; i < 4; i++) {
+ if (_pageSizeCacheKeys[i] == width
+ && _pageSizeCacheValues[i] != null)
+ return _pageSizeCacheValues[i];
+ }
+
+ _pageSizeCacheKeys[3] = _pageSizeCacheKeys[2];
+ _pageSizeCacheKeys[2] = _pageSizeCacheKeys[1];
+ _pageSizeCacheKeys[1] = _pageSizeCacheKeys[0];
+ _pageSizeCacheKeys[0] = width;
+
+ _pageSizeCacheValues[3] = _pageSizeCacheValues[2];
+ _pageSizeCacheValues[2] = _pageSizeCacheValues[1];
+ _pageSizeCacheValues[1] = _pageSizeCacheValues[0];
+
+ // Flowpage must temporarily layout to determine its preferred size
+ int oldWidth = getRecommendedWidth();
+ setRecommendedWidth(width);
+ validate();
+ _pageSizeCacheValues[0] = _pageSize.getExpanded(getInsets().getWidth(),
+ getInsets().getHeight());
+
+ if (width != oldWidth) {
+ setRecommendedWidth(oldWidth);
+ getUpdateManager().addInvalidFigure(this);
+ }
+ return _pageSizeCacheValues[0];
+ }
+
+ int getRecommendedWidth() {
+ return _recommendedWidth;
+ }
+
+ /**
+ * @see BlockFlow#postValidate()
+ */
+ public void postValidate() {
+ Rectangle r = getBlockBox().toRectangle();
+ _pageSize.width = r.width;
+ _pageSize.height = r.height;
+ List v = getChildren();
+ for (int i = 0; i < v.size(); i++)
+ ((FlowFigure) v.get(i)).postValidate();
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigure#setBounds(Rectangle)
+ */
+ public void setBounds(Rectangle r) {
+ if (getBounds().equals(r))
+ return;
+ boolean invalidate = getBounds().width != r.width
+ || getBounds().height != r.height;
+ super.setBounds(r);
+ int newWidth = r.width - getInsets().getWidth();
+ if (invalidate || getRecommendedWidth() != newWidth) {
+ setRecommendedWidth(newWidth);
+ getUpdateManager().addInvalidFigure(this);
+ }
+ }
+
+ private void setRecommendedWidth(int width) {
+ if (_recommendedWidth == width)
+ return;
+ _recommendedWidth = width;
+ super.invalidate();
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#validate()
+ */
+ public void validate() {
+ if (isValid())
+ return;
+ super.validate();
+ postValidate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.Figure#setValid(boolean)
+ */
+ public void setValid(boolean value) {
+ super.setValid(value);
+ }
+
+ public Insets getInsets() {
+ return new Insets(8);
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowUtilities.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowUtilities.java
new file mode 100644
index 000000000..5ebde828b
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/FlowUtilities.java
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * 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.text.BreakIterator;
+
+import org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+
+/**
+ * Utility class for FlowFigures.
+ *
+ */
+public class FlowUtilities extends FigureUtilities {
+ /**
+ * Returns the number of characters from the specified String that will fit
+ * in the available amount of space. An average character width can be
+ * provided as a hint for faster calculation.
+ *
+ * @param frag
+ * the TextFragmentBox
+ * @param string
+ * the String
+ * @param font
+ * the Font used for measuring
+ * @param availableWidth
+ * the available width in pixels
+ * @param avg
+ * 0.0, or an avg character width to use during calculation
+ * @param wrapping
+ * the word wrap style
+ * @return the number of characters that will fit in the space
+ */
+ public static int setupFragmentBasedOnTextSpace(TextFragmentBox frag,
+ String string, Font font, int availableWidth, float avg,
+ int wrapping) {
+ int result = getTextForSpace(string, font, availableWidth, avg,
+ wrapping);
+ frag._length = result;
+ setupFragment(frag, font, string);
+ return result;
+ }
+
+ /**
+ * given the text string, font and available width and wrapping mode.
+ * Calculate how much text can fit into.
+ *
+ * @param string
+ * @param font
+ * @param availableWidth
+ * @param avg
+ * @param wrapping
+ * @return
+ */
+ public static int getTextForSpace(String string, Font font,
+ int availableWidth, float avg, int wrapping) {
+ if (string.length() == 0) {
+ return 0;
+ }
+
+ FontMetrics metrics = getFontMetrics(font);
+ BreakIterator breakItr = BreakIterator.getLineInstance();
+ breakItr.setText(string);
+ int MIN, min, max;
+ if (avg == 0.0) {
+ avg = metrics.getAverageCharWidth();
+ }
+
+ int firstBreak = breakItr.next();
+
+ int winNL = string.indexOf("\r\n"); //$NON-NLS-1$
+ int macNL = string.indexOf('\r');
+ int unixNL = string.indexOf('\n');
+
+ MIN = min = (wrapping == CSSTextLayout.WORD_WRAP_HARD) ? firstBreak : 1;
+ if (macNL == winNL) {
+ macNL = -1; // If the Mac newline is just the prefix to the win NL,
+ // ignore it
+ }
+
+ max = string.length() + 1;
+
+ if (winNL != -1) {
+ max = Math.min(max, winNL);
+ min = Math.min(min, winNL);
+ }
+ if (unixNL != -1) {
+ max = Math.min(max, unixNL);
+ min = Math.min(min, unixNL);
+ }
+ if (macNL != -1) {
+ max = Math.min(max, macNL);
+ min = Math.min(min, macNL);
+ }
+
+ int origMax = max;
+ // The size of the current guess
+ int guess = 0, guessSize = 0;
+
+ while ((max - min) > 1) {
+ // Pick a new guess size
+ // New guess is the last guess plus the missing width in pixels
+ // divided by the average character size in pixels
+ guess = guess + (int) ((availableWidth - guessSize) / avg);
+
+ if (guess >= max) {
+ guess = max - 1;
+ }
+ if (guess <= min) {
+ guess = min + 1;
+ }
+
+ // Measure the current guess
+ guessSize = getStringExtents2(string.substring(0, guess), font).width;
+
+ if (guessSize <= availableWidth) {
+ // We did not use the available width
+ min = guess;
+ } else {
+ // We exceeded the available width
+ max = guess;
+ }
+ }
+
+ int result = string.length();
+ switch (wrapping) {
+ case CSSTextLayout.WORD_WRAP_HARD:
+ if (min == string.length() || min == winNL || min == unixNL
+ || min == macNL) {
+ result = min;
+ } else if (max == origMax
+ && getStringExtents2(string.substring(0, max), font).width <= availableWidth) {
+ result = max;
+ } else {
+ result = Math.max(MIN, breakItr.preceding(Math.min(max, string
+ .length() - 1)));
+ }
+ break;
+
+ case CSSTextLayout.WORD_WRAP_SOFT:
+ if (min == string.length() || min == winNL || min == unixNL
+ || min == macNL) {
+ result = min;
+ } else if (max == origMax
+ && getStringExtents2(string.substring(0, max), font).width <= availableWidth) {
+ result = max;
+ } else if (breakItr.isBoundary(min)) {
+ result = min;
+ } else if (breakItr.isBoundary(Math.min(max, string.length() - 1))) {
+ result = max;
+ } else {
+ result = breakItr.preceding(Math.min(max, string.length() - 1));
+ }
+ if (result <= 0) {
+ result = min;
+ }
+ break;
+ // case CSSTextLayout.WORD_WRAP_TRUNCATE:
+ // if (min == string.length() || min == winNL || min == unixNL || min ==
+ // macNL)
+ // {
+ // result = frag._length = min;
+ // setupFragment(frag, font, string);
+ // if (frag.getWidth() <= availableWidth)
+ // return result;
+ // min -= 1;
+ // }
+ // else if (max == origMax && getStringExtents(string.substring(0, max),
+ // font).width <= availableWidth)
+ // {
+ // result = frag._length = max;
+ // setupFragment(frag, font, string);
+ // return result;
+ // }
+ // result = breakItr.preceding(Math.min(max + 1, string.length() - 1));
+ // if (result <= 0)
+ // {
+ // ELLIPSIS_SIZE =
+ // FigureUtilities.getStringExtents(CSSTextFigure.ELLIPSIS, font);
+ // getTextForSpace(frag, string, font, availableWidth -
+ // ELLIPSIS_SIZE.width, avg, CSSTextLayout.WORD_WRAP_SOFT);
+ // //frag.length = min;
+ // frag._truncated = true;
+ // result = breakItr.following(min);
+ // if (result == BreakIterator.DONE)
+ // result = string.length();
+ // }
+ // else
+ // {
+ // frag._length = result;
+ // }
+ }
+
+ return result;
+ }
+
+ public static int getTextInWidth(String string, Font font,
+ int availableWidth, float avg) {
+ if (string.length() == 0) {
+ return 0;
+ }
+ int guess = 0;
+ while (true) {
+ Dimension a = getTextExtents(string.substring(0, guess), font);
+ if (a.width >= availableWidth) {
+ return guess;
+ }
+ guess++;
+ if (guess == string.length()) {
+ return guess;
+ }
+ }
+ }
+
+ /**
+ * change the parent implementation of getStringExtents(). Don't expend the
+ * 1 width. So empty string will not have any width.
+ *
+ * @param s
+ * @param f
+ * @return
+ */
+ public static Dimension getStringExtents2(String s, Font f) {
+ return new Dimension(getStringDimension(s, f));
+ }
+
+ static void setupFragment(TextFragmentBox frag, Font f, String s) {
+ // if (frag.length != s.length())
+ // we don't skip whitespace here. since already truncated in
+ // CSSTextLayout
+
+ // while (frag.length > 0 &&
+ // Character.isElementContentWhitespace(s.charAt(frag.length - 1)))
+ // frag.length--;
+ frag.setTextData(s.substring(0, frag._length));
+ Dimension d = getStringExtents2(s.substring(0, frag._length), f);
+ FontMetrics fm = getFontMetrics(f);
+ frag.setHeight(fm.getHeight());
+ frag.setAscent(fm.getAscent() + fm.getLeading());
+ if (frag._length > 0
+ && Character.isWhitespace(s.charAt(frag._length - 1))) {
+ frag._isLastCharWhitespace = true;
+ } else {
+ frag._isLastCharWhitespace = false;
+ }
+ frag.setWidth(d.width);
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSFigure.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSFigure.java
new file mode 100644
index 000000000..b0a193562
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSFigure.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.IFigure;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+
+/**
+ * @author mengbo
+ */
+public interface ICSSFigure extends IFigure {
+ /**
+ * get fragments of this figure. Each item of the list will be a FlowBox.
+ * Note, this method is for read only, caller should not change the returned
+ * list and items in the returned list.
+ *
+ * @return
+ */
+ public List getFragmentsForRead();
+
+ /**
+ * get the CSSStyle of this CSS figure.
+ *
+ * @return
+ */
+ public ICSSStyle getCSSStyle();
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSLayout.java
new file mode 100644
index 000000000..1320103f3
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSLayout.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.LayoutManager;
+
+/**
+ * There are several kinds of layout involved. 1. the layout need let the child
+ * figures do certain layouting of themselves first, then decide the final
+ * result based on child information. 2. the layout could decide the size
+ * information of this figure without child information.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public interface ICSSLayout extends LayoutManager {
+ /**
+ * Each ICSSLayout is dedicated to a single CSSFigure.
+ *
+ * @return
+ */
+ public ICSSFigure getICSSFigure();
+
+ /**
+ *
+ * @return
+ */
+ // public List getFragmentsForRead();
+ /**
+ * postValidate the child figures of this CSSFigure. Normally layout fall
+ * into the first category need implement this method.
+ */
+ // public 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);
+ /**
+ * @return
+ */
+ // public boolean useLocalCoordinates();
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter.java
new file mode 100644
index 000000000..5f83cb868
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.Graphics;
+
+/**
+ * @author mengbo
+ */
+public interface ICSSPainter {
+ /**
+ * this method is called in the figure's <code>paintFigure</code> method,
+ * before <code>paintClientArea</code>. So it is called before children.
+ * Thus, children may override its effects.
+ *
+ * @param g
+ */
+ public void paintFigure(Graphics g);
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter2.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter2.java
new file mode 100644
index 000000000..f93fb8447
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/ICSSPainter2.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.Graphics;
+
+/**
+ * If the layout implements this interface, then it will have chance to paint
+ * something to override children effect.
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSPainter
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSFigure
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public interface ICSSPainter2 {
+ /**
+ * this method is called after <code>paintClientArea</code>. So it is
+ * called after children. Thus, it could override some children effects.
+ *
+ * @param g
+ */
+ public void paintFigurePostClientArea(Graphics g);
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/LineBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/LineBox.java
new file mode 100644
index 000000000..5ab842f2f
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/LineBox.java
@@ -0,0 +1,414 @@
+/*******************************************************************************
+ * 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 org.eclipse.jst.pagedesigner.css2.property.VerticalAlignMeta;
+import org.eclipse.jst.pagedesigner.css2.value.Length;
+import org.eclipse.swt.graphics.FontMetrics;
+
+/**
+ * A composite box representing a single line. LineBox calculates its ascent and
+ * descent from the child boxes it contains. Clients can call
+ * {@link #getAscent()}or {@link#getHeight()}at any time and expect valid
+ * values. The child boxes that are added to a line have unspecied locations
+ * until {@link #commit()}is called, at which time the child boxes are layed
+ * out in left-to-right order, and their baselines are all aligned vertically.
+ *
+ */
+public class LineBox extends CompositeBox {
+ private final static int BASELINE = 0;
+
+ private final static int MIDDLE = 1;
+
+ private final static int SUB = 2;
+
+ private final static int SUPER = 3;
+
+ private final static int TEXT_TOP = 4;
+
+ private final static int TEXT_BOTTOM = 5;
+
+ private final static int TOP = 6;
+
+ private final static int BOTTOM = 7;
+
+ private final static int LENGTH = 8;
+
+ private int _ascent = 0;
+
+ private int _descent = 0;
+
+ private int _fontAscent = 0;
+
+ private int _fontDescent = 0;
+
+ private int _fontLeading = 0;
+
+ private Object _horizonalData = null;
+
+ private Object _htmlInitData = null;
+
+ private int _accumlatedWidth = 0;
+
+ /**
+ * Removes all owned fragments and invalidates this CompositeBox.
+ */
+ public void clear() {
+ super.clear();
+ _horizonalData = null;
+ _htmlInitData = null;
+ }
+
+ /**
+ * Committing a LineBox will position its children correctly. All children
+ * boxes are made to have the same baseline, and are layed out from
+ * left-to-right.
+ */
+ public void commit() {
+ int baseline = getBaseline();
+ int xLocation = _x;
+ for (int i = 0; i < _fragments.size(); i++) {
+ FlowBox block = (FlowBox) _fragments.get(i);
+ block._x = xLocation + block._marginInsets.left;
+ xLocation = block._x + block._width + block._marginInsets.right;
+
+ if (_fragments.size() > 1 && block instanceof TextFragmentBox) {
+ TextFragmentBox textBox = (TextFragmentBox) block;
+ if (textBox.getTextData().length() == 0) {
+ textBox._height = _fontAscent + _fontDescent + _fontLeading;
+ textBox.setAscent(_fontAscent + _fontLeading);
+ block._y = this._y;
+ continue;
+ }
+ }
+
+ switch (getVerticalAlignType(block)) {
+ case TOP:
+ block._y = this._y;
+ break;
+ case BOTTOM:
+ block._y = this.getBaseline() - (block.getHeight() - _descent);
+ break;
+ case MIDDLE:
+ int halfXHeight = getHalfXHeight();
+ block._y = this.getBaseline() - halfXHeight
+ - (block.getHeight() + 1) / 2;
+ break;
+ case TEXT_TOP:
+ block._y = this.getBaseline() - _fontAscent - _fontLeading;
+ break;
+ case TEXT_BOTTOM:
+ block._y = this.getBaseline() - (block._height - _fontDescent);
+ break;
+ case LENGTH:
+ block._y = this.getBaseline() + getIncrement(block);
+ break;
+ case SUPER:
+ block._y = this.getBaseline() - getHalfXHeight() * 2
+ - block._height;
+ break;
+ case SUB:
+ block._y = this.getBaseline() - block._height * _fontLeading
+ / getFontHeight();
+ break;
+ case BASELINE:
+ default:
+ block.makeBaseline(baseline);
+ break;
+ }
+ if (block instanceof LineBox) {
+ ((LineBox) block).commit();
+ }
+ }
+ }
+
+ protected int getVerticalAlignType(FlowBox box) {
+ Object data = box.getVerticalAlignData();
+
+ if (data != null) {
+ if (data instanceof Length) {
+ return LENGTH;
+ } else if (VerticalAlignMeta.BASELINE.equals(data)) {
+ return BASELINE;
+ } else if (VerticalAlignMeta.MIDDLE.equals(data)) {
+ return MIDDLE;
+ } else if (VerticalAlignMeta.SUB.equals(data)) {
+ return SUB;
+ } else if (VerticalAlignMeta.SUPER.equals(data)) {
+ return SUPER;
+ } else if (VerticalAlignMeta.TEXT_TOP.equals(data)) {
+ return TEXT_TOP;
+ } else if (VerticalAlignMeta.TEXT_BOTTOM.equals(data)) {
+ return TEXT_BOTTOM;
+ } else if (VerticalAlignMeta.TOP.equals(data)) {
+ return TOP;
+ } else if (VerticalAlignMeta.BOTTOM.equals(data)) {
+ return BOTTOM;
+ }
+ return BASELINE;
+ }
+ return BASELINE;
+ }
+
+ /**
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowBox#getAscent()
+ */
+ public int getAscent() {
+ // because at initial, ascent is 0. And the linebox
+ // could have some size setting without children. In
+ // that case, we need handle differently.
+ if (_ascent == 0 && _fragments.isEmpty()) {
+ return getHeight();
+ }
+ return _ascent;
+ }
+
+ /**
+ * Returns the width available to child fragments.
+ *
+ * @return the width in pixels
+ */
+ public int getAvailableWidth() {
+ if (_recommendedWidth < 0) {
+ return Integer.MAX_VALUE;
+ }
+ int availableWidth = _recommendedWidth - _accumlatedWidth;
+ if (availableWidth < 0) {
+ availableWidth = 0;
+ }
+ return availableWidth;
+ }
+
+ /**
+ * Returns the baseline of this LineBox, which is the y value plus the
+ * ascent.
+ *
+ * @return the baseline value.
+ */
+ public int getBaseline() {
+ return _y + getAscent();
+ }
+
+ /**
+ * @see CompositeBox#resetInfo()
+ */
+ protected void resetInfo() {
+ super.resetInfo();
+ _accumlatedWidth = 0;
+ _ascent = 0;
+ }
+
+ /**
+ * @see CompositeBox#unionInfo(FlowBox)
+ */
+ protected void unionInfo(FlowBox blockInfo) {
+ if (blockInfo instanceof TextFragmentBox) {
+ if (((TextFragmentBox) blockInfo).getTextData().length() == 0) {
+ return;
+ }
+ }
+
+ if (_fragments == null || _fragments.isEmpty()) {
+ this._ascent = 0;
+ this._descent = 0;
+ this._height = 0;
+ }
+
+ int valign = getVerticalAlignType(blockInfo);
+
+ if (valign == BASELINE) {
+ _ascent = Math.max(_ascent, blockInfo.getAscent());
+ if (blockInfo instanceof WidgetBox) {
+ _descent = 0;
+ } else {
+ _descent = Math.max(_descent, blockInfo.getDescent());
+ }
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == MIDDLE) {
+ int halfXHeight = getHalfXHeight();
+ _ascent = Math.max(_ascent, (blockInfo.getHeight() + 1) / 2
+ + halfXHeight);
+ _descent = Math.max(_descent, blockInfo.getHeight() / 2
+ - halfXHeight);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == TEXT_TOP) {
+ _ascent = Math.max(_ascent, _fontAscent + _fontLeading);
+ _descent = Math.max(_descent, blockInfo.getHeight() - _fontAscent
+ - _fontLeading);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == TEXT_BOTTOM) {
+ _ascent = Math.max(_ascent, blockInfo.getHeight() - _fontDescent);
+ _descent = Math.max(_descent, _fontDescent);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == SUB) {
+ int blockTop = blockInfo._height * _fontLeading / getFontHeight();
+ _ascent = Math.max(_ascent, blockTop);
+ _descent = Math.max(_descent, blockInfo.getHeight() - blockTop);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == SUPER) {
+ int blockTop = blockInfo._height;
+ _ascent = Math.max(_ascent, getHalfXHeight() * 2 + blockTop);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == LENGTH) {
+ int increment = getIncrement(blockInfo);
+ _ascent = Math.max(_ascent, blockInfo.getAscent() + increment);
+ _descent = Math.max(_descent, blockInfo.getDescent() - increment);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == TOP) {
+ _descent = Math.max(_descent, blockInfo.getHeight() - _ascent);
+ _height = Math.max(_height, _ascent + _descent);
+ } else if (valign == BOTTOM) {
+ // XXX:the render of IE is not consistent with spec, mozilla is. so
+ // we follow mozilla's implementation.
+ _ascent = Math.max(_ascent, blockInfo.getHeight() - _descent);
+ _height = Math.max(_height, _ascent + _descent);
+ } else {
+ _ascent = Math.max(_ascent, blockInfo.getAscent());
+ _descent = Math.max(_descent, blockInfo.getDescent());
+ _height = Math.max(_height, blockInfo.getHeight());
+ }
+
+ _accumlatedWidth += blockInfo._width
+ + blockInfo._marginInsets.getWidth();
+ if (_accumlatedWidth > _width) {
+ _width = _accumlatedWidth;
+ }
+ }
+
+ private int getIncrement(FlowBox blockInfo) {
+ int valign = getVerticalAlignType(blockInfo);
+ if (valign == LENGTH) {
+ int increment = 0;
+ Length length = (Length) blockInfo.getVerticalAlignData();
+ if (length.isPercentage()) {
+ increment = length.getValue() * getFontHeight() / 100;
+ } else {
+ increment = length.getValue();
+ }
+ return increment;
+ }
+ return 0;
+ }
+
+ /**
+ * @see org.eclipse.draw2d.geometry.Rectangle#isEmpty()
+ */
+ public boolean isOccupied() {
+ if (_width > 0) {
+ return true;
+ }
+
+ if (_fragments.isEmpty()) {
+ return false;
+ }
+ // int size = _fragments.size();
+ // if (size > 1)
+ // {
+ // return true;
+ // }
+ // ok, we have one segment
+ // FlowBox box = (FlowBox) _fragments.get(0);
+ // if (box instanceof TextFragmentBox)
+ // {
+ // if (((TextFragmentBox) box).getTextData().length() == 0)
+ // {
+ // // this is an empty string text box.
+ // return false;
+ // }
+ // }
+ return true;
+ }
+
+ public boolean isEmptyStringLine() {
+ // if(this.getWidth() == 0)
+ // {
+ // return true;
+ // }
+ // else
+ // {
+ // return false;
+ // }
+ if (_fragments.size() == 1) {
+ FlowBox box = (FlowBox) _fragments.get(0);
+ if (box instanceof TextFragmentBox) {
+ if (box instanceof TextFragmentBox) {
+ if (((TextFragmentBox) box).getTextData().length() == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param fontMetrics
+ */
+ public void setFontMetrics(FontMetrics fontMetrics) {
+ if (fontMetrics != null) {
+ _fontAscent = fontMetrics.getAscent();
+ _fontDescent = fontMetrics.getDescent();
+ _fontLeading = fontMetrics.getLeading();
+ // if (_fragments == null || _fragments.isEmpty())
+ // {
+ // this._ascent = _fontAscent + _fontLeading;
+ // this._descent = _fontDescent;
+ // if (this._height < this._ascent + this._descent)
+ // {
+ // this._height = this._ascent + this._descent;
+ // }
+ // }
+ } else {
+ _fontAscent = 0;
+ _fontDescent = 0;
+ _fontLeading = 0;
+ }
+ }
+
+ private int getHalfXHeight() {
+ return (_fontAscent + _fontDescent + _fontLeading) / 5;
+ }
+
+ private int getFontHeight() {
+ return _fontAscent + _fontDescent + _fontLeading;
+ }
+
+ /**
+ * @return Returns the horizonalData.
+ */
+ public Object getHorizonalData() {
+ return _horizonalData;
+ }
+
+ /**
+ * @param horizonalData
+ * The horizonalData to set.
+ */
+ public void setHorizonalData(Object horizonalData) {
+ this._horizonalData = horizonalData;
+ }
+
+ /**
+ * @return Returns the htmlInitData.
+ */
+ public Object getHtmlInitData() {
+ return _htmlInitData;
+ }
+
+ /**
+ * @param htmlInitData
+ * The htmlInitData to set.
+ */
+ public void setHtmlInitData(Object htmlInitData) {
+ this._htmlInitData = htmlInitData;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/MultiLineLabel.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/MultiLineLabel.java
new file mode 100644
index 000000000..24ed25588
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/MultiLineLabel.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.Label;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+
+public class MultiLineLabel extends Label {
+ private static String ELLIPSIS = "..."; //$NON-NLS-1$
+
+ protected void paintFigure(Graphics graphics) {
+ if (isOpaque()) {
+ graphics.fillRectangle(getBounds());
+ }
+ Rectangle bounds = getBounds();
+ graphics.translate(bounds.x, bounds.y);
+ drawText(graphics);
+ graphics.translate(-bounds.x, -bounds.y);
+ }
+
+ private void drawText(Graphics graphics) {
+ String[] strings = splitString(getText());
+ int y = 0;
+ int lineHeight = FigureUtilities.getFontMetrics(getFont()).getHeight();
+ for (int i = 0; i < strings.length; i++) {
+ graphics.drawText(getSubStringText(strings[i]), 0, y);
+ y += lineHeight;
+ }
+
+ }
+
+ private String[] splitString(String text) {
+ String[] lines = new String[1];
+ int start = 0, pos;
+ do {
+ pos = text.indexOf('\n', start);
+ if (pos == -1) {
+ lines[lines.length - 1] = text.substring(start);
+ } else {
+ boolean crlf = (pos > 0) && (text.charAt(pos - 1) == '\r');
+ lines[lines.length - 1] = text.substring(start, pos
+ - (crlf ? 1 : 0));
+ start = pos + 1;
+ String[] newLines = new String[lines.length + 1];
+ System.arraycopy(lines, 0, newLines, 0, lines.length);
+ lines = newLines;
+ }
+ } while (pos != -1);
+ return lines;
+ }
+
+ public String getSubStringText(String text) {
+ String subStringText = text;
+
+ Font currentFont = getFont();
+ int textWidth = FigureUtilities.getTextWidth(text, currentFont);
+ if (textWidth - getSize().width <= 0) {
+ return subStringText;
+ }
+
+ Dimension effectiveSize = new Dimension(getSize().width, 0);
+
+ int dotsWidth = FigureUtilities.getTextWidth(ELLIPSIS, currentFont);
+
+ if (effectiveSize.width < dotsWidth) {
+ effectiveSize.width = dotsWidth;
+ }
+
+ int subStringLength = getLargestSubstringConfinedTo(text, currentFont,
+ effectiveSize.width - dotsWidth);
+ subStringText = new String(text.substring(0, subStringLength)
+ + ELLIPSIS);
+ return subStringText;
+ }
+
+ int getLargestSubstringConfinedTo(String s, Font f, int availableWidth) {
+ FontMetrics metrics = FigureUtilities.getFontMetrics(f);
+ int min, max;
+ float avg = metrics.getAverageCharWidth();
+ min = 0;
+ max = s.length() + 1;
+
+ // The size of the current guess
+ int guess = 0, guessSize = 0;
+ while ((max - min) > 1) {
+ // Pick a new guess size
+ // New guess is the last guess plus the missing width in pixels
+ // divided by the average character size in pixels
+ guess = guess + (int) ((availableWidth - guessSize) / avg);
+
+ if (guess >= max) {
+ guess = max - 1;
+ }
+ if (guess <= min) {
+ guess = min + 1;
+ }
+
+ // Measure the current guess
+ guessSize = FigureUtilities
+ .getTextExtents(s.substring(0, guess), f).width;
+
+ if (guessSize < availableWidth) {
+ // We did not use the available width
+ min = guess;
+ } else {
+ // We exceeded the available width
+ max = guess;
+ }
+ }
+ return min;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/PageFlowLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/PageFlowLayout.java
new file mode 100644
index 000000000..54dedbfaf
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/PageFlowLayout.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * 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 org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.jst.pagedesigner.css2.font.CSSFont;
+import org.eclipse.jst.pagedesigner.css2.font.CSSFontManager;
+import org.eclipse.swt.graphics.Font;
+
+/**
+ * A block layout which requires no FlowContext to perform its layout. This
+ * class is used by {@link FlowPage}.
+ * <p>
+ * WARNING: This class is not intended to be subclassed by clients.
+ */
+public class PageFlowLayout extends BlockFlowLayout {
+
+ /**
+ * Creates a new PageFlowLayout with the given FlowPage
+ *
+ * @param page
+ * the FlowPage
+ */
+ public PageFlowLayout(FlowPage page) {
+ super(page);
+ }
+
+ /**
+ * @see BlockFlowLayout#endBlock()
+ */
+ protected void endBlock() {
+ }
+
+ /**
+ * TODO: This method is not being called.
+ */
+ public void postValidate() {
+ }
+
+ protected void setupLine(LineBox line, int topMargin) {
+ super.setupLine(line, topMargin);
+
+ CSSFontManager fontManager = CSSFontManager.getInstance();
+ Font font = fontManager.getSwtFont((CSSFont) fontManager
+ .createDefaultFont());
+ line.setFontMetrics(FigureUtilities.getFontMetrics(font));
+ }
+
+ /**
+ * Setup blockBox to the initial bounds of the Page
+ */
+ protected void setupBlock() {
+ // Remove all current Fragments
+ _blockBox.clear();
+
+ // Setup the one fragment for this Block with the correct X and
+ // available width
+ _blockBox.setRecommendedWidth(((FlowPage) getFlowFigure())
+ .getRecommendedWidth());
+ _blockBox._x = 0;
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextFragmentBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextFragmentBox.java
new file mode 100644
index 000000000..00b181da8
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextFragmentBox.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * A Geometric object for representing a TextFragment region on a line of Text.
+ */
+public class TextFragmentBox extends FlowBox {
+
+ /** The offset in pixels * */
+ public int _offset;
+
+ /** The length in pixels * */
+ public int _length;
+
+ private int _ascent;
+
+ // boolean _truncated;
+
+ public boolean _isLastCharWhitespace = false;
+
+ private String _textData;
+
+ /**
+ * Creates a new TextFragmentBox
+ */
+ public TextFragmentBox() {
+ }
+
+ /**
+ * Returns the ascent of this TextFragmentBox
+ *
+ * @return the ascent
+ */
+ public int getAscent() {
+ return _ascent;
+ }
+
+ /**
+ * Sets the ascent of this TextFragmentBox to the given value
+ *
+ * @param a
+ * the ascent
+ */
+ public void setAscent(int a) {
+ _ascent = a;
+ }
+
+ /**
+ * Sets the height of this TextFragmentBox to the given value
+ *
+ * @param h
+ * the height
+ */
+ public void setHeight(int h) {
+ _height = h;
+ }
+
+ /**
+ * Sets the width of this TextFragmentBox to the given value
+ *
+ * @param w
+ * the width
+ */
+ public void setWidth(int w) {
+ _width = w;
+ }
+
+ public String getTextData() {
+ return _textData;
+ }
+
+ public void setTextData(String txt) {
+ _textData = txt;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextLayoutSupport.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextLayoutSupport.java
new file mode 100644
index 000000000..008d7369b
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/TextLayoutSupport.java
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * 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.Graphics;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.PDPlugin;
+import org.eclipse.jst.pagedesigner.common.logging.Logger;
+import org.eclipse.jst.pagedesigner.css2.property.TextDecorationMeta;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+
+/**
+ * @author mengbo
+ */
+public class TextLayoutSupport {
+ private static final Logger _log = PDPlugin
+ .getLogger(TextLayoutSupport.class);
+
+ private static final String[] DELIMITERS = { "\r\n", //$NON-NLS-1$
+ "\n", //$NON-NLS-1$
+ "\r" //$NON-NLS-1$
+ }; //$NON-NLS-1$
+
+ static private int delimeterLength;
+
+ /**
+ * Reuses an existing <code>TextFragmentBox</code>, or creates a new one.
+ *
+ * @param i
+ * the index
+ * @param fragments
+ * the original list of fragments
+ * @return a TextFragmentBox
+ */
+ // copied from TextLayout
+ protected static TextFragmentBox getFragment(int i, List fragments) {
+ if (fragments.size() > i) {
+ return (TextFragmentBox) fragments.get(i);
+ }
+ TextFragmentBox box = new TextFragmentBox();
+ fragments.add(box);
+ return box;
+ }
+
+ /**
+ * Returns the average character width of given TextFragmentbox
+ *
+ * @param fragment
+ * the TextFragmentBox
+ * @return the average character width
+ */
+ public static float getAverageCharWidth(TextFragmentBox fragment) {
+ if (fragment._width != 0 && fragment._length != 0) {
+ return fragment._width / (float) fragment._length;
+ }
+ return 0.0f;
+ }
+
+ // ----------------------------------------------------------------------------------------
+ /**
+ * this method will create a set of TextFragment. Each fragment will offset
+ * to the original text (whole text for the text figure).
+ */
+ public static void layoutNormal(FlowContext context, String text,
+ List fragments, Font font, int wrappingStyle, boolean trimLeading) {
+ int i = 0; // The index of the current fragment;
+ int offset = 0;
+ if (trimLeading) {
+ offset = 1;
+ text = text.substring(1);
+ }
+
+ int length = 0; // The length of the current fragment
+ float prevAvgCharWidth;
+ LineBox currentLine;
+ TextFragmentBox fragment;
+
+ while (text.length() > 0) {
+ fragment = null;
+ prevAvgCharWidth = 0f;
+ fragment = getFragment(i, fragments);
+ prevAvgCharWidth = getAverageCharWidth(fragment);
+
+ // Check for newline, if it exists, call context.endLine and skip
+ // over the newline
+ // Exccept for first time through, don't do this.
+ if (i != 0) {
+ boolean changed = false;
+ if (text.charAt(0) == '\r') {
+ text = text.substring(1);
+ changed = true;
+ offset += 1;
+ }
+ if (text.length() != 0 && text.charAt(0) == '\n') {
+ text = text.substring(1);
+ changed = true;
+ offset += 1;
+ }
+ if (changed) {
+ context.endLine();
+ }
+ }
+
+ fragment._offset = offset;
+
+ // This loop is done at most twice.
+ // The second time through, a context.endLine()
+ // was requested, and the loop will break.
+ while (true) {
+ currentLine = context.getCurrentLine();
+ length = FlowUtilities.setupFragmentBasedOnTextSpace(fragment,
+ text, font, currentLine.getAvailableWidth(),
+ prevAvgCharWidth, wrappingStyle);
+
+ if (fragment._width <= currentLine.getAvailableWidth()
+ || !context.isCurrentLineOccupied()) {
+ break;
+ }
+ context.endLine();
+ }
+ // fragment.x = context.getCurrentX();
+ context.addToCurrentLine(fragment);
+ text = text.substring(length);
+ offset += length;
+ if (text.length() > 0) {
+ context.endLine();
+ }
+ i++;
+ }
+
+ // Remove the remaining unused fragments.
+ while (i < fragments.size()) {
+ fragments.remove(fragments.size() - 1);
+ }
+ }
+
+ public static void layoutNoWrap(FlowContext context, String text,
+ List fragments, Font font) {
+ TextFragmentBox fragment;
+ int i = 0;
+ int offset = 0;
+
+ while (offset < text.length()) {
+ int result = nextLineBreak(text, offset);
+ fragment = getFragment(i++, fragments);
+ fragment._length = result - offset;
+ fragment._offset = offset;
+ FlowUtilities.setupFragment(fragment, font, text.substring(offset));
+ context.getCurrentLine().add(fragment);
+ offset = result + delimeterLength;
+ if (delimeterLength != 0) {
+ // in nextLineBreak we fo
+ context.endLine();
+ }
+
+ }
+ // Remove the remaining unused fragments.
+ while (i < fragments.size()) {
+ fragments.remove(i++);
+ }
+ }
+
+ private static int nextLineBreak(String text, int offset) {
+ int result = text.length();
+ delimeterLength = 0;
+ int current;
+ for (int i = 0; i < DELIMITERS.length; i++) {
+ current = text.indexOf(DELIMITERS[i], offset);
+ if (current != -1 && current < result) {
+ result = current;
+ delimeterLength = DELIMITERS[i].length();
+ }
+ }
+ return result;
+ }
+
+ public static void paintTextFigure(Graphics g, List fragments, Font font,
+ int textDecoration) {
+ paintTextFigure(g, fragments, font, null, textDecoration);
+ }
+
+ public static void paintTextDecoration(Graphics g, Rectangle rect,
+ int textDecoration) {
+ if ((textDecoration & TextDecorationMeta.UNDERLINE) != 0) {
+ g.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width
+ - 1, rect.y + rect.height - 1);
+ }
+ if ((textDecoration & TextDecorationMeta.OVERLINE) != 0) {
+ g.drawLine(rect.x, rect.y + 1, rect.x + rect.width - 1, rect.y + 1);
+ }
+ if ((textDecoration & TextDecorationMeta.LINETHROUGH) != 0) {
+ g.drawLine(rect.x, rect.y + rect.height / 2, rect.x + rect.width
+ - 1, rect.y + rect.height / 2);
+ }
+ }
+
+ public static void paintTextFigure(Graphics g, List fragments, Font font,
+ Color color, int textDecoration) {
+ // FIXME: It happens there is problem in this method's parameters. what
+ // exception should be catched?
+ try {
+ TextFragmentBox frag;
+ // XXX: adjust font. Here is not using setFont(), because that will
+ // result in revalidate
+ g.setFont(font);
+
+ for (int i = 0; i < fragments.size(); i++) {
+ frag = (TextFragmentBox) fragments.get(i);
+ // if (!g.getClip(Rectangle.SINGLETON).intersects(frag))
+ // continue;
+ String draw;
+ draw = frag.getTextData();
+
+ if (color != null) {
+ g.setForegroundColor(color);
+ }
+ g.drawText(draw, frag._x, frag._y);
+ if ((textDecoration & TextDecorationMeta.UNDERLINE) != 0) {
+ g.drawLine(frag._x, frag._y + frag.getHeight() - 1, frag._x
+ + frag.getWidth(), frag._y + frag.getHeight() - 1);
+ }
+ if ((textDecoration & TextDecorationMeta.OVERLINE) != 0) {
+ g.drawLine(frag._x, frag._y, frag._x + frag.getWidth(),
+ frag._y);
+ }
+ if ((textDecoration & TextDecorationMeta.LINETHROUGH) != 0) {
+ g.drawLine(frag._x, frag._y + frag.getHeight() / 2, frag._x
+ + frag.getWidth(), frag._y + frag.getHeight() / 2);
+ }
+
+ if (Debug.DEBUG_BASELINE) {
+ g.drawLine(frag._x, frag._y + frag.getAscent(), frag._x
+ + frag.getWidth(), frag._y + frag.getAscent());
+ }
+ }
+ } catch (Exception e) {
+ // "Error in text painting:"
+ _log.info("TextLayoutSupport.Info.1", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ *
+ * @param g
+ * @param fragments
+ * @param text
+ * all the text in the Text figure.
+ * @param font
+ * @param color
+ * @param textDecoration
+ * @param start
+ * @param end
+ * @param selectionForeColor
+ * @param selectionBackColor
+ */
+ public static void paintTextFigureWithSelection(Graphics g, List fragments,
+ String text, Font font, Color color, int textDecoration, int start,
+ int end, Color selectionForeColor, Color selectionBackColor) {
+ // FIXME: It happens there is problem in this method's parameters. what
+ // exception should be catched?
+ try {
+ TextFragmentBox frag;
+
+ Color originalForeground = g.getForegroundColor();
+ Color originalBackgroud = g.getBackgroundColor();
+
+ // XXX: adjust font. Here is not using setFont(), because that will
+ // result in revalidate
+ g.setFont(font);
+
+ for (int i = 0, n = fragments.size(); i < n; i++) {
+ frag = (TextFragmentBox) fragments.get(i);
+
+ // to make things simpler, we always draw the line using default
+ // color
+ if (color != null) {
+ g.setForegroundColor(color);
+ }
+
+ // if (!g.getClip(Rectangle.SINGLETON).intersects(frag))
+ // continue;
+ String draw;
+ draw = frag.getTextData();
+ if (frag._offset >= end || frag._offset + frag._length <= start) {
+ // we are not in selection. no need to change color
+ g.drawText(draw, frag._x, frag._y);
+ paintTextDecoration(g, frag.getRectangle(), textDecoration);
+ } else if (frag._offset >= start
+ && frag._offset + frag._length <= end) {
+ // we are fully in selection
+ g.setForegroundColor(selectionForeColor);
+ g.setBackgroundColor(selectionBackColor);
+ g
+ .fillRectangle(frag._x, frag._y, FlowUtilities
+ .getTextExtents(draw, font).width, frag
+ .getHeight());
+ g.drawText(draw, frag._x, frag._y);
+ paintTextDecoration(g, frag.getRectangle(), textDecoration);
+ } else {
+ // partial of the fragment's text is in selection.
+
+ // draw the original string first
+ g.drawText(draw, frag._x, frag._y);
+ // then override with the selected parts.
+ g.setForegroundColor(selectionForeColor);
+ g.setBackgroundColor(selectionBackColor);
+ int partialStart = frag._offset > start ? frag._offset
+ : start;
+ int partialEnd = (frag._offset + frag._length > end) ? end
+ : (frag._offset + frag._length);
+ int x = 0;
+ String skip = text.substring(frag._offset, partialStart);
+ x = FlowUtilities.getTextExtents(skip, font).width;
+ String todraw = text.substring(partialStart, partialEnd);
+ if (todraw.length() > 0) {
+ Dimension dimension = FlowUtilities.getTextExtents(skip
+ + todraw, font);
+ g.fillRectangle(frag._x + x, frag._y, dimension.width
+ - x, dimension.height);
+ g.drawText(skip + todraw, frag._x, frag._y);
+ if (color != null) {
+ g.setForegroundColor(color);
+ } else {
+ g.setForegroundColor(originalForeground);
+ }
+ g.drawText(skip, frag._x, frag._y);
+ paintTextDecoration(g, frag.getRectangle(),
+ textDecoration);
+ g.setForegroundColor(selectionForeColor);
+ paintTextDecoration(g,
+ new Rectangle(frag._x + x, frag._y,
+ dimension.width - x, dimension.height),
+ textDecoration);
+ }
+ }
+
+ // we do this in each loop, to make sure we are using correct
+ // color
+ g.setForegroundColor(originalForeground);
+ g.setBackgroundColor(originalBackgroud);
+
+ }
+ } catch (Exception e) {
+ // "Error in text painting:"
+ _log.info("TextLayoutSupport.Info.1", e); //$NON-NLS-1$
+ }
+ }
+
+ public static int getBeginX(Object textAlign, Rectangle rect, int textWidth) {
+ int x = rect.x;
+ if (textAlign != null) {
+ String align = textAlign.toString();
+ if ("left".equalsIgnoreCase(align)) //$NON-NLS-1$
+ {
+ x = rect.x + 1;
+ } else if ("right".equalsIgnoreCase(align)) //$NON-NLS-1$
+ {
+ x = rect.x + rect.width - textWidth - 1;
+ if (x < 1) {
+ x = 1;
+ }
+ } else if ("center".equalsIgnoreCase(align)) //$NON-NLS-1$
+ {
+ int offset = (rect.width - textWidth) / 2;
+ if (offset <= 0) {
+ offset = 0;
+ }
+ x = x + offset + 1;
+ }
+ }
+ return x;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/WidgetBox.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/WidgetBox.java
new file mode 100644
index 000000000..7143e83d2
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/WidgetBox.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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;
+
+/**
+ * Simple box support ascent.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class WidgetBox extends FlowBox {
+ private int _ascent = -1;
+
+ public int getAscent() {
+ if (_ascent < 0) {
+ return super.getAscent();
+ } else {
+ return _ascent;
+ }
+ }
+
+ public void setAscent(int ascent) {
+ _ascent = ascent;
+ }
+
+ /**
+ * @return
+ */
+ public boolean supportAscent() {
+ return _ascent > 0;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRGroupLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRGroupLayout.java
new file mode 100644
index 000000000..814c7026a
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRGroupLayout.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.FlowFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSTRGroupLayout extends CSSBlockFlowLayout {
+
+ /**
+ * @param cssfigure
+ */
+ public CSSTRGroupLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /**
+ * the parent figure of TRGroup should be table figure. If so, return the
+ * corresponding table layout.
+ *
+ * @return
+ */
+ public CSSTableLayout2 getTableLayoutContext() {
+ IFigure parent = getCSSFigure().getParent();
+ if (parent != null) {
+ LayoutManager parentLayout = parent.getLayoutManager();
+ if (parentLayout instanceof CSSTableLayout2) {
+ return (CSSTableLayout2) parentLayout;
+ }
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#postValidate()
+ */
+ public void postValidate() {
+ CSSTableLayout2 tableLayout = getTableLayoutContext();
+ if (tableLayout == null) {
+ super.postValidate();
+ } else {
+ Rectangle r = getTRGroupRect(tableLayout);
+ if (r != null) {
+ _blockBox.setXYWidthHeight(r);
+ getCSSFigure().setBounds(r);
+ List list = getCSSFigure().getChildren();
+ for (int i = 0; i < list.size(); i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ } else {
+ super.postValidate();
+ }
+ }
+ }
+
+ /**
+ * @return
+ */
+ private Rectangle getTRGroupRect(CSSTableLayout2 tableLayout) {
+ TableRowGroupInfo groupinfo = tableLayout.getGroupInfo(this
+ .getCSSFigure());
+ int rowIndex = groupinfo.getRowIndex();
+ int rowCount = groupinfo.getRowCount();
+ int y = (rowIndex + 1) * tableLayout.getVSpacing();
+ for (int k = 0; k < rowIndex; k++) {
+ y += tableLayout.getRowHeights()[k];
+ }
+ if (tableLayout.getCaptionInfo() != null
+ && "top".equalsIgnoreCase(tableLayout.getCaptionInfo().getAlign())) //$NON-NLS-1$
+ {
+ y += tableLayout.getCaptionSize().height;
+ }
+
+ int height = (rowCount - 1) * tableLayout.getVSpacing();
+ for (int k = 0; k < rowCount; k++) {
+ height += tableLayout.getRowHeights()[rowIndex + k];
+ }
+ ICSSFigure figure = groupinfo.getFigure();
+ return new Rectangle(tableLayout.getRowX(), y, tableLayout
+ .getRowWidth(), height);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#useLocalCoordinates()
+ */
+ public boolean useLocalCoordinates() {
+ // if is in table, we don't use local coordinates.
+ return getTableLayoutContext() == null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#endBlock()
+ */
+ protected void endBlock() {
+ if (getTableLayoutContext() == null) {
+ super.endBlock();
+ } else {
+ layoutLines();
+ }
+ }
+
+ // /* (non-Javadoc)
+ // * @see
+ // org.eclipse.jst.pagedesigner.css2.layout.FlowContainerLayout#layout()
+ // */
+ // protected void layout()
+ // {
+ // CSSTableLayout2 tableLayout = getTableLayoutContext();
+ // if (tableLayout == null)
+ // {
+ // // we are not in table? treat as block.
+ // super.layout();
+ // }
+ // else
+ // {
+ // // ok, we are in table. we need to layout our children.
+ // TableRowGroupInfo groupInfo =
+ // tableLayout.getGroupInfo(this.getCSSFigure());
+ // int[] rowHeights = tableLayout.getRowHeights();
+ // int vspacing = tableLayout.getVSpacing();
+ // int rowwidth = getCSSFigure().getBounds().width;// XXX: get from table
+ // layout?
+ // int grouprowindex = groupInfo.getRowIndex();
+ // List rows = groupInfo.getRowList();
+ // for (int i=0, size=rows.size(); i<size; i++)
+ // {
+ // TableRowInfo rowinfo = (TableRowInfo) rows.get(i);
+ // ICSSFigure figure = rowinfo.getFigure();
+ //
+ // int y = 0;
+ // int rowindex = rowinfo.getRowIndex();
+ // for (int row=grouprowindex; row<rowindex; row++)
+ // {
+ // y += rowHeights[row];
+ // y += vspacing;
+ // }
+ // int height = rowHeights[rowindex];
+ // Rectangle rect = new Rectangle(0, y, rowwidth, height);
+ // figure.setBounds(rect);
+ // }
+ // }
+ // }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#handlingBorderForBlock()
+ */
+ public boolean handlingBorderForBlock() {
+ return false;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRLayout.java
new file mode 100644
index 000000000..d29fdfcf4
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTRLayout.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.FlowFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSTRLayout extends CSSBlockFlowLayout {
+ /**
+ * @param cssfigure
+ */
+ public CSSTRLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /**
+ * the parent figure of TRGroup should be table figure. If so, return the
+ * corresponding table layout.
+ *
+ * @return
+ */
+ public CSSTableLayout2 getTableLayoutContext() {
+ IFigure parent = getCSSFigure().getParent();
+ if (parent != null) {
+ LayoutManager parentLayout = parent.getLayoutManager();
+ if (parentLayout instanceof CSSTableLayout2) {
+ return (CSSTableLayout2) parentLayout;
+ } else if (parentLayout instanceof CSSTRGroupLayout) {
+ return ((CSSTRGroupLayout) parentLayout)
+ .getTableLayoutContext();
+ }
+ }
+
+ return null;
+ }
+
+ public CSSTRGroupLayout getTRGroupLayout() {
+ IFigure parent = getCSSFigure().getParent();
+ if (parent != null) {
+ LayoutManager parentLayout = parent.getLayoutManager();
+ if (parentLayout instanceof CSSTRGroupLayout) {
+ return ((CSSTRGroupLayout) parentLayout);
+ }
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#postValidate()
+ */
+ public void postValidate() {
+ CSSTableLayout2 tableLayout = getTableLayoutContext();
+ if (tableLayout == null) {
+ // we are not in table? treat as block.
+ super.postValidate();
+ } else {
+ Rectangle r = getTRRect(tableLayout, getTRGroupLayout());
+ if (r != null) {
+ _blockBox.setXYWidthHeight(r);
+ getCSSFigure().setBounds(r);
+ List list = getCSSFigure().getChildren();
+ for (int i = 0; i < list.size(); i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ } else {
+ super.postValidate();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#endBlock()
+ */
+ protected void endBlock() {
+ if (this.getTableLayoutContext() == null) {
+ super.endBlock();
+ } else {
+ layoutLines();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#useLocalCoordinates()
+ */
+ public boolean useLocalCoordinates() {
+ return this.getTableLayoutContext() == null;
+ }
+
+ private Rectangle getTRRect(CSSTableLayout2 tableLayout,
+ CSSTRGroupLayout groupLayout) {
+ TableRowInfo rowinfo = tableLayout.getRowInfo(this.getCSSFigure());
+ int rowIndex = rowinfo.getRowIndex();
+ int y = (rowIndex + 1) * tableLayout.getVSpacing();
+ for (int k = 0; k < rowIndex; k++) {
+ y += tableLayout.getRowHeights()[k];
+ }
+ if (tableLayout.getCaptionInfo() != null
+ && "top".equalsIgnoreCase(tableLayout.getCaptionInfo().getAlign())) //$NON-NLS-1$
+ {
+ y += tableLayout.getCaptionSize().height;
+ }
+
+ int height = tableLayout.getRowHeights()[rowIndex];
+ ICSSFigure figure = rowinfo.getFigure();
+ return new Rectangle(tableLayout.getRowX(), y, tableLayout
+ .getRowWidth(), height);
+ }
+
+ /**
+ * @param tableLayout
+ * @param groupLayout
+ * @return
+ */
+ // private Rectangle getTRRect(CSSTableLayout2 tableLayout, CSSTRGroupLayout
+ // groupLayout)
+ // {
+ // TableRowGroupInfo groupInfo = null;
+ // if (groupLayout != null)
+ // {
+ // groupInfo = tableLayout.getGroupInfo(groupLayout.getCSSFigure());
+ // }
+ // if (groupInfo != null)
+ // {
+ // // This TR is in tr group
+ // int[] rowHeights = tableLayout.getRowHeights();
+ // int vspacing = tableLayout.getVSpacing();
+ // int rowwidth = tableLayout.getRowWidth();
+ // int grouprowindex = groupInfo.getRowIndex();
+ // TableRowInfo rowinfo = tableLayout.getRowInfo(this.getCSSFigure());
+ // ICSSFigure figure = rowinfo.getFigure();
+ //
+ // int y = 0;
+ // int rowindex = rowinfo.getRowIndex();
+ // for (int row = grouprowindex; row < rowindex; row++)
+ // {
+ // y += rowHeights[row];
+ // y += vspacing;
+ // }
+ // int height = rowHeights[rowindex];
+ // Rectangle rect = new Rectangle(0, y, rowwidth, height);
+ // return rect;
+ // }
+ // else
+ // {
+ // TableRowInfo rowinfo = tableLayout.getRowInfo(this.getCSSFigure());
+ // int rowIndex = rowinfo.getRowIndex();
+ // int y = (rowIndex+1) * tableLayout.getVSpacing();
+ // int rowHeights[] = tableLayout.getRowHeights();
+ // for (int k=0; k<rowIndex; k++)
+ // {
+ // y += rowHeights[k];
+ // }
+ // int height = rowHeights[rowIndex];
+ // return new Rectangle(tableLayout.getRowX(), y, tableLayout.getRowWidth(),
+ // height);
+ // }
+ // }
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#handlingBorderForBlock()
+ */
+ public boolean handlingBorderForBlock() {
+ return false;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCaptionLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCaptionLayout.java
new file mode 100644
index 000000000..27d15717c
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCaptionLayout.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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.table;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSTableCaptionLayout extends CachedTableCellLayout {
+ private CSSTableLayout2 _tableLayout;
+
+ private TableCaptionInfo _caption;
+
+ /**
+ * @param cssfigure
+ */
+ public CSSTableCaptionLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#invalidate()
+ */
+ public void invalidate() {
+ super.invalidate();
+
+ _tableLayout = null;
+ _caption = null;
+ }
+
+ public Rectangle getCellRect() {
+ int x = 0;
+
+ int[] rowHeights = _tableLayout.getRowHeights();
+ int vspacing = _tableLayout.getVSpacing();
+ int y = vspacing;
+ if (_caption != null && "bottom".equalsIgnoreCase(_caption.getAlign())) //$NON-NLS-1$
+ {
+ for (int row = 0; row < rowHeights.length; row++) {
+ y += rowHeights[row];
+ y += vspacing;
+ }
+ }
+
+ int height = 0;
+ height = _tableLayout.getCaptionSize().height;
+ int width = _tableLayout.getCaptionSize().width;
+ Rectangle rect = new Rectangle(x, y, width, height);
+ return rect;
+ }
+
+ /**
+ * the parent figure of TRGroup should be table figure. If so, return the
+ * corresponding table layout.
+ *
+ * @return
+ */
+ public CSSTableLayout2 getTableLayoutContext() {
+ IFigure parent = getCSSFigure().getParent();
+ if (parent != null) {
+ LayoutManager parentLayout = parent.getLayoutManager();
+ if (parentLayout instanceof CSSTableLayout2) {
+ return (CSSTableLayout2) parentLayout;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return
+ */
+ public boolean initializeTableInfo() {
+ _caption = null;
+ _tableLayout = getTableLayoutContext();
+ if (_tableLayout != null) {
+ _caption = _tableLayout.getCaptionInfo();
+ return _caption != null;
+ }
+ return false;
+ }
+
+ public CSSTableLayout2 getTableLayout() {
+ return _tableLayout;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#isCalculatingMaxWidth()
+ */
+ public boolean isCalculatingMaxWidth() {
+ return false;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCellLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCellLayout.java
new file mode 100644
index 000000000..f09529ef0
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableCellLayout.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.FlowBox;
+import org.eclipse.jst.pagedesigner.css2.layout.LineBox;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.property.VerticalAlignMeta;
+
+/**
+ * This layout is for those thigns that it's parent will decide its size. Such
+ * as table cell.
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSTableCellLayout extends CachedTableCellLayout {
+ private CSSTableLayout2 _tableLayout;
+
+ private TableRowInfo _rowinfo;
+
+ private TableCellInfo _cellinfo;
+
+ /**
+ * @param cssfigure
+ */
+ public CSSTableCellLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#invalidate()
+ */
+ public void invalidate() {
+ super.invalidate();
+
+ _tableLayout = null;
+ _rowinfo = null;
+ _cellinfo = null;
+ }
+
+ protected void endBlock() {
+ if (isTable()) {
+ verticalLayoutLines();
+ layoutLines();
+ } else {
+ super.endBlock();
+ }
+ }
+
+ protected void verticalLayoutLines() {
+ List lines = _blockBox.getFragments();
+
+ String verticalStyle = getVerticalAlign();
+ int linesHeight = 0;
+
+ if (lines != null && !lines.isEmpty()) {
+ FlowBox bottomBox = ((FlowBox) lines.get(lines.size() - 1));
+ FlowBox topBox = ((FlowBox) lines.get(0));
+ linesHeight = bottomBox._y + bottomBox.getHeight() - topBox._y;
+ }
+ int movement = 0;
+ if (VerticalAlignMeta.BOTTOM.equals(verticalStyle)) {
+ movement = _blockBox.getHeight() - linesHeight
+ - _blockBox.getBorderPaddingHeight() / 2;
+ } else if (VerticalAlignMeta.TOP.equals(verticalStyle)) {
+ movement = 0;
+ }
+ // else if (VerticalAlignMeta.BASELINE.equals(verticalStyle))
+ // {
+ // movement = _blockBox.getHeight() - linesHeight;
+ // }
+ else // if (VerticalAlignMeta.MIDDLE.equals(verticalStyle))
+ {
+ movement = (_blockBox.getHeight() - linesHeight - _blockBox
+ .getBorderPaddingHeight()) / 2;
+ }
+ // VerticalAlignMeta.TOP, ICSSPropertyID.VAL_AUTO and others
+ // else
+ // {
+ // movement = 0;
+ // }
+ if (lines != null) {
+ for (int i = 0, n = lines.size(); i < n; i++) {
+ if (lines.get(i) instanceof LineBox) {
+ LineBox lineBox = (LineBox) lines.get(i);
+ int LineMovement = Math.max(lineBox._marginInsets
+ .getHeight(), movement);
+ lineBox._y = lineBox._y + LineMovement
+ - lineBox._marginInsets.getHeight();
+ }
+ }
+ }
+ }
+
+ private String getVerticalAlign() {
+ ICSSStyle style = getCSSStyle();
+ if (style != null) {
+ return style.getStyleProperty(ICSSPropertyID.ATTR_VERTICAL_ALIGN)
+ .toString();
+ }
+ return VerticalAlignMeta.MIDDLE;
+ }
+
+ public Rectangle getCellRect() {
+ int columnIndex = _cellinfo.getColumnIndex();
+ int rowIndex = _cellinfo.getRowIndex();
+ int[] columnWidths = _tableLayout.getColumnWidths();
+ int hspacing = _tableLayout.getHSpacing();
+ int x = hspacing;
+ for (int col = 0; col < columnIndex; col++) {
+ x += columnWidths[col];
+ x += hspacing;
+ }
+
+ int[] rowHeights = _tableLayout.getRowHeights();
+ int vspacing = _tableLayout.getVSpacing();
+ int y = vspacing;
+ for (int row = 0; row < rowIndex; row++) {
+ y += rowHeights[row];
+ y += vspacing;
+ }
+ if (_tableLayout.getCaptionInfo() != null
+ && "top".equalsIgnoreCase(_tableLayout.getCaptionInfo().getAlign())) //$NON-NLS-1$
+ {
+ y += _tableLayout.getCaptionSize().height;
+ }
+
+ int width = _tableLayout.getCellWidth(_cellinfo, columnWidths);
+ int height = _tableLayout.getCellHeight(_cellinfo, rowHeights);
+
+ Rectangle rect = new Rectangle(x, y, width, height);
+ return rect;
+ }
+
+ /**
+ * the parent figure of TRGroup should be table figure. If so, return the
+ * corresponding table layout.
+ *
+ * @return
+ */
+ public CSSTableLayout2 getTableLayoutContext() {
+ IFigure parent = getCSSFigure().getParent();
+ if (parent != null) {
+ LayoutManager parentLayout = parent.getLayoutManager();
+ if (parentLayout instanceof CSSTRLayout) {
+ return ((CSSTRLayout) parentLayout).getTableLayoutContext();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return
+ */
+ public boolean initializeTableInfo() {
+ _rowinfo = null;
+ _cellinfo = null;
+ _tableLayout = getTableLayoutContext();
+ if (_tableLayout != null) {
+ _rowinfo = _tableLayout.getRowInfo((CSSFigure) this.getCSSFigure()
+ .getParent());
+ if (_rowinfo != null) {
+ _cellinfo = _rowinfo.getCellInfo(this.getCSSFigure());
+ if (_cellinfo != null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public CSSTableLayout2 getTableLayout() {
+ return _tableLayout;
+ }
+
+ public TableCellInfo getTableCellInfo() {
+ return _cellinfo;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableLayout2.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableLayout2.java
new file mode 100644
index 000000000..5acdfb1af
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CSSTableLayout2.java
@@ -0,0 +1,628 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.PDPlugin;
+import org.eclipse.jst.pagedesigner.common.logging.Logger;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSPainter;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.style.ITagEditInfo;
+import org.eclipse.swt.SWT;
+
+/**
+ * @see http://www.w3.org/TR/REC-CSS2/tables.html
+ *
+ * @author mengbo
+ * @version 1.5
+ */
+public class CSSTableLayout2 extends CSSBlockFlowLayout implements ICSSPainter {
+ static Logger _log = PDPlugin.getLogger(CSSTableLayout2.class);
+
+ int _hspacing;
+
+ int _vspacing;
+
+ int[] _columnWidths;
+
+ int[] _rowHeights;
+
+ Dimension _captionSize;
+
+ // _tableInfo will be initialized in preLayout
+ TableInfo _tableInfo;
+
+ private int _internalTableWidth;
+
+ private int _internalTableHeight;
+
+ private int _rowx;
+
+ private int _rowwidth;
+
+ /**
+ * @param flowfigure
+ */
+ public CSSTableLayout2(CSSFigure flowfigure) {
+ super(flowfigure);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#preLayout()
+ */
+ protected void preLayout() {
+ // super.preLayout will setup the block box.
+ super.preLayout();
+
+ ICSSStyle style = this.getCSSStyle();
+
+ _hspacing = _vspacing = 3; // default value
+
+ if (style != null) {
+ Object borderspacing = style
+ .getStyleProperty(ICSSPropertyID.ATTR_BORDER_SPACING);
+ if (borderspacing instanceof int[]) {
+ int[] intvalues = (int[]) borderspacing;
+ _hspacing = intvalues[0];
+ _vspacing = intvalues[1];
+ } else {
+ ITagEditInfo info = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (info != null && info.needTableDecorator()) {
+ // default decorating value. to make things look more
+ // separated.
+ if (_hspacing < 5) {
+ _hspacing = 5;
+ }
+ if (_vspacing < 5) {
+ _vspacing = 5;
+ }
+ }
+ }
+ }
+
+ // TODO: support caption
+ _tableInfo = new TableInfo(getCSSFigure());
+
+ // construct the table structure.
+ _tableInfo.constructTable();
+
+ // calculate the user specified width/height for table and cells.
+ // contentWidth is the user specified content width. If <= 0 means no
+ // user
+ // specification.
+ int contentWidth = this._blockBox.getContentWidth();
+ int availableWidth = this._blockBox.getRecommendedContentWidth();
+ int contentHeight = this._blockBox.getContentHeight();
+
+ _tableInfo.calculateWidth(contentWidth, availableWidth);
+ _tableInfo.calculateHeight(contentHeight);
+
+ int columnCount = _tableInfo.getColumnCount();
+
+ int columnMinWidths[] = new int[columnCount];
+ int columnMaxWidths[] = new int[columnCount];
+
+ // For each column, determine a maximum and minimum column width from
+ // the cells that span only that column. The minimum is that required by
+ // the cell with the largest minimum cell width (or the column 'width',
+ // whichever is larger). The maximum is that required by the cell with
+ // the
+ // largest maximum cell width (or the column 'width', whichever is
+ // larger).
+ List cells = _tableInfo.getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ if (cellinfo.getColSpan() == 1) {
+ int column = cellinfo.getColumnIndex();
+ Dimension mincw = cellinfo.getMinCWDimension();
+ Dimension maxcw = cellinfo.getMaxCWDimension();
+ if (maxcw.width < mincw.width) {
+ maxcw.width = mincw.width;
+ }
+ if (mincw.width > columnMinWidths[column]) {
+ columnMinWidths[column] = mincw.width;
+ }
+ if (maxcw.width > columnMaxWidths[column]) {
+ columnMaxWidths[column] = maxcw.width;
+ }
+ }
+ }
+ // For caption, determine a maximum and minimum width from it.
+ int captionWidth = 0;
+ if (_tableInfo._caption != null) {
+ captionWidth = _tableInfo._caption.getDimension().width;
+ }
+
+ // For each cell that spans more than one column, increase the
+ // minimum widths of the columns it spans so that together, they
+ // are at least as wide as the cell. Do the same for the maximum
+ // widths. If possible, widen all spanned columns by approximately
+ // the same amount.
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ int colspan = cellinfo.getColSpan();
+ if (colspan > 1) {
+ int column = cellinfo.getColumnIndex();
+ Dimension mincw = cellinfo.getMinCWDimension();
+ Dimension maxcw = cellinfo.getMaxCWDimension();
+
+ adjustWidth(column, colspan, mincw.width, columnMinWidths);
+ adjustWidth(column, colspan, maxcw.width, columnMaxWidths);
+ }
+ }
+
+ int sigmaMinWidth = 0;
+ int sigmaMaxWidth = 0;
+ for (int i = 0; i < columnMinWidths.length; i++) {
+ sigmaMinWidth += columnMinWidths[i];
+ if (columnMaxWidths[i] == Integer.MAX_VALUE) {
+ sigmaMaxWidth = Integer.MAX_VALUE;
+ } else if (sigmaMaxWidth != Integer.MAX_VALUE) {
+ sigmaMaxWidth += columnMaxWidths[i];
+ if (sigmaMaxWidth < 0) {
+ sigmaMaxWidth = Integer.MAX_VALUE;
+ }
+ }
+ }
+ int spacingall = (columnMinWidths.length + 1) * _hspacing;
+ sigmaMinWidth += spacingall;
+ if (sigmaMaxWidth != Integer.MAX_VALUE) {
+ sigmaMaxWidth += spacingall;
+ if (sigmaMaxWidth < 0) {
+ sigmaMaxWidth = Integer.MAX_VALUE;
+ }
+ }
+
+ int tableWidth = _tableInfo.getTableWidth();
+ if (tableWidth > 0) {
+ // If the 'table' or 'inline-table' element's 'width' property has a
+ // specified value (W) other than 'auto', the property's computed
+ // value
+ // is the greater of W and the minimum width required by all the
+ // columns
+ // plus cell spacing or borders (MIN). If W is greater than MIN, the
+ // extra
+ // width should be distributed over the columns.
+ int maxMin = Math.max(captionWidth, sigmaMinWidth);
+ if (maxMin >= tableWidth) {
+ tableWidth = maxMin;
+ }
+ distribute(tableWidth - sigmaMinWidth, columnMinWidths,
+ columnMaxWidths);
+ } else {
+ // If the 'table' or 'inline-table' element has 'width: auto', the
+ // computed
+ // table width is the greater of the table's containing block width
+ // and MIN.
+ // However, if the maximum width required by the columns plus cell
+ // spacing or
+ // borders (MAX) is less than that of the containing block, use MAX.
+ // int availableWidth = this.getCurrentLine().getAvailableWidth();
+ int maxMin = Math.max(captionWidth, sigmaMaxWidth);
+ if (maxMin <= availableWidth) {
+ // TODO: if _tableInfo.hasWidthPercentage, then we need take
+ // that into consideration
+ // to distribute the column width. Left to next version.
+ tableWidth = maxMin;
+ // columnMinWidths = columnMaxWidths;
+ } else {
+ tableWidth = availableWidth;
+ }
+ distribute(tableWidth - sigmaMinWidth, columnMinWidths,
+ columnMaxWidths);
+ }
+
+ // now columnMinWidths contains width for each column
+ _columnWidths = columnMinWidths;
+
+ // ok, we have finished calculating column width.
+ // next we need to find out row heights.
+ _rowHeights = new int[_tableInfo.getRowCount()];
+
+ // first find out those TR that has height settings and use them.
+ List rows = _tableInfo.getRows();
+ for (int i = 0, size = rows.size(); i < size && i < _rowHeights.length; i++) {
+ TableRowInfo rowInfo = (TableRowInfo) rows.get(i);
+ if (rowInfo.getSpecifiedRowHeight() > 0) {
+ _rowHeights[i] = rowInfo.getSpecifiedRowHeight();
+ }
+ }
+
+ // First the cells don't span multiple rows.
+ cells = _tableInfo.getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ IFigure figure = cellinfo.getFigure();
+ int rowspan = cellinfo.getRowSpan();
+ if (rowspan == 1) {
+ int cellWidth = getCellWidth(cellinfo, _columnWidths);
+ Dimension d = figure.getPreferredSize(cellWidth, cellinfo
+ .getHeight());
+ if (d.height > _rowHeights[cellinfo.getRowIndex()]) {
+ _rowHeights[cellinfo.getRowIndex()] = d.height;
+ }
+ }
+ }
+
+ // Next those cells span multiple rows.
+ cells = _tableInfo.getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ IFigure figure = cellinfo.getFigure();
+ int rowspan = cellinfo.getRowSpan();
+ if (rowspan > 1) {
+ int cellWidth = getCellWidth(cellinfo, _columnWidths);
+ Dimension d = figure.getPreferredSize(cellWidth, cellinfo
+ .getHeight());
+ if (d.height > getCellHeight(cellinfo, _rowHeights)) {
+ adjustHeight(cellinfo.getRowIndex(), rowspan, d.height,
+ _rowHeights);
+ }
+ }
+ }
+
+ // Next we may need distribute height.
+ int sigmaHeight = (_tableInfo.getRowCount() + 1) * _vspacing;
+ for (int i = 0; i < _rowHeights.length; i++) {
+ sigmaHeight += _rowHeights[i];
+ }
+ if (sigmaHeight < contentHeight) {
+ distributeHeights(contentHeight - sigmaHeight, _rowHeights);
+ }
+
+ // now we have calculated the width and height of all cells.
+ // FIXME: border?
+ Insets insets = (style == null ? new Insets() : style.getBorderInsets()
+ .getAdded(style.getPaddingInsets()));
+ _internalTableWidth = (_tableInfo.getColumnCount() + 1) * _hspacing;
+ for (int i = 0; i < _columnWidths.length; i++) {
+ _internalTableWidth += _columnWidths[i];
+ }
+ int minWidth = getLengthValue(style, ICSSPropertyID.ATTR_MIN_WIDTH);
+ _internalTableWidth = _internalTableWidth > minWidth ? _internalTableWidth
+ : minWidth;
+
+ _blockBox.setWidth(_internalTableWidth + insets.getWidth());
+ _internalTableHeight = (_tableInfo.getRowCount() + 1) * _vspacing;
+ for (int i = 0; i < _rowHeights.length; i++) {
+ _internalTableHeight += _rowHeights[i];
+ }
+ int minHeight = getLengthValue(style, ICSSPropertyID.ATTR_MIN_HEIGHT);
+ _internalTableHeight = _internalTableHeight > minHeight ? _internalTableHeight
+ : minHeight;
+
+ int captionHeight = 0;
+ if (_tableInfo._caption != null) {
+ _captionSize = _tableInfo._caption.getFigure().getPreferredSize(
+ _internalTableWidth, SWT.DEFAULT);
+ captionHeight = _captionSize.height;
+ } else {
+ _captionSize = null;
+ }
+ _internalTableHeight += captionHeight;
+
+ _blockBox.setHeight(_internalTableHeight + insets.getHeight());
+
+ _rowwidth = _internalTableWidth - 2 * _hspacing;
+ _rowx = _hspacing; // XXX: table border width left?
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#endBlock()
+ */
+ protected void endBlock() {
+ _blockBox.setWidth(_internalTableWidth
+ + _blockBox.getBorderPaddingWidth());
+ _blockBox.setHeight(_internalTableHeight
+ + _blockBox.getBorderPaddingHeight());
+ super.endBlock();
+ }
+
+ //
+ // /**
+ // * when some of the column has percentage width, and sigmaMax smaller than
+ // container,
+ // * @param containerWidth
+ // * @param columnMinWidths
+ // * @param columnMaxWidths
+ // * @return
+ // */
+ // private int distribute2(int containerWidth, int[] columnMinWidths, int[]
+ // columnMaxWidths)
+ // {
+ //
+ // }
+ //
+ /**
+ * Distribute the additional width to columnMinWidths, using max width as a
+ * possible reference on how to distribute.
+ *
+ * @param toDistribute
+ * @param columnMinWidths
+ * @param columnMaxWidths
+ */
+ private void distribute(int toDistribute, int[] columnMinWidths,
+ int[] columnMaxWidths) {
+ if (toDistribute <= 0)
+ return;
+ if (columnMinWidths.length == 0)
+ return;
+
+ int[] delta = new int[columnMinWidths.length];
+ int sigmaDelta = 0;
+ for (int i = 0; i < columnMinWidths.length && toDistribute > 0; i++) {
+ if (_tableInfo._widthSpecified[i]) {
+ delta[i] = 0;
+ } else {
+ delta[i] = columnMaxWidths[i] - columnMinWidths[i];
+ if (delta[i] <= 0) {
+ delta[i] = 0;
+ }
+ sigmaDelta += delta[i];
+ }
+ }
+ if (sigmaDelta == 0) {
+ // should not happen, but anyway, distribute all to the last column
+ // columnMinWidths[columnMinWidths.length-1] += toDistribute;
+ averageDeltaToCell(columnMinWidths, toDistribute);
+ } else {
+ int left = toDistribute;
+ for (int i = 0; i < columnMinWidths.length - 1; i++) {
+ if (delta[i] > 0) {
+ int add = delta[i] * toDistribute / sigmaDelta;
+ left -= add;
+ columnMinWidths[i] += add;
+ }
+ }
+ columnMinWidths[columnMinWidths.length - 1] += left;
+ }
+ }
+
+ private void averageDeltaToCell(int[] columnMinWidths, int toDistribute) {
+
+ if (toDistribute <= 0) {
+ return;
+ }
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < columnMinWidths.length; i++) {
+ if (!_tableInfo._widthSpecified[i]) {
+ list.add(new Integer(i));
+ }
+ }
+ if (list.size() == 0) {
+ for (int i = 0; i < columnMinWidths.length; i++) {
+ list.add(new Integer(i));
+ }
+ }
+ int padding = toDistribute / list.size();
+ int left = toDistribute % list.size();
+ for (int i = 0, n = list.size(); i < n; i++) {
+ columnMinWidths[((Integer) list.get(i)).intValue()] += padding;
+ }
+ if (left > 0) {
+ for (int i = 0; i < left; i++) {
+ columnMinWidths[((Integer) list.get(i)).intValue()] += 1;
+ }
+ }
+ }
+
+ /**
+ * @param i
+ * @param heights
+ */
+ private void distributeHeights(int toDistribute, int[] heights) {
+ if (heights.length == 0)
+ return;
+ int eachDelta = toDistribute / heights.length;
+ for (int i = 0; i < heights.length - 1; i++) {
+ heights[i] += eachDelta;
+ }
+ heights[heights.length - 1] += toDistribute - (heights.length - 1)
+ * eachDelta;
+ }
+
+ /**
+ * @param cellinfo
+ * @param heights
+ * @return
+ */
+ public int getCellHeight(TableCellInfo cellinfo, int[] heights) {
+ int rowIndex = cellinfo.getRowIndex();
+ int rowspan = cellinfo.getRowSpan();
+ int h = 0;
+ for (int i = 0; i < rowspan; i++) {
+ h += heights[rowIndex + i];
+ }
+ h += (rowspan - 1) * _vspacing;
+ return h;
+ }
+
+ /**
+ * @param cellinfo
+ * @param widths
+ * @return
+ */
+ public int getCellWidth(TableCellInfo cellinfo, int[] widths) {
+ int columnIndex = cellinfo.getColumnIndex();
+ int colspan = cellinfo.getColSpan();
+ int w = 0;
+ for (int i = 0; i < colspan; i++) {
+ w += widths[columnIndex + i];
+ }
+ w += (colspan - 1) * _hspacing;
+ return w;
+ }
+
+ /**
+ * @param column
+ * the start column
+ * @param colspan
+ * number of columns
+ * @param width
+ * desired width
+ * @param columnWidths
+ * current columns widths. After the adjust, need make sure the
+ * columnWidths to be bigger than desired width
+ */
+ private void adjustWidth(int column, int colspan, int width,
+ int[] columnWidths) {
+ adjustSpan(column, colspan, width, columnWidths, _hspacing);
+ }
+
+ /**
+ * @see #adjustWidth(int, int, int, int[])
+ */
+ private void adjustHeight(int rowIndex, int rowspan, int height,
+ int[] heights) {
+ adjustSpan(rowIndex, rowspan, height, heights, _vspacing);
+ }
+
+ static private void adjustSpan(int column, int colspan, int width,
+ int[] columnWidths, int spacing) {
+ int spanwidth = 0;
+ for (int i = 0; i < colspan; i++) {
+ spanwidth += columnWidths[column + i];
+ }
+ // XXX: vspacing here?
+ spanwidth += (colspan - 1) * spacing;
+
+ if (spanwidth >= width) {
+ return;
+ } else {
+ int delta = width - spanwidth;
+ int deltaeach = delta / colspan;
+ for (int i = 0; i < colspan - 1; i++) {
+ columnWidths[column + i] += deltaeach;
+ }
+ columnWidths[column + colspan - 1] += (delta - (colspan - 1)
+ * deltaeach);
+ }
+ }
+
+ /**
+ * @return
+ */
+ public int[] getRowHeights() {
+ return _rowHeights;
+ }
+
+ /**
+ * @return
+ */
+ public int[] getColumnWidths() {
+ return _columnWidths;
+ }
+
+ /**
+ * @return
+ */
+ public int getVSpacing() {
+ return _vspacing;
+ }
+
+ /**
+ * @return
+ */
+ public int getHSpacing() {
+ return _hspacing;
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableRowInfo getRowInfo(CSSFigure figure) {
+ return _tableInfo.findRowInfo(figure);
+ }
+
+ public TableCaptionInfo getCaptionInfo() {
+ return _tableInfo._caption;
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableRowGroupInfo getGroupInfo(CSSFigure figure) {
+ return _tableInfo.findGroupInfo(figure);
+ }
+
+ /**
+ * @return
+ */
+ public int getRowX() {
+ return _rowx;
+ }
+
+ /**
+ * @return
+ */
+ public int getRowWidth() {
+ return _rowwidth;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#shouldExpand()
+ */
+ public boolean shouldExpand() {
+ return false;
+ }
+
+ public Dimension getCaptionSize() {
+ return _captionSize;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSPainter#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics g) {
+ ICSSStyle style = this.getCSSStyle();
+ if (style != null) {
+ ITagEditInfo info = (ITagEditInfo) style
+ .getAdapter(ITagEditInfo.class);
+ if (info != null && info.needTableDecorator()) {
+ List cells = _tableInfo.getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellInfo = (TableCellInfo) cells.get(i);
+ IFigure cellfigure = cellInfo.getFigure();
+ Rectangle rect = cellfigure.getBounds().getCopy();
+ rect = rect.expand(1, 1);
+ g.setLineStyle(Graphics.LINE_SOLID);
+ g.setLineWidth(1);
+ g.setForegroundColor(ColorConstants.lightBlue);
+ g.drawRectangle(rect);
+ }
+ }
+ }
+ }
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CachedTableCellLayout.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CachedTableCellLayout.java
new file mode 100644
index 000000000..40c734e00
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/CachedTableCellLayout.java
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.jst.pagedesigner.css2.layout.BoxUtil;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.FlowFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public abstract class CachedTableCellLayout extends CSSBlockFlowLayout {
+ protected Dimension _pageSize = new Dimension();
+
+ protected boolean _calculatingSize = false;
+
+ private int _pageSizeCacheKeys[] = new int[4];
+
+ private Dimension _pageSizeCacheValues[] = new Dimension[4];
+
+ private int _recommendedWidth;
+
+ private Dimension _cacheMaxWidthSize = null;
+
+ private boolean _isTable;
+
+ /**
+ * @param cssfigure
+ */
+ public CachedTableCellLayout(CSSFigure cssfigure) {
+ super(cssfigure);
+ }
+
+ /**
+ * when figure revalidated, means some child or itself get changed somehow,
+ * so clear the cache information here.
+ */
+ public void figureRevalidate() {
+ super.figureRevalidate();
+ _pageSizeCacheKeys = new int[4];
+ _pageSizeCacheValues = new Dimension[4];
+ _pageSize = new Dimension();
+ _recommendedWidth = 0;
+ _cacheMaxWidthSize = null;
+ _isTable = false;
+ }
+
+ /**
+ * TODO: This method is not being called.
+ */
+ public void postValidate() {
+ if (_isTable) {
+ if (_calculatingSize) {
+ _pageSize.width = _blockBox.getWidth();
+ _pageSize.height = _blockBox.getHeight();
+ } else {
+ if (_isTable) {
+ Rectangle rect = getCellRect();
+ _blockBox.setXYWidthHeight(rect);
+ this.getCSSFigure().setBounds(rect);
+ }
+ }
+ List list = getCSSFigure().getChildren();
+ for (int i = 0, n = list.size(); i < n; i++) {
+ ((FlowFigure) list.get(i)).postValidate();
+ }
+ } else {
+ super.postValidate();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jst.pagedesigner.css2.layout.CSSBlockFlowLayout#preLayout()
+ */
+ protected void preLayout() {
+ _isTable = initializeTableInfo();
+ if (_isTable) {
+ if (!_calculatingSize) {
+ // XXX: I don't know why need to call setValid(false) here, if I
+ // don't call
+ // it, the layout will be wrong.
+ getCSSFigure().setValid(false);
+ }
+ }
+ super.preLayout();
+ }
+
+ public abstract Rectangle getCellRect();
+
+ public abstract boolean initializeTableInfo();
+
+ protected void setupBlock() {
+ if (_isTable) {
+ // Remove all current Fragments
+ _blockBox.clear();
+
+ if (_calculatingSize) {
+ // we are not in the real layout
+ // Setup the one fragment for this Block with the correct X and
+ // available width
+ int recommendedWidth = getRecommendedWidth();
+ _blockBox.setRecommendedWidth(recommendedWidth);
+
+ if (recommendedWidth > 0
+ && recommendedWidth != Integer.MAX_VALUE) {
+ _blockBox.setWidth(recommendedWidth);
+ }
+ } else {
+ Rectangle rect = getCellRect();
+ _blockBox.setWidth(rect.width);
+ _blockBox.setRecommendedWidth(rect.width);
+ _blockBox.setHeight(rect.height);
+ _blockBox.setRecommendedHeight(rect.height);
+ }
+
+ BoxUtil.setupBorderPaddingMargin(_blockBox, getCSSStyle());
+ } else {
+ super.setupBlock();
+ }
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int)
+ */
+ public Dimension getPreferredSize(IFigure container, int width, int h) {
+ if (this.isCalculatingMaxWidth()) {
+ return getMaxContentWidthSize(container, width, h);
+ }
+ try {
+ _calculatingSize = true;
+ // if (width >= 0)
+ // {
+ // width = Math.max(0, width - container.getInsets().getWidth());
+ // }
+
+ for (int i = 0; i < 4; i++) {
+ if (_pageSizeCacheKeys[i] == width
+ && _pageSizeCacheValues[i] != null) {
+ if (h > _pageSizeCacheValues[i].height) {
+ return new Dimension(_pageSizeCacheValues[i].width, h);
+ }
+ return _pageSizeCacheValues[i];
+ }
+ }
+
+ _pageSizeCacheKeys[3] = _pageSizeCacheKeys[2];
+ _pageSizeCacheKeys[2] = _pageSizeCacheKeys[1];
+ _pageSizeCacheKeys[1] = _pageSizeCacheKeys[0];
+ _pageSizeCacheKeys[0] = width;
+
+ _pageSizeCacheValues[3] = _pageSizeCacheValues[2];
+ _pageSizeCacheValues[2] = _pageSizeCacheValues[1];
+ _pageSizeCacheValues[1] = _pageSizeCacheValues[0];
+
+ // Flowpage must temporarily layout to determine its preferred size
+ int oldWidth = getRecommendedWidth();
+ setRecommendedWidth(width);
+ ((CSSFigure) container).setValid(false);
+ container.validate();
+ ((CSSFigure) container).postValidate();
+ _pageSizeCacheValues[0] = new Dimension(_pageSize);
+
+ if (width != oldWidth) {
+ setRecommendedWidth(oldWidth);
+ // container.getUpdateManager().addInvalidFigure(container);
+ }
+ if (h > _pageSizeCacheValues[0].height) {
+ return new Dimension(_pageSizeCacheValues[0].width, h);
+ } else {
+ return _pageSizeCacheValues[0];
+ }
+ } finally {
+ _calculatingSize = false;
+ }
+ }
+
+ public int getRecommendedWidth() {
+ return _recommendedWidth;
+ }
+
+ private void setRecommendedWidth(int width) {
+ if (_recommendedWidth == width) {
+ return;
+ }
+ _recommendedWidth = width;
+ }
+
+ public Dimension getMaxContentWidthSize(IFigure container, int width,
+ int height) {
+ try {
+ _calculatingSize = true;
+
+ if (this._cacheMaxWidthSize == null) {
+ boolean b = getCalcuatingMaxWidth();
+ setCalculatingMaxWidth(true);
+
+ // Flowpage must temporarily layout to determine its preferred
+ // size
+ int oldWidth = getRecommendedWidth();
+ if (width <= 0) {
+ setRecommendedWidth(Integer.MAX_VALUE);
+ } else {
+ setRecommendedWidth(width);
+ }
+ ((CSSFigure) container).setValid(false);
+ container.validate();
+
+ ((CSSFigure) container).postValidate();
+ _cacheMaxWidthSize = new Dimension(_pageSize);
+ if (height > _pageSize.height) {
+ _cacheMaxWidthSize.height = height;
+ }
+
+ if (0 != oldWidth) {
+ setRecommendedWidth(oldWidth);
+ // container.getUpdateManager().addInvalidFigure(container);
+ }
+
+ setCalculatingMaxWidth(b);
+ }
+ return _cacheMaxWidthSize;
+ } finally {
+ _calculatingSize = false;
+ }
+ }
+
+ /**
+ * @return Returns the _isTable.
+ */
+ protected boolean isTable() {
+ return _isTable;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCaptionInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCaptionInfo.java
new file mode 100644
index 000000000..8a8b5c18f
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCaptionInfo.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.table;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.swt.SWT;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableCaptionInfo extends TableItemInfo {
+ String _align;
+
+ /**
+ * @param figure
+ */
+ public TableCaptionInfo(ICSSFigure figure) {
+ super(figure);
+ ICSSStyle style = figure.getCSSStyle();
+ if (style != null) {
+ _align = style.getStyleProperty(
+ ICSSPropertyID.ATTR_HORIZONTAL_ALIGN).toString();
+ }
+ }
+
+ /**
+ * @return
+ */
+ public Dimension getDimension(int width, int height) {
+ return getFigure().getPreferredSize(width, height);
+ }
+
+ public Dimension getDimension() {
+ return getDimension(SWT.DEFAULT, SWT.DEFAULT);
+ }
+
+ /**
+ * @return Returns the align.
+ */
+ public String getAlign() {
+ // TODO:We do not support left/right align of caption currently. so we
+ // treat them as top.
+ if ("bottom".equalsIgnoreCase(_align)) //$NON-NLS-1$
+ {
+ return _align;
+ } else {
+ return "top"; //$NON-NLS-1$
+ }
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCellInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCellInfo.java
new file mode 100644
index 000000000..cc41b1f92
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableCellInfo.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * 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.table;
+
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.value.Length;
+import org.eclipse.jst.pagedesigner.utils.IntFlexArray;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableCellInfo extends TableItemInfo {
+ int _rowSpan = 1;
+
+ int _colSpan = 1;
+
+ int _colIndex;
+
+ int _rowIndex;
+
+ int _cellWidth = 0;
+
+ int _cellHeight = 0;
+
+ /**
+ * @param childfigure
+ */
+ public TableCellInfo(ICSSFigure childfigure) {
+ super(childfigure);
+ }
+
+ /**
+ * @return
+ */
+ public int getColSpan() {
+ return _colSpan;
+ }
+
+ /**
+ * @return
+ */
+ public int getRowSpan() {
+ return _rowSpan;
+ }
+
+ /**
+ * @return
+ */
+ public int getRowIndex() {
+ return _rowIndex;
+ }
+
+ /**
+ * @return
+ */
+ public int getColumnIndex() {
+ return _colIndex;
+ }
+
+ /**
+ * @return
+ */
+ public Dimension getMinCWDimension() {
+ return getFigure().getPreferredSize(_cellWidth, _cellHeight);
+ }
+
+ /**
+ * @return
+ */
+ public Dimension getMaxCWDimension() {
+ ICSSFigure figure = getFigure();
+ LayoutManager layout = figure.getLayoutManager();
+ if (layout instanceof CSSTableCellLayout) {
+ Dimension d = ((CSSTableCellLayout) layout).getMaxContentWidthSize(
+ figure, _cellWidth, _cellHeight);
+ return d;
+ } else {
+ // should not happen
+ return getMinCWDimension();
+ }
+ }
+
+ /**
+ * @param context
+ */
+ public void calculateCellInfo(TableInfoContext context) {
+ ICSSStyle style = this.getStyle();
+ _rowSpan = style.getRowSpan();
+ _colSpan = style.getColSpan();
+
+ // FIXME: we don't support rowspan and colspan to be 0.
+ // by spec, 0 means span from current col/row to end.
+ if (_rowSpan <= 0) {
+ _rowSpan = 1;
+ }
+ if (_colSpan <= 0) {
+ _colSpan = 1;
+ }
+
+ _rowIndex = context.getCurrentRow();
+
+ IntFlexArray array = context.getIntFlexArray();
+ int currentCol = context.getCurrentCol();
+
+ // find a cell that is not occupied by cells in previous rows.
+ while (array.getAt(currentCol) > 0) {
+ currentCol++;
+ }
+
+ // ok, now array.getAt(currentCol) == 0
+ _colIndex = currentCol;
+
+ for (int i = 0; i < _colSpan; i++, currentCol++) {
+ array.setAt(currentCol, _rowSpan);
+ }
+ context.setCurrentCol(currentCol);
+ }
+
+ /**
+ * @param tablewidth
+ * table width
+ */
+ public void calculateWidth(TableInfo tableInfo, int tablewidth) {
+ ICSSStyle style = this.getFigure().getCSSStyle();
+ if (style == null) {
+ _cellWidth = -1;
+ } else {
+ Object width = style.getStyleProperty(ICSSPropertyID.ATTR_WIDTH);
+ Length recommendedWidth = (width instanceof Length) ? (Length) width
+ : null;
+
+ int rw = 0;
+ if (recommendedWidth == null || recommendedWidth.getValue() <= 0) {
+ rw = 0;
+ } else {
+ if (recommendedWidth.isPercentage()) {
+ // percentage width is used for remaining width
+ // distribution, so not used here.
+ int colspan = this.getColSpan();
+ for (int i = 0; i < colspan; i++) {
+ tableInfo.setWidthPercentage(this.getColumnIndex() + i,
+ recommendedWidth.getValue() / colspan);
+ }
+ } else {
+ rw = recommendedWidth.getValue();
+ if (!style.isSizeIncludeBorderPadding()) {
+ rw += style.getBorderInsets().getWidth()
+ + style.getPaddingInsets().getWidth();
+ }
+ if (this.getColSpan() == 1) {
+ tableInfo._widthSpecified[this.getColumnIndex()] = true;
+ }
+ }
+
+ }
+ _cellWidth = rw;
+ }
+
+ }
+
+ /**
+ * @param height
+ */
+ public void calculateHeight(TableInfo tableInfo, int tableheight) {
+ ICSSStyle style = this.getFigure().getCSSStyle();
+ if (style == null) {
+ _cellHeight = -1;
+ } else {
+ Object height = style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);
+ Length recommendedHeight = (height instanceof Length) ? (Length) height
+ : null;
+
+ int rh = 0;
+ if (recommendedHeight == null || recommendedHeight.getValue() <= 0) {
+ rh = 0;
+ } else {
+ if (recommendedHeight.isPercentage()) {
+ int rowspan = this.getRowSpan();
+ for (int i = 0; i < rowspan; i++) {
+ tableInfo.setHeightPercentage(this.getRowIndex() + i,
+ recommendedHeight.getValue() / rowspan);
+ }
+ } else {
+ rh = recommendedHeight.getValue();
+ }
+ if (!style.isSizeIncludeBorderPadding()) {
+ rh += style.getBorderInsets().getHeight()
+ + style.getPaddingInsets().getHeight();
+ }
+ }
+ _cellHeight = rh;
+ }
+
+ }
+
+ /**
+ * @return
+ */
+ public int getHeight() {
+ return _cellHeight;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfo.java
new file mode 100644
index 000000000..a458c0e62
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfo.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableInfo extends TableItemInfo {
+ List _tableHeaderGroups = new ArrayList();
+
+ List _tableTRandTRGs = new ArrayList();
+
+ List _tableFooterGroups = new ArrayList();
+
+ TableCaptionInfo _caption;
+
+ int _columnCount;
+
+ int _rowCount;
+
+ List _cells = null;
+
+ private List _rows = null;
+
+ int _tableWidth; // calculated table width, valid after calling to
+
+ // calculateTableWidth
+
+ int _availableWidth;
+
+ int _tableHeight;
+
+ private int[] _widthPercentage;
+
+ private int[] _heightPercentage;
+
+ boolean[] _widthSpecified;
+
+ /**
+ * @param figure
+ */
+ public TableInfo(ICSSFigure figure) {
+ super(figure);
+ }
+
+ public List getTableHeaderGroups() {
+ return _tableHeaderGroups;
+ }
+
+ public List getTRandTRGs() {
+ return _tableTRandTRGs;
+ }
+
+ public List getTableFooterGroups() {
+ return _tableFooterGroups;
+ }
+
+ public int getColumnCount() {
+ return _columnCount;
+ }
+
+ public int getRowCount() {
+ return _rowCount;
+ }
+
+ protected void constructTable() {
+ List child = getFigure().getChildren();
+ for (int i = 0, size = child.size(); i < size; i++) {
+ IFigure childfigure = (IFigure) child.get(i);
+ if (childfigure instanceof ICSSFigure) {
+ ICSSStyle style = ((ICSSFigure) childfigure).getCSSStyle();
+ if (style != null) {
+ String display = style.getDisplay();
+ if ("table-caption".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ _caption = new TableCaptionInfo(
+ (ICSSFigure) childfigure);
+ } else if ("table-row".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ TableRowInfo rowInfo = new TableRowInfo(
+ (ICSSFigure) childfigure);
+ _tableTRandTRGs.add(rowInfo);
+ } else if ("table-row-group".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ TableRowGroupInfo groupInfo = new TableRowGroupInfo(
+ (ICSSFigure) childfigure);
+ _tableTRandTRGs.add(groupInfo);
+ } else if ("table-header-group".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ TableRowGroupInfo groupInfo = new TableRowGroupInfo(
+ (ICSSFigure) childfigure);
+ _tableHeaderGroups.add(groupInfo);
+ } else if ("table-footer-group".equalsIgnoreCase(display)) //$NON-NLS-1$
+ {
+ TableRowGroupInfo groupInfo = new TableRowGroupInfo(
+ (ICSSFigure) childfigure);
+ _tableFooterGroups.add(groupInfo);
+ } else {
+ // something unexpected inside table
+ }
+ } else {
+ // something unexpected inside table
+ }
+ } else {
+ // something unexpected inside table
+ }
+ }
+
+ TableInfoContext context = new TableInfoContext();
+ // now we have the rows ordered, need to calculate row details now.
+ for (int i = 0, size = _tableHeaderGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableHeaderGroups
+ .get(i);
+ groupInfo.calculateRowGroup(context);
+ }
+ for (int i = 0, size = _tableTRandTRGs.size(); i < size; i++) {
+ Object obj = _tableTRandTRGs.get(i);
+ if (obj instanceof TableRowGroupInfo) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) obj;
+ groupInfo.calculateRowGroup(context);
+ } else {
+ TableRowInfo rowInfo = (TableRowInfo) obj;
+ rowInfo.calculateRow(context);
+ }
+ }
+ for (int i = 0, size = _tableFooterGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableFooterGroups
+ .get(i);
+ groupInfo.calculateRowGroup(context);
+ }
+ context.finishTable();
+
+ _columnCount = context.getColumnCount();
+ _rowCount = context.getRowCount();
+
+ this._widthPercentage = new int[_columnCount];
+ this._heightPercentage = new int[_rowCount];
+
+ this._widthSpecified = new boolean[_columnCount];
+ for (int i = 0; i < _columnCount; i++) {
+ this._widthSpecified[i] = false;
+ }
+ }
+
+ public void setWidthPercentage(int columnIndex, int percentageValue) {
+ if (percentageValue > this._widthPercentage[columnIndex]) {
+ this._widthPercentage[columnIndex] = percentageValue;
+ }
+ }
+
+ public void setHeightPercentage(int rowIndex, int percentageValue) {
+ if (percentageValue > this._heightPercentage[rowIndex]) {
+ this._heightPercentage[rowIndex] = percentageValue;
+ }
+ }
+
+ /**
+ * width percentage will be used to calculate remaining width distribution.
+ *
+ * @return
+ */
+ public int[] getWidthPercentages() {
+ return this._widthPercentage;
+ }
+
+ public int[] getHeightPercentages() {
+ return this._heightPercentage;
+ }
+
+ public List getRows() {
+ if (_rows == null) {
+ this._rows = new ArrayList();
+
+ for (int i = 0, size = _tableHeaderGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableHeaderGroups
+ .get(i);
+ _rows.addAll(groupInfo.getRowList());
+ }
+ for (int i = 0, size = _tableTRandTRGs.size(); i < size; i++) {
+ Object obj = _tableTRandTRGs.get(i);
+ if (obj instanceof TableRowGroupInfo) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) obj;
+ _rows.addAll(groupInfo.getRowList());
+ } else {
+ TableRowInfo rowInfo = (TableRowInfo) obj;
+ _rows.add(rowInfo);
+ }
+ }
+ for (int i = 0, size = _tableFooterGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableFooterGroups
+ .get(i);
+ _rows.addAll(groupInfo.getRowList());
+ }
+ }
+ return _rows;
+ }
+
+ public List getCells() {
+ if (_cells == null) {
+ _cells = new ArrayList();
+
+ for (int i = 0, size = _tableHeaderGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableHeaderGroups
+ .get(i);
+ groupInfo.getCells(_cells);
+ }
+ for (int i = 0, size = _tableTRandTRGs.size(); i < size; i++) {
+ Object obj = _tableTRandTRGs.get(i);
+ if (obj instanceof TableRowGroupInfo) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) obj;
+ groupInfo.getCells(_cells);
+ } else {
+ TableRowInfo rowInfo = (TableRowInfo) obj;
+ rowInfo.getCells(_cells);
+ }
+ }
+ for (int i = 0, size = _tableFooterGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableFooterGroups
+ .get(i);
+ groupInfo.getCells(_cells);
+ }
+ }
+ return _cells;
+ }
+
+ /**
+ * @param containerWidth
+ * if the width specification is percentage, then will use
+ * container width.
+ */
+ public void calculateWidth(int contentWidth, int availableWidth) {
+ _tableWidth = contentWidth;
+ _availableWidth = availableWidth;
+
+ // next calculate cell width
+ List cells = getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ cellinfo.calculateWidth(this, _tableWidth);
+ }
+ }
+
+ public void calculateHeight(int contentHeight) {
+ _tableHeight = contentHeight;
+
+ List rows = getRows();
+ for (int i = 0, size = rows.size(); i < size; i++) {
+ TableRowInfo rowinfo = (TableRowInfo) rows.get(i);
+ rowinfo.calculateHeight(this, _tableHeight);
+ }
+
+ // next calculate cell width
+ List cells = getCells();
+ for (int i = 0, size = cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) cells.get(i);
+ cellinfo.calculateHeight(this, _tableHeight);
+ }
+ }
+
+ /**
+ * @return
+ */
+ public int getTableWidth() {
+ return _tableWidth;
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableRowGroupInfo findGroupInfo(CSSFigure figure) {
+ for (int i = 0, size = _tableHeaderGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableHeaderGroups
+ .get(i);
+ if (figure == groupInfo.getFigure()) {
+ return groupInfo;
+ }
+ }
+ for (int i = 0, size = _tableTRandTRGs.size(); i < size; i++) {
+ Object obj = _tableTRandTRGs.get(i);
+ if (obj instanceof TableRowGroupInfo) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) obj;
+ if (figure == groupInfo.getFigure()) {
+ return groupInfo;
+ }
+
+ }
+ }
+ for (int i = 0, size = _tableFooterGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableFooterGroups
+ .get(i);
+ if (figure == groupInfo.getFigure()) {
+ return groupInfo;
+ }
+ }
+ return null; // should not happen.
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableRowInfo findRowInfo(CSSFigure figure) {
+ for (int i = 0, size = _tableHeaderGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableHeaderGroups
+ .get(i);
+ TableRowInfo rowinfo = groupInfo.findRowInfo(figure);
+ if (rowinfo != null) {
+ return rowinfo;
+ }
+ }
+ for (int i = 0, size = _tableTRandTRGs.size(); i < size; i++) {
+ Object obj = _tableTRandTRGs.get(i);
+ if (obj instanceof TableRowGroupInfo) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) obj;
+ TableRowInfo rowinfo = groupInfo.findRowInfo(figure);
+ if (rowinfo != null) {
+ return rowinfo;
+ }
+ } else if (obj instanceof TableRowInfo) {
+ TableRowInfo info = (TableRowInfo) obj;
+ if (figure == info.getFigure()) {
+ return info;
+ }
+ }
+ }
+ for (int i = 0, size = _tableFooterGroups.size(); i < size; i++) {
+ TableRowGroupInfo groupInfo = (TableRowGroupInfo) _tableFooterGroups
+ .get(i);
+ TableRowInfo rowinfo = groupInfo.findRowInfo(figure);
+ if (rowinfo != null) {
+ return rowinfo;
+ }
+ }
+ return null; // should not happen.
+ }
+
+ /**
+ *
+ * @return
+ */
+ public boolean hasWidthPercentage() {
+ for (int i = 0; i < this._widthPercentage.length; i++) {
+ if (this._widthPercentage[i] > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfoContext.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfoContext.java
new file mode 100644
index 000000000..4cd3fbdd2
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableInfoContext.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * 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.table;
+
+import org.eclipse.jst.pagedesigner.PDPlugin;
+import org.eclipse.jst.pagedesigner.common.logging.Logger;
+import org.eclipse.jst.pagedesigner.utils.IntFlexArray;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableInfoContext {
+ static Logger _log = PDPlugin.getLogger(TableInfoContext.class);
+
+ int _currentCol = 0;
+
+ int _currentRow = 0;
+
+ IntFlexArray _array = new IntFlexArray();
+
+ int _colCount = 0;
+
+ int _rowCount = 0;
+
+ /**
+ *
+ */
+ public TableInfoContext() {
+ }
+
+ /**
+ * @return
+ */
+ public IntFlexArray getIntFlexArray() {
+ return _array;
+ }
+
+ /**
+ * @return
+ */
+ public int getCurrentCol() {
+ return _currentCol;
+ }
+
+ public void setCurrentCol(int currentcol) {
+ _currentCol = currentcol;
+ }
+
+ public int getCurrentRow() {
+ return _currentRow;
+ }
+
+ /**
+ * @return
+ */
+ public int getColumnCount() {
+ return _colCount;
+ }
+
+ /**
+ *
+ */
+ public void finishRow() {
+ if (_currentCol > _colCount) {
+ _colCount = _currentCol;
+ }
+ _currentCol = 0;
+ _currentRow++;
+ for (int i = 0; i < _colCount; i++) {
+ if (_array.getAt(i) > 0) {
+ _array.setAt(i, _array.getAt(i) - 1);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ public void finishTable() {
+ // do some checking here.
+ int additionalRow = 0;
+ for (int i = 0; i < _colCount; i++) {
+ if (_array.getAt(i) > additionalRow) {
+ additionalRow = _array.getAt(i);
+ }
+ }
+ _rowCount = _currentRow + additionalRow;
+ }
+
+ /**
+ *
+ */
+ public void finishRowGroup() {
+ }
+
+ /**
+ * @return
+ */
+ public int getRowCount() {
+ return _rowCount;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableItemInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableItemInfo.java
new file mode 100644
index 000000000..33c6e12e3
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableItemInfo.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.table;
+
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableItemInfo {
+ public ICSSFigure _figure;
+
+ /**
+ *
+ */
+ public TableItemInfo(ICSSFigure figure) {
+ _figure = figure;
+ }
+
+ public ICSSFigure getFigure() {
+ return _figure;
+ }
+
+ public ICSSStyle getStyle() {
+ return _figure.getCSSStyle();
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowGroupInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowGroupInfo.java
new file mode 100644
index 000000000..d9ae2feb3
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowGroupInfo.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableRowGroupInfo extends TableItemInfo {
+ List _rowList = new ArrayList();
+
+ private int _rowIndex;
+
+ private int _rowCount;
+
+ /**
+ * @param figure
+ */
+ public TableRowGroupInfo(ICSSFigure figure) {
+ super(figure);
+ }
+
+ public List getRowList() {
+ return _rowList;
+ }
+
+ public int getRowIndex() {
+ return _rowIndex;
+ }
+
+ public int getRowCount() {
+ return this._rowCount;
+ }
+
+ /**
+ * @param context
+ */
+ public void calculateRowGroup(TableInfoContext context) {
+ this._rowIndex = context.getCurrentRow();
+ List children = getFigure().getChildren();
+ for (int i = 0, size = children.size(); i < size; i++) {
+ IFigure childfigure = (IFigure) children.get(i);
+ if (childfigure instanceof ICSSFigure) {
+ ICSSStyle childstyle = ((ICSSFigure) childfigure).getCSSStyle();
+ if (childstyle != null
+ && "table-row"
+ .equalsIgnoreCase(childstyle.getDisplay())) {
+ TableRowInfo rowInfo = new TableRowInfo(
+ (ICSSFigure) childfigure);
+ _rowList.add(rowInfo);
+ rowInfo.calculateRow(context);
+ } else {
+ // skip
+ }
+ } else {
+ // skip
+ }
+ }
+ context.finishRowGroup();
+ this._rowCount = context.getCurrentRow() - this._rowIndex;
+ }
+
+ /**
+ * @param _cells
+ */
+ public void getCells(List _cells) {
+ for (int i = 0, size = _rowList.size(); i < size; i++) {
+ TableRowInfo rowInfo = (TableRowInfo) _rowList.get(i);
+ rowInfo.getCells(_cells);
+ }
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableRowInfo findRowInfo(CSSFigure figure) {
+ for (int i = 0, size = _rowList.size(); i < size; i++) {
+ TableRowInfo rowInfo = (TableRowInfo) _rowList.get(i);
+ if (figure == rowInfo.getFigure()) {
+ return rowInfo;
+ }
+ }
+ return null;
+ }
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowInfo.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowInfo.java
new file mode 100644
index 000000000..f305d0dfd
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/css2/layout/table/TableRowInfo.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * 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.table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
+import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
+import org.eclipse.jst.pagedesigner.css2.layout.ICSSFigure;
+import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;
+import org.eclipse.jst.pagedesigner.css2.value.Length;
+
+/**
+ * @author mengbo
+ * @version 1.5
+ */
+public class TableRowInfo extends TableItemInfo {
+ List _cells = new ArrayList();
+
+ int _rowIndex;
+
+ private int _rowHeight;
+
+ /**
+ * @param figure
+ */
+ public TableRowInfo(ICSSFigure figure) {
+ super(figure);
+ }
+
+ public List getCells() {
+ return _cells;
+ }
+
+ public int getRowIndex() {
+ return _rowIndex;
+ }
+
+ public int getSpecifiedRowHeight() {
+ return _rowHeight;
+ }
+
+ /**
+ * @param context
+ */
+ public void calculateRow(TableInfoContext context) {
+ this._rowIndex = context.getCurrentRow();
+
+ List children = getFigure().getChildren();
+ for (int i = 0, size = children.size(); i < size; i++) {
+ IFigure childfigure = (IFigure) children.get(i);
+ if (childfigure instanceof ICSSFigure) {
+ ICSSStyle childstyle = ((ICSSFigure) childfigure).getCSSStyle();
+ if (childstyle != null) {
+ String display = childstyle.getDisplay();
+ if ("table-cell".equalsIgnoreCase(display)) {
+ TableCellInfo cellInfo = new TableCellInfo(
+ (ICSSFigure) childfigure);
+ cellInfo.calculateCellInfo(context);
+ _cells.add(cellInfo);
+ } else {
+ // skip
+ }
+ }
+ } else {
+ // skip
+ }
+ }
+ // ok, we have finished a row
+ context.finishRow();
+ }
+
+ /**
+ * @param _cells2
+ */
+ public void getCells(List cells) {
+ cells.addAll(this._cells);
+ }
+
+ /**
+ * @param figure
+ * @return
+ */
+ public TableCellInfo getCellInfo(CSSFigure figure) {
+ for (int i = 0, size = _cells.size(); i < size; i++) {
+ TableCellInfo cellinfo = (TableCellInfo) _cells.get(i);
+ if (cellinfo.getFigure() == figure) {
+ return cellinfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param info
+ * @param height
+ */
+ public void calculateHeight(TableInfo info, int tableHeight) {
+ ICSSStyle style = this.getFigure().getCSSStyle();
+ if (style == null) {
+ this._rowHeight = -1;
+ } else {
+ Object height = style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);
+ Length recommendedHeight = (height instanceof Length) ? (Length) height
+ : null;
+
+ int rh = 0;
+ if (recommendedHeight == null || recommendedHeight.getValue() <= 0) {
+ rh = 0;
+ } else {
+ if (recommendedHeight.isPercentage()) {
+ // not supported.
+ } else {
+ rh = recommendedHeight.getValue();
+ }
+ if (rh > 0 && !style.isSizeIncludeBorderPadding()) {
+ rh += style.getBorderInsets().getHeight()
+ + style.getPaddingInsets().getHeight();
+ }
+ }
+ this._rowHeight = rh;
+ }
+
+ }
+}

Back to the top