1 7 package javax.swing.text.html; 8 9 import java.awt.*; 10 import java.util.BitSet ; 11 import java.util.Vector ; 12 import java.util.Arrays ; 13 import javax.swing.SizeRequirements ; 14 import javax.swing.event.DocumentEvent ; 15 16 import javax.swing.text.*; 17 18 25 class TableView extends BoxView implements ViewFactory { 26 27 32 public TableView(Element elem) { 33 super(elem, View.Y_AXIS); 34 rows = new Vector (); 35 gridValid = false; 36 captionIndex = -1; 37 totalColumnRequirements = new SizeRequirements (); 38 } 39 40 46 protected RowView createTableRow(Element elem) { 47 Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute); 51 if (o == HTML.Tag.TR) { 52 return new RowView(elem); 53 } 54 return null; 55 } 56 57 60 public int getColumnCount() { 61 return columnSpans.length; 62 } 63 64 69 public int getColumnSpan(int col) { 70 if (col < columnSpans.length) { 71 return columnSpans[col]; 72 } 73 return 0; 74 } 75 76 79 public int getRowCount() { 80 return rows.size(); 81 } 82 83 87 public int getMultiRowSpan(int row0, int row1) { 88 RowView rv0 = getRow(row0); 89 RowView rv1 = getRow(row1); 90 if ((rv0 != null) && (rv1 != null)) { 91 int index0 = rv0.viewIndex; 92 int index1 = rv1.viewIndex; 93 int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) + 94 getSpan(Y_AXIS, index1); 95 return span; 96 } 97 return 0; 98 } 99 100 103 public int getRowSpan(int row) { 104 RowView rv = getRow(row); 105 if (rv != null) { 106 return getSpan(Y_AXIS, rv.viewIndex); 107 } 108 return 0; 109 } 110 111 RowView getRow(int row) { 112 if (row < rows.size()) { 113 return (RowView) rows.elementAt(row); 114 } 115 return null; 116 } 117 118 protected View getViewAtPoint(int x, int y, Rectangle alloc) { 119 int n = getViewCount(); 120 View v = null; 121 Rectangle allocation = new Rectangle(); 122 for (int i = 0; i < n; i++) { 123 allocation.setBounds(alloc); 124 childAllocation(i, allocation); 125 v = getView(i); 126 if (v instanceof RowView) { 127 v = ((RowView)v).findViewAtPoint(x, y, allocation); 128 if (v != null) { 129 alloc.setBounds(allocation); 130 return v; 131 } 132 } 133 } 134 return super.getViewAtPoint(x, y, alloc); 135 } 136 137 141 protected int getColumnsOccupied(View v) { 142 AttributeSet a = v.getElement().getAttributes(); 143 144 if (a.isDefined(HTML.Attribute.COLSPAN)) { 145 String s = (String ) a.getAttribute(HTML.Attribute.COLSPAN); 146 if (s != null) { 147 try { 148 return Integer.parseInt(s); 149 } catch (NumberFormatException nfe) { 150 } 152 } 153 } 154 155 return 1; 156 } 157 158 162 protected int getRowsOccupied(View v) { 163 AttributeSet a = v.getElement().getAttributes(); 164 165 if (a.isDefined(HTML.Attribute.ROWSPAN)) { 166 String s = (String ) a.getAttribute(HTML.Attribute.ROWSPAN); 167 if (s != null) { 168 try { 169 return Integer.parseInt(s); 170 } catch (NumberFormatException nfe) { 171 } 173 } 174 } 175 176 return 1; 177 } 178 179 protected void invalidateGrid() { 180 gridValid = false; 181 } 182 183 protected StyleSheet getStyleSheet() { 184 HTMLDocument doc = (HTMLDocument ) getDocument(); 185 return doc.getStyleSheet(); 186 } 187 188 192 void updateInsets() { 193 short top = (short) painter.getInset(TOP, this); 194 short bottom = (short) painter.getInset(BOTTOM, this); 195 if (captionIndex != -1) { 196 View caption = getView(captionIndex); 197 short h = (short) caption.getPreferredSpan(Y_AXIS); 198 AttributeSet a = caption.getAttributes(); 199 Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE); 200 if ((align != null) && (align.equals("bottom"))) { 201 bottom += h; 202 } else { 203 top += h; 204 } 205 } 206 setInsets(top, (short) painter.getInset(LEFT, this), 207 bottom, (short) painter.getInset(RIGHT, this)); 208 } 209 210 213 protected void setPropertiesFromAttributes() { 214 StyleSheet sheet = getStyleSheet(); 215 attr = sheet.getViewAttributes(this); 216 painter = sheet.getBoxPainter(attr); 217 if (attr != null) { 218 setInsets((short) painter.getInset(TOP, this), 219 (short) painter.getInset(LEFT, this), 220 (short) painter.getInset(BOTTOM, this), 221 (short) painter.getInset(RIGHT, this)); 222 223 CSS.LengthValue lv = (CSS.LengthValue ) 224 attr.getAttribute(CSS.Attribute.BORDER_SPACING); 225 if (lv != null) { 226 cellSpacing = (int) lv.getValue(); 227 } else { 228 cellSpacing = 0; 229 } 230 lv = (CSS.LengthValue ) 231 attr.getAttribute(CSS.Attribute.BORDER_TOP_WIDTH); 232 if (lv != null) { 233 borderWidth = (int) lv.getValue(); 234 } else { 235 borderWidth = 0; 236 } 237 238 } 239 } 240 241 246 void updateGrid() { 247 if (! gridValid) { 248 relativeCells = false; 249 multiRowCells = false; 250 251 captionIndex = -1; 254 rows.removeAllElements(); 255 int n = getViewCount(); 256 for (int i = 0; i < n; i++) { 257 View v = getView(i); 258 if (v instanceof RowView) { 259 rows.addElement(v); 260 RowView rv = (RowView) v; 261 rv.clearFilledColumns(); 262 rv.rowIndex = rows.size() - 1; 263 rv.viewIndex = i; 264 } else { 265 Object o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute); 266 if (o instanceof HTML.Tag ) { 267 HTML.Tag kind = (HTML.Tag ) o; 268 if (kind == HTML.Tag.CAPTION) { 269 captionIndex = i; 270 } 271 } 272 } 273 } 274 275 int maxColumns = 0; 276 int nrows = rows.size(); 277 for (int row = 0; row < nrows; row++) { 278 RowView rv = getRow(row); 279 int col = 0; 280 for (int cell = 0; cell < rv.getViewCount(); cell++, col++) { 281 View cv = rv.getView(cell); 282 if (! relativeCells) { 283 AttributeSet a = cv.getAttributes(); 284 CSS.LengthValue lv = (CSS.LengthValue ) 285 a.getAttribute(CSS.Attribute.WIDTH); 286 if ((lv != null) && (lv.isPercentage())) { 287 relativeCells = true; 288 } 289 } 290 for (; rv.isFilled(col); col++); 292 int rowSpan = getRowsOccupied(cv); 293 if (rowSpan > 1) { 294 multiRowCells = true; 295 } 296 int colSpan = getColumnsOccupied(cv); 297 if ((colSpan > 1) || (rowSpan > 1)) { 298 int rowLimit = row + rowSpan; 300 int colLimit = col + colSpan; 301 for (int i = row; i < rowLimit; i++) { 302 for (int j = col; j < colLimit; j++) { 303 if (i != row || j != col) { 304 addFill(i, j); 305 } 306 } 307 } 308 if (colSpan > 1) { 309 col += colSpan - 1; 310 } 311 } 312 } 313 maxColumns = Math.max(maxColumns, col); 314 } 315 316 columnSpans = new int[maxColumns]; 318 columnOffsets = new int[maxColumns]; 319 columnRequirements = new SizeRequirements [maxColumns]; 320 for (int i = 0; i < maxColumns; i++) { 321 columnRequirements[i] = new SizeRequirements (); 322 columnRequirements[i].maximum = Integer.MAX_VALUE; 323 } 324 gridValid = true; 325 } 326 } 327 328 331 void addFill(int row, int col) { 332 RowView rv = getRow(row); 333 if (rv != null) { 334 rv.fillColumn(col); 335 } 336 } 337 338 353 protected void layoutColumns(int targetSpan, int[] offsets, int[] spans, 354 SizeRequirements [] reqs) { 355 Arrays.fill(offsets, 0); 357 Arrays.fill(spans, 0); 358 colIterator.setLayoutArrays(offsets, spans, targetSpan); 359 CSS.calculateTiledLayout(colIterator, targetSpan); 360 } 361 362 376 void calculateColumnRequirements(int axis) { 377 for (SizeRequirements req : columnRequirements) { 379 req.minimum = 0; 380 req.preferred = 0; 381 req.maximum = Integer.MAX_VALUE; 382 } 383 Container host = getContainer(); 384 if (host != null) { 385 if (host instanceof JTextComponent) { 386 skipComments = !((JTextComponent)host).isEditable(); 387 } else { 388 skipComments = true; 389 } 390 } 391 boolean hasMultiColumn = false; 393 int nrows = getRowCount(); 394 for (int i = 0; i < nrows; i++) { 395 RowView row = getRow(i); 396 int col = 0; 397 int ncells = row.getViewCount(); 398 for (int cell = 0; cell < ncells; cell++) { 399 View cv = row.getView(cell); 400 if (skipComments && !(cv instanceof CellView)) { 401 continue; 402 } 403 for (; row.isFilled(col); col++); int rowSpan = getRowsOccupied(cv); 405 int colSpan = getColumnsOccupied(cv); 406 if (colSpan == 1) { 407 checkSingleColumnCell(axis, col, cv); 408 } else { 409 hasMultiColumn = true; 410 col += colSpan - 1; 411 } 412 col++; 413 } 414 } 415 416 if (hasMultiColumn) { 418 for (int i = 0; i < nrows; i++) { 419 RowView row = getRow(i); 420 int col = 0; 421 int ncells = row.getViewCount(); 422 for (int cell = 0; cell < ncells; cell++) { 423 View cv = row.getView(cell); 424 if (skipComments && !(cv instanceof CellView)) { 425 continue; 426 } 427 for (; row.isFilled(col); col++); int colSpan = getColumnsOccupied(cv); 429 if (colSpan > 1) { 430 checkMultiColumnCell(axis, col, colSpan, cv); 431 col += colSpan - 1; 432 } 433 col++; 434 } 435 } 436 } 437 } 438 439 442 void checkSingleColumnCell(int axis, int col, View v) { 443 SizeRequirements req = columnRequirements[col]; 444 req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum); 445 req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred); 446 } 447 448 452 void checkMultiColumnCell(int axis, int col, int ncols, View v) { 453 long min = 0; 455 long pref = 0; 456 long max = 0; 457 for (int i = 0; i < ncols; i++) { 458 SizeRequirements req = columnRequirements[col + i]; 459 min += req.minimum; 460 pref += req.preferred; 461 max += req.maximum; 462 } 463 464 int cmin = (int) v.getMinimumSpan(axis); 466 if (cmin > min) { 467 471 SizeRequirements [] reqs = new SizeRequirements [ncols]; 472 for (int i = 0; i < ncols; i++) { 473 reqs[i] = columnRequirements[col + i]; 474 } 475 int[] spans = new int[ncols]; 476 int[] offsets = new int[ncols]; 477 SizeRequirements.calculateTiledPositions(cmin, null, reqs, 478 offsets, spans); 479 for (int i = 0; i < ncols; i++) { 481 SizeRequirements req = reqs[i]; 482 req.minimum = Math.max(spans[i], req.minimum); 483 req.preferred = Math.max(req.minimum, req.preferred); 484 req.maximum = Math.max(req.preferred, req.maximum); 485 } 486 } 487 488 int cpref = (int) v.getPreferredSpan(axis); 490 if (cpref > pref) { 491 495 SizeRequirements [] reqs = new SizeRequirements [ncols]; 496 for (int i = 0; i < ncols; i++) { 497 reqs[i] = columnRequirements[col + i]; 498 } 499 int[] spans = new int[ncols]; 500 int[] offsets = new int[ncols]; 501 SizeRequirements.calculateTiledPositions(cpref, null, reqs, 502 offsets, spans); 503 for (int i = 0; i < ncols; i++) { 505 SizeRequirements req = reqs[i]; 506 req.preferred = Math.max(spans[i], req.preferred); 507 req.maximum = Math.max(req.preferred, req.maximum); 508 } 509 } 510 511 } 512 513 515 525 protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 526 updateGrid(); 527 528 calculateColumnRequirements(axis); 530 531 532 if (r == null) { 534 r = new SizeRequirements (); 535 } 536 long min = 0; 537 long pref = 0; 538 int n = columnRequirements.length; 539 for (int i = 0; i < n; i++) { 540 SizeRequirements req = columnRequirements[i]; 541 min += req.minimum; 542 pref += req.preferred; 543 } 544 int adjust = (n + 1) * cellSpacing + 2 * borderWidth; 545 min += adjust; 546 pref += adjust; 547 r.minimum = (int) min; 548 r.preferred = (int) pref; 549 r.maximum = (int) pref; 550 551 552 AttributeSet attr = getAttributes(); 553 CSS.LengthValue cssWidth = (CSS.LengthValue )attr.getAttribute( 554 CSS.Attribute.WIDTH); 555 556 if (BlockView.spanSetFromAttributes(axis, r, cssWidth, null)) { 557 if (r.minimum < (int)min) { 558 r.maximum = r.minimum = r.preferred = (int) min; 561 } 562 } 563 totalColumnRequirements.minimum = r.minimum; 564 totalColumnRequirements.preferred = r.preferred; 565 totalColumnRequirements.maximum = r.maximum; 566 567 Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN); 569 if (o != null) { 570 String ta = o.toString(); 572 if (ta.equals("left")) { 573 r.alignment = 0; 574 } else if (ta.equals("center")) { 575 r.alignment = 0.5f; 576 } else if (ta.equals("right")) { 577 r.alignment = 1; 578 } else { 579 r.alignment = 0; 580 } 581 } else { 582 r.alignment = 0; 583 } 584 585 return r; 586 } 587 588 596 protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) { 597 updateInsets(); 598 rowIterator.updateAdjustments(); 599 r = CSS.calculateTiledRequirements(rowIterator, r); 600 r.maximum = r.preferred; 601 return r; 602 } 603 604 628 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 629 updateGrid(); 631 632 int n = getRowCount(); 634 for (int i = 0; i < n; i++) { 635 RowView row = getRow(i); 636 row.layoutChanged(axis); 637 } 638 639 layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements); 641 642 super.layoutMinorAxis(targetSpan, axis, offsets, spans); 644 } 645 646 647 671 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 672 rowIterator.setLayoutArrays(offsets, spans); 673 CSS.calculateTiledLayout(rowIterator, targetSpan); 674 675 if (captionIndex != -1) { 676 View caption = getView(captionIndex); 678 int h = (int) caption.getPreferredSpan(Y_AXIS); 679 spans[captionIndex] = h; 680 short boxBottom = (short) painter.getInset(BOTTOM, this); 681 if (boxBottom != getBottomInset()) { 682 offsets[captionIndex] = targetSpan + boxBottom; 683 } else { 684 offsets[captionIndex] = - getTopInset(); 685 } 686 } 687 } 688 689 702 protected View getViewAtPosition(int pos, Rectangle a) { 703 int n = getViewCount(); 704 for (int i = 0; i < n; i++) { 705 View v = getView(i); 706 int p0 = v.getStartOffset(); 707 int p1 = v.getEndOffset(); 708 if ((pos >= p0) && (pos < p1)) { 709 if (a != null) { 711 childAllocation(i, a); 712 } 713 return v; 714 } 715 } 716 if (pos == getEndOffset()) { 717 View v = getView(n - 1); 718 if (a != null) { 719 this.childAllocation(n - 1, a); 720 } 721 return v; 722 } 723 return null; 724 } 725 726 728 733 public AttributeSet getAttributes() { 734 if (attr == null) { 735 StyleSheet sheet = getStyleSheet(); 736 attr = sheet.getViewAttributes(this); 737 } 738 return attr; 739 } 740 741 756 public void paint(Graphics g, Shape allocation) { 757 Rectangle a = allocation.getBounds(); 759 setSize(a.width, a.height); 760 if (captionIndex != -1) { 761 short top = (short) painter.getInset(TOP, this); 763 short bottom = (short) painter.getInset(BOTTOM, this); 764 if (top != getTopInset()) { 765 int h = getTopInset() - top; 766 a.y += h; 767 a.height -= h; 768 } else { 769 a.height -= getBottomInset() - bottom; 770 } 771 } 772 for (int i = borderWidth; i > 0; i--) { 773 painter.paint(g, a.x + i, a.y + i, a.width - 2 * i, a.height - 2 * i, this); 774 } 775 int n = getViewCount(); 777 for (int i = 0; i < n; i++) { 778 View v = getView(i); 779 v.paint(g, getChildAllocation(i, allocation)); 780 } 781 } 783 784 801 public void setParent(View parent) { 802 super.setParent(parent); 803 if (parent != null) { 804 setPropertiesFromAttributes(); 805 } 806 } 807 808 819 public ViewFactory getViewFactory() { 820 return this; 821 } 822 823 837 public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { 838 super.insertUpdate(e, a, this); 839 } 840 841 855 public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 856 super.removeUpdate(e, a, this); 857 } 858 859 873 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { 874 super.changedUpdate(e, a, this); 875 } 876 877 protected void forwardUpdate(DocumentEvent.ElementChange ec, 878 DocumentEvent e, Shape a, ViewFactory f) { 879 super.forwardUpdate(ec, e, a, f); 880 if (a != null) { 883 Component c = getContainer(); 884 if (c != null) { 885 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : 886 a.getBounds(); 887 c.repaint(alloc.x, alloc.y, alloc.width, alloc.height); 888 } 889 } 890 } 891 892 897 public void replace(int offset, int length, View[] views) { 898 super.replace(offset, length, views); 899 invalidateGrid(); 900 } 901 902 904 910 public View create(Element elem) { 911 Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute); 912 if (o instanceof HTML.Tag ) { 913 HTML.Tag kind = (HTML.Tag ) o; 914 if (kind == HTML.Tag.TR) { 915 return createTableRow(elem); 916 } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) { 917 return new CellView(elem); 918 } else if (kind == HTML.Tag.CAPTION) { 919 return new javax.swing.text.html.ParagraphView (elem); 920 } 921 } 922 View p = getParent(); 924 if (p != null) { 925 ViewFactory f = p.getViewFactory(); 926 if (f != null) { 927 return f.create(elem); 928 } 929 } 930 return null; 931 } 932 933 935 private AttributeSet attr; 936 private StyleSheet.BoxPainter painter; 937 938 private int cellSpacing; 939 private int borderWidth; 940 941 947 private int captionIndex; 948 949 956 private boolean relativeCells; 957 958 965 private boolean multiRowCells; 966 967 int[] columnSpans; 968 int[] columnOffsets; 969 972 SizeRequirements totalColumnRequirements; 973 SizeRequirements [] columnRequirements; 974 975 RowIterator rowIterator = new RowIterator(); 976 ColumnIterator colIterator = new ColumnIterator(); 977 978 Vector rows; 979 980 boolean skipComments = false; 982 983 boolean gridValid; 984 static final private BitSet EMPTY = new BitSet (); 985 986 class ColumnIterator implements CSS.LayoutIterator { 987 988 992 void disablePercentages() { 993 percentages = null; 994 } 995 996 999 private void updatePercentagesAndAdjustmentWeights(int span) { 1000 adjustmentWeights = new int[columnRequirements.length]; 1001 for (int i = 0; i < columnRequirements.length; i++) { 1002 adjustmentWeights[i] = 0; 1003 } 1004 if (relativeCells) { 1005 percentages = new int[columnRequirements.length]; 1006 } else { 1007 percentages = null; 1008 } 1009 int nrows = getRowCount(); 1010 for (int rowIndex = 0; rowIndex < nrows; rowIndex++) { 1011 RowView row = getRow(rowIndex); 1012 int col = 0; 1013 int ncells = row.getViewCount(); 1014 for (int cell = 0; cell < ncells; cell++, col++) { 1015 View cv = row.getView(cell); 1016 for (; row.isFilled(col); col++); int rowSpan = getRowsOccupied(cv); 1018 int colSpan = getColumnsOccupied(cv); 1019 AttributeSet a = cv.getAttributes(); 1020 CSS.LengthValue lv = (CSS.LengthValue ) 1021 a.getAttribute(CSS.Attribute.WIDTH); 1022 if ( lv != null ) { 1023 int len = (int) (lv.getValue(span) / colSpan + 0.5f); 1024 for (int i = 0; i < colSpan; i++) { 1025 if (lv.isPercentage()) { 1026 percentages[col+i] = Math.max(percentages[col+i], len); 1028 adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight); 1029 } else { 1030 adjustmentWeights[col + i] = Math.max(adjustmentWeights[col + i], WorstAdjustmentWeight - 1); 1031 } 1032 } 1033 } 1034 col += colSpan - 1; 1035 } 1036 } 1037 } 1038 1039 1042 public void setLayoutArrays(int offsets[], int spans[], int targetSpan) { 1043 this.offsets = offsets; 1044 this.spans = spans; 1045 updatePercentagesAndAdjustmentWeights(targetSpan); 1046 } 1047 1048 1050 public int getCount() { 1051 return columnRequirements.length; 1052 } 1053 1054 public void setIndex(int i) { 1055 col = i; 1056 } 1057 1058 public void setOffset(int offs) { 1059 offsets[col] = offs; 1060 } 1061 1062 public int getOffset() { 1063 return offsets[col]; 1064 } 1065 1066 public void setSpan(int span) { 1067 spans[col] = span; 1068 } 1069 1070 public int getSpan() { 1071 return spans[col]; 1072 } 1073 1074 public float getMinimumSpan(float parentSpan) { 1075 return columnRequirements[col].minimum; 1079 } 1080 1081 public float getPreferredSpan(float parentSpan) { 1082 if ((percentages != null) && (percentages[col] != 0)) { 1083 return Math.max(percentages[col], columnRequirements[col].minimum); 1084 } 1085 return columnRequirements[col].preferred; 1086 } 1087 1088 public float getMaximumSpan(float parentSpan) { 1089 return columnRequirements[col].maximum; 1090 } 1091 1092 public float getBorderWidth() { 1093 return borderWidth; 1094 } 1095 1096 1097 public float getLeadingCollapseSpan() { 1098 return cellSpacing; 1099 } 1100 1101 public float getTrailingCollapseSpan() { 1102 return cellSpacing; 1103 } 1104 1105 public int getAdjustmentWeight() { 1106 return adjustmentWeights[col]; 1107 } 1108 1109 1112 private int col; 1113 1114 1118 private int[] percentages; 1119 1120 private int[] adjustmentWeights; 1121 1122 private int[] offsets; 1123 private int[] spans; 1124 } 1125 1126 class RowIterator implements CSS.LayoutIterator { 1127 1128 RowIterator() { 1129 } 1130 1131 void updateAdjustments() { 1132 int axis = Y_AXIS; 1133 if (multiRowCells) { 1134 int n = getRowCount(); 1136 adjustments = new int[n]; 1137 for (int i = 0; i < n; i++) { 1138 RowView rv = getRow(i); 1139 if (rv.multiRowCells == true) { 1140 int ncells = rv.getViewCount(); 1141 for (int j = 0; j < ncells; j++) { 1142 View v = rv.getView(j); 1143 int nrows = getRowsOccupied(v); 1144 if (nrows > 1) { 1145 int spanNeeded = (int) v.getPreferredSpan(axis); 1146 adjustMultiRowSpan(spanNeeded, nrows, i); 1147 } 1148 } 1149 } 1150 } 1151 } else { 1152 adjustments = null; 1153 } 1154 } 1155 1156 1162 void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) { 1163 if ((rowIndex + nrows) > getCount()) { 1164 nrows = getCount() - rowIndex; 1168 if (nrows < 1) { 1169 return; 1170 } 1171 } 1172 int span = 0; 1173 for (int i = 0; i < nrows; i++) { 1174 RowView rv = getRow(rowIndex + i); 1175 span += rv.getPreferredSpan(Y_AXIS); 1176 } 1177 if (spanNeeded > span) { 1178 int adjust = (spanNeeded - span); 1179 int rowAdjust = adjust / nrows; 1180 int firstAdjust = rowAdjust + (adjust - (rowAdjust * nrows)); 1181 RowView rv = getRow(rowIndex); 1182 adjustments[rowIndex] = Math.max(adjustments[rowIndex], 1183 firstAdjust); 1184 for (int i = 1; i < nrows; i++) { 1185 adjustments[rowIndex + i] = Math.max( 1186 adjustments[rowIndex + i], rowAdjust); 1187 } 1188 } 1189 } 1190 1191 void setLayoutArrays(int[] offsets, int[] spans) { 1192 this.offsets = offsets; 1193 this.spans = spans; 1194 } 1195 1196 1198 public void setOffset(int offs) { 1199 RowView rv = getRow(row); 1200 if (rv != null) { 1201 offsets[rv.viewIndex] = offs; 1202 } 1203 } 1204 1205 public int getOffset() { 1206 RowView rv = getRow(row); 1207 if (rv != null) { 1208 return offsets[rv.viewIndex]; 1209 } 1210 return 0; 1211 } 1212 1213 public void setSpan(int span) { 1214 RowView rv = getRow(row); 1215 if (rv != null) { 1216 spans[rv.viewIndex] = span; 1217 } 1218 } 1219 1220 public int getSpan() { 1221 RowView rv = getRow(row); 1222 if (rv != null) { 1223 return spans[rv.viewIndex]; 1224 } 1225 return 0; 1226 } 1227 1228 public int getCount() { 1229 return rows.size(); 1230 } 1231 1232 public void setIndex(int i) { 1233 row = i; 1234 } 1235 1236 public float getMinimumSpan(float parentSpan) { 1237 return getPreferredSpan(parentSpan); 1238 } 1239 1240 public float getPreferredSpan(float parentSpan) { 1241 RowView rv = getRow(row); 1242 if (rv != null) { 1243 int adjust = (adjustments != null) ? adjustments[row] : 0; 1244 return rv.getPreferredSpan(TableView.this.getAxis()) + adjust; 1245 } 1246 return 0; 1247 } 1248 1249 public float getMaximumSpan(float parentSpan) { 1250 return getPreferredSpan(parentSpan); 1251 } 1252 1253 public float getBorderWidth() { 1254 return borderWidth; 1255 } 1256 1257 public float getLeadingCollapseSpan() { 1258 return cellSpacing; 1259 } 1260 1261 public float getTrailingCollapseSpan() { 1262 return cellSpacing; 1263 } 1264 1265 public int getAdjustmentWeight() { 1266 return 0; 1267 } 1268 1269 1272 private int row; 1273 1274 1278 private int[] adjustments; 1279 1280 private int[] offsets; 1281 private int[] spans; 1282 } 1283 1284 1287 public class RowView extends BoxView { 1288 1289 1294 public RowView(Element elem) { 1295 super(elem, View.X_AXIS); 1296 fillColumns = new BitSet (); 1297 RowView.this.setPropertiesFromAttributes(); 1298 } 1299 1300 void clearFilledColumns() { 1301 fillColumns.and(EMPTY); 1302 } 1303 1304 void fillColumn(int col) { 1305 fillColumns.set(col); 1306 } 1307 1308 boolean isFilled(int col) { 1309 return fillColumns.get(col); 1310 } 1311 1312 1315 int getColumnCount() { 1316 int nfill = 0; 1317 int n = fillColumns.size(); 1318 for (int i = 0; i < n; i++) { 1319 if (fillColumns.get(i)) { 1320 nfill ++; 1321 } 1322 } 1323 return getViewCount() + nfill; 1324 } 1325 1326 1331 public AttributeSet getAttributes() { 1332 return attr; 1333 } 1334 1335 View findViewAtPoint(int x, int y, Rectangle alloc) { 1336 int n = getViewCount(); 1337 for (int i = 0; i < n; i++) { 1338 if (getChildAllocation(i, alloc).contains(x, y)) { 1339 childAllocation(i, alloc); 1340 return getView(i); 1341 } 1342 } 1343 return null; 1344 } 1345 1346 protected StyleSheet getStyleSheet() { 1347 HTMLDocument doc = (HTMLDocument ) getDocument(); 1348 return doc.getStyleSheet(); 1349 } 1350 1351 1364 public void preferenceChanged(View child, boolean width, boolean height) { 1365 super.preferenceChanged(child, width, height); 1366 if (TableView.this.multiRowCells && height) { 1367 for (int i = rowIndex - 1; i >= 0; i--) { 1368 RowView rv = TableView.this.getRow(i); 1369 if (rv.multiRowCells) { 1370 rv.preferenceChanged(null, false, true); 1371 break; 1372 } 1373 } 1374 } 1375 } 1376 1377 protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) { 1381 SizeRequirements req = new SizeRequirements (); 1382 req.minimum = totalColumnRequirements.minimum; 1383 req.maximum = totalColumnRequirements.maximum; 1384 req.preferred = totalColumnRequirements.preferred; 1385 req.alignment = 0f; 1386 return req; 1387 } 1388 1389 public float getMinimumSpan(int axis) { 1390 float value; 1391 1392 if (axis == View.X_AXIS) { 1393 value = totalColumnRequirements.minimum + getLeftInset() + 1394 getRightInset(); 1395 } 1396 else { 1397 value = super.getMinimumSpan(axis); 1398 } 1399 return value; 1400 } 1401 1402 public float getMaximumSpan(int axis) { 1403 float value; 1404 1405 if (axis == View.X_AXIS) { 1406 value = (float)Integer.MAX_VALUE; 1408 } 1409 else { 1410 value = super.getMaximumSpan(axis); 1411 } 1412 return value; 1413 } 1414 1415 public float getPreferredSpan(int axis) { 1416 float value; 1417 1418 if (axis == View.X_AXIS) { 1419 value = totalColumnRequirements.preferred + getLeftInset() + 1420 getRightInset(); 1421 } 1422 else { 1423 value = super.getPreferredSpan(axis); 1424 } 1425 return value; 1426 } 1427 1428 public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { 1429 super.changedUpdate(e, a, f); 1430 int pos = e.getOffset(); 1431 if (pos <= getStartOffset() && (pos + e.getLength()) >= 1432 getEndOffset()) { 1433 RowView.this.setPropertiesFromAttributes(); 1434 } 1435 } 1436 1437 1447 public void paint(Graphics g, Shape allocation) { 1448 Rectangle a = (Rectangle) allocation; 1449 painter.paint(g, a.x, a.y, a.width, a.height, this); 1450 super.paint(g, a); 1451 } 1452 1453 1458 public void replace(int offset, int length, View[] views) { 1459 super.replace(offset, length, views); 1460 invalidateGrid(); 1461 } 1462 1463 1471 protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 1472 long min = 0; 1474 long pref = 0; 1475 long max = 0; 1476 multiRowCells = false; 1477 int n = getViewCount(); 1478 for (int i = 0; i < n; i++) { 1479 View v = getView(i); 1480 if (getRowsOccupied(v) > 1) { 1481 multiRowCells = true; 1482 max = Math.max((int) v.getMaximumSpan(axis), max); 1483 } else { 1484 min = Math.max((int) v.getMinimumSpan(axis), min); 1485 pref = Math.max((int) v.getPreferredSpan(axis), pref); 1486 max = Math.max((int) v.getMaximumSpan(axis), max); 1487 } 1488 } 1489 1490 if (r == null) { 1491 r = new SizeRequirements (); 1492 r.alignment = 0.5f; 1493 } 1494 r.preferred = (int) pref; 1495 r.minimum = (int) min; 1496 r.maximum = (int) max; 1497 return r; 1498 } 1499 1500 1521 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 1522 int col = 0; 1523 int ncells = getViewCount(); 1524 for (int cell = 0; cell < ncells; cell++) { 1525 View cv = getView(cell); 1526 if (skipComments && !(cv instanceof CellView)) { 1527 continue; 1528 } 1529 for (; isFilled(col); col++); int colSpan = getColumnsOccupied(cv); 1531 spans[cell] = columnSpans[col]; 1532 offsets[cell] = columnOffsets[col]; 1533 if (colSpan > 1) { 1534 int n = columnSpans.length; 1535 for (int j = 1; j < colSpan; j++) { 1536 if ((col+j) < n) { 1540 spans[cell] += columnSpans[col+j]; 1541 spans[cell] += cellSpacing; 1542 } 1543 } 1544 col += colSpan - 1; 1545 } 1546 col++; 1547 } 1548 } 1549 1550 1572 protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 1573 super.layoutMinorAxis(targetSpan, axis, offsets, spans); 1574 int col = 0; 1575 int ncells = getViewCount(); 1576 for (int cell = 0; cell < ncells; cell++, col++) { 1577 View cv = getView(cell); 1578 for (; isFilled(col); col++); int colSpan = getColumnsOccupied(cv); 1580 int rowSpan = getRowsOccupied(cv); 1581 if (rowSpan > 1) { 1582 1583 int row0 = rowIndex; 1584 int row1 = Math.min(rowIndex + rowSpan - 1, getRowCount()-1); 1585 spans[cell] = getMultiRowSpan(row0, row1); 1586 } 1587 if (colSpan > 1) { 1588 col += colSpan - 1; 1589 } 1590 } 1591 } 1592 1593 1601 public int getResizeWeight(int axis) { 1602 return 1; 1603 } 1604 1605 1618 protected View getViewAtPosition(int pos, Rectangle a) { 1619 int n = getViewCount(); 1620 for (int i = 0; i < n; i++) { 1621 View v = getView(i); 1622 int p0 = v.getStartOffset(); 1623 int p1 = v.getEndOffset(); 1624 if ((pos >= p0) && (pos < p1)) { 1625 if (a != null) { 1627 childAllocation(i, a); 1628 } 1629 return v; 1630 } 1631 } 1632 if (pos == getEndOffset()) { 1633 View v = getView(n - 1); 1634 if (a != null) { 1635 this.childAllocation(n - 1, a); 1636 } 1637 return v; 1638 } 1639 return null; 1640 } 1641 1642 1645 void setPropertiesFromAttributes() { 1646 StyleSheet sheet = getStyleSheet(); 1647 attr = sheet.getViewAttributes(this); 1648 painter = sheet.getBoxPainter(attr); 1649 } 1650 1651 private StyleSheet.BoxPainter painter; 1652 private AttributeSet attr; 1653 1654 1655 BitSet fillColumns; 1656 1657 1660 int rowIndex; 1661 1662 1666 int viewIndex; 1667 1668 1671 boolean multiRowCells; 1672 1673 } 1674 1675 1679 class CellView extends BlockView { 1680 1681 1686 public CellView(Element elem) { 1687 super(elem, Y_AXIS); 1688 } 1689 1690 1714 protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { 1715 super.layoutMajorAxis(targetSpan, axis, offsets, spans); 1716 1717 int used = 0; 1719 int n = spans.length; 1720 for (int i = 0; i < n; i++) { 1721 used += spans[i]; 1722 } 1723 1724 int adjust = 0; 1726 if (used < targetSpan) { 1727 String valign = (String ) getElement().getAttributes().getAttribute( 1729 HTML.Attribute.VALIGN); 1730 if (valign == null) { 1731 AttributeSet rowAttr = getElement().getParentElement().getAttributes(); 1732 valign = (String ) rowAttr.getAttribute(HTML.Attribute.VALIGN); 1733 } 1734 if ((valign == null) || valign.equals("middle")) { 1735 adjust = (targetSpan - used) / 2; 1736 } else if (valign.equals("bottom")) { 1737 adjust = targetSpan - used; 1738 } 1739 } 1740 1741 if (adjust != 0) { 1743 for (int i = 0; i < n; i++) { 1744 offsets[i] += adjust; 1745 } 1746 } 1747 } 1748 1749 1763 protected SizeRequirements calculateMajorAxisRequirements(int axis, 1764 SizeRequirements r) { 1765 SizeRequirements req = super.calculateMajorAxisRequirements(axis, r); 1766 req.maximum = Integer.MAX_VALUE; 1767 return req; 1768 } 1769 1770 @Override 1771 protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 1772 SizeRequirements rv = super.calculateMinorAxisRequirements(axis, r); 1773 int n = getViewCount(); 1776 int min = 0; 1777 for (int i = 0; i < n; i++) { 1778 View v = getView(i); 1779 min = Math.max((int) v.getMinimumSpan(axis), min); 1780 } 1781 rv.minimum = Math.min(rv.minimum, min); 1782 return rv; 1783 } 1784 } 1785 1786} 1787 | Popular Tags |