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.Component;
023: import java.awt.Graphics;
024: import java.awt.Rectangle;
025: import java.awt.Shape;
026: import java.util.ArrayList;
027:
028: import javax.swing.event.DocumentEvent;
029: import javax.swing.text.Position.Bias;
030:
031: import org.apache.harmony.awt.text.TextKit;
032: import org.apache.harmony.awt.text.TextUtils;
033:
034: import org.apache.harmony.x.swing.internal.nls.Messages;
035:
036: public class WrappedPlainView extends BoxView implements TabExpander {
037:
038: private class LineView extends View {
039:
040: private ArrayList breaks = new ArrayList();
041: private int wrappedWidth;
042:
043: public LineView(final Element element) {
044: super (element);
045: }
046:
047: public float getPreferredSpan(final int axis) {
048: final int width = getWidth();
049: if (axis == X_AXIS) {
050: return width > 0 ? width : getTextWidth(
051: getStartOffset(), getEndOffset());
052: }
053:
054: if (wrappedWidth != width) {
055: wrapLines();
056: wrappedWidth = width;
057: }
058: return getLineCount() * paintParams.metrics.getHeight();
059: }
060:
061: public void insertUpdate(final DocumentEvent event,
062: final Shape shape, final ViewFactory factory) {
063: updateView(shape);
064: super .insertUpdate(event, shape, factory);
065: }
066:
067: public Shape modelToView(final int pos, final Shape shape,
068: final Bias bias) throws BadLocationException {
069:
070: final int lineStart = getStartOffset();
071: int start = lineStart;
072: int end = getEndOffset() - 1;
073:
074: if (pos < start || pos > end) {
075: throw new BadLocationException(Messages
076: .getString("swing.98"), pos); //$NON-NLS-1$
077: }
078:
079: int lineNo = 0;
080: for (int i = 0; i < breaks.size(); i++) {
081: int breakPos = ((Integer) breaks.get(i)).intValue()
082: + lineStart;
083: if (pos < breakPos || bias == Bias.Backward
084: && pos == breakPos) {
085:
086: end = breakPos;
087: break;
088: }
089: start = breakPos;
090: ++lineNo;
091: }
092:
093: Rectangle bounds = shape.getBounds();
094: getDocument().getText(start, pos - start, getLineBuffer());
095: Rectangle result = new Rectangle(TextUtils
096: .getTabbedTextWidth(getLineBuffer(),
097: paintParams.metrics, bounds.x,
098: WrappedPlainView.this , pos)
099: + bounds.x, bounds.y + lineNo
100: * paintParams.metrics.getHeight(), 1,
101: paintParams.metrics.getHeight());
102: return result;
103: }
104:
105: public void paint(final Graphics g, final Shape shape) {
106: final int lineStart = getStartOffset();
107: int start = lineStart;
108: Rectangle bounds = shape.getBounds();
109: int y = bounds.y + paintParams.metrics.getHeight()
110: - paintParams.metrics.getDescent();
111:
112: if (breaks.size() > 0) {
113: for (int i = 0; i < breaks.size(); i++) {
114: int endPos = ((Integer) breaks.get(i)).intValue()
115: + lineStart;
116: paintLine(start, endPos, g, shape, bounds.x, y,
117: false);
118: start = endPos;
119: y += paintParams.metrics.getHeight();
120: }
121: }
122: paintLine(start, getEndOffset(), g, shape, bounds.x, y,
123: true);
124: }
125:
126: public void removeUpdate(final DocumentEvent event,
127: final Shape shape, final ViewFactory factory) {
128: updateView(shape);
129: super .removeUpdate(event, shape, factory);
130: }
131:
132: public int viewToModel(final float x, final float y,
133: final Shape shape, final Bias[] biasReturn) {
134: biasReturn[0] = Position.Bias.Forward;
135:
136: final Rectangle bounds = shape.getBounds();
137: final int lineHeight = paintParams.metrics.getHeight();
138:
139: final int lineNo = ((int) y - bounds.y) / lineHeight;
140:
141: if (lineNo > breaks.size()) {
142: return getEndOffset() - 1;
143: } else {
144: final Element line = getElement();
145: final int lineStart = line.getStartOffset();
146: final int start = lineNo > 0 && breaks.size() > 0 ? ((Integer) breaks
147: .get(lineNo - 1)).intValue()
148: + lineStart
149: : lineStart;
150: final int end = lineNo < breaks.size() ? ((Integer) breaks
151: .get(lineNo)).intValue()
152: + lineStart
153: : line.getEndOffset() - 1;
154:
155: try {
156: getDocument().getText(start, end - start,
157: getLineBuffer());
158: } catch (final BadLocationException e) {
159: }
160:
161: return start
162: + TextUtils.getTabbedTextOffset(
163: getLineBuffer(), paintParams.metrics,
164: bounds.x, (int) x,
165: WrappedPlainView.this , start);
166: }
167: }
168:
169: private int getLineCount() {
170: return breaks.size() + 1;
171: }
172:
173: private int getTextWidth(final int start, final int end) {
174: try {
175: getDocument().getText(start, end - start,
176: getLineBuffer());
177: } catch (BadLocationException e) {
178: e.printStackTrace();
179: }
180: return TextUtils.getTabbedTextWidth(getLineBuffer(),
181: paintParams.metrics, 0, WrappedPlainView.this ,
182: start);
183:
184: }
185:
186: private void paintHilite(final int start, final int end,
187: final Graphics g, final Shape shape) {
188: TextKit textKit = getTextKit();
189: if (textKit != null) {
190: textKit.paintLayeredHighlights(g, start, end, shape,
191: this );
192: }
193: }
194:
195: private void paintLine(final int start, final int end,
196: final Graphics g, final Shape shape, final int x,
197: final int y, final boolean chopDrawing) {
198: int drawEnd = end;
199: if (chopDrawing) {
200: --drawEnd;
201: }
202: paintHilite(start, drawEnd, g, shape);
203:
204: WrappedPlainView.this .drawLine(start, drawEnd, g, x, y);
205: }
206:
207: private void updateView(final Shape shape) {
208: final int lineCount = getLineCount();
209: final boolean widthValid = getWidth() > 0;
210: if (widthValid) {
211: wrapLines();
212: }
213: final boolean widthChanged = !widthValid;
214: final boolean heightChanged = lineCount != getLineCount();
215: if (widthChanged || heightChanged) {
216: preferenceChanged(this , widthChanged, heightChanged);
217: } else if (shape != null) {
218: Component c = getComponent();
219: if (c != null) {
220: Rectangle bounds = shape.getBounds();
221: getComponent().repaint(bounds.x, bounds.y,
222: bounds.width, bounds.height);
223: }
224: }
225: }
226:
227: private void wrapLines() {
228: final Element line = getElement();
229: final int lineStart = line.getStartOffset();
230: int start = lineStart;
231: int end = line.getEndOffset() - 1;
232:
233: breaks.clear();
234:
235: final int width = getWidth();
236: int textWidth = getTextWidth(start, end);
237: while (textWidth > width) {
238: int breakPos = calculateBreakPosition(start, end);
239: breaks.add(new Integer(breakPos - lineStart));
240: start = breakPos;
241: textWidth = getTextWidth(start, end);
242: }
243: }
244:
245: }
246:
247: final ViewFactory viewFactory = new ViewFactory() {
248: public View create(final Element element) {
249: return new LineView(element);
250: }
251: };
252:
253: private final TextPaintParams paintParams = new TextPaintParams(
254: this );
255:
256: private boolean wordWrap;
257:
258: public WrappedPlainView(final Element element) {
259: this (element, false);
260: }
261:
262: public WrappedPlainView(final Element element,
263: final boolean wordWrap) {
264: super (element, Y_AXIS);
265: this .wordWrap = wordWrap;
266: }
267:
268: public void changedUpdate(final DocumentEvent event,
269: final Shape shape, final ViewFactory factory) {
270: super .changedUpdate(event, shape, viewFactory);
271: }
272:
273: public float getMaximumSpan(final int axis) {
274: paintParams.conditionalUpdateMetrics();
275: return super .getMaximumSpan(axis);
276: }
277:
278: public float getMinimumSpan(final int axis) {
279: paintParams.conditionalUpdateMetrics();
280: return super .getMinimumSpan(axis);
281: }
282:
283: public float getPreferredSpan(final int axis) {
284: paintParams.conditionalUpdateMetrics();
285: return super .getPreferredSpan(axis);
286: }
287:
288: public ViewFactory getViewFactory() {
289: return viewFactory;
290: }
291:
292: public void insertUpdate(final DocumentEvent event,
293: final Shape shape, final ViewFactory factory) {
294: super .insertUpdate(event, shape, viewFactory);
295: }
296:
297: public float nextTabStop(final float x, final int tabOffset) {
298: return paintParams.nextTabStop(x);
299: }
300:
301: public void paint(final Graphics g, final Shape shape) {
302: paintParams.updateFields();
303: super .paint(g, shape);
304: }
305:
306: public void removeUpdate(final DocumentEvent event,
307: final Shape shape, final ViewFactory factory) {
308: super .removeUpdate(event, shape, viewFactory);
309: }
310:
311: public void setSize(final float width, final float height) {
312: if (getWidth() != width - getLeftInset() - getRightInset()) {
313: preferenceChanged(null, true, true);
314: }
315: paintParams.conditionalUpdateMetrics();
316: super .setSize(width, height);
317: }
318:
319: protected int calculateBreakPosition(final int start, final int end) {
320: paintParams.conditionalUpdateMetrics();
321:
322: try {
323: getDocument().getText(start, end - start,
324: paintParams.buffer);
325: } catch (BadLocationException e) {
326: }
327:
328: int offset;
329: if (wordWrap) {
330: offset = TextUtils.getBreakLocation(paintParams.buffer,
331: paintParams.metrics, 0, getWidth(), this , start);
332: } else {
333: offset = TextUtils.getTabbedTextOffset(paintParams.buffer,
334: paintParams.metrics, 0, getWidth(), this , start,
335: false);
336: }
337:
338: return offset + start;
339: }
340:
341: protected void drawLine(final int start, final int end,
342: final Graphics g, final int x, final int y) {
343: drawLine(paintParams, start, end, g, x, y);
344: }
345:
346: protected int drawSelectedText(final Graphics g, final int x,
347: final int y, final int start, final int end)
348: throws BadLocationException {
349:
350: return drawText(g, paintParams.selColor, paintParams, x, y,
351: start, end);
352: }
353:
354: protected int drawUnselectedText(final Graphics g, final int x,
355: final int y, final int start, final int end)
356: throws BadLocationException {
357:
358: return drawText(g, paintParams.color, paintParams, x, y, start,
359: end);
360: }
361:
362: protected final Segment getLineBuffer() {
363: return paintParams.buffer;
364: }
365:
366: protected int getTabSize() {
367: return paintParams.getTabSize();
368: }
369:
370: protected void loadChildren(final ViewFactory factory) {
371: super.loadChildren(viewFactory);
372: }
373: }
|