| /******************************************************************************* |
| * Copyright (c) 2000, 2010 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.draw2d.text; |
| |
| import java.util.List; |
| |
| |
| import org.eclipse.draw2d.Figure; |
| import org.eclipse.draw2d.PositionConstants; |
| import org.eclipse.draw2d.geometry.Insets; |
| import org.eclipse.swt.SWT; |
| |
| /** |
| * The layout for {@link BlockFlow} figures. |
| * |
| * <P> |
| * WARNING: This class is not intended to be subclassed by clients. |
| * |
| * @author hudsonr |
| * @since 2.1 |
| */ |
| public class BlockFlowLayout extends FlowContainerLayout { |
| |
| BlockBox blockBox; |
| boolean blockInvalid = false; |
| private boolean continueOnSameLine = false; |
| private CompositeBox previousLine = null; |
| |
| /** |
| * Creates a new BlockFlowLayout with the given BlockFlow. |
| * |
| * @param blockFlow |
| * the BlockFlow |
| */ |
| public BlockFlowLayout(BlockFlow blockFlow) { |
| super(blockFlow); |
| } |
| |
| private void addBelowPreviousLine(CompositeBox line) { |
| if (previousLine == null) |
| line.setLineTop(line.getTopMargin()); |
| else |
| line.setLineTop(previousLine.getBaseline() |
| + previousLine.getDescent() |
| + Math.max(previousLine.getBottomMargin(), |
| line.getTopMargin())); |
| |
| int alignment = getBlockFlow().getHorizontalAligment(); |
| if (alignment == PositionConstants.LEFT |
| || alignment == PositionConstants.RIGHT) { |
| int orientation = getBlockFlow().getOrientation(); |
| if (alignment == PositionConstants.LEFT) |
| alignment = orientation == SWT.LEFT_TO_RIGHT ? PositionConstants.ALWAYS_LEFT |
| : PositionConstants.ALWAYS_RIGHT; |
| else |
| alignment = orientation == SWT.LEFT_TO_RIGHT ? PositionConstants.ALWAYS_RIGHT |
| : PositionConstants.ALWAYS_LEFT; |
| } |
| if (alignment != PositionConstants.CENTER |
| && getBlockFlow().isMirrored()) |
| alignment = (PositionConstants.ALWAYS_LEFT | PositionConstants.ALWAYS_RIGHT) |
| & ~alignment; |
| |
| switch (alignment) { |
| case PositionConstants.ALWAYS_RIGHT: |
| line.setX(blockBox.getRecommendedWidth() - line.getWidth()); |
| break; |
| case PositionConstants.CENTER: |
| line.setX((blockBox.getRecommendedWidth() - line.getWidth()) / 2); |
| break; |
| case PositionConstants.ALWAYS_LEFT: |
| line.setX(0); |
| break; |
| default: |
| throw new RuntimeException("Unexpected state"); //$NON-NLS-1$ |
| } |
| blockBox.add(line); |
| previousLine = line; |
| } |
| |
| /** |
| * Align the line horizontally and then commit it. |
| */ |
| protected void addCurrentLine() { |
| addBelowPreviousLine(currentLine); |
| ((LineRoot) currentLine).commit(); |
| } |
| |
| /** |
| * @see FlowContext#addLine(CompositeBox) |
| */ |
| public void addLine(CompositeBox box) { |
| endLine(); |
| addBelowPreviousLine(box); |
| } |
| |
| /** |
| * Marks the blocks contents as changed. This means that children will be |
| * invalidated during validation. |
| * |
| * @since 3.1 |
| */ |
| public void blockContentsChanged() { |
| blockInvalid = true; |
| } |
| |
| /** |
| * @see FlowContainerLayout#cleanup() |
| */ |
| protected void cleanup() { |
| super.cleanup(); |
| previousLine = null; |
| } |
| |
| /** |
| * @see FlowContainerLayout#createNewLine() |
| */ |
| protected void createNewLine() { |
| currentLine = new LineRoot(getBlockFlow().isMirrored()); |
| currentLine.setRecommendedWidth(blockBox.getRecommendedWidth()); |
| } |
| |
| /** |
| * Called by flush(), adds the BlockBox associated with this BlockFlowLayout |
| * to the current line and then ends the line. |
| */ |
| protected void endBlock() { |
| if (blockInvalid) { |
| Insets insets = getBlockFlow().getInsets(); |
| blockBox.height += insets.getHeight(); |
| blockBox.width += insets.getWidth(); |
| } |
| |
| if (getContext() != null) |
| getContext().addLine(blockBox); |
| |
| if (blockInvalid) { |
| blockInvalid = false; |
| List v = getFlowFigure().getChildren(); |
| for (int i = 0; i < v.size(); i++) |
| ((FlowFigure) v.get(i)).postValidate(); |
| } |
| } |
| |
| /** |
| * @see FlowContext#endLine() |
| */ |
| public void endLine() { |
| if (currentLine == null || !currentLine.isOccupied()) |
| return; |
| addCurrentLine(); |
| currentLine = null; |
| } |
| |
| /** |
| * @see FlowContainerLayout#flush() |
| */ |
| protected void flush() { |
| endLine(); |
| endBlock(); |
| } |
| |
| boolean forceChildInvalidation(Figure f) { |
| return blockInvalid; |
| } |
| |
| /** |
| * Returns the BlockFlow associated with this BlockFlowLayout |
| * |
| * @return the BlockFlow |
| */ |
| protected final BlockFlow getBlockFlow() { |
| return (BlockFlow) getFlowFigure(); |
| } |
| |
| int getContextWidth() { |
| return getContext().getRemainingLineWidth(); |
| } |
| |
| /** |
| * @see FlowContext#getContinueOnSameLine() |
| */ |
| public boolean getContinueOnSameLine() { |
| return continueOnSameLine; |
| } |
| |
| /** |
| * @see FlowContext#getWidthLookahead(FlowFigure, int[]) |
| */ |
| public void getWidthLookahead(FlowFigure child, int result[]) { |
| List children = getFlowFigure().getChildren(); |
| int index = -1; |
| if (child != null) |
| index = children.indexOf(child); |
| |
| for (int i = index + 1; i < children.size(); i++) |
| if (((FlowFigure) children.get(i)) |
| .addLeadingWordRequirements(result)) |
| return; |
| } |
| |
| /** |
| * @see FlowContainerLayout#preLayout() |
| */ |
| protected void preLayout() { |
| setContinueOnSameLine(false); |
| blockBox = getBlockFlow().getBlockBox(); |
| setupBlock(); |
| // Probably could setup current and previous line here, or just previous |
| } |
| |
| /** |
| * @see org.eclipse.draw2d.text.FlowContext#setContinueOnSameLine(boolean) |
| */ |
| public void setContinueOnSameLine(boolean value) { |
| continueOnSameLine = value; |
| } |
| |
| /** |
| * sets up the single block that contains all of the lines. |
| */ |
| protected void setupBlock() { |
| int recommended = getContextWidth(); |
| if (recommended == Integer.MAX_VALUE) |
| recommended = -1; |
| BlockFlow bf = getBlockFlow(); |
| if (recommended > 0) { |
| int borderCorrection = bf.getInsets().getWidth() |
| + bf.getLeftMargin() + bf.getRightMargin(); |
| recommended = Math.max(0, recommended - borderCorrection); |
| } |
| |
| if (recommended != blockBox.recommendedWidth) { |
| blockInvalid = true; |
| blockBox.setRecommendedWidth(recommended); |
| } |
| |
| if (blockInvalid) { |
| blockBox.height = 0; |
| blockBox.setWidth(Math.max(0, recommended)); |
| } |
| } |
| |
| } |