/******************************************************************************* * 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.ColorConstants; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; /** * A <code>FlowFigure</code> represented by a single {@link BlockBox} 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 foundation for a * paragraph. * <P> * BlockFlows must be parented by a <code>FlowFigure</code>. {@link FlowPage} * can be used as a "root" block and can be parented by normal Figures. * <P> * Only {@link FlowFigure}s can be added to a BlockFlow. * <P> * WARNING: This class is not intended to be subclassed by clients. * * @author hudsonr * @since 2.1 */ public class BlockFlow extends FlowFigure { private final BlockBox blockBox; private int alignment = PositionConstants.NONE; private int orientation = SWT.NONE; private boolean bidiValid; /** * Constructs a new BlockFlow. */ public BlockFlow() { blockBox = createBlockBox(); } /** * BlockFlows contribute a paragraph separator so as to keep the Bidi state * of the text on either side of this block from affecting each other. Since * each block is like a different paragraph, it does not contribute any * actual text to its containing block. * * @see org.eclipse.draw2d.text.FlowFigure#contributeBidi(org.eclipse.draw2d.text.BidiProcessor) */ protected void contributeBidi(BidiProcessor proc) { proc.addControlChar(BidiChars.P_SEP); } BlockBox createBlockBox() { return new BlockBox(this); } /** * @see org.eclipse.draw2d.text.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; } int getBottomMargin() { int margin = 0; if (getBorder() instanceof FlowBorder) { FlowBorder border = (FlowBorder) getBorder(); return border.getBottomMargin(); } List children = getChildren(); int childIndex = children.size() - 1; if (childIndex >= 0 && children.get(childIndex) instanceof BlockFlow) { margin = Math.max(margin, ((BlockFlow) children.get(childIndex)).getBottomMargin()); } return margin; } /** * Returns the effective horizontal alignment. This method will never return * {@link PositionConstants#NONE}. If the value is none, it will return the * inherited alignment. If no alignment was inherited, it will return the * default alignment ({@link PositionConstants#LEFT}). * * @return the effective alignment */ public int getHorizontalAligment() { if (alignment != PositionConstants.NONE) return alignment; IFigure parent = getParent(); while (parent != null && !(parent instanceof BlockFlow)) parent = parent.getParent(); if (parent != null) return ((BlockFlow) parent).getHorizontalAligment(); return PositionConstants.LEFT; } int getLeftMargin() { if (getBorder() instanceof FlowBorder) return ((FlowBorder) getBorder()).getLeftMargin(); return 0; } /** * Returns the orientation set on this block. * * @return LTR, RTL or NONE * @see #setOrientation(int) * @since 3.1 */ public int getLocalOrientation() { return orientation; } /** * Returns the horizontal alignment set on this block. * * @return LEFT, RIGHT, ALWAYS_LEFT, ALWAYS_RIGHT, NONE * @see #setHorizontalAligment(int) * @since 3.1 */ public int getLocalHorizontalAlignment() { return alignment; } /** * Returns this block's Bidi orientation. If none was set on this block, it * will inherit the one from its containing block. If there is no containing * block, it will return the default orientation (SWT.RIGHT_TO_LEFT if * mirrored; SWT.LEFT_TO_RIGHT otherwise). * * @return SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT * @see #setOrientation(int) * @since 3.1 */ public int getOrientation() { if (orientation != SWT.NONE) return orientation; IFigure parent = getParent(); while (parent != null && !(parent instanceof BlockFlow)) parent = parent.getParent(); if (parent != null) return ((BlockFlow) parent).getOrientation(); return isMirrored() ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT; } int getRightMargin() { if (getBorder() instanceof FlowBorder) return ((FlowBorder) getBorder()).getRightMargin(); return 0; } int getTopMargin() { int margin = 0; if (getBorder() instanceof FlowBorder) { FlowBorder border = (FlowBorder) getBorder(); return border.getTopMargin(); } List children = getChildren(); if (children.size() > 0 && children.get(0) instanceof BlockFlow) { margin = Math.max(margin, ((BlockFlow) children.get(0)).getTopMargin()); } return margin; } /** * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics) */ public void paintBorder(Graphics graphics) { if (getBorder() instanceof FlowBorder) { Rectangle where = getBlockBox().toRectangle(); where.crop(new Insets(getTopMargin(), getLeftMargin(), getBottomMargin(), getRightMargin())); ((FlowBorder) getBorder()).paint(this, graphics, where, SWT.LEAD | SWT.TRAIL); } else super.paintBorder(graphics); if (selectionStart != -1) { graphics.restoreState(); graphics.setXORMode(true); graphics.setBackgroundColor(ColorConstants.white()); graphics.fillRectangle(getBounds()); } } /** * @see org.eclipse.draw2d.text.FlowFigure#postValidate() */ public void postValidate() { Rectangle newBounds = getBlockBox().toRectangle(); newBounds.crop(new Insets(getTopMargin(), getLeftMargin(), getBottomMargin(), getRightMargin())); setBounds(newBounds); } /** * @see FlowFigure#revalidate() */ public void revalidate() { BlockFlowLayout layout = (BlockFlowLayout) getLayoutManager(); layout.blockContentsChanged(); super.revalidate(); } /** * A Block will invalidate the Bidi state of all its children, so that it is * re-evaluated when this block is next validated. * * @see org.eclipse.draw2d.text.FlowFigure#revalidateBidi(org.eclipse.draw2d.IFigure) */ protected void revalidateBidi(IFigure origin) { if (bidiValid) { bidiValid = false; revalidate(); } } /** * Sets the horitontal aligment of the block. Valid values are: * <UL> * <LI>{@link PositionConstants#NONE NONE} - (default) Alignment is * inherited from parent. If a parent is not found then LEFT is used.</LI> * <LI>{@link PositionConstants#LEFT} - Alignment is with leading edge</LI> * <LI>{@link PositionConstants#RIGHT} - Alignment is with trailing edge</LI> * <LI>{@link PositionConstants#CENTER}</LI> * <LI>{@link PositionConstants#ALWAYS_LEFT} - Left, irrespective of * orientation</LI> * <LI>{@link PositionConstants#ALWAYS_RIGHT} - Right, irrespective of * orientation</LI> * </UL> * * @param value * the aligment * @see #getHorizontalAligment() */ public void setHorizontalAligment(int value) { value &= PositionConstants.LEFT | PositionConstants.CENTER | PositionConstants.RIGHT | PositionConstants.ALWAYS_LEFT | PositionConstants.ALWAYS_RIGHT; if (value == alignment) return; alignment = value; revalidate(); } /** * Sets the orientation for this block. Orientation can be one of: * <UL> * <LI>{@link SWT#LEFT_TO_RIGHT} * <LI>{@link SWT#RIGHT_TO_LEFT} * <LI>{@link SWT#NONE} (default) * </UL> * <code>NONE</code> is used to indicate that orientation should be * inherited from the encompassing block. * * @param orientation * LTR, RTL or NONE * @see #getOrientation() * @since 3.1 */ public void setOrientation(int orientation) { orientation &= SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; if (this.orientation == orientation) return; this.orientation = orientation; revalidateBidi(this); } /** * @see org.eclipse.draw2d.Figure#useLocalCoordinates() */ protected boolean useLocalCoordinates() { return true; } /** * Re-evaluate the Bidi state of all the fragments if it has been * invalidated. * * @see org.eclipse.draw2d.IFigure#validate() */ public void validate() { if (!bidiValid) { BidiProcessor.INSTANCE().setOrientation(getOrientation()); if (getOrientation() == SWT.LEFT_TO_RIGHT && isMirrored()) BidiProcessor.INSTANCE().addControlChar(BidiChars.LRE); super.contributeBidi(BidiProcessor.INSTANCE()); BidiProcessor.INSTANCE().process(); bidiValid = true; } super.validate(); } }