blob: 0c2fc2dc02f4de6e033be1082d18e5b0baa18970 [file] [log] [blame]
/*******************************************************************************
* 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.draw2d.rap.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();
}
}