1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48:
49: import ;
50: import ;
51: import ;
52:
53: public class PlainView extends View implements TabExpander
54: {
55: Color selectedColor;
56: Color unselectedColor;
57:
58:
61: Color disabledColor;
62:
63: Font font;
64:
65:
66: float maxLineLength = -1;
67:
68:
69: Element longestLine = null;
70:
71: protected FontMetrics metrics;
72:
73:
76: private transient Segment lineBuffer;
77:
78: public PlainView(Element elem)
79: {
80: super(elem);
81: }
82:
83:
86: protected void updateMetrics()
87: {
88: Component component = getContainer();
89: Font font = component.getFont();
90:
91: if (this.font != font)
92: {
93: this.font = font;
94: metrics = component.getFontMetrics(font);
95: }
96: }
97:
98:
101: protected Rectangle lineToRect(Shape a, int line)
102: {
103:
104: updateMetrics();
105:
106: Rectangle rect = a.getBounds();
107: int fontHeight = metrics.getHeight();
108: return new Rectangle(rect.x, rect.y + (line * fontHeight),
109: rect.width, fontHeight);
110: }
111:
112: public Shape modelToView(int position, Shape a, Position.Bias b)
113: throws BadLocationException
114: {
115:
116: updateMetrics();
117:
118: Document document = getDocument();
119:
120:
121: int lineIndex = getElement().getElementIndex(position);
122: Rectangle rect = lineToRect(a, lineIndex);
123:
124:
125: Element line = getElement().getElement(lineIndex);
126: int lineStart = line.getStartOffset();
127: Segment segment = getLineBuffer();
128: document.getText(lineStart, position - lineStart, segment);
129: int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
130: this, lineStart);
131:
132:
133: rect.x += xoffset;
134: rect.width = 1;
135: rect.height = metrics.getHeight();
136:
137: return rect;
138: }
139:
140: protected void drawLine(int lineIndex, Graphics g, int x, int y)
141: {
142: try
143: {
144: metrics = g.getFontMetrics();
145:
146: Element line = getElement().getElement(lineIndex);
147: drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset());
148:
149: }
150: catch (BadLocationException e)
151: {
152: AssertionError ae = new AssertionError("Unexpected bad location");
153: ae.initCause(e);
154: throw ae;
155: }
156: }
157:
158: protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
159: throws BadLocationException
160: {
161: g.setColor(selectedColor);
162: Segment segment = getLineBuffer();
163: getDocument().getText(p0, p1 - p0, segment);
164: return Utilities.drawTabbedText(segment, x, y, g, this, 0);
165: }
166:
167: protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
168: throws BadLocationException
169: {
170: JTextComponent textComponent = (JTextComponent) getContainer();
171: if (textComponent.isEnabled())
172: g.setColor(unselectedColor);
173: else
174: g.setColor(disabledColor);
175:
176: Segment segment = getLineBuffer();
177: getDocument().getText(p0, p1 - p0, segment);
178: return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
179: }
180:
181: public void paint(Graphics g, Shape s)
182: {
183:
184: updateMetrics();
185:
186: JTextComponent textComponent = (JTextComponent) getContainer();
187:
188: g.setFont(textComponent.getFont());
189: selectedColor = textComponent.getSelectedTextColor();
190: unselectedColor = textComponent.getForeground();
191: disabledColor = textComponent.getDisabledTextColor();
192:
193: Rectangle rect = s.getBounds();
194:
195:
196: Document document = textComponent.getDocument();
197: Element root = document.getDefaultRootElement();
198: int y = rect.y;
199:
200: for (int i = 0; i < root.getElementCount(); i++)
201: {
202: drawLine(i, g, rect.x, y);
203: y += metrics.getHeight();
204: }
205: }
206:
207:
214: protected int getTabSize()
215: {
216: Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
217: if (tabSize == null)
218: return 8;
219: return ((Integer)tabSize).intValue();
220: }
221:
222:
230: public float nextTabStop(float x, int tabStop)
231: {
232: float tabSizePixels = getTabSize() * metrics.charWidth('m');
233: return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
234: }
235:
236:
240: float determineMaxLineLength()
241: {
242:
243: if (maxLineLength != -1)
244: return maxLineLength;
245:
246:
247: Element el = getElement();
248: Segment seg = getLineBuffer();
249: float span = 0;
250: for (int i = 0; i < el.getElementCount(); i++)
251: {
252: Element child = el.getElement(i);
253: int start = child.getStartOffset();
254: int end = child.getEndOffset();
255: try
256: {
257: el.getDocument().getText(start, end - start, seg);
258: }
259: catch (BadLocationException ex)
260: {
261: AssertionError ae = new AssertionError("Unexpected bad location");
262: ae.initCause(ex);
263: throw ae;
264: }
265:
266: if (seg == null || seg.array == null || seg.count == 0)
267: continue;
268:
269: int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
270: if (width > span)
271: {
272: longestLine = child;
273: span = width;
274: }
275: }
276: maxLineLength = span;
277: return maxLineLength;
278: }
279:
280: public float getPreferredSpan(int axis)
281: {
282: if (axis != X_AXIS && axis != Y_AXIS)
283: throw new IllegalArgumentException();
284:
285:
286: updateMetrics();
287:
288: float span = 0;
289: Element el = getElement();
290:
291: switch (axis)
292: {
293: case X_AXIS:
294: span = determineMaxLineLength();
295: case Y_AXIS:
296: default:
297: span = metrics.getHeight() * el.getElementCount();
298: break;
299: }
300: return span;
301: }
302:
303:
315: public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
316: {
317: Rectangle rec = a.getBounds();
318: Document doc = getDocument();
319: Element root = doc.getDefaultRootElement();
320:
321:
322:
323: int lineClicked = (int) (y - rec.y) / metrics.getHeight();
324: if (lineClicked >= root.getElementCount())
325: return getEndOffset() - 1;
326:
327: Element line = root.getElement(lineClicked);
328: Segment s = getLineBuffer();
329: int start = line.getStartOffset();
330:
331: int end = line.getEndOffset() - 1;
332: try
333: {
334: doc.getText(start, end - start, s);
335: }
336: catch (BadLocationException ble)
337: {
338: AssertionError ae = new AssertionError("Unexpected bad location");
339: ae.initCause(ble);
340: throw ae;
341: }
342:
343: int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start);
344: return Math.max (0, pos);
345: }
346:
347:
355: protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
356: {
357: Element el = getElement();
358: ElementChange ec = changes.getChange(el);
359:
360:
361:
362: if (ec == null)
363: {
364: int line = getElement().getElementIndex(changes.getOffset());
365: damageLineRange(line, line, a, getContainer());
366: return;
367: }
368:
369: Element[] removed = ec.getChildrenRemoved();
370: Element[] newElements = ec.getChildrenAdded();
371:
372:
373:
374: if (removed == null && newElements == null)
375: {
376: int line = getElement().getElementIndex(changes.getOffset());
377: damageLineRange(line, line, a, getContainer());
378: return;
379: }
380:
381:
382:
383: if (removed != null)
384: {
385: for (int i = 0; i < removed.length; i++)
386: if (removed[i].equals(longestLine))
387: {
388:
389: maxLineLength = -1;
390: determineMaxLineLength();
391: ((JTextComponent)getContainer()).repaint();
392: return;
393: }
394: }
395:
396:
397: if (newElements == null)
398: {
399:
400: ((JTextComponent)getContainer()).repaint();
401: return;
402: }
403:
404:
405: updateMetrics();
406:
407:
408:
409:
410: Segment seg = getLineBuffer();
411: float longestNewLength = 0;
412: Element longestNewLine = null;
413:
414:
415: for (int i = 0; i < newElements.length; i++)
416: {
417: Element child = newElements[i];
418: int start = child.getStartOffset();
419: int end = child.getEndOffset();
420: try
421: {
422: el.getDocument().getText(start, end - start, seg);
423: }
424: catch (BadLocationException ex)
425: {
426: AssertionError ae = new AssertionError("Unexpected bad location");
427: ae.initCause(ex);
428: throw ae;
429: }
430:
431: if (seg == null || seg.array == null || seg.count == 0)
432: continue;
433:
434: int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
435: if (width > longestNewLength)
436: {
437: longestNewLine = child;
438: longestNewLength = width;
439: }
440: }
441:
442:
443:
444: if (longestNewLength > maxLineLength)
445: {
446: maxLineLength = longestNewLength;
447: longestLine = longestNewLine;
448: }
449:
450: ((JTextComponent)getContainer()).repaint();
451: }
452:
453:
461: public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
462: {
463: updateDamage(changes, a, f);
464: }
465:
466:
474: public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
475: {
476: updateDamage(changes, a, f);
477: }
478:
479:
483: public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
484: {
485: updateDamage(changes, a, f);
486: }
487:
488:
502: protected void damageLineRange (int line0, int line1, Shape a, Component host)
503: {
504: if (a == null)
505: return;
506:
507: Rectangle rec0 = lineToRect(a, line0);
508: Rectangle rec1 = lineToRect(a, line1);
509:
510: if (rec0 == null || rec1 == null)
511:
512: host.repaint();
513: else
514: {
515: Rectangle repaintRec = rec0.union(rec1);
516: host.repaint();
517: }
518: }
519:
520:
527: protected Segment getLineBuffer()
528: {
529: if (lineBuffer == null)
530: lineBuffer = new Segment();
531: return lineBuffer;
532: }
533:
534:
555: public int getNextVisualPositionFrom(JTextComponent c, int pos,
556: Position.Bias b, int d,
557: Position.Bias[] biasRet)
558: throws BadLocationException
559: {
560:
561: throw new AssertionError("Not implemented yet.");
562: }
563: }