| /******************************************************************************* |
| * 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.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.swt.SWT; |
| |
| import org.eclipse.draw2d.Border; |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| |
| /** |
| * A <code>FlowFigure</code> represented by multiple <code>LineBox</code> |
| * fragments. An <code>InlineFlow</code>'s parent must be either a |
| * {@link BlockFlow} or another InlineFlow. |
| * |
| * <P> |
| * An InlineFlow may contain other InlineFlow figures. |
| * |
| * <P> |
| * WARNING: This class is not intended to be subclassed by clients. |
| * |
| * @author Randy Hudson |
| * @since 2.0 |
| */ |
| public class InlineFlow extends FlowFigure { |
| |
| List fragments = new ArrayList(1); |
| |
| /** |
| * Iterates over the children to find the width before a line-break is |
| * encountered. |
| * |
| * @see org.eclipse.draw2d.text.FlowFigure#addLeadingWordRequirements(int[]) |
| */ |
| public boolean addLeadingWordRequirements(int[] width) { |
| Iterator iter = getChildren().iterator(); |
| while (iter.hasNext()) { |
| if (((FlowFigure) iter.next()).addLeadingWordRequirements(width)) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Extended to return false if the point is not also contained by at least |
| * one fragment. |
| * |
| * @return <code>true</code> if a fragment contains the given point |
| * @param x |
| * the relative x coordinate |
| * @param y |
| * the relative y coordinate |
| */ |
| public boolean containsPoint(int x, int y) { |
| if (super.containsPoint(x, y)) { |
| List frags = getFragments(); |
| for (int i = 0; i < frags.size(); i++) |
| if (((FlowBox) frags.get(i)).containsPoint(x, y)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * @see FlowFigure#createDefaultFlowLayout() |
| */ |
| protected FlowFigureLayout createDefaultFlowLayout() { |
| return new InlineFlowLayout(this); |
| } |
| |
| /** |
| * Returns the <code>FlowBox</code> fragments contained in this InlineFlow. |
| * The returned list should not be modified. |
| * |
| * @return The fragments |
| */ |
| public List getFragments() { |
| return fragments; |
| } |
| |
| /** |
| * Overridden to paint a {@link FlowBorder} if present, and draw selection. |
| * The border is painted first, followed by selection which is generally |
| * done in XOR, which still allows the border to be seen. |
| * |
| * @param graphics |
| * the graphics |
| */ |
| protected void paintBorder(Graphics graphics) { |
| if (getBorder() != null) { |
| FlowBorder fb = (FlowBorder) getBorder(); |
| List frags = getFragments(); |
| Rectangle where = new Rectangle(); |
| int sides; |
| for (int i = 0; i < frags.size(); i++) { |
| FlowBox box = (FlowBox) frags.get(i); |
| |
| where.x = box.getX(); |
| where.width = box.getWidth(); |
| where.y = -box.getAscentWithBorder(); |
| where.height = box.getDescentWithBorder() - where.y; |
| where.y += box.getBaseline(); |
| sides = 0; |
| if (i == 0) |
| sides = SWT.LEAD; |
| if (i == frags.size() - 1) |
| sides |= SWT.TRAIL; |
| fb.paint(this, graphics, where, sides); |
| } |
| graphics.restoreState(); |
| } |
| if (selectionStart != -1) |
| paintSelection(graphics); |
| } |
| |
| /** |
| * Renders the XOR selection rectangles to the graphics. |
| * |
| * @param graphics |
| * the graphics to paint on |
| * @since 3.1 |
| */ |
| protected void paintSelection(Graphics graphics) { |
| graphics.restoreState(); |
| graphics.setXORMode(true); |
| graphics.setBackgroundColor(ColorConstants.white()); |
| List list = getFragments(); |
| FlowBox box; |
| for (int i = 0; i < list.size(); i++) { |
| box = (FlowBox) list.get(i); |
| int top = box.getLineRoot().getVisibleTop(); |
| int bottom = box.getLineRoot().getVisibleBottom(); |
| graphics.fillRectangle(box.getX(), top, box.getWidth(), bottom |
| - top); |
| } |
| } |
| |
| /** |
| * @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; i < list.size(); i++) { |
| box = (FlowBox) list.get(i); |
| left = Math.min(left, box.getX()); |
| right = Math.max(right, box.getX() + box.getWidth()); |
| top = Math.min(top, box.getLineRoot().getVisibleTop()); |
| bottom = Math.max(bottom, box.getLineRoot().getVisibleBottom()); |
| } |
| |
| setBounds(new Rectangle(left, top, right - left, bottom - top)); |
| repaint(); |
| list = getChildren(); |
| for (int i = 0; i < list.size(); i++) |
| ((FlowFigure) list.get(i)).postValidate(); |
| } |
| |
| /** |
| * Overridden to assert that only {@link FlowBorder} is used. |
| * <code>null</code> is still a valid value as well. |
| * |
| * @param border |
| * <code>null</code> or a FlowBorder |
| */ |
| public void setBorder(Border border) { |
| if (border == null || border instanceof FlowBorder) |
| super.setBorder(border); |
| else |
| throw new RuntimeException( |
| "Border must be an instance of FlowBorder"); //$NON-NLS-1$ |
| } |
| |
| } |