/******************************************************************************* * Copyright (c) 2000, 2005 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.swt.SWT; 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; /** * 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(); } }