1 7 package javax.swing.text; 8 9 import java.util.Vector ; 10 import java.util.Properties ; 11 import java.awt.*; 12 import javax.swing.event.*; 13 14 23 public class PlainView extends View implements TabExpander { 24 25 30 public PlainView(Element elem) { 31 super(elem); 32 } 33 34 39 protected int getTabSize() { 40 Integer i = (Integer ) getDocument().getProperty(PlainDocument.tabSizeAttribute); 41 int size = (i != null) ? i.intValue() : 8; 42 return size; 43 } 44 45 59 protected void drawLine(int lineIndex, Graphics g, int x, int y) { 60 Element line = getElement().getElement(lineIndex); 61 Element elem; 62 63 try { 64 if (line.isLeaf()) { 65 drawElement(lineIndex, line, g, x, y); 66 } else { 67 int count = line.getElementCount(); 69 for(int i = 0; i < count; i++) { 70 elem = line.getElement(i); 71 x = drawElement(lineIndex, elem, g, x, y); 72 } 73 } 74 } catch (BadLocationException e) { 75 throw new StateInvariantError ("Can't render line: " + lineIndex); 76 } 77 } 78 79 private int drawElement(int lineIndex, Element elem, Graphics g, int x, int y) throws BadLocationException { 80 int p0 = elem.getStartOffset(); 81 int p1 = elem.getEndOffset(); 82 p1 = Math.min(getDocument().getLength(), p1); 83 84 if (lineIndex == 0) { 85 x += firstLineOffset; 86 } 87 AttributeSet attr = elem.getAttributes(); 88 if (Utilities.isComposedTextAttributeDefined(attr)) { 89 g.setColor(unselected); 90 x = Utilities.drawComposedText(this, attr, g, x, y, 91 p0-elem.getStartOffset(), 92 p1-elem.getStartOffset()); 93 } else { 94 if (sel0 == sel1 || selected == unselected) { 95 x = drawUnselectedText(g, x, y, p0, p1); 97 } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { 98 x = drawSelectedText(g, x, y, p0, p1); 99 } else if (sel0 >= p0 && sel0 <= p1) { 100 if (sel1 >= p0 && sel1 <= p1) { 101 x = drawUnselectedText(g, x, y, p0, sel0); 102 x = drawSelectedText(g, x, y, sel0, sel1); 103 x = drawUnselectedText(g, x, y, sel1, p1); 104 } else { 105 x = drawUnselectedText(g, x, y, p0, sel0); 106 x = drawSelectedText(g, x, y, sel0, p1); 107 } 108 } else if (sel1 >= p0 && sel1 <= p1) { 109 x = drawSelectedText(g, x, y, p0, sel1); 110 x = drawUnselectedText(g, x, y, sel1, p1); 111 } else { 112 x = drawUnselectedText(g, x, y, p0, p1); 113 } 114 } 115 116 return x; 117 } 118 119 131 protected int drawUnselectedText(Graphics g, int x, int y, 132 int p0, int p1) throws BadLocationException { 133 g.setColor(unselected); 134 Document doc = getDocument(); 135 Segment s = SegmentCache.getSharedSegment(); 136 doc.getText(p0, p1 - p0, s); 137 int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0); 138 SegmentCache.releaseSharedSegment(s); 139 return ret; 140 } 141 142 156 protected int drawSelectedText(Graphics g, int x, 157 int y, int p0, int p1) throws BadLocationException { 158 g.setColor(selected); 159 Document doc = getDocument(); 160 Segment s = SegmentCache.getSharedSegment(); 161 doc.getText(p0, p1 - p0, s); 162 int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0); 163 SegmentCache.releaseSharedSegment(s); 164 return ret; 165 } 166 167 173 protected final Segment getLineBuffer() { 174 if (lineBuffer == null) { 175 lineBuffer = new Segment (); 176 } 177 return lineBuffer; 178 } 179 180 186 protected void updateMetrics() { 187 Component host = getContainer(); 188 Font f = host.getFont(); 189 if (font != f) { 190 calculateLongestLine(); 193 tabSize = getTabSize() * metrics.charWidth('m'); 194 } 195 } 196 197 199 210 public float getPreferredSpan(int axis) { 211 updateMetrics(); 212 switch (axis) { 213 case View.X_AXIS: 214 return getLineWidth(longLine); 215 case View.Y_AXIS: 216 return getElement().getElementCount() * metrics.getHeight(); 217 default: 218 throw new IllegalArgumentException ("Invalid axis: " + axis); 219 } 220 } 221 222 232 public void paint(Graphics g, Shape a) { 233 Shape originalA = a; 234 a = adjustPaintRegion(a); 235 Rectangle alloc = (Rectangle) a; 236 tabBase = alloc.x; 237 JTextComponent host = (JTextComponent ) getContainer(); 238 Highlighter h = host.getHighlighter(); 239 g.setFont(host.getFont()); 240 sel0 = host.getSelectionStart(); 241 sel1 = host.getSelectionEnd(); 242 unselected = (host.isEnabled()) ? 243 host.getForeground() : host.getDisabledTextColor(); 244 Caret c = host.getCaret(); 245 selected = c.isSelectionVisible() && h != null ? 246 host.getSelectedTextColor() : unselected; 247 updateMetrics(); 248 249 Rectangle clip = g.getClipBounds(); 254 int fontHeight = metrics.getHeight(); 255 int heightBelow = (alloc.y + alloc.height) - (clip.y + clip.height); 256 int linesBelow = Math.max(0, heightBelow / fontHeight); 257 int heightAbove = clip.y - alloc.y; 258 int linesAbove = Math.max(0, heightAbove / fontHeight); 259 int linesTotal = alloc.height / fontHeight; 260 261 if (alloc.height % fontHeight != 0) { 262 linesTotal++; 263 } 264 Rectangle lineArea = lineToRect(a, linesAbove); 266 int y = lineArea.y + metrics.getAscent(); 267 int x = lineArea.x; 268 Element map = getElement(); 269 int lineCount = map.getElementCount(); 270 int endLine = Math.min(lineCount, linesTotal - linesBelow); 271 lineCount--; 272 LayeredHighlighter dh = (h instanceof LayeredHighlighter ) ? 273 (LayeredHighlighter )h : null; 274 for (int line = linesAbove; line < endLine; line++) { 275 if (dh != null) { 276 Element lineElement = map.getElement(line); 277 if (line == lineCount) { 278 dh.paintLayeredHighlights(g, lineElement.getStartOffset(), 279 lineElement.getEndOffset(), 280 originalA, host, this); 281 } 282 else { 283 dh.paintLayeredHighlights(g, lineElement.getStartOffset(), 284 lineElement.getEndOffset() - 1, 285 originalA, host, this); 286 } 287 } 288 drawLine(line, g, x, y); 289 y += fontHeight; 290 if (line == 0) { 291 x -= firstLineOffset; 295 } 296 } 297 } 298 299 304 Shape adjustPaintRegion(Shape a) { 305 return a; 306 } 307 308 319 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 320 Document doc = getDocument(); 322 Element map = getElement(); 323 int lineIndex = map.getElementIndex(pos); 324 Rectangle lineArea = lineToRect(a, lineIndex); 325 326 tabBase = lineArea.x; 328 Element line = map.getElement(lineIndex); 329 int p0 = line.getStartOffset(); 330 Segment s = SegmentCache.getSharedSegment(); 331 doc.getText(p0, pos - p0, s); 332 int xOffs = Utilities.getTabbedTextWidth(s, metrics, tabBase, this,p0); 333 SegmentCache.releaseSharedSegment(s); 334 335 lineArea.x += xOffs; 337 lineArea.width = 1; 338 lineArea.height = metrics.getHeight(); 339 return lineArea; 340 } 341 342 353 public int viewToModel(float fx, float fy, Shape a, Position.Bias [] bias) { 354 bias[0] = Position.Bias.Forward; 356 357 Rectangle alloc = a.getBounds(); 358 Document doc = getDocument(); 359 int x = (int) fx; 360 int y = (int) fy; 361 if (y < alloc.y) { 362 return getStartOffset(); 365 } else if (y > alloc.y + alloc.height) { 366 return getEndOffset() - 1; 369 } else { 370 Element map = doc.getDefaultRootElement(); 376 int lineIndex = Math.abs((y - alloc.y) / metrics.getHeight() ); 377 if (lineIndex >= map.getElementCount()) { 378 return getEndOffset() - 1; 379 } 380 Element line = map.getElement(lineIndex); 381 int dx = 0; 382 if (lineIndex == 0) { 383 alloc.x += firstLineOffset; 384 alloc.width -= firstLineOffset; 385 } 386 if (x < alloc.x) { 387 return line.getStartOffset(); 389 } else if (x > alloc.x + alloc.width) { 390 return line.getEndOffset() - 1; 392 } else { 393 try { 395 int p0 = line.getStartOffset(); 396 int p1 = line.getEndOffset() - 1; 397 Segment s = SegmentCache.getSharedSegment(); 398 doc.getText(p0, p1 - p0, s); 399 tabBase = alloc.x; 400 int offs = p0 + Utilities.getTabbedTextOffset(s, metrics, 401 tabBase, x, this, p0); 402 SegmentCache.releaseSharedSegment(s); 403 return offs; 404 } catch (BadLocationException e) { 405 return -1; 407 } 408 } 409 } 410 } 411 412 421 public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) { 422 updateDamage(changes, a, f); 423 } 424 425 434 public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) { 435 updateDamage(changes, a, f); 436 } 437 438 447 public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) { 448 updateDamage(changes, a, f); 449 } 450 451 459 public void setSize(float width, float height) { 460 super.setSize(width, height); 461 updateMetrics(); 462 } 463 464 466 476 public float nextTabStop(float x, int tabOffset) { 477 if (tabSize == 0) { 478 return x; 479 } 480 int ntabs = (((int) x) - tabBase) / tabSize; 481 return tabBase + ((ntabs + 1) * tabSize); 482 } 483 484 486 496 protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { 497 Component host = getContainer(); 498 updateMetrics(); 499 Element elem = getElement(); 500 DocumentEvent.ElementChange ec = changes.getChange(elem); 501 502 Element [] added = (ec != null) ? ec.getChildrenAdded() : null; 503 Element [] removed = (ec != null) ? ec.getChildrenRemoved() : null; 504 if (((added != null) && (added.length > 0)) || 505 ((removed != null) && (removed.length > 0))) { 506 if (added != null) { 508 int currWide = getLineWidth(longLine); 509 for (int i = 0; i < added.length; i++) { 510 int w = getLineWidth(added[i]); 511 if (w > currWide) { 512 currWide = w; 513 longLine = added[i]; 514 } 515 } 516 } 517 if (removed != null) { 518 for (int i = 0; i < removed.length; i++) { 519 if (removed[i] == longLine) { 520 calculateLongestLine(); 521 break; 522 } 523 } 524 } 525 preferenceChanged(null, true, true); 526 host.repaint(); 527 } else { 528 Element map = getElement(); 529 int line = map.getElementIndex(changes.getOffset()); 530 damageLineRange(line, line, a, host); 531 if (changes.getType() == DocumentEvent.EventType.INSERT) { 532 int w = getLineWidth(longLine); 535 Element e = map.getElement(line); 536 if (e == longLine) { 537 preferenceChanged(null, true, false); 538 } else if (getLineWidth(e) > w) { 539 longLine = e; 540 preferenceChanged(null, true, false); 541 } 542 } else if (changes.getType() == DocumentEvent.EventType.REMOVE) { 543 if (map.getElement(line) == longLine) { 544 calculateLongestLine(); 546 preferenceChanged(null, true, false); 547 } 548 } 549 } 550 } 551 552 563 protected void damageLineRange(int line0, int line1, Shape a, Component host) { 564 if (a != null) { 565 Rectangle area0 = lineToRect(a, line0); 566 Rectangle area1 = lineToRect(a, line1); 567 if ((area0 != null) && (area1 != null)) { 568 Rectangle damage = area0.union(area1); 569 host.repaint(damage.x, damage.y, damage.width, damage.height); 570 } else { 571 host.repaint(); 572 } 573 } 574 } 575 576 584 protected Rectangle lineToRect(Shape a, int line) { 585 Rectangle r = null; 586 updateMetrics(); 587 if (metrics != null) { 588 Rectangle alloc = a.getBounds(); 589 if (line == 0) { 590 alloc.x += firstLineOffset; 591 alloc.width -= firstLineOffset; 592 } 593 r = new Rectangle(alloc.x, alloc.y + (line * metrics.getHeight()), 594 alloc.width, metrics.getHeight()); 595 } 596 return r; 597 } 598 599 607 private void calculateLongestLine() { 608 Component c = getContainer(); 609 font = c.getFont(); 610 metrics = c.getFontMetrics(font); 611 Document doc = getDocument(); 612 Element lines = getElement(); 613 int n = lines.getElementCount(); 614 int maxWidth = -1; 615 for (int i = 0; i < n; i++) { 616 Element line = lines.getElement(i); 617 int w = getLineWidth(line); 618 if (w > maxWidth) { 619 maxWidth = w; 620 longLine = line; 621 } 622 } 623 } 624 625 630 private int getLineWidth(Element line) { 631 int p0 = line.getStartOffset(); 632 int p1 = line.getEndOffset(); 633 int w; 634 Segment s = SegmentCache.getSharedSegment(); 635 try { 636 line.getDocument().getText(p0, p1 - p0, s); 637 w = Utilities.getTabbedTextWidth(s, metrics, tabBase, this, p0); 638 } catch (BadLocationException ble) { 639 w = 0; 640 } 641 SegmentCache.releaseSharedSegment(s); 642 return w; 643 } 644 645 647 650 protected FontMetrics metrics; 651 652 658 Element longLine; 659 660 664 Font font; 665 666 Segment lineBuffer; 667 int tabSize; 668 int tabBase; 669 670 int sel0; 671 int sel1; 672 Color unselected; 673 Color selected; 674 675 681 int firstLineOffset; 682 683 } 684 | Popular Tags |