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:
52: public class PlainView extends View implements TabExpander
53: {
54: Color selectedColor;
55: Color unselectedColor;
56:
57:
60: Color disabledColor;
61:
62: Font font;
63:
64:
65: float maxLineLength = -1;
66:
67:
68: Element longestLine = null;
69:
70: protected FontMetrics metrics;
71:
72:
75: private transient Segment lineBuffer;
76:
77: public PlainView(Element elem)
78: {
79: super(elem);
80: }
81:
82:
85: protected void updateMetrics()
86: {
87: Component component = getContainer();
88: Font font = component.getFont();
89:
90: if (this.font != font)
91: {
92: this.font = font;
93: metrics = component.getFontMetrics(font);
94: }
95: }
96:
97:
100: protected Rectangle lineToRect(Shape a, int line)
101: {
102:
103: updateMetrics();
104:
105: Rectangle rect = a.getBounds();
106: int fontHeight = metrics.getHeight();
107: return new Rectangle(rect.x, rect.y + (line * fontHeight),
108: rect.width, fontHeight);
109: }
110:
111: public Shape modelToView(int position, Shape a, Position.Bias b)
112: throws BadLocationException
113: {
114:
115: updateMetrics();
116:
117: Document document = getDocument();
118:
119:
120: int lineIndex = getElement().getElementIndex(position);
121: Rectangle rect = lineToRect(a, lineIndex);
122:
123:
124: Element line = getElement().getElement(lineIndex);
125: int lineStart = line.getStartOffset();
126: Segment segment = getLineBuffer();
127: document.getText(lineStart, position - lineStart, segment);
128: int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
129: this, lineStart);
130:
131:
132: rect.x += xoffset;
133: rect.width = 1;
134: rect.height = metrics.getHeight();
135:
136: return rect;
137: }
138:
139: protected void drawLine(int lineIndex, Graphics g, int x, int y)
140: {
141: try
142: {
143: metrics = g.getFontMetrics();
144:
145: Element line = getElement().getElement(lineIndex);
146: drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset());
147:
148: }
149: catch (BadLocationException e)
150: {
151: AssertionError ae = new AssertionError("Unexpected bad location");
152: ae.initCause(e);
153: throw ae;
154: }
155: }
156:
157: protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
158: throws BadLocationException
159: {
160: g.setColor(selectedColor);
161: Segment segment = getLineBuffer();
162: getDocument().getText(p0, p1 - p0, segment);
163: return Utilities.drawTabbedText(segment, x, y, g, this, 0);
164: }
165:
166: protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
167: throws BadLocationException
168: {
169: JTextComponent textComponent = (JTextComponent) getContainer();
170: if (textComponent.isEnabled())
171: g.setColor(unselectedColor);
172: else
173: g.setColor(disabledColor);
174:
175: Segment segment = getLineBuffer();
176: getDocument().getText(p0, p1 - p0, segment);
177: return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
178: }
179:
180: public void paint(Graphics g, Shape s)
181: {
182:
183: updateMetrics();
184:
185: JTextComponent textComponent = (JTextComponent) getContainer();
186:
187: g.setFont(textComponent.getFont());
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:
329: int start = line.getStartOffset();
330: int end = line.getEndOffset();
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();
516: }
517: }
518:
519:
526: protected Segment getLineBuffer()
527: {
528: if (lineBuffer == null)
529: lineBuffer = new Segment();
530: return lineBuffer;
531: }
532: }