1 19 20 package org.netbeans.lib.editor.view; 21 22 import java.awt.Component ; 23 import java.awt.Graphics ; 24 import java.awt.Rectangle ; 25 import java.awt.Shape ; 26 import java.util.ArrayList ; 27 import java.util.List ; 28 import javax.swing.event.DocumentEvent ; 29 import javax.swing.text.AbstractDocument ; 30 import javax.swing.text.AttributeSet ; 31 import javax.swing.text.BadLocationException ; 32 import javax.swing.text.Document ; 33 import javax.swing.text.Element ; 34 import javax.swing.text.LayoutQueue ; 35 import javax.swing.text.Position ; 36 import javax.swing.text.StyleConstants ; 37 import javax.swing.text.View ; 38 import javax.swing.text.ViewFactory ; 39 import org.netbeans.editor.view.spi.EstimatedSpanView; 40 import org.netbeans.editor.view.spi.LockView; 41 import org.netbeans.editor.view.spi.ViewInsets; 42 import org.netbeans.editor.view.spi.ViewLayoutQueue; 43 import org.netbeans.editor.view.spi.ViewLayoutState; 44 import org.netbeans.editor.view.spi.ViewUtilities; 45 import org.netbeans.lib.editor.util.swing.ElementUtilities; 46 47 49 130 131 public class GapBoxView extends View 132 implements ViewLayoutState.Parent, ViewLayoutState, 133 EstimatedSpanView { 134 135 private static final boolean debugRebuild 136 = Boolean.getBoolean("netbeans.debug.editor.view.rebuild"); 138 145 private static final int X_MAJOR_AXIS_BIT = 1; 146 147 153 private static final int MAJOR_AXES_ORTHOGONAL_BIT = 2; 154 155 159 private static final int MAJOR_AXIS_PREFERENCE_CHANGED_BIT = 4; 160 161 165 private static final int MINOR_AXIS_PREFERENCE_CHANGED_BIT = 8; 166 167 172 private static final int CHILDREN_LAYOUT_NECESSARY_BIT = 16; 173 174 179 private static final int REPAINT_PENDING_BIT = 32; 180 181 189 private static final int REPAINT_TILL_END_BIT = 64; 190 191 197 private static final int ESTIMATED_SPAN_BIT = 128; 198 199 203 private static final int UPDATE_LAYOUT_IN_PROGRESS = 256; 204 205 211 private static final int ACTIVE_LAYOUT_STATE = 512; 212 213 214 216 221 private static final int LAYOUT_STATE_X_MAJOR_AXIS_BIT 222 = (ACTIVE_LAYOUT_STATE << 1); 223 224 229 private static final int LAYOUT_STATE_VIEW_SIZE_INVALID_BIT 230 = (LAYOUT_STATE_X_MAJOR_AXIS_BIT << 1); 231 232 236 protected static final int GAP_BOX_VIEW_LAST_USED_STATUS_BIT 237 = LAYOUT_STATE_VIEW_SIZE_INVALID_BIT; 238 239 244 private static final int LAYOUT_STATE_ANY_INVALID 245 = MAJOR_AXIS_PREFERENCE_CHANGED_BIT 246 | MINOR_AXIS_PREFERENCE_CHANGED_BIT 247 | LAYOUT_STATE_VIEW_SIZE_INVALID_BIT 248 | REPAINT_PENDING_BIT; 249 250 253 private int statusBits; 255 258 private GapBoxViewChildren children; 260 264 private double layoutStateMajorAxisRawOffset; 266 270 private int viewRawIndex; 272 285 private float lastMajorAxisPreferredSpan; 287 296 private float lastMinorAxisPreferredSpan; 298 303 private float minorAxisAssignedSpan; 305 312 public GapBoxView(Element elem, int majorAxis) { 313 super(elem); 314 315 if (majorAxis == View.X_AXIS) { 316 setStatusBits(X_MAJOR_AXIS_BIT); 317 } } 319 320 331 public float getPreferredSpan(int axis) { 332 334 return (axis == getMajorAxis()) 335 ? (float)getMajorAxisPreferredSpan() 336 : getMinorAxisPreferredSpan(); 337 } 338 339 347 public float getMinimumSpan(int axis) { 348 return getPreferredSpan(axis); } 353 354 362 public float getMaximumSpan(int axis) { 363 return getPreferredSpan(axis); } 368 369 public float getAlignment(int axis) { 370 return 0.0f; 371 } 372 373 379 public ViewInsets getInsets() { 380 return null; 381 } 382 383 386 final double getMajorAxisPreferredSpan() { 387 return (children != null) 388 ? children.getMajorAxisPreferredSpan() + getMajorAxisInsetSpan() 389 : lastMajorAxisPreferredSpan; } 391 392 final float getMinorAxisPreferredSpan() { 393 return (children != null) 394 ? children.getMinorAxisPreferredSpan() + getMinorAxisInsetSpan() 395 : lastMinorAxisPreferredSpan; 396 } 397 398 402 final float getMinorAxisAssignedSpan() { 403 return minorAxisAssignedSpan; 404 } 405 406 411 public final int getMajorAxis() { 412 return isXMajorAxis() ? View.X_AXIS : View.Y_AXIS; 413 } 414 415 420 public final int getMinorAxis() { 421 return isXMajorAxis() ? View.Y_AXIS : View.X_AXIS; 422 } 423 424 427 final boolean isXMajorAxis() { 428 return isStatusBitsNonZero(X_MAJOR_AXIS_BIT); 429 } 430 431 444 final boolean isMajorAxesOrthogonal() { 445 return isStatusBitsNonZero(MAJOR_AXES_ORTHOGONAL_BIT); 446 } 447 448 454 public int getViewCount() { 455 return getChildren().getChildCount(); 456 } 457 458 464 public View getView(int index) { 465 return getChild(index).getView(); 466 } 467 468 485 public void replace(int index, int length, View [] views) { 486 if (length < 0) { 487 throw new IllegalArgumentException ("length=" + length + " < 0"); } 489 490 if (length == 0 && (views == null || views.length == 0)) { return; 492 } 493 494 GapBoxViewChildren children = getChildren(); 496 497 children.replace(index, length, views); 500 } 501 502 511 protected int getReplaceEstimatedThreshold() { 512 return Integer.MAX_VALUE; 513 } 514 515 public final boolean isEstimatedSpan() { 516 return isStatusBitsNonZero(ESTIMATED_SPAN_BIT); 517 } 518 519 public void setEstimatedSpan(boolean estimatedSpan) { 520 if (isEstimatedSpan() != estimatedSpan) { if (estimatedSpan) { 522 setStatusBits(ESTIMATED_SPAN_BIT); 523 } else { 524 clearStatusBits(ESTIMATED_SPAN_BIT); 525 526 if (children != null) { 528 int viewCount = getViewCount(); 529 if (viewCount > 0) { 530 resetEstimatedSpan(0, viewCount); } 532 } 533 } 534 535 } 536 } 537 538 547 protected void resetEstimatedSpan(int childIndex, int count) { 548 while (--count >= 0) { 549 ViewLayoutState child = getChild(childIndex); 550 View childView = child.getView(); 551 if (childView instanceof EstimatedSpanView) { 552 ((EstimatedSpanView)childView).setEstimatedSpan(false); 553 } 554 childIndex++; 555 } 556 } 557 558 572 public void rebuild(int index, int count) { 573 if (count != 0) { 574 int startOffset = (index == 0) ? -1 : getView(index - 1).getEndOffset(); 575 int viewCount = getViewCount(); 576 int endIndex = Math.min(index + count, viewCount); 577 int endOffset = (endIndex == viewCount) ? -1 : getView(endIndex).getStartOffset(); 578 579 if (debugRebuild) { 580 System.err.println("GapBoxView.rebuild(): index=" + index + ", count=" + count + ", so=" + startOffset + ", eo=" + endOffset ); 584 } 585 586 reloadChildren(index, count, startOffset, endOffset); 587 } 588 } 589 590 598 public void offsetRebuild(int startOffset, int endOffset) { 599 int index = ViewUtilitiesImpl.findLowerViewIndex(this, startOffset, false); 600 int count; 601 if (index == -1) { index = 0; 603 count = 0; 604 605 } else { count = ViewUtilitiesImpl.findUpperViewIndex(this, endOffset, true) - index + 1; 607 } 608 609 rebuild(index, count); 610 } 611 612 621 public void setParent(View parent) { 622 super.setParent(parent); 623 624 628 if (parent != null) { 629 if (parent instanceof ViewLayoutState.Parent) { 630 setStatusBits(ACTIVE_LAYOUT_STATE); 631 } else { 632 clearStatusBits(ACTIVE_LAYOUT_STATE); 633 } 634 635 getChildren(); 637 638 } else { releaseChildren(); 640 clearStatusBits(ACTIVE_LAYOUT_STATE); 641 } 642 } 643 644 public final boolean isActiveLayoutState() { 645 return isStatusBitsNonZero(ACTIVE_LAYOUT_STATE); 646 } 647 648 protected GapBoxViewChildren getChildren() { 649 if (children == null) { 650 children = createChildren(); 651 652 View parent = getParent(); 654 if (parent != null) { reloadChildren(0, 0, -1, -1); 656 } 657 } 658 659 return children; 660 } 661 662 665 protected final GapBoxViewChildren getChildrenNull() { 666 return children; 667 } 668 669 677 public void releaseChildren() { 678 if (children != null) { 679 unloadChildren(); 680 681 children.unload(); 682 children = null; 683 } 684 } 685 686 public final View getView() { 688 return this; 689 } 690 691 public ViewLayoutState selectLayoutMajorAxis(int axis) { 693 695 if (axis == View.X_AXIS) { 696 setStatusBits(LAYOUT_STATE_X_MAJOR_AXIS_BIT); 697 } else { clearStatusBits(LAYOUT_STATE_X_MAJOR_AXIS_BIT); 699 } 700 701 if (axis == getMajorAxis()) { clearStatusBits(MAJOR_AXES_ORTHOGONAL_BIT); 705 } else { setStatusBits(MAJOR_AXES_ORTHOGONAL_BIT); 707 } 708 709 return this; 710 } 711 712 public boolean isFlyweight() { 714 return false; 715 } 716 717 public void updateLayout() { 719 if (isLayoutValid()) { return; 721 } 722 723 if (isStatusBitsNonZero(UPDATE_LAYOUT_IN_PROGRESS)) { 724 return; 725 } 726 setStatusBits(UPDATE_LAYOUT_IN_PROGRESS); 727 728 View parent = getParent(); 729 if (parent == null) { return; 731 } 732 ViewLayoutState.Parent lsParent = (parent instanceof ViewLayoutState.Parent) 733 ? (ViewLayoutState.Parent)parent 734 : null; 735 736 children.childrenUpdateLayout(); 738 739 if (isChildrenLayoutNecessary()) { 741 resetChildrenLayoutNecessary(); 742 743 children.childrenLayout(); } 745 746 boolean parentWillRepaint = false; 748 749 boolean majorAxisPreferenceChanged = isMajorAxisPreferenceChanged(); 753 boolean minorAxisPreferenceChanged = isMinorAxisPreferenceChanged(); 754 resetAxesPreferenceChanged(); 755 756 if (majorAxisPreferenceChanged) { 757 if (children != null) { double delta = updateLastMajorAxisPreferredSpan(); 760 if (delta != 0.0d && lsParent != null) { 761 if (isMajorAxesOrthogonal()) { 762 lsParent.minorAxisPreferenceChanged(this); 763 } else { 764 lsParent.majorAxisPreferenceChanged(this, delta); 765 parentWillRepaint = true; 766 } 767 } 768 } 769 } 770 771 if (minorAxisPreferenceChanged) { 772 if (children != null) { double delta = updateLastMinorAxisPreferredSpan(); 775 if (delta != 0.0d && lsParent != null) { 776 if (isMajorAxesOrthogonal()) { 777 lsParent.majorAxisPreferenceChanged(this, delta); 778 parentWillRepaint = true; 779 } else { 780 lsParent.minorAxisPreferenceChanged(this); 781 } 782 } 783 } 784 } 785 786 if (majorAxisPreferenceChanged || minorAxisPreferenceChanged || !isActiveLayoutState()) { 791 boolean horizontalChange = false; 793 boolean verticalChange = false; 794 795 if (isXMajorAxis()) { 796 horizontalChange = majorAxisPreferenceChanged; 797 verticalChange = minorAxisPreferenceChanged; 798 } else { 799 horizontalChange = minorAxisPreferenceChanged; 800 verticalChange = majorAxisPreferenceChanged; 801 } 802 803 parent.preferenceChanged(this, horizontalChange, verticalChange); 804 } 805 806 if (isStatusBitsNonZero(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT)) { 808 clearStatusBits(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT); 809 810 if (lsParent != null) { float width; 812 float height; 813 float layoutStateMajorAxisSpan = getPreferredSpan(getLayoutStateMajorAxis()); 814 float layoutStateMinorAxisSpan = lsParent.getMinorAxisSpan(this); 815 if (isXLayoutStateMajorAxis()) { 816 width = layoutStateMajorAxisSpan; 817 height = layoutStateMinorAxisSpan; 818 } else { 819 width = layoutStateMinorAxisSpan; 820 height = layoutStateMajorAxisSpan; 821 } 822 823 setSize(width, height); 824 } 825 } 826 827 if (children != null && isRepaintPending()) { 828 if (!parentWillRepaint) { 829 processRepaint(lsParent); 830 } 831 resetRepaintPending(); 833 } 834 835 clearStatusBits(UPDATE_LAYOUT_IN_PROGRESS); 836 837 updateLayout(); 839 } 840 841 853 protected void updateLayout(DocumentEvent.ElementChange ec, 854 DocumentEvent e, Shape a) { 855 856 } 858 859 863 public void layoutInvalid(ViewLayoutState child) { 864 int childIndex = children.getChildIndexNoCheck(child); 865 children.markLayoutInvalid(childIndex, 1); 866 } 867 868 protected void markLayoutInvalid() { 869 if (isActiveLayoutState()) { 870 ((ViewLayoutState.Parent)getParent()).layoutInvalid(this); 871 } else { directUpdateLayout(); 874 } 875 } 876 877 885 protected void directUpdateLayout() { 886 updateLayout(); 887 } 888 889 894 protected void processRepaint(ViewLayoutState.Parent lsParent) { 895 if (lsParent != null) { int firstRepaintChildIndex = children.getFirstRepaintChildIndex(); 897 double majorAxisOffset = children.getMajorAxisOffset(firstRepaintChildIndex); 898 double repaintMajorOffset; 899 double repaintMajorSpan; 900 float repaintMinorOffset; 901 float repaintMinorSpan; 902 if (isRepaintTillEnd() 903 || firstRepaintChildIndex >= getViewCount() ) { 905 if (isMajorAxesOrthogonal()) { 906 repaintMajorOffset = 0; 907 repaintMajorSpan = 0; repaintMinorOffset = (float)majorAxisOffset; 909 repaintMinorSpan = 0; 911 } else { repaintMajorOffset = majorAxisOffset; 913 repaintMajorSpan = 0; repaintMinorOffset = 0; 915 repaintMinorSpan = 0; } 917 918 } else { double majorAxisSpan = getChild(firstRepaintChildIndex).getLayoutMajorAxisPreferredSpan(); 920 if (isMajorAxesOrthogonal()) { 921 repaintMajorOffset = 0; 922 repaintMajorSpan = 0; repaintMinorOffset = (float)majorAxisOffset; 924 repaintMinorSpan = (float)majorAxisSpan; 925 926 } else { repaintMajorOffset = majorAxisOffset; 928 repaintMajorSpan = majorAxisSpan; 929 repaintMinorOffset = 0; 930 repaintMinorSpan = 0; } 932 } 933 934 lsParent.repaint(this, repaintMajorOffset, repaintMajorSpan, 935 repaintMinorOffset, repaintMinorSpan); 936 937 } else { Component c = getContainer(); 939 if (c != null) { 940 c.repaint(); 941 } 942 } 943 } 944 945 954 protected boolean markRepaint(int childIndex, boolean repaintTillEnd) { 955 boolean lowerIndexMarked = false; 956 if (children != null) { 957 int firstRepaintChildIndex = children.getFirstRepaintChildIndex(); 958 if (!isRepaintTillEnd()) { if (firstRepaintChildIndex == -1) { lowerIndexMarked = true; 961 markRepaintPending(); 962 children.setFirstRepaintChildIndex(childIndex); 963 if (repaintTillEnd) { 964 setStatusBits(REPAINT_TILL_END_BIT); 965 } 966 967 } else if (firstRepaintChildIndex != childIndex) { if (childIndex < firstRepaintChildIndex) { 969 lowerIndexMarked = true; 970 children.setFirstRepaintChildIndex(childIndex); 971 } 972 setStatusBits(REPAINT_TILL_END_BIT); 974 } else { if (repaintTillEnd) { 976 setStatusBits(REPAINT_TILL_END_BIT); 977 } 978 } 979 980 } else { if (childIndex < firstRepaintChildIndex) { 982 lowerIndexMarked = true; 983 children.setFirstRepaintChildIndex(childIndex); 984 } 985 } 986 } 987 988 return lowerIndexMarked; 989 } 990 991 public final boolean isRepaintPending() { 992 return isStatusBitsNonZero(REPAINT_PENDING_BIT); 993 } 994 995 protected final void markRepaintPending() { 996 setStatusBits(REPAINT_PENDING_BIT); 997 } 998 999 protected void resetRepaintPending() { 1000 if (children != null) { 1001 children.setFirstRepaintChildIndex(-1); 1002 } 1003 clearStatusBits(REPAINT_PENDING_BIT | REPAINT_TILL_END_BIT); 1004 } 1005 1006 public final boolean isRepaintTillEnd() { 1007 return isStatusBitsNonZero(REPAINT_TILL_END_BIT); 1008 } 1009 1010 1020 protected boolean isLayoutMinorAxisPreferenceChanged(boolean majorAxesOrthogonal) { 1021 double delta; 1022 if (majorAxesOrthogonal) { 1023 delta = updateLastMajorAxisPreferredSpan(); 1025 } else { delta = updateLastMinorAxisPreferredSpan(); 1028 } 1029 1030 return (delta != 0.0d); 1031 } 1032 1033 private double updateLastMinorAxisPreferredSpan() { 1034 float currentMinorAxisPreferredSpan = children.getMinorAxisPreferredSpan(); 1035 double delta = currentMinorAxisPreferredSpan - lastMinorAxisPreferredSpan; 1036 lastMinorAxisPreferredSpan = currentMinorAxisPreferredSpan; 1037 return delta; 1038 } 1039 1040 private double updateLastMajorAxisPreferredSpan() { 1041 double currentMajorAxisPreferredSpan = children.getMajorAxisPreferredSpan(); 1042 double delta = currentMajorAxisPreferredSpan - lastMajorAxisPreferredSpan; 1043 lastMajorAxisPreferredSpan = (float)currentMajorAxisPreferredSpan; 1047 return delta; 1048 } 1049 1050 public boolean isLayoutValid() { 1052 return !isStatusBitsNonZero(LAYOUT_STATE_ANY_INVALID) 1053 && (children == null || children.getUpdateLayoutChildCount() == 0); 1054 } 1055 1056 public double getLayoutMajorAxisPreferredSpan() { 1058 return (isMajorAxesOrthogonal()) 1059 ? lastMinorAxisPreferredSpan 1060 : lastMajorAxisPreferredSpan; 1061 } 1062 1063 public float getLayoutMinorAxisPreferredSpan() { 1065 return isMajorAxesOrthogonal() 1066 ? lastMajorAxisPreferredSpan 1067 : lastMinorAxisPreferredSpan; 1068 } 1069 1070 public float getLayoutMinorAxisMinimumSpan() { 1072 return getLayoutMinorAxisPreferredSpan(); 1074 } 1075 1076 public float getLayoutMinorAxisMaximumSpan() { 1078 return getLayoutMinorAxisPreferredSpan(); 1080 } 1081 1082 public float getLayoutMinorAxisAlignment() { 1084 return getAlignment(getLayoutStateMinorAxis()); 1087 } 1088 1089 public double getLayoutMajorAxisRawOffset() { 1091 return layoutStateMajorAxisRawOffset; 1092 } 1093 1094 public void setLayoutMajorAxisRawOffset(double majorAxisRawOffset) { 1096 this.layoutStateMajorAxisRawOffset = majorAxisRawOffset; 1097 } 1098 1099 protected final ViewLayoutState.Parent getLayoutStateParent() { 1100 View parent = getParent(); 1101 return (parent instanceof ViewLayoutState.Parent) 1102 ? ((ViewLayoutState.Parent)parent) 1103 : null; 1104 } 1105 1106 protected final boolean isXLayoutStateMajorAxis() { 1107 return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT)); 1108 } 1109 1110 protected final int getLayoutStateMajorAxis() { 1111 return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT)) 1112 ? View.X_AXIS 1113 : View.Y_AXIS; 1114 } 1115 1116 protected final int getLayoutStateMinorAxis() { 1117 return (isStatusBitsNonZero(LAYOUT_STATE_X_MAJOR_AXIS_BIT)) 1118 ? View.Y_AXIS 1119 : View.X_AXIS; 1120 } 1121 1122 public int getViewRawIndex() { 1124 return viewRawIndex; 1125 } 1126 1127 public void setViewRawIndex(int viewRawIndex) { 1129 this.viewRawIndex = viewRawIndex; 1130 } 1131 1132 public void viewPreferenceChanged(boolean width, boolean height) { 1134 markViewSizeInvalid(); 1135 } 1136 1137 public void markViewSizeInvalid() { 1139 setStatusBits(LAYOUT_STATE_VIEW_SIZE_INVALID_BIT); 1140 } 1141 1142 1146 public void majorAxisPreferenceChanged(ViewLayoutState child, double majorAxisSpanDelta) { 1147 int childIndex = getChildIndexNoCheck(child); 1148 if (majorAxisSpanDelta != 0.0d) { 1149 markRepaint(childIndex, true); 1151 children.majorAxisPreferenceChanged(child, childIndex, majorAxisSpanDelta); 1152 1153 } else { markRepaint(childIndex, false); 1155 } 1156 } 1157 1158 1162 public void minorAxisPreferenceChanged(ViewLayoutState child) { 1163 int childIndex = getChildIndexNoCheck(child); 1164 markRepaint(childIndex, false); 1165 children.minorAxisPreferenceChanged(child, childIndex); 1166 } 1167 1168 1172 public float getMinorAxisSpan(ViewLayoutState child) { 1173 return getChildren().getMinorAxisSpan(child); 1175 } 1176 1177 public void repaint(ViewLayoutState child, 1179 double majorAxisOffset, double majorAxisSpan, 1180 float minorAxisOffset, float minorAxisSpan) { 1181 1182 int childIndex = getChildIndexNoCheck(child); 1183 markRepaint(childIndex, false); 1184 } 1185 1186 1189 public final boolean isChildrenLayoutNecessary() { 1190 return isStatusBitsNonZero(CHILDREN_LAYOUT_NECESSARY_BIT); 1191 } 1192 1193 1198 public final void markChildrenLayoutNecessary() { 1199 setStatusBits(CHILDREN_LAYOUT_NECESSARY_BIT); 1200 } 1201 1202 final void resetChildrenLayoutNecessary() { 1203 clearStatusBits(CHILDREN_LAYOUT_NECESSARY_BIT); 1204 } 1205 1206 1219 public void preferenceChanged(View childView, boolean width, boolean height) { 1220 if (childView == null) { getParent().preferenceChanged(this, width, height); 1222 1223 } else { int index; 1226 if (childView instanceof ViewLayoutState) { 1228 index = getChildIndexNoCheck((ViewLayoutState)childView); 1230 } else { index = getViewIndex(childView.getStartOffset()); 1233 } 1234 1235 ViewLayoutState child = getChild(index); 1236 if (child.getView() != childView) { 1237 int ind; 1238 for (ind = getViewCount() - 1; ind >= 0; ind--) { 1239 if (getView(ind) == childView) { 1240 break; 1241 } 1242 } 1243 if (ind == -1) { 1244 throw new IllegalArgumentException ("childView=" + childView + " not child of view " + this); 1247 } else { throw new IllegalStateException ( 1249 "Internal error. Child expected at index=" + index + " but found at index=" + ind); } 1252 } 1253 1254 child.viewPreferenceChanged(width, height); 1256 1257 children.markLayoutInvalid(index, 1); 1262 } 1263 } 1264 1265 1277 public void setSize(float width, float height) { 1278 float targetMajorAxisSpan; 1279 float targetMinorAxisSpan; 1280 if (isXMajorAxis()) { 1281 targetMajorAxisSpan = width; 1282 targetMinorAxisSpan = height; 1283 } else { targetMajorAxisSpan = height; 1285 targetMinorAxisSpan = width; 1286 } 1287 1288 setSpanOnMajorAxis(targetMajorAxisSpan); 1290 setSpanOnMinorAxis(targetMinorAxisSpan); 1291 } 1292 1293 protected void setSpanOnMajorAxis(float targetMajorAxisSpan) { 1294 } 1297 1298 protected void setSpanOnMinorAxis(float targetMinorAxisSpan) { 1299 if (targetMinorAxisSpan != minorAxisAssignedSpan) { 1300 minorAxisAssignedSpan = targetMinorAxisSpan; 1301 1303 if (!isEstimatedSpan() && !isChildrenResizeDisabled()) { 1305 int viewCount = getViewCount(); 1308 if (viewCount != 0) { 1309 markSizeInvalid(0, viewCount); 1310 } 1311 } 1312 } 1313 } 1314 1315 1329 protected void markSizeInvalid(int childIndex, int count) { 1330 while (--count >= 0) { 1331 ViewLayoutState child = getChild(childIndex); 1332 if (!child.isFlyweight()) { 1333 child.markViewSizeInvalid(); 1334 } 1335 childIndex++; 1336 } 1337 1338 children.markLayoutInvalid(childIndex, count); 1343 } 1344 1345 1353 protected boolean isChildrenResizeDisabled() { 1354 return false; } 1356 1357 1368 public Shape getChildAllocation(int index, Shape a) { 1369 if (a == null) { 1370 return null; 1371 } 1372 1373 Rectangle alloc = reallocate(a); int thisViewAllocX = alloc.x; 1375 int thisViewAllocY = alloc.y; 1376 1377 getChildren().getChildCoreAllocation(index, alloc); alloc.x += thisViewAllocX; 1379 alloc.y += thisViewAllocY; 1380 1381 ViewInsets insets = getInsets(); 1383 if (insets != null) { 1384 alloc.x += insets.getLeft(); 1385 alloc.y += insets.getRight(); 1386 } 1387 1388 return alloc; 1389 } 1390 1391 1409 public int getViewIndexAtPoint(float x, float y, Shape a) { 1410 Rectangle alloc = reallocate(a); x -= alloc.x; 1412 y -= alloc.y; 1413 1414 ViewInsets insets = getInsets(); 1416 if (insets != null) { 1417 x -= insets.getLeft(); 1418 y -= insets.getRight(); 1419 } 1420 1421 return getChildren().getChildIndexAtCorePoint(x, y); 1422 } 1423 1424 1433 public int getViewIndex(int offset, Position.Bias b) { 1434 if (b == Position.Bias.Backward) { 1435 offset -= 1; 1436 } 1437 1438 return getViewIndex(offset); 1439 } 1440 1441 1449 public int getViewIndex(int offset) { 1450 return ViewUtilitiesImpl.findViewIndexBounded(this, offset); 1451 } 1452 1453 1461 public void paint(Graphics g, Shape a) { 1462 Rectangle alloc = reallocate(a); getChildren().paintChildren(g, alloc); 1464 } 1465 1466 1481 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 1482 int index = getViewIndex(pos, b); 1483 Shape ret; 1484 if (index >= 0) { 1485 Shape ca = getChildAllocation(index, a); 1486 1487 ViewLayoutState child = getChild(index); 1489 View cv = child.getView(); 1490 ret = cv.modelToView(pos, ca, b); 1491 1492 } else { 1493 ret = null; 1494 } 1495 1496 return ret; 1497 } 1498 1499 1520 public int viewToModel(float x, float y, Shape a, Position.Bias [] biasReturn) { 1521 int pos; int index; Shape ca; 1525 index = getViewIndexAtPoint(x, y, a); 1526 index = Math.max(index, 0); 1527 if (index < getViewCount()) { 1528 ca = getChildAllocation(index, a); 1529 1530 ViewLayoutState child = getChild(index); 1532 View v = child.getView(); 1533 pos = v.viewToModel(x, y, ca, biasReturn); 1534 1535 } else { int endOff = getEndOffset(); 1537 Document doc = getDocument(); 1538 pos = (doc!=null && doc.getLength() < endOff) ? doc.getLength() : endOff; 1539 } 1540 1541 return pos; 1542 } 1543 1544 1567 public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, 1568 int direction, Position.Bias [] biasRet) throws BadLocationException { 1569 1570 return ViewUtilitiesImpl.getNextVisualPositionFrom( 1571 this, pos, b, a, direction, biasRet); 1572 } 1573 1574 1582 protected final ViewLayoutState getChild(int index) { 1583 return getChildren().getChild(index); 1584 } 1585 1586 1594 protected final int getChildIndex(ViewLayoutState child) { 1595 return getChildren().getChildIndex(child); 1596 } 1597 1598 1606 protected final int getChildIndexNoCheck(ViewLayoutState child) { 1607 return getChildren().getChildIndexNoCheck(child); 1608 } 1609 1610 1614 protected GapBoxViewChildren createChildren() { 1615 return new GapBoxViewChildren(this); 1616 } 1617 1618 protected boolean useCustomReloadChildren() { 1619 return (getElement() == null); 1620 } 1621 1622 public void insertUpdate(DocumentEvent evt, Shape a, ViewFactory f) { 1623 if (children == null && getParent() == null) { 1625 return; 1626 } 1627 1628 if (useCustomReloadChildren()) { 1629 customInsertUpdate(evt, a, f); 1630 } else { super.insertUpdate(evt, a, f); } 1633 } 1634 1635 protected void customInsertUpdate(DocumentEvent evt, Shape a, ViewFactory f) { 1636 int[] offsetRange = getInsertUpdateRebuildOffsetRange(evt); 1637 if (offsetRange != null) { 1638 offsetRebuild(offsetRange[0], offsetRange[1]); 1639 } else { 1640 forwardUpdate(null, evt, a, f); 1641 } 1642 } 1643 1644 1653 protected int[] getInsertUpdateRebuildOffsetRange(DocumentEvent evt) { 1654 DocumentEvent.ElementChange lineChange = evt.getChange(evt.getDocument().getDefaultRootElement()); 1655 if (lineChange == null) { 1656 return null; 1657 } 1658 1659 int startOffset = evt.getOffset(); 1660 int endOffset = startOffset + evt.getLength(); 1661 int[] offsetRange = new int[] {startOffset, endOffset}; 1662 Element [] addedLines = lineChange.getChildrenAdded(); 1663 ElementUtilities.updateOffsetRange(addedLines, offsetRange); 1664 Element [] removedLines = lineChange.getChildrenRemoved(); 1665 ElementUtilities.updateOffsetRange(removedLines, offsetRange); 1666 return offsetRange; 1667 } 1668 1669 public void removeUpdate(DocumentEvent evt, Shape a, ViewFactory f) { 1670 if (children == null && getParent() == null) { 1672 return; 1673 } 1674 1675 if (useCustomReloadChildren()) { 1676 customRemoveUpdate(evt, a, f); 1677 } else { 1678 super.removeUpdate(evt, a, f); } 1680 } 1681 1682 protected void customRemoveUpdate(DocumentEvent evt, Shape a, ViewFactory f) { 1683 int[] offsetRange = getRemoveUpdateRebuildOffsetRange(evt); 1684 if (offsetRange != null) { 1685 offsetRebuild(offsetRange[0], offsetRange[1]); 1686 } else { 1687 forwardUpdate(null, evt, a, f); 1688 } 1689 } 1690 1691 1700 protected int[] getRemoveUpdateRebuildOffsetRange(DocumentEvent evt) { 1701 DocumentEvent.ElementChange lineChange = evt.getChange(evt.getDocument().getDefaultRootElement()); 1702 if (lineChange == null) { 1703 return null; 1704 } 1705 1706 int startOffset = evt.getOffset(); 1707 int endOffset = startOffset; 1708 int[] offsetRange = new int[] {startOffset, endOffset}; 1709 Element [] addedLines = lineChange.getChildrenAdded(); 1710 ElementUtilities.updateOffsetRange(addedLines, offsetRange); 1711 Element [] removedLines = lineChange.getChildrenRemoved(); 1712 ElementUtilities.updateOffsetRange(removedLines, offsetRange); 1713 return offsetRange; 1714 } 1715 1716 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { 1717 if (children == null && getParent() == null) { 1719 return; 1720 } 1721 1722 super.changedUpdate(e, a, f); 1723 } 1724 1725 1738 protected void reloadChildren(int index, int removeLength, int startOffset, int endOffset) { 1739 if (useCustomReloadChildren()) { 1740 if (startOffset == -1) { 1741 startOffset = getStartOffset(); 1742 } 1743 if (endOffset == -1) { 1744 endOffset = getEndOffset(); 1745 } 1746 1747 customReloadChildren(index, removeLength, startOffset, endOffset); 1748 1749 } else { Element elem = getElement(); 1751 int startIndex; 1752 if (startOffset == -1) { 1753 startIndex = 0; 1754 } else { 1755 if (index == 0) { 1756 if (startOffset != getStartOffset()) { 1757 throw new IllegalArgumentException ("Invalid startOffset=" + startOffset); } 1759 } else { 1760 if (startOffset != getView(index - 1).getEndOffset()) { 1761 throw new IllegalArgumentException ("Invalid startOffset=" + startOffset); } 1763 } 1764 startIndex = index; 1765 } 1766 1767 int endIndex = (endOffset == -1) 1768 ? elem.getElementCount() 1769 : elem.getElementIndex(endOffset - 1) + 1; 1770 1771 1773 elementReloadChildren(index, removeLength, endIndex - startIndex); 1774 } 1775 } 1776 1777 1787 protected void elementReloadChildren(int index, int removeLength, 1788 int elementCount) { 1789 1790 Element e = getElement(); 1791 View [] added = null; 1792 1793 ViewFactory f = getViewFactory(); 1794 1797 if (f != null) { 1798 added = new View [elementCount]; 1799 for (int i = 0; i < elementCount; i++) { 1800 added[i] = f.create(e.getElement(index + i)); 1801 } 1802 1803 } 1804 1805 replace(index, removeLength, added); 1806 } 1807 1808 1817 protected void customReloadChildren(int index, int removeLength, 1818 int startOffset, int endOffset) { 1819 1820 View [] added = null; 1821 ViewFactory f = getViewFactory(); 1822 1825 if (f != null) { 1826 Element elem = getElement(); 1827 1828 int elementCount = elem.getElementCount(); 1829 int elementIndex = (elem != null) ? elem.getElementIndex(startOffset) : -1; 1830 if (elementIndex >= elementCount) { 1831 return; } 1833 List childViews = new ArrayList (); 1834 int viewCount = getViewCount(); 1835 1836 while (startOffset < endOffset) { 1837 View childView = createCustomView(f, startOffset, endOffset, elementIndex); 1839 if (childView == null) { 1840 throw new IllegalStateException ("No view created for area (" + startOffset + ", " + endOffset + ")"); } 1843 1844 childViews.add(childView); 1846 1847 int childViewEndOffset = childView.getEndOffset(); 1849 while (childViewEndOffset > endOffset) { 1850 1855 1866 if (index + removeLength >= viewCount) { 1867 break; 1869 } 1870 endOffset = getView(index + removeLength).getEndOffset(); 1871 removeLength++; 1872 if (debugRebuild) { 1873 System.err.println( 1874 "GapBoxView.customReloadChildren(): Increased removeLength to " + removeLength + ", eo=" + endOffset ); 1877 } 1878 } 1879 1880 Element childElem = elem.getElement(elementIndex); 1881 while (childElem.getEndOffset() <= childViewEndOffset) { 1882 elementIndex++; 1883 if (elementIndex == elementCount) { 1884 break; 1885 } 1886 childElem = elem.getElement(elementIndex); 1887 } 1888 1889 startOffset = childViewEndOffset; 1890 } 1891 1892 added = new View [childViews.size()]; 1893 childViews.toArray(added); 1894 } 1895 1896 replace(index, removeLength, added); 1897 } 1898 1899 1911 protected View createCustomView(ViewFactory f, 1912 int startOffset, int maxEndOffset, int elementIndex) { 1913 1914 1915 1937 1938 return null; 1939 } 1940 1941 1953 protected void unloadChildren() { 1954 } 1955 1956 1961 protected ViewLayoutState createChild(View v) { 1962 ViewLayoutState child; 1963 if (v instanceof ViewLayoutState) { 1964 child = (ViewLayoutState)v; 1965 } else { child = createDefaultChild(v); 1967 } 1968 return child; 1969 } 1970 1971 1974 protected ViewLayoutState createDefaultChild(View v) { 1975 return new SimpleViewLayoutState(v); } 1977 1978 protected final boolean isMajorAxisPreferenceChanged() { 1979 return (isStatusBitsNonZero(MAJOR_AXIS_PREFERENCE_CHANGED_BIT)); 1980 } 1981 1982 protected void markMajorAxisPreferenceChanged() { 1983 setStatusBits(MAJOR_AXIS_PREFERENCE_CHANGED_BIT); 1984 } 1985 1986 protected final boolean isMinorAxisPreferenceChanged() { 1987 return (isStatusBitsNonZero(MINOR_AXIS_PREFERENCE_CHANGED_BIT)); 1988 } 1989 1990 protected void markMinorAxisPreferenceChanged() { 1991 setStatusBits(MINOR_AXIS_PREFERENCE_CHANGED_BIT); 1992 } 1993 1994 protected final void resetAxesPreferenceChanged() { 1995 clearStatusBits(MAJOR_AXIS_PREFERENCE_CHANGED_BIT | MINOR_AXIS_PREFERENCE_CHANGED_BIT); 1996 } 1997 1998 2005 protected final float getInsetSpan(int axis) { 2006 2008 ViewInsets insets = getInsets(); 2009 return (insets != null) 2010 ? ((axis == X_AXIS) ? insets.getLeftRight() : insets.getTopBottom()) 2011 : 0; 2012 } 2013 2014 2019 protected final float getMajorAxisInsetSpan() { 2020 ViewInsets insets = getInsets(); 2021 return (insets != null) 2022 ? (isXMajorAxis() ? insets.getLeftRight() : insets.getTopBottom()) 2023 : 0; 2024 } 2025 2026 2031 protected final float getMinorAxisInsetSpan() { 2032 ViewInsets insets = getInsets(); 2033 return (insets != null) 2034 ? (isXMajorAxis() ? insets.getTopBottom() : insets.getLeftRight()) 2035 : 0; 2036 } 2037 2038 protected final int getStatusBits(int bits) { 2039 return (statusBits & bits); 2040 } 2041 2042 protected final boolean isStatusBitsNonZero(int bits) { 2043 return (getStatusBits(bits) != 0); 2044 } 2045 2046 protected final void setStatusBits(int bits) { 2047 statusBits |= bits; 2048 } 2049 2050 protected final void clearStatusBits(int bits) { 2051 statusBits &= ~bits; 2052 } 2053 2054 2061 protected Rectangle reallocate(Shape a) { 2062 Rectangle alloc = a.getBounds(); 2064 setSize(alloc.width, alloc.height); 2066 return alloc; 2067 } 2068 2069 public int getStartOffset(int childViewIndex) { 2071 return getChildren().getChildStartOffset(childViewIndex); 2072 } 2073 2074 public int getEndOffset(int childViewIndex) { 2076 return getChildren().getChildEndOffset(childViewIndex); 2077 } 2078 2079 public String childToString(int childIndex) { 2080 StringBuffer sb = new StringBuffer (); 2081 appendChildToStringBuffer(sb, childIndex, 0); 2082 return sb.toString(); 2083 } 2084 2085 public void appendChildToStringBuffer(StringBuffer sb, int childIndex, int indent) { 2086 ViewLayoutState child = getChild(childIndex); 2087 View childView = child.getView(); 2088 Document doc = getDocument(); 2089 boolean isFly = child.isFlyweight(); 2090 boolean isEstimated = (childView instanceof EstimatedSpanView) 2091 && ((EstimatedSpanView)childView).isEstimatedSpan(); 2092 boolean layoutValid = child.isLayoutValid(); 2093 double offset = children.getMajorAxisOffset(childIndex); 2094 boolean indexesDiffer = !isFly && (getChildIndexNoCheck(child) != childIndex); 2095 boolean showRaw = false; 2097 sb.append((isFly ? 'F' : 'R')); sb.append(':'); 2099 if (indexesDiffer) { 2100 sb.append(" WRONG-INDEX=" + getChildIndexNoCheck(child)); } 2102 if (showRaw) { 2103 sb.append("rI=" + child.getViewRawIndex()); } 2105 sb.append('<'); 2106 appendOffsetInfo(sb, doc, childView.getStartOffset()); 2107 sb.append(','); 2108 appendOffsetInfo(sb, doc, childView.getEndOffset()); 2109 sb.append('>'); 2110 2111 sb.append(", major=").append(child.getLayoutMajorAxisPreferredSpan()); sb.append("(off=").append(offset); 2114 if (showRaw) { 2115 sb.append('(').append(child.getLayoutMajorAxisRawOffset()).append(')'); } 2117 2118 sb.append("), minor[pref=").append(child.getLayoutMinorAxisPreferredSpan()); sb.append(", min=").append(child.getLayoutMinorAxisMinimumSpan()); sb.append(", max=").append(child.getLayoutMinorAxisMaximumSpan()); sb.append("] "); sb.append(isEstimated ? "E" : ""); sb.append(layoutValid ? "" : "I"); 2125 if (childView instanceof GapBoxView) { 2127 sb.append("\n"); appendSpaces(sb, indent + 4); 2129 sb.append("VIEW: "); sb.append(childView.toString()); 2131 sb.append(((GapBoxView)childView).childrenToString(indent + 4)); 2132 } 2133 } 2134 2135 private static void appendOffsetInfo(StringBuffer sb, Document doc, int offset) { 2136 sb.append(offset); 2137 sb.append('['); 2138 sb.append(org.netbeans.editor.Utilities.debugPosition( 2140 (org.netbeans.editor.BaseDocument)doc, offset)); 2141 sb.append(']'); 2142 } 2143 2144 private static void appendSpaces(StringBuffer sb, int spaceCount) { 2145 while (--spaceCount >= 0) { 2146 sb.append(' '); 2147 } 2148 } 2149 2150 public String childrenToString() { 2151 return childrenToString(0); 2152 } 2153 2154 public String childrenToString(int indent) { 2155 StringBuffer sb = new StringBuffer (); 2156 2157 int viewCount = getViewCount(); 2158 int totalDigitCount = Integer.toString(viewCount).length(); 2159 for (int i = 0; i < viewCount; i++) { 2160 sb.append('\n'); 2161 String iToString = Integer.toString(i); 2162 appendSpaces(sb, indent + (totalDigitCount - iToString.length())); 2163 2164 sb.append('['); 2165 sb.append(iToString); 2166 sb.append("]: "); appendChildToStringBuffer(sb, i, indent); 2168 } 2169 2170 return sb.toString(); 2171 } 2172 2173 public String toString() { 2174 return "lastMajorAxisPreferredSpan=" + lastMajorAxisPreferredSpan + ", lastMinorAxisPreferredSpan=" + lastMinorAxisPreferredSpan + ", minorAxisAssignedSpan=" + getMinorAxisAssignedSpan(); } 2180 2181} 2182 | Popular Tags |