001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.awt.Graphics;
023: import java.awt.Shape;
024:
025: import javax.swing.SizeRequirements;
026: import javax.swing.event.DocumentEvent;
027: import javax.swing.text.Position.Bias;
028:
029: import org.apache.harmony.awt.text.TextUtils;
030:
031: import org.apache.harmony.x.swing.internal.nls.Messages;
032:
033: public class ParagraphView extends FlowView implements TabExpander {
034: private static final int DEFAULT_TAB = 72;
035: private static final int MIN_TEXT_CHUNK = 10;
036: private static final char[] TABS = new char[] { '\t' };
037: private static final char[] TABS_DECIMAL = new char[] { '\t', '.' };
038:
039: private class Row extends BoxView {
040: private int lineSpace;
041:
042: public Row(final Element element) {
043: super (element, X_AXIS);
044: }
045:
046: public int getStartOffset() {
047: if (getViewCount() > 0) {
048: return getView(0).getStartOffset();
049: }
050: return super .getStartOffset();
051: }
052:
053: public int getEndOffset() {
054: if (getViewCount() > 0) {
055: return getView(getViewCount() - 1).getEndOffset();
056: }
057: return super .getEndOffset();
058: }
059:
060: public AttributeSet getAttributes() {
061: final View parent = getParent();
062: return parent != null ? parent.getAttributes() : null;
063: }
064:
065: protected void loadChildren(final ViewFactory factory) {
066: }
067:
068: protected SizeRequirements calculateMajorAxisRequirements(
069: final int axis, final SizeRequirements r) {
070:
071: SizeRequirements result = super
072: .calculateMajorAxisRequirements(axis, r);
073: result.alignment = getAlignByJustification();
074: return result;
075: }
076:
077: protected SizeRequirements calculateMinorAxisRequirements(
078: final int axis, final SizeRequirements r) {
079:
080: SizeRequirements result = baselineRequirements(axis, r);
081: lineSpace = (int) (result.preferred * lineSpacing);
082: return result;
083: }
084:
085: protected void layoutMinorAxis(final int targetSpan,
086: final int axis, final int[] offsets, final int[] spans) {
087: baselineLayout(targetSpan, axis, offsets, spans);
088: }
089:
090: protected short getLeftInset() {
091: if (ParagraphView.this .isAllocationValid()
092: && ParagraphView.this .getViewCount() > 0
093: && this == ParagraphView.this .getView(0)) {
094:
095: return (short) (super .getLeftInset() + firstLineIndent);
096: }
097: return super .getLeftInset();
098: }
099:
100: protected short getBottomInset() {
101: return (short) (super .getBottomInset() + lineSpace);
102: }
103:
104: private float getAlignByJustification() {
105: switch (justification) {
106: case StyleConstants.ALIGN_LEFT:
107: return ALIGN_LEFT;
108: case StyleConstants.ALIGN_CENTER:
109: return ALIGN_CENTER;
110: case StyleConstants.ALIGN_RIGHT:
111: return ALIGN_RIGHT;
112: default:
113: return ALIGN_CENTER;
114: }
115: }
116: }
117:
118: protected int firstLineIndent;
119: private int justification;
120: private float lineSpacing;
121:
122: private int tabBase;
123:
124: public ParagraphView(final Element element) {
125: super (element, Y_AXIS);
126: setPropertiesFromAttributes();
127: }
128:
129: public int getFlowStart(final int rowIndex) {
130: int result = super .getFlowStart(rowIndex);
131: if (rowIndex == 0) {
132: result += firstLineIndent;
133: }
134: View child = getView(rowIndex);
135: if (child instanceof CompositeView) {
136: result += ((CompositeView) child).getLeftInset();
137: }
138: return result;
139: }
140:
141: public int getFlowSpan(final int rowIndex) {
142: int result = super .getFlowSpan(rowIndex);
143: if (rowIndex == 0) {
144: result -= firstLineIndent;
145: }
146: View child = getView(rowIndex);
147: if (child instanceof CompositeView) {
148: CompositeView cv = (CompositeView) child;
149: result -= cv.getLeftInset();
150: result -= cv.getRightInset();
151: }
152: return result;
153: }
154:
155: public float getAlignment(final int axis) {
156: if (axis == Y_AXIS && getViewCount() > 0) {
157: return (getSpan(Y_AXIS, 0) / 2) / getPreferredSpan(Y_AXIS);
158: }
159: return super .getAlignment(axis);
160: }
161:
162: public void paint(final Graphics g, final Shape a) {
163: tabBase = a.getBounds().x + getLeftInset();
164: super .paint(g, a);
165: }
166:
167: public float nextTabStop(final float x, final int tabOffset) {
168: final float base = getTabBase();
169: final float basedX = x > base ? x - base : 0;
170: final TabSet tabSet = getTabSet();
171: if (tabSet == null) {
172: return base + ((int) (basedX / DEFAULT_TAB) + 1)
173: * DEFAULT_TAB;
174: }
175:
176: final TabStop tabStop = tabSet.getTabAfter(basedX);
177: if (tabStop == null) {
178: return base + ((int) (basedX / DEFAULT_TAB) + 1)
179: * DEFAULT_TAB;
180: }
181:
182: final int align = tabStop.getAlignment();
183: if (align == TabStop.ALIGN_LEFT || align == TabStop.ALIGN_BAR) {
184: return base + tabStop.getPosition();
185: }
186:
187: int nextTab = findOffsetToCharactersInString(
188: align == TabStop.ALIGN_DECIMAL ? TABS_DECIMAL : TABS,
189: tabOffset + 1);
190: if (nextTab == -1) {
191: nextTab = getEndOffset();
192: }
193:
194: float partSpan = getPartialSize(tabOffset + 1, nextTab);
195: if (align == TabStop.ALIGN_CENTER) {
196: return base + tabStop.getPosition() - partSpan / 2;
197: }
198: return base + tabStop.getPosition() - partSpan;
199: }
200:
201: public View breakView(final int axis, final float len, final Shape a) {
202: return this ;
203: }
204:
205: public int getBreakWeight(final int axis, final float len) {
206: return BadBreakWeight;
207: }
208:
209: public void changedUpdate(final DocumentEvent changes,
210: final Shape a, final ViewFactory f) {
211: preferenceChanged(null, true, true);
212: setPropertiesFromAttributes();
213: super .changedUpdate(changes, a, f);
214: }
215:
216: protected View createRow() {
217: return new Row(getElement());
218: }
219:
220: protected void setJustification(final int j) {
221: justification = j;
222: }
223:
224: protected void setLineSpacing(final float ls) {
225: lineSpacing = ls;
226: }
227:
228: protected void setFirstLineIndent(final float fi) {
229: firstLineIndent = (int) fi;
230: }
231:
232: protected void setPropertiesFromAttributes() {
233: final AttributeSet attrs = getAttributes();
234: setJustification(StyleConstants.getAlignment(attrs));
235: setFirstLineIndent(StyleConstants.getFirstLineIndent(attrs));
236: setLineSpacing(StyleConstants.getLineSpacing(attrs));
237: setParagraphInsets(attrs);
238: }
239:
240: protected int getLayoutViewCount() {
241: return layoutPool.getViewCount();
242: }
243:
244: protected View getLayoutView(final int index) {
245: return layoutPool.getView(index);
246: }
247:
248: /**
249: * This method does nothing and is not supposed to be called.
250: * The functionality described for this method in the API Specification
251: * is equivalent to that of
252: * @link FlowView.FlowStrategy#adjustRow(FlowView, int, int, int)
253: */
254: protected void adjustRow(final Row r, final int desiredSpan,
255: final int x) {
256: }
257:
258: protected int getClosestPositionTo(final int pos, final Bias b,
259: final Shape a, final int direction, final Bias[] biasRet,
260: final int rowIndex, final int x)
261: throws BadLocationException {
262: throw new UnsupportedOperationException(Messages
263: .getString("swing.27")); //$NON-NLS-1$
264: }
265:
266: protected float getPartialSize(final int startOffset,
267: final int endOffset) {
268: float result = 0;
269: int index = layoutPool.getViewIndex(startOffset, Bias.Forward);
270: if (index == -1) {
271: return 0;
272: }
273:
274: View child;
275: int childStart;
276: int childEnd;
277: do {
278: child = getLayoutView(index);
279: childStart = child.getStartOffset();
280: childEnd = child.getEndOffset();
281: if (startOffset <= childStart && childEnd <= endOffset) {
282: result += child.getPreferredSpan(X_AXIS);
283: } else if (!(child instanceof TabableView)) {
284: return 0;
285: } else {
286: TabableView tv = (TabableView) child;
287: result += tv.getPartialSpan(
288: childStart > startOffset ? childStart
289: : startOffset,
290: childEnd < endOffset ? childEnd : endOffset);
291: }
292: } while (childEnd < endOffset && ++index < getLayoutViewCount());
293:
294: return result;
295: }
296:
297: protected int findOffsetToCharactersInString(final char[] string,
298: final int start) {
299: final Segment text = new Segment();
300: text.setPartialReturn(true);
301: int offset = start;
302: final int limit = getEndOffset();
303: final Document doc = getDocument();
304: while (offset < limit) {
305: try {
306: doc.getText(offset, Math.min(MIN_TEXT_CHUNK, limit
307: - offset), text);
308: } catch (BadLocationException e) {
309: e.printStackTrace();
310: return -1;
311: }
312:
313: char c = text.first();
314: while (c != Segment.DONE) {
315: for (int i = 0; i < string.length; i++) {
316: if (c == string[i]) {
317: return offset + text.getIndex()
318: - text.getBeginIndex();
319: }
320: }
321: c = text.next();
322: }
323: offset += text.count;
324: }
325: return -1;
326: }
327:
328: protected int getNextNorthSouthVisualPositionFrom(final int pos,
329: final Bias b, final Shape a, final int direction,
330: final Bias[] biasRet) throws BadLocationException {
331: if (true) {
332: throw new UnsupportedOperationException(Messages
333: .getString("swing.27")); //$NON-NLS-1$
334: }
335: return TextUtils.getNextVisualPositionFrom(getTextKit(), this ,
336: pos, b, a, direction, biasRet);
337: }
338:
339: protected boolean flipEastAndWestAtEnds(final int position,
340: final Bias bias) {
341: throw new UnsupportedOperationException(Messages
342: .getString("swing.27")); //$NON-NLS-1$
343: }
344:
345: protected TabSet getTabSet() {
346: return StyleConstants.getTabSet(getAttributes());
347: }
348:
349: protected float getTabBase() {
350: return tabBase;
351: }
352: }
|