| /******************************************************************************* |
| * Copyright (c) 2006 Sybase, Inc. 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: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.pagedesigner.css2.layout; |
| |
| import java.util.List; |
| |
| import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID; |
| import org.eclipse.swt.graphics.Font; |
| |
| /** |
| * @author mengbo |
| */ |
| // NOTE: CSSTextLayout does not extends CSSFlowLayout. Since text is a little |
| // special, |
| // we don't want to do things like "preLayout()" as in CSSFlowLayout. |
| public class CSSTextLayout extends FlowFigureLayout { |
| /** |
| * Wrapping will ONLY occur at valid line breaks |
| */ |
| public static final int WORD_WRAP_HARD = 0; |
| |
| /** |
| * Wrapping will always occur at the end of the available space, breaking in |
| * the middle of a word. |
| */ |
| public static final int WORD_WRAP_SOFT = 1; |
| |
| /** |
| * Wrapping will always occur at the end of available space, truncating a |
| * word if it doesn't fit. |
| */ |
| // don't support this flag |
| // public static final int WORD_WRAP_TRUNCATE = 2; |
| private int _wrappingStyle = WORD_WRAP_HARD; |
| |
| public CSSTextLayout(CSSTextFigure textfigure) { |
| super(textfigure); |
| } |
| |
| // -------------------------------------------------------------------------------------------------- |
| FlowBox findLastNonLineBox(LineBox box) { |
| List fragments = box.getFragments(); |
| for (int i = fragments.size() - 1; i >= 0; i--) { |
| FlowBox item = (FlowBox) fragments.get(i); |
| if (item instanceof LineBox) { |
| FlowBox found = findLastNonLineBox((LineBox) item); |
| if (found != null) { |
| return found; |
| } |
| } else { |
| return item; |
| } |
| } |
| return null; |
| } |
| |
| // boolean isElementContentWhitespaceEnding() |
| // { |
| // if (!this._context.isCurrentLineOccupied()) |
| // return true; |
| // LineBox line = this._context.getCurrentLine(); |
| // FlowBox lastNoneLinebox = findLastNonLineBox(line); |
| // if (lastNoneLinebox instanceof TextFragmentBox) |
| // return ((TextFragmentBox) lastNoneLinebox)._isLastCharWhitespace; |
| // else |
| // return true; |
| // } |
| // |
| // String normalize(String text) |
| // { |
| // text = EntityMap.translateAndCompact(text); |
| // if (text.length() > 0 && |
| // Character.isElementContentWhitespace(text.charAt(0)) && |
| // isElementContentWhitespaceEnding()) |
| // return text.substring(1); |
| // else |
| // return text; |
| // } |
| |
| private void layoutEmptyString(List fragments, Font font) { |
| // empty node! we want to create a fake fragment, so things can be |
| // consistent |
| // that all the CSSTextFigure will have something inside, also in this |
| // way, even |
| // empty text node will have a position, thus we can support showing |
| // caret associated |
| // with this text figure. |
| fragments.clear(); |
| TextFragmentBox box = TextLayoutSupport.getFragment(0, fragments); |
| box._length = 0; |
| box._offset = 0; |
| box._height = 0; |
| box._width = 0; |
| box.setTextData(""); |
| |
| // {following comments deprecated XXX: If is empty string, we only want |
| // to this figure to have a size, but don't |
| // want to it to be added into current line. Otherwise, a line with only |
| // a empty string |
| // will also take a line's space.} |
| |
| // please reference LineBox.isOccupied() |
| // now we treat a line with only an empty text as not occupied. |
| getFlowContext().getCurrentLine().add(box); |
| } |
| |
| /** |
| * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#layout() |
| */ |
| protected void layout() { |
| CSSTextFigure flowFigure = (CSSTextFigure) getFlowFigure(); |
| |
| List fragments = flowFigure.getFragments();// Reuse the previous List |
| // of fragments |
| String text = flowFigure.getText(); |
| Font font = flowFigure.getCSSStyle().getCSSFont().getSwtFont(); |
| Object whitespace = flowFigure.getCSSStyle().getStyleProperty( |
| ICSSPropertyID.ATTR_WHITESPACE); |
| |
| if (whitespace == ICSSPropertyID.VAL_PRE) { |
| if (text == null || text.length() == 0) |
| layoutEmptyString(fragments, font); |
| else |
| TextLayoutSupport.layoutNoWrap(getFlowContext(), text, |
| fragments, font); |
| } else if (whitespace == ICSSPropertyID.VAL_NOWRAP) { |
| if (text == null || text.length() == 0) |
| layoutEmptyString(fragments, font); |
| else |
| TextLayoutSupport.layoutNoWrap(getFlowContext(), text, |
| fragments, font); |
| } else { |
| if (text == null || text.length() == 0) |
| layoutEmptyString(fragments, font); |
| else { |
| boolean trimLeadingChar = (text.charAt(0) == ' ' && shouldTrimLeadingWhitespace(getFlowContext())); |
| TextLayoutSupport.layoutNormal(getFlowContext(), text, |
| fragments, font, _wrappingStyle, trimLeadingChar); |
| } |
| } |
| } |
| |
| // XXX: maybe should move to TextSupport later. |
| public boolean shouldTrimLeadingWhitespace(FlowContext context) { |
| if (!context.isCurrentLineOccupied()) { |
| return true; |
| } |
| while (context instanceof CSSInlineFlowLayout) { |
| context = ((CSSInlineFlowLayout) context).getFlowContext(); |
| } |
| LineBox line = context.getCurrentLine(); |
| if (line == null || !line.isOccupied()) { |
| return true; |
| } |
| FlowBox lastNoneLinebox = findLastNonLineBox(line); |
| if (lastNoneLinebox == null || lastNoneLinebox.getWidth() == 0) { |
| return true; |
| } else if (lastNoneLinebox instanceof TextFragmentBox) { |
| return ((TextFragmentBox) lastNoneLinebox)._isLastCharWhitespace; |
| } else { |
| return false; |
| } |
| } |
| |
| public void dispose() { |
| } |
| } |