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: selectedColor = textComponent.getSelectedTextColor();
189: unselectedColor = textComponent.getForeground();
190: disabledColor = textComponent.getDisabledTextColor();
191:
192: Rectangle rect = s.getBounds();
193:
194:
195: Document document = textComponent.getDocument();
196: Element root = document.getDefaultRootElement();
197: int y = rect.y;
198:
199: for (int i = 0; i < root.getElementCount(); i++)
200: {
201: drawLine(i, g, rect.x, y);
202: y += metrics.getHeight();
203: }
204: }
205:
206:
213: protected int getTabSize()
214: {
215: Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
216: if (tabSize == null)
217: return 8;
218: return ((Integer)tabSize).intValue();
219: }
220:
221:
229: public float nextTabStop(float x, int tabStop)
230: {
231: float tabSizePixels = getTabSize() * metrics.charWidth('m');
232: return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
233: }
234:
235:
239: float determineMaxLineLength()
240: {
241:
242: if (maxLineLength != -1)
243: return maxLineLength;
244:
245:
246: Element el = getElement();
247: Segment seg = getLineBuffer();
248: float span = 0;
249: for (int i = 0; i < el.getElementCount(); i++)
250: {
251: Element child = el.getElement(i);
252: int start = child.getStartOffset();
253: int end = child.getEndOffset();
254: try
255: {
256: el.getDocument().getText(start, end - start, seg);
257: }
258: catch (BadLocationException ex)
259: {
260: AssertionError ae = new AssertionError("Unexpected bad location");
261: ae.initCause(ex);
262: throw ae;
263: }
264:
265: if (seg == null || seg.array == null || seg.count == 0)
266: continue;
267:
268: int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
269: if (width > span)
270: {
271: longestLine = child;
272: span = width;
273: }
274: }
275: maxLineLength = span;
276: return maxLineLength;
277: }
278:
279: public float getPreferredSpan(int axis)
280: {
281: if (axis != X_AXIS && axis != Y_AXIS)
282: throw new IllegalArgumentException();
283:
284:
285: updateMetrics();
286:
287: float span = 0;
288: Element el = getElement();
289:
290: switch (axis)
291: {
292: case X_AXIS:
293: span = determineMaxLineLength();
294: case Y_AXIS:
295: default:
296: span = metrics.getHeight() * el.getElementCount();
297: break;
298: }
299: return span;
300: }
301:
302:
314: public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
315: {
316: Rectangle rec = a.getBounds();
317: Document doc = getDocument();
318: Element root = doc.getDefaultRootElement();
319:
320:
321:
322: int lineClicked = (int) (y - rec.y) / metrics.getHeight();
323: if (lineClicked >= root.getElementCount())
324: return getEndOffset() - 1;
325:
326: Element line = root.getElement(lineClicked);
327: Segment s = getLineBuffer();
328: int start = line.getStartOffset();
329:
330: int end = line.getEndOffset() - 1;
331: try
332: {
333: doc.getText(start, end - start, s);
334: }
335: catch (BadLocationException ble)
336: {
337: AssertionError ae = new AssertionError("Unexpected bad location");
338: ae.initCause(ble);
339: throw ae;
340: }
341:
342: int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start);
343: return Math.max (0, pos);
344: }
345:
346:
354: protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
355: {
356: Element el = getElement();
357: ElementChange ec = changes.getChange(el);
358:
359:
360:
361: if (ec == null)
362: {
363: int line = getElement().getElementIndex(changes.getOffset());
364: damageLineRange(line, line, a, getContainer());
365: return;
366: }
367:
368: Element[] removed = ec.getChildrenRemoved();
369: Element[] newElements = ec.getChildrenAdded();
370:
371:
372:
373: if (removed == null && newElements == null)
374: {
375: int line = getElement().getElementIndex(changes.getOffset());
376: damageLineRange(line, line, a, getContainer());
377: return;
378: }
379:
380:
381:
382: if (removed != null)
383: {
384: for (int i = 0; i < removed.length; i++)
385: if (removed[i].equals(longestLine))
386: {
387:
388: maxLineLength = -1;
389: determineMaxLineLength();
390: ((JTextComponent)getContainer()).repaint();
391: return;
392: }
393: }
394:
395:
396: if (newElements == null)
397: {
398:
399: ((JTextComponent)getContainer()).repaint();
400: return;
401: }
402:
403:
404: updateMetrics();
405:
406:
407:
408:
409: Segment seg = getLineBuffer();
410: float longestNewLength = 0;
411: Element longestNewLine = null;
412:
413:
414: for (int i = 0; i < newElements.length; i++)
415: {
416: Element child = newElements[i];
417: int start = child.getStartOffset();
418: int end = child.getEndOffset();
419: try
420: {
421: el.getDocument().getText(start, end - start, seg);
422: }
423: catch (BadLocationException ex)
424: {
425: AssertionError ae = new AssertionError("Unexpected bad location");
426: ae.initCause(ex);
427: throw ae;
428: }
429:
430: if (seg == null || seg.array == null || seg.count == 0)
431: continue;
432:
433: int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
434: if (width > longestNewLength)
435: {
436: longestNewLine = child;
437: longestNewLength = width;
438: }
439: }
440:
441:
442:
443: if (longestNewLength > maxLineLength)
444: {
445: maxLineLength = longestNewLength;
446: longestLine = longestNewLine;
447: }
448:
449: ((JTextComponent)getContainer()).repaint();
450: }
451:
452:
460: public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
461: {
462: updateDamage(changes, a, f);
463: }
464:
465:
473: public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
474: {
475: updateDamage(changes, a, f);
476: }
477:
478:
482: public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
483: {
484: updateDamage(changes, a, f);
485: }
486:
487:
501: protected void damageLineRange (int line0, int line1, Shape a, Component host)
502: {
503: if (a == null)
504: return;
505:
506: Rectangle rec0 = lineToRect(a, line0);
507: Rectangle rec1 = lineToRect(a, line1);
508:
509: if (rec0 == null || rec1 == null)
510:
511: host.repaint();
512: else
513: {
514: Rectangle repaintRec = rec0.union(rec1);
515: host.repaint(repaintRec.x, repaintRec.y, repaintRec.width,
516: repaintRec.height);
517: }
518: }
519:
520:
527: protected Segment getLineBuffer()
528: {
529: if (lineBuffer == null)
530: lineBuffer = new Segment();
531: return lineBuffer;
532: }
533: }