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 37 public class WrappedPlainView extends BoxView implements TabExpander { 38 39 45 public WrappedPlainView(Element elem) { 46 this(elem, false); 47 } 48 49 57 public WrappedPlainView(Element elem, boolean wordWrap) { 58 super(elem, Y_AXIS); 59 this.wordWrap = wordWrap; 60 } 61 62 67 protected int getTabSize() { 68 Integer i = (Integer ) getDocument().getProperty(PlainDocument.tabSizeAttribute); 69 int size = (i != null) ? i.intValue() : 8; 70 return size; 71 } 72 73 88 protected void drawLine(int p0, int p1, Graphics g, int x, int y) { 89 Element lineMap = getElement(); 90 Element line = lineMap.getElement(lineMap.getElementIndex(p0)); 91 Element elem; 92 93 try { 94 if (line.isLeaf()) { 95 drawText(line, p0, p1, g, x, y); 96 } else { 97 int idx = line.getElementIndex(p0); 99 int lastIdx = line.getElementIndex(p1); 100 for(; idx <= lastIdx; idx++) { 101 elem = line.getElement(idx); 102 int start = Math.max(elem.getStartOffset(), p0); 103 int end = Math.min(elem.getEndOffset(), p1); 104 x = drawText(elem, start, end, g, x, y); 105 } 106 } 107 } catch (BadLocationException e) { 108 throw new StateInvariantError ("Can't render: " + p0 + "," + p1); 109 } 110 } 111 112 private int drawText(Element elem, int p0, int p1, Graphics g, int x, int y) throws BadLocationException { 113 p1 = Math.min(getDocument().getLength(), p1); 114 AttributeSet attr = elem.getAttributes(); 115 116 if (Utilities.isComposedTextAttributeDefined(attr)) { 117 g.setColor(unselected); 118 x = Utilities.drawComposedText(this, attr, g, x, y, 119 p0-elem.getStartOffset(), 120 p1-elem.getStartOffset()); 121 } else { 122 if (sel0 == sel1 || selected == unselected) { 123 x = drawUnselectedText(g, x, y, p0, p1); 125 } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { 126 x = drawSelectedText(g, x, y, p0, p1); 127 } else if (sel0 >= p0 && sel0 <= p1) { 128 if (sel1 >= p0 && sel1 <= p1) { 129 x = drawUnselectedText(g, x, y, p0, sel0); 130 x = drawSelectedText(g, x, y, sel0, sel1); 131 x = drawUnselectedText(g, x, y, sel1, p1); 132 } else { 133 x = drawUnselectedText(g, x, y, p0, sel0); 134 x = drawSelectedText(g, x, y, sel0, p1); 135 } 136 } else if (sel1 >= p0 && sel1 <= p1) { 137 x = drawSelectedText(g, x, y, p0, sel1); 138 x = drawUnselectedText(g, x, y, sel1, p1); 139 } else { 140 x = drawUnselectedText(g, x, y, p0, p1); 141 } 142 } 143 144 return x; 145 } 146 147 159 protected int drawUnselectedText(Graphics g, int x, int y, 160 int p0, int p1) throws BadLocationException { 161 g.setColor(unselected); 162 Document doc = getDocument(); 163 Segment segment = SegmentCache.getSharedSegment(); 164 doc.getText(p0, p1 - p0, segment); 165 int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0); 166 SegmentCache.releaseSharedSegment(segment); 167 return ret; 168 } 169 170 184 protected int drawSelectedText(Graphics g, int x, 185 int y, int p0, int p1) throws BadLocationException { 186 g.setColor(selected); 187 Document doc = getDocument(); 188 Segment segment = SegmentCache.getSharedSegment(); 189 doc.getText(p0, p1 - p0, segment); 190 int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0); 191 SegmentCache.releaseSharedSegment(segment); 192 return ret; 193 } 194 195 201 protected final Segment getLineBuffer() { 202 if (lineBuffer == null) { 203 lineBuffer = new Segment (); 204 } 205 return lineBuffer; 206 } 207 208 216 protected int calculateBreakPosition(int p0, int p1) { 217 int p; 218 Segment segment = SegmentCache.getSharedSegment(); 219 loadText(segment, p0, p1); 220 int currentWidth = getWidth(); 221 if (wordWrap) { 222 p = p0 + Utilities.getBreakLocation(segment, metrics, 223 tabBase, tabBase + currentWidth, 224 this, p0); 225 } else { 226 p = p0 + Utilities.getTabbedTextOffset(segment, metrics, 227 tabBase, tabBase + currentWidth, 228 this, p0, false); 229 } 230 SegmentCache.releaseSharedSegment(segment); 231 return p; 232 } 233 234 244 protected void loadChildren(ViewFactory f) { 245 Element e = getElement(); 246 int n = e.getElementCount(); 247 if (n > 0) { 248 View [] added = new View [n]; 249 for (int i = 0; i < n; i++) { 250 added[i] = new WrappedLine(e.getElement(i)); 251 } 252 replace(0, 0, added); 253 } 254 } 255 256 260 void updateChildren(DocumentEvent e, Shape a) { 261 Element elem = getElement(); 262 DocumentEvent.ElementChange ec = e.getChange(elem); 263 if (ec != null) { 264 Element [] removedElems = ec.getChildrenRemoved(); 266 Element [] addedElems = ec.getChildrenAdded(); 267 View [] added = new View [addedElems.length]; 268 for (int i = 0; i < addedElems.length; i++) { 269 added[i] = new WrappedLine(addedElems[i]); 270 } 271 replace(ec.getIndex(), removedElems.length, added); 272 273 if (a != null) { 275 preferenceChanged(null, true, true); 276 getContainer().repaint(); 277 } 278 } 279 280 updateMetrics(); 282 } 283 284 290 final void loadText(Segment segment, int p0, int p1) { 291 try { 292 Document doc = getDocument(); 293 doc.getText(p0, p1 - p0, segment); 294 } catch (BadLocationException bl) { 295 throw new StateInvariantError ("Can't get line text"); 296 } 297 } 298 299 final void updateMetrics() { 300 Component host = getContainer(); 301 Font f = host.getFont(); 302 metrics = host.getFontMetrics(f); 303 tabSize = getTabSize() * metrics.charWidth('m'); 304 } 305 306 308 318 public float nextTabStop(float x, int tabOffset) { 319 if (tabSize == 0) 320 return x; 321 int ntabs = ((int) x - tabBase) / tabSize; 322 return tabBase + ((ntabs + 1) * tabSize); 323 } 324 325 326 328 339 public void paint(Graphics g, Shape a) { 340 Rectangle alloc = (Rectangle) a; 341 tabBase = alloc.x; 342 JTextComponent host = (JTextComponent ) getContainer(); 343 sel0 = host.getSelectionStart(); 344 sel1 = host.getSelectionEnd(); 345 unselected = (host.isEnabled()) ? 346 host.getForeground() : host.getDisabledTextColor(); 347 Caret c = host.getCaret(); 348 selected = c.isSelectionVisible() && host.getHighlighter() != null ? 349 host.getSelectedTextColor() : unselected; 350 g.setFont(host.getFont()); 351 352 super.paint(g, a); 354 } 355 356 364 public void setSize(float width, float height) { 365 updateMetrics(); 366 if ((int) width != getWidth()) { 367 preferenceChanged(null, true, true); 370 widthChanging = true; 371 } 372 super.setSize(width, height); 373 widthChanging = false; 374 } 375 376 391 public float getPreferredSpan(int axis) { 392 updateMetrics(); 393 return super.getPreferredSpan(axis); 394 } 395 396 411 public float getMinimumSpan(int axis) { 412 updateMetrics(); 413 return super.getMinimumSpan(axis); 414 } 415 416 431 public float getMaximumSpan(int axis) { 432 updateMetrics(); 433 return super.getMaximumSpan(axis); 434 } 435 436 446 public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { 447 updateChildren(e, a); 448 449 Rectangle alloc = ((a != null) && isAllocationValid()) ? 450 getInsideAllocation(a) : null; 451 int pos = e.getOffset(); 452 View v = getViewAtPosition(pos, alloc); 453 if (v != null) { 454 v.insertUpdate(e, alloc, f); 455 } 456 } 457 458 468 public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 469 updateChildren(e, a); 470 471 Rectangle alloc = ((a != null) && isAllocationValid()) ? 472 getInsideAllocation(a) : null; 473 int pos = e.getOffset(); 474 View v = getViewAtPosition(pos, alloc); 475 if (v != null) { 476 v.removeUpdate(e, alloc, f); 477 } 478 } 479 480 489 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { 490 updateChildren(e, a); 491 } 492 493 495 FontMetrics metrics; 496 Segment lineBuffer; 497 boolean widthChanging; 498 int tabBase; 499 int tabSize; 500 boolean wordWrap; 501 502 int sel0; 503 int sel1; 504 Color unselected; 505 Color selected; 506 507 508 515 class WrappedLine extends View { 516 517 WrappedLine(Element elem) { 518 super(elem); 519 } 520 521 525 final int calculateLineCount() { 526 int nlines = 0; 527 int p1 = getEndOffset(); 528 for (int p0 = getStartOffset(); p0 < p1; ) { 529 nlines += 1; 530 int p = calculateBreakPosition(p0, p1); 531 p0 = (p == p0) ? ++p : p; } 537 return nlines; 538 } 539 540 551 public float getPreferredSpan(int axis) { 552 switch (axis) { 553 case View.X_AXIS: 554 float width = getWidth(); 555 if (width == Integer.MAX_VALUE) { 556 return 100f; 559 } 560 return width; 561 case View.Y_AXIS: 562 if (nlines == 0 || widthChanging) { 563 nlines = calculateLineCount(); 564 } 565 int h = nlines * metrics.getHeight(); 566 return h; 567 default: 568 throw new IllegalArgumentException ("Invalid axis: " + axis); 569 } 570 } 571 572 581 public void paint(Graphics g, Shape a) { 582 Rectangle alloc = (Rectangle) a; 583 int y = alloc.y + metrics.getAscent(); 584 int x = alloc.x; 585 586 JTextComponent host = (JTextComponent )getContainer(); 587 Highlighter h = host.getHighlighter(); 588 LayeredHighlighter dh = (h instanceof LayeredHighlighter ) ? 589 (LayeredHighlighter )h : null; 590 int p1 = getEndOffset(); 591 for (int p0 = getStartOffset(); p0 < p1; ) { 592 int p = calculateBreakPosition(p0, p1); 593 if (dh != null) { 594 if (p == p1) { 595 dh.paintLayeredHighlights(g, p0, p - 1, a, host, this); 596 } 597 else { 598 dh.paintLayeredHighlights(g, p0, p, a, host, this); 599 } 600 } 601 drawLine(p0, p, g, x, y); 602 603 p0 = (p == p0) ? p1 : p; 604 y += metrics.getHeight(); 605 } 606 } 607 608 619 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 620 Rectangle alloc = a.getBounds(); 621 alloc.height = metrics.getHeight(); 622 alloc.width = 1; 623 624 int p1 = getEndOffset(); 625 int p0 = getStartOffset(); 626 int testP = (b == Position.Bias.Forward) ? pos : 627 Math.max(p0, pos - 1); 628 while (p0 < p1) { 629 int p = calculateBreakPosition(p0, p1); 630 if ((pos >= p0) && (testP < p)) { 631 Segment segment = SegmentCache.getSharedSegment(); 633 loadText(segment, p0, pos); 634 alloc.x += Utilities.getTabbedTextWidth(segment, metrics, 635 alloc.x, 636 WrappedPlainView.this, p0); 637 SegmentCache.releaseSharedSegment(segment); 638 return alloc; 639 } 640 if (p == p1 && pos == p1) { 641 if (pos > p0) { 643 Segment segment = SegmentCache.getSharedSegment(); 644 loadText(segment, p0, pos); 645 alloc.x += Utilities.getTabbedTextWidth(segment, 646 metrics, alloc.x, 647 WrappedPlainView.this, p0); 648 SegmentCache.releaseSharedSegment(segment); 649 } 650 return alloc; 651 } 652 p0 = (p == p0) ? p1 : p; 653 alloc.y += alloc.height; 654 } 655 throw new BadLocationException (null, pos); 656 } 657 658 669 public int viewToModel(float fx, float fy, Shape a, Position.Bias [] bias) { 670 bias[0] = Position.Bias.Forward; 672 673 Rectangle alloc = (Rectangle) a; 674 Document doc = getDocument(); 675 int x = (int) fx; 676 int y = (int) fy; 677 if (y < alloc.y) { 678 return getStartOffset(); 681 } else if (y > alloc.y + alloc.height) { 682 return getEndOffset() - 1; 685 } else { 686 alloc.height = metrics.getHeight(); 692 int p1 = getEndOffset(); 693 for (int p0 = getStartOffset(); p0 < p1; ) { 694 int p = calculateBreakPosition(p0, p1); 695 if ((y >= alloc.y) && (y < (alloc.y + alloc.height))) { 696 if (x < alloc.x) { 698 return p0; 700 } else if (x > alloc.x + alloc.width) { 701 return p - 1; 703 } else { 704 Segment segment = SegmentCache.getSharedSegment(); 706 loadText(segment, p0, p1); 707 int n = Utilities.getTabbedTextOffset(segment, metrics, 708 alloc.x, x, 709 WrappedPlainView.this, p0); 710 SegmentCache.releaseSharedSegment(segment); 711 return Math.min(p0 + n, p1 - 1); 712 } 713 } 714 715 p0 = (p == p0) ? p1 : p; 716 alloc.y += alloc.height; 717 } 718 return getEndOffset() - 1; 719 } 720 } 721 722 public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { 723 int n = calculateLineCount(); 724 if (this.nlines != n) { 725 this.nlines = n; 726 WrappedPlainView.this.preferenceChanged(this, false, true); 727 getContainer().repaint(); 729 } 730 else if (a != null) { 731 Component c = getContainer(); 732 Rectangle alloc = (Rectangle) a; 733 c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 734 } 735 } 736 737 public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 738 int n = calculateLineCount(); 739 if (this.nlines != n) { 740 this.nlines = n; 742 WrappedPlainView.this.preferenceChanged(this, false, true); 743 getContainer().repaint(); 744 } 745 else if (a != null) { 746 Component c = getContainer(); 747 Rectangle alloc = (Rectangle) a; 748 c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 749 } 750 } 751 752 754 int nlines; 755 } 756 757 } 758 759 | Popular Tags |