| 1 7 package javax.swing.text; 8 9 import java.util.*; 10 import java.awt.*; 11 import javax.swing.SwingUtilities ; 12 import javax.swing.event.DocumentEvent ; 13 14 33 public class AsyncBoxView extends View { 34 35 42 public AsyncBoxView(Element elem, int axis) { 43 super(elem); 44 stats = new ArrayList(); 45 this.axis = axis; 46 locator = new ChildLocator(); 47 flushTask = new FlushTask(); 48 minorSpan = Short.MAX_VALUE; 49 estimatedMajorSpan = false; 50 } 51 52 57 public int getMajorAxis() { 58 return axis; 59 } 60 61 66 public int getMinorAxis() { 67 return (axis == X_AXIS) ? Y_AXIS : X_AXIS; 68 } 69 70 73 public float getTopInset() { 74 return topInset; 75 } 76 77 82 public void setTopInset(float i) { 83 topInset = i; 84 } 85 86 89 public float getBottomInset() { 90 return bottomInset; 91 } 92 93 98 public void setBottomInset(float i) { 99 bottomInset = i; 100 } 101 102 105 public float getLeftInset() { 106 return leftInset; 107 } 108 109 114 public void setLeftInset(float i) { 115 leftInset = i; 116 } 117 118 121 public float getRightInset() { 122 return rightInset; 123 } 124 125 130 public void setRightInset(float i) { 131 rightInset = i; 132 } 133 134 141 protected float getInsetSpan(int axis) { 142 float margin = (axis == X_AXIS) ? 143 getLeftInset() + getRightInset() : getTopInset() + getBottomInset(); 144 return margin; 145 } 146 147 160 protected void setEstimatedMajorSpan(boolean isEstimated) { 161 estimatedMajorSpan = isEstimated; 162 } 163 164 169 protected boolean getEstimatedMajorSpan() { 170 return estimatedMajorSpan; 171 } 172 173 180 protected ChildState getChildState(int index) { 181 synchronized(stats) { 182 if ((index >= 0) && (index < stats.size())) { 183 return (ChildState) stats.get(index); 184 } 185 return null; 186 } 187 } 188 189 192 protected LayoutQueue getLayoutQueue() { 193 return LayoutQueue.getDefaultQueue(); 194 } 195 196 201 protected ChildState createChildState(View v) { 202 return new ChildState(v); 203 } 204 205 223 protected synchronized void majorRequirementChange(ChildState cs, float delta) { 224 if (estimatedMajorSpan == false) { 225 majorSpan += delta; 226 } 227 majorChanged = true; 228 } 229 230 240 protected synchronized void minorRequirementChange(ChildState cs) { 241 minorChanged = true; 242 } 243 244 248 protected void flushRequirementChanges() { 249 AbstractDocument doc = (AbstractDocument ) getDocument(); 250 try { 251 doc.readLock(); 252 253 View parent = null; 254 boolean horizontal = false; 255 boolean vertical = false; 256 257 synchronized(this) { 258 synchronized(stats) { 261 int n = getViewCount(); 262 if ((n > 0) && (minorChanged || estimatedMajorSpan)) { 263 LayoutQueue q = getLayoutQueue(); 264 ChildState min = getChildState(0); 265 ChildState pref = getChildState(0); 266 float span = 0f; 267 for (int i = 1; i < n; i++) { 268 ChildState cs = getChildState(i); 269 if (minorChanged) { 270 if (cs.min > min.min) { 271 min = cs; 272 } 273 if (cs.pref > pref.pref) { 274 pref = cs; 275 } 276 } 277 if (estimatedMajorSpan) { 278 span += cs.getMajorSpan(); 279 } 280 } 281 282 if (minorChanged) { 283 minRequest = min; 284 prefRequest = pref; 285 } 286 if (estimatedMajorSpan) { 287 majorSpan = span; 288 estimatedMajorSpan = false; 289 majorChanged = true; 290 } 291 } 292 } 293 294 if (majorChanged || minorChanged) { 296 parent = getParent(); 297 if (parent != null) { 298 if (axis == X_AXIS) { 299 horizontal = majorChanged; 300 vertical = minorChanged; 301 } else { 302 vertical = majorChanged; 303 horizontal = minorChanged; 304 } 305 } 306 majorChanged = false; 307 minorChanged = false; 308 } 309 } 310 311 if (parent != null) { 314 parent.preferenceChanged(this, horizontal, vertical); 315 316 Component c = getContainer(); 318 if (c != null) { 319 c.repaint(); 320 } 321 } 322 } finally { 323 doc.readUnlock(); 324 } 325 } 326 327 339 public void replace(int offset, int length, View [] views) { 340 synchronized(stats) { 341 for (int i = 0; i < length; i++) { 343 ChildState cs = (ChildState)stats.remove(offset); 344 float csSpan = cs.getMajorSpan(); 345 346 cs.getChildView().setParent(null); 347 if (csSpan != 0) { 348 majorRequirementChange(cs, -csSpan); 349 } 350 } 351 352 LayoutQueue q = getLayoutQueue(); 354 if (views != null) { 355 for (int i = 0; i < views.length; i++) { 356 ChildState s = createChildState(views[i]); 357 stats.add(offset + i, s); 358 q.addTask(s); 359 } 360 } 361 362 q.addTask(flushTask); 364 } 365 } 366 367 385 protected void loadChildren(ViewFactory f) { 386 Element e = getElement(); 387 int n = e.getElementCount(); 388 if (n > 0) { 389 View [] added = new View [n]; 390 for (int i = 0; i < n; i++) { 391 added[i] = f.create(e.getElement(i)); 392 } 393 replace(0, 0, added); 394 } 395 } 396 397 406 protected synchronized int getViewIndexAtPosition(int pos, Position.Bias b) { 407 boolean isBackward = (b == Position.Bias.Backward); 408 pos = (isBackward) ? Math.max(0, pos - 1) : pos; 409 Element elem = getElement(); 410 return elem.getElementIndex(pos); 411 } 412 413 427 protected void updateLayout(DocumentEvent.ElementChange ec, 428 DocumentEvent e, Shape a) { 429 if (ec != null) { 430 int index = Math.max(ec.getIndex() - 1, 0); 435 ChildState cs = getChildState(index); 436 locator.childChanged(cs); 437 } 438 } 439 440 442 457 public void setParent(View parent) { 458 super.setParent(parent); 459 if ((parent != null) && (getViewCount() == 0)) { 460 ViewFactory f = getViewFactory(); 461 loadChildren(f); 462 } 463 } 464 465 477 public synchronized void preferenceChanged(View child, boolean width, boolean height) { 478 if (child == null) { 479 getParent().preferenceChanged(this, width, height); 480 } else { 481 if (changing != null) { 482 View cv = changing.getChildView(); 483 if (cv == child) { 484 changing.preferenceChanged(width, height); 487 return; 488 } 489 } 490 int index = getViewIndex(child.getStartOffset(), 491 Position.Bias.Forward); 492 ChildState cs = getChildState(index); 493 cs.preferenceChanged(width, height); 494 LayoutQueue q = getLayoutQueue(); 495 q.addTask(cs); 496 q.addTask(flushTask); 497 } 498 } 499 500 513 public void setSize(float width, float height) { 514 setSpanOnAxis(X_AXIS, width); 515 setSpanOnAxis(Y_AXIS, height); 516 } 517 518 525 float getSpanOnAxis(int axis) { 526 if (axis == getMajorAxis()) { 527 return majorSpan; 528 } 529 return minorSpan; 530 } 531 532 543 void setSpanOnAxis(int axis, float span) { 544 float margin = getInsetSpan(axis); 545 if (axis == getMinorAxis()) { 546 float targetSpan = span - margin; 547 if (targetSpan != minorSpan) { 548 minorSpan = targetSpan; 549 550 int n = getViewCount(); 553 if (n != 0) { 554 LayoutQueue q = getLayoutQueue(); 555 for (int i = 0; i < n; i++) { 556 ChildState cs = getChildState(i); 557 cs.childSizeValid = false; 558 q.addTask(cs); 559 } 560 q.addTask(flushTask); 561 } 562 } 563 } else { 564 if (estimatedMajorSpan) { 568 majorSpan = span - margin; 569 } 570 } 571 } 572 573 591 public void paint(Graphics g, Shape alloc) { 592 synchronized (locator) { 593 locator.setAllocation(alloc); 594 locator.paintChildren(g); 595 } 596 } 597 598 609 public float getPreferredSpan(int axis) { 610 float margin = getInsetSpan(axis); 611 if (axis == this.axis) { 612 return majorSpan + margin; 613 } 614 if (prefRequest != null) { 615 View child = prefRequest.getChildView(); 616 return child.getPreferredSpan(axis) + margin; 617 } 618 619 return margin + 30; 621 } 622 623 634 public float getMinimumSpan(int axis) { 635 if (axis == this.axis) { 636 return getPreferredSpan(axis); 637 } 638 if (minRequest != null) { 639 View child = minRequest.getChildView(); 640 return child.getMinimumSpan(axis); 641 } 642 643 if (axis == X_AXIS) { 645 return getLeftInset() + getRightInset() + 5; 646 } else { 647 return getTopInset() + getBottomInset() + 5; 648 } 649 } 650 651 662 public float getMaximumSpan(int axis) { 663 if (axis == this.axis) { 664 return getPreferredSpan(axis); 665 } 666 return Integer.MAX_VALUE; 667 } 668 669 670 678 public int getViewCount() { 679 synchronized(stats) { 680 return stats.size(); 681 } 682 } 683 684 691 public View getView(int n) { 692 ChildState cs = getChildState(n); 693 if (cs != null) { 694 return cs.getChildView(); 695 } 696 return null; 697 } 698 699 710 public Shape getChildAllocation(int index, Shape a) { 711 Shape ca = locator.getChildAllocation(index, a); 712 return ca; 713 } 714 715 726 public int getViewIndex(int pos, Position.Bias b) { 727 return getViewIndexAtPosition(pos, b); 728 } 729 730 745 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 746 int index = getViewIndex(pos, b); 747 Shape ca = locator.getChildAllocation(index, a); 748 749 ChildState cs = getChildState(index); 753 synchronized (cs) { 754 View cv = cs.getChildView(); 755 Shape v = cv.modelToView(pos, ca, b); 756 return v; 757 } 758 } 759 760 781 public int viewToModel(float x, float y, Shape a, Position.Bias [] biasReturn) { 782 int pos; int index; Shape ca; 786 synchronized (locator) { 792 index = locator.getViewIndexAtPoint(x, y, a); 793 ca = locator.getChildAllocation(index, a); 794 } 795 796 ChildState cs = getChildState(index); 800 synchronized (cs) { 801 View v = cs.getChildView(); 802 pos = v.viewToModel(x, y, ca, biasReturn); 803 } 804 return pos; 805 } 806 807 830 public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, 831 int direction, 832 Position.Bias [] biasRet) 833 throws BadLocationException { 834 return Utilities.getNextVisualPositionFrom( 835 this, pos, b, a, direction, biasRet); 836 } 837 838 840 844 int axis; 845 846 849 java.util.List stats; 850 851 857 float majorSpan; 858 859 862 boolean estimatedMajorSpan; 863 864 869 float minorSpan; 870 871 876 protected ChildLocator locator; 877 878 float topInset; 879 float bottomInset; 880 float leftInset; 881 float rightInset; 882 883 ChildState minRequest; 884 ChildState prefRequest; 885 boolean majorChanged; 886 boolean minorChanged; 887 Runnable flushTask; 888 889 896 ChildState changing; 897 898 906 public class ChildLocator { 907 908 911 public ChildLocator() { 912 lastAlloc = new Rectangle(); 913 childAlloc = new Rectangle(); 914 } 915 916 923 public synchronized void childChanged(ChildState cs) { 924 if (lastValidOffset == null) { 925 lastValidOffset = cs; 926 } else if (cs.getChildView().getStartOffset() < 927 lastValidOffset.getChildView().getStartOffset()) { 928 lastValidOffset = cs; 929 } 930 } 931 932 935 public synchronized void paintChildren(Graphics g) { 936 Rectangle clip = g.getClipBounds(); 937 float targetOffset = (axis == X_AXIS) ? 938 clip.x - lastAlloc.x : clip.y - lastAlloc.y; 939 int index = getViewIndexAtVisualOffset(targetOffset); 940 int n = getViewCount(); 941 float offs = getChildState(index).getMajorOffset(); 942 for (int i = index; i < n; i++) { 943 ChildState cs = getChildState(i); 944 cs.setMajorOffset(offs); 945 Shape ca = getChildAllocation(i); 946 if (intersectsClip(ca, clip)) { 947 synchronized (cs) { 948 View v = cs.getChildView(); 949 v.paint(g, ca); 950 } 951 } else { 952 break; 954 } 955 offs += cs.getMajorSpan(); 956 } 957 } 958 959 964 public synchronized Shape getChildAllocation(int index, Shape a) { 965 if (a == null) { 966 return null; 967 } 968 setAllocation(a); 969 ChildState cs = getChildState(index); 970 if (lastValidOffset == null) { 971 lastValidOffset = getChildState(0); 972 } 973 if (cs.getChildView().getStartOffset() > 974 lastValidOffset.getChildView().getStartOffset()) { 975 updateChildOffsetsToIndex(index); 977 } 978 Shape ca = getChildAllocation(index); 979 return ca; 980 } 981 982 996 public int getViewIndexAtPoint(float x, float y, Shape a) { 997 setAllocation(a); 998 float targetOffset = (axis == X_AXIS) ? x - lastAlloc.x : y - lastAlloc.y; 999 int index = getViewIndexAtVisualOffset(targetOffset); 1000 return index; 1001 } 1002 1003 1008 protected Shape getChildAllocation(int index) { 1009 ChildState cs = getChildState(index); 1010 if (! cs.isLayoutValid()) { 1011 cs.run(); 1012 } 1013 if (axis == X_AXIS) { 1014 childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset(); 1015 childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset(); 1016 childAlloc.width = (int) cs.getMajorSpan(); 1017 childAlloc.height = (int) cs.getMinorSpan(); 1018 } else { 1019 childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset(); 1020 childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset(); 1021 childAlloc.height = (int) cs.getMajorSpan(); 1022 childAlloc.width = (int) cs.getMinorSpan(); 1023 } 1024 childAlloc.x += (int)getLeftInset()
|