| 1 7 package javax.swing.text; 8 9 import java.util.Arrays ; 10 import java.awt.*; 11 import java.awt.font.TextAttribute ; 12 import javax.swing.event.*; 13 import javax.swing.SizeRequirements ; 14 15 33 public class ParagraphView extends FlowView implements TabExpander { 34 35 40 public ParagraphView(Element elem) { 41 super(elem, View.Y_AXIS); 42 setPropertiesFromAttributes(); 43 Document doc = elem.getDocument(); 44 Object i18nFlag = doc.getProperty(AbstractDocument.I18NProperty); 45 if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) { 46 try { 47 if (i18nStrategy == null) { 48 String classname = "javax.swing.text.TextLayoutStrategy"; 50 ClassLoader loader = getClass().getClassLoader(); 51 if (loader != null) { 52 i18nStrategy = loader.loadClass(classname); 53 } else { 54 i18nStrategy = Class.forName(classname); 55 } 56 } 57 Object o = i18nStrategy.newInstance(); 58 if (o instanceof FlowStrategy) { 59 strategy = (FlowStrategy) o; 60 } 61 } catch (Throwable e) { 62 throw new StateInvariantError ("ParagraphView: Can't create i18n strategy: " 63 + e.getMessage()); 64 } 65 } 66 } 67 68 78 protected void setJustification(int j) { 79 justification = j; 80 } 81 82 87 protected void setLineSpacing(float ls) { 88 lineSpacing = ls; 89 } 90 91 96 protected void setFirstLineIndent(float fi) { 97 firstLineIndent = (int) fi; 98 } 99 100 103 protected void setPropertiesFromAttributes() { 104 AttributeSet attr = getAttributes(); 105 if (attr != null) { 106 setParagraphInsets(attr); 107 Integer a = (Integer )attr.getAttribute(StyleConstants.Alignment); 108 int alignment; 109 if (a == null) { 110 Document doc = getElement().getDocument(); 111 Object o = doc.getProperty(TextAttribute.RUN_DIRECTION); 112 if ((o != null) && o.equals(TextAttribute.RUN_DIRECTION_RTL)) { 113 alignment = StyleConstants.ALIGN_RIGHT; 114 } else { 115 alignment = StyleConstants.ALIGN_LEFT; 116 } 117 } else { 118 alignment = a.intValue(); 119 } 120 setJustification(alignment); 121 setLineSpacing(StyleConstants.getLineSpacing(attr)); 122 setFirstLineIndent(StyleConstants.getFirstLineIndent(attr)); 123 } 124 } 125 126 139 protected int getLayoutViewCount() { 140 return layoutPool.getViewCount(); 141 } 142 143 156 protected View getLayoutView(int index) { 157 return layoutPool.getView(index); 158 } 159 160 174 protected void adjustRow(Row r, int desiredSpan, int x) { 175 } 176 177 192 protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b, 193 Shape a, int direction, 194 Position.Bias [] biasRet) 195 throws BadLocationException { 196 int vIndex; 197 if(pos == -1) { 198 vIndex = (direction == NORTH) ? 199 getViewCount() - 1 : 0; 200 } 201 else { 202 if(b == Position.Bias.Backward && pos > 0) { 203 vIndex = getViewIndexAtPosition(pos - 1); 204 } 205 else { 206 vIndex = getViewIndexAtPosition(pos); 207 } 208 if(direction == NORTH) { 209 if(vIndex == 0) { 210 return -1; 211 } 212 vIndex--; 213 } 214 else if(++vIndex >= getViewCount()) { 215 return -1; 216 } 217 } 218 JTextComponent text = (JTextComponent )getContainer(); 220 Caret c = text.getCaret(); 221 Point magicPoint; 222 magicPoint = (c != null) ? c.getMagicCaretPosition() : null; 223 int x; 224 if(magicPoint == null) { 225 Shape posBounds; 226 try { 227 posBounds = text.getUI().modelToView(text, pos, b); 228 } catch (BadLocationException exc) { 229 posBounds = null; 230 } 231 if(posBounds == null) { 232 x = 0; 233 } 234 else { 235 x = posBounds.getBounds().x; 236 } 237 } 238 else { 239 x = magicPoint.x; 240 } 241 return getClosestPositionTo(pos, b, a, direction, biasRet, vIndex, x); 242 } 243 244 261 protected int getClosestPositionTo(int pos, Position.Bias b, Shape a, 265 int direction, Position.Bias [] biasRet, 266 int rowIndex, int x) 267 throws BadLocationException { 268 JTextComponent text = (JTextComponent )getContainer(); 269 Document doc = getDocument(); 270 AbstractDocument aDoc = (doc instanceof AbstractDocument ) ? 271 (AbstractDocument )doc : null; 272 View row = getView(rowIndex); 273 int lastPos = -1; 274 biasRet[0] = Position.Bias.Forward; 276 for(int vc = 0, numViews = row.getViewCount(); vc < numViews; vc++) { 277 View v = row.getView(vc); 278 int start = v.getStartOffset(); 279 boolean ltr = (aDoc != null) ? aDoc.isLeftToRight 280 (start, start + 1) : true; 281 if(ltr) { 282 lastPos = start; 283 for(int end = v.getEndOffset(); lastPos < end; lastPos++) { 284 float xx = text.modelToView(lastPos).getBounds().x; 285 if(xx >= x) { 286 while (++lastPos < end && 287 text.modelToView(lastPos).getBounds().x == xx) { 288 } 289 return --lastPos; 290 } 291 } 292 lastPos--; 293 } 294 else { 295 for(lastPos = v.getEndOffset() - 1; lastPos >= start; 296 lastPos--) { 297 float xx = text.modelToView(lastPos).getBounds().x; 298 if(xx >= x) { 299 while (--lastPos >= start && 300 text.modelToView(lastPos).getBounds().x == xx) { 301 } 302 return ++lastPos; 303 } 304 } 305 lastPos++; 306 } 307 } 308 if(lastPos == -1) { 309 return getStartOffset(); 310 } 311 return lastPos; 312 } 313 314 338 protected boolean flipEastAndWestAtEnds(int position, 339 Position.Bias bias) { 340 Document doc = getDocument(); 341 if(doc instanceof AbstractDocument && 342 !((AbstractDocument )doc).isLeftToRight(getStartOffset(), 343 getStartOffset() + 1)) { 344 return true; 345 } 346 return false; 347 } 348 349 351 358 public int getFlowSpan(int index) { 359 View child = getView(index); 360 int adjust = 0; 361 if (child instanceof Row) { 362 Row row = (Row) child; 363 adjust = row.getLeftInset() + row.getRightInset(); 364 } 365 int span = layoutSpan - adjust; 366 return span; 367 } 368 369 376 public int getFlowStart(int index) { 377 View child = getView(index); 378 int adjust = 0; 379 if (child instanceof Row) { 380 Row row = (Row) child; 381 adjust = row.getLeftInset(); 382 } 383 return tabBase + adjust; 384 } 385 386 391 protected View createRow() { 392 return new Row(getElement()); 393 } 394 395 397 422 public float nextTabStop(float x, int tabOffset) { 423 if(justification != StyleConstants.ALIGN_LEFT) 425 return x + 10.0f; 426 x -= tabBase; 427 TabSet tabs = getTabSet(); 428 if(tabs == null) { 429 return (float)(tabBase + (((int)x / 72 + 1) * 72)); 431 } 432 TabStop tab = tabs.getTabAfter(x + .01f); 433 if(tab == null) { 434 return tabBase + x + 5.0f; 437 } 438 int alignment = tab.getAlignment(); 439 int offset; 440 switch(alignment) { 441 default: 442 case TabStop.ALIGN_LEFT: 443 return tabBase + tab.getPosition(); 445 case TabStop.ALIGN_BAR: 446 return tabBase + tab.getPosition(); 448 case TabStop.ALIGN_RIGHT: 449 case TabStop.ALIGN_CENTER: 450 offset = findOffsetToCharactersInString(tabChars, 451 tabOffset + 1); 452 break; 453 case TabStop.ALIGN_DECIMAL: 454 offset = findOffsetToCharactersInString(tabDecimalChars, 455 tabOffset + 1); 456 break; 457 } 458 if (offset == -1) { 459 offset = getEndOffset(); 460 } 461 float charsSize = getPartialSize(tabOffset + 1, offset); 462 switch(alignment) { 463 case TabStop.ALIGN_RIGHT: 464 case TabStop.ALIGN_DECIMAL: 465 return tabBase + Math.max(x, tab.getPosition() - charsSize); 469 case TabStop.ALIGN_CENTER: 470 return tabBase + Math.max(x, tab.getPosition() - charsSize / 2.0f); 472 } 473 return x; 475 } 476 477 482 protected TabSet getTabSet() { 483 return StyleConstants.getTabSet(getElement().getAttributes()); 484 } 485 486 500 protected float getPartialSize(int startOffset, int endOffset) { 501 float size = 0.0f; 502 int viewIndex; 503 int numViews = getViewCount(); 504 View view; 505 int viewEnd; 506 int tempEnd; 507 508 viewIndex = getElement().getElementIndex(startOffset); 512 numViews = layoutPool.getViewCount(); 513 while(startOffset < endOffset && viewIndex < numViews) { 514 view = layoutPool.getView(viewIndex++); 515 viewEnd = view.getEndOffset(); 516 tempEnd = Math.min(endOffset, viewEnd); 517 if(view instanceof TabableView ) 518 size += ((TabableView )view).getPartialSpan(startOffset, tempEnd); 519 else if(startOffset == view.getStartOffset() && 520 tempEnd == view.getEndOffset()) 521 size += view.getPreferredSpan(View.X_AXIS); 522 else 523 return 0.0f; 525 startOffset = viewEnd; 526 } 527 return size; 528 } 529 530 539 protected int findOffsetToCharactersInString(char[] string, 540 int start) { 541 int stringLength = string.length; 542 int end = getEndOffset(); 543 Segment seg = new Segment (); 544 try { 545 getDocument().getText(start, end - start, seg); 546 } catch (BadLocationException ble) { 547 return -1; 548 } 549 for(int counter = seg.offset, maxCounter = seg.offset + seg.count; 550 counter < maxCounter; counter++) { 551 char currentChar = seg.array[counter]; 552 for(int subCounter = 0; subCounter < stringLength; 553 subCounter++) { 554 if(currentChar == string[subCounter]) 555 return counter - seg.offset + start; 556 } 557 } 558 return -1; 560 } 561 562 566 protected float getTabBase() { 567 return (float)tabBase; 568 } 569 570 572 581 public void paint(Graphics g, Shape a) { 582 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds(); 583 tabBase = alloc.x + getLeftInset(); 584 super.paint(g, a); 585 586 if (firstLineIndent < 0) { 589 Shape sh = getChildAllocation(0, a); 590 if ((sh != null) && sh.intersects(alloc)) { 591 int x = alloc.x + getLeftInset() + firstLineIndent; 592 int y = alloc.y + getTopInset(); 593 594 Rectangle clip = g.getClipBounds(); 595 tempRect.x = x + getOffset(X_AXIS, 0); 596 tempRect.y = y + getOffset(Y_AXIS, 0); 597 tempRect.width = getSpan(X_AXIS, 0) - firstLineIndent; 598 tempRect.height = getSpan(Y_AXIS, 0); 599 if (tempRect.intersects(clip)) { 600 tempRect.x = tempRect.x - firstLineIndent; 601 paintChild(g, tempRect, 0); 602 } 603 } 604 } 605 } 606 607 621 public float getAlignment(int axis) { 622 switch (axis) { 623 case Y_AXIS: 624 float a = 0.5f; 625 if (getViewCount() != 0) { 626 int paragraphSpan = (int) getPreferredSpan(View.Y_AXIS); 627 View v = getView(0); 628 int rowSpan = (int) v.getPreferredSpan(View.Y_AXIS); 629 a = (paragraphSpan != 0) ? ((float)(rowSpan / 2)) / paragraphSpan : 0; 630 } 631 return a; 632 case X_AXIS: 633 return 0.5f; 634 default: 635 throw new IllegalArgumentException ("Invalid axis: " + axis); 636 } 637 } 638 639 657 public View breakView(int axis, float len, Shape a) { 658 if(axis == View.Y_AXIS) { 659 if(a != null) { 660 Rectangle alloc = a.getBounds(); 661 setSize(alloc.width, alloc.height); 662 } 663 665 return this; 667 } 668 return this; 669 } 670 671 687 public int getBreakWeight(int axis, float len) { 688 if(axis == View.Y_AXIS) { 689 return BadBreakWeight; 695 } 696 return BadBreakWeight; 697 } 698 699 709 public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) { 710 setPropertiesFromAttributes(); 713 layoutChanged(X_AXIS); 714 layoutChanged(Y_AXIS); 715 super.changedUpdate(changes, a, f); 716 } 717 718 719 721 private int justification; 722 private float lineSpacing; 723 724 protected int firstLineIndent = 0; 725 726 731 private int tabBase; 732 733 736 static Class i18nStrategy; 737 738 739 static char[] tabChars; 740 741 static char[] tabDecimalChars; 742 743 static { 744 tabChars = new char[1]; 745 tabChars[0] = '\t'; 746 tabDecimalChars = new char[2]; 747 tabDecimalChars[0] = '\t'; 748 tabDecimalChars[1] = '.'; 749 } 750 751 756 class Row extends BoxView { 757 758 Row(Element elem) { 759 super(elem, View.X_AXIS); 760 } 761 762 767 protected void loadChildren(ViewFactory f) { 768 } 769 770 775 public AttributeSet getAttributes() { 776 View p = getParent(); 777 return (p != null) ? p.getAttributes() : null; 778 } 779 780 public float getAlignment(int axis) { 781 if (axis == View.X_AXIS) { 782 switch (justification) { 783 case StyleConstants.ALIGN_LEFT: 784 return 0; 785 case StyleConstants.ALIGN_RIGHT: 786 return 1; 787 case StyleConstants.ALIGN_CENTER: 788 return 0.5f; 789 case StyleConstants.ALIGN_JUSTIFIED: 790 float rv = 0.5f; 791 if (isJustifiableDocument()) { 794 rv = 0f; 795 } 796 return rv; 797 } 798 } 799 return super.getAlignment(axis); 800 } 801 802 817 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 818 Rectangle r = a.getBounds(); 819 View v = getViewAtPosition(pos, r); 820 if ((v != null) && (!v.getElement().isLeaf())) { 821 return super.modelToView(pos, a, b); 823 } 824 r = a.getBounds(); 825 int height = r.height; 826 int y = r.y; 827 Shape loc = super.modelToView(pos, a, b); 828 r = loc.getBounds(); 829 r.height = height; 830 r.y = y; 831 return r; 832 } 833 834 839 public int getStartOffset() { 840 int offs = Integer.MAX_VALUE; 841 int n = getViewCount(); 842 for (int i = 0; i < n; i++) { 843 View v = getView(i); 844 offs = Math.min(offs, v.getStartOffset()); 845 } 846 return offs; 847 } 848 849 public int getEndOffset() { 850 int offs = 0; 851 int n = getViewCount(); 852 for (int i = 0; i < n; i++) { 853 View v = getView(i); 854 offs = Math.max(offs, v.getEndOffset()); 855 } 856 return offs; 857 } 858 859 879 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 880
|