001 /* 002 * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 /* $Id: Mtable.java,v bc1d5fde7b73 2009/06/01 14:40:54 maxberger $ */ 018 019 package net.sourceforge.jeuclid.elements.presentation.table; 020 021 import java.awt.Color; 022 import java.awt.Graphics2D; 023 import java.awt.geom.Dimension2D; 024 import java.util.ArrayList; 025 import java.util.List; 026 import java.util.Locale; 027 028 import net.sourceforge.jeuclid.Constants; 029 import net.sourceforge.jeuclid.LayoutContext; 030 import net.sourceforge.jeuclid.context.InlineLayoutContext; 031 import net.sourceforge.jeuclid.context.Parameter; 032 import net.sourceforge.jeuclid.elements.JEuclidElement; 033 import net.sourceforge.jeuclid.elements.support.Dimension2DImpl; 034 import net.sourceforge.jeuclid.elements.support.ElementListSupport; 035 import net.sourceforge.jeuclid.elements.support.GraphicsSupport; 036 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper; 037 import net.sourceforge.jeuclid.elements.support.attributes.HAlign; 038 import net.sourceforge.jeuclid.layout.GraphicsObject; 039 import net.sourceforge.jeuclid.layout.LayoutInfo; 040 import net.sourceforge.jeuclid.layout.LayoutStage; 041 import net.sourceforge.jeuclid.layout.LayoutView; 042 import net.sourceforge.jeuclid.layout.LayoutableNode; 043 import net.sourceforge.jeuclid.layout.LineObject; 044 045 import org.apache.batik.dom.AbstractDocument; 046 import org.apache.commons.logging.Log; 047 import org.apache.commons.logging.LogFactory; 048 import org.w3c.dom.Node; 049 import org.w3c.dom.mathml.MathMLLabeledRowElement; 050 import org.w3c.dom.mathml.MathMLNodeList; 051 import org.w3c.dom.mathml.MathMLTableCellElement; 052 import org.w3c.dom.mathml.MathMLTableElement; 053 import org.w3c.dom.mathml.MathMLTableRowElement; 054 055 /** 056 * This class presents a table. 057 * 058 * @version $Revision: bc1d5fde7b73 $ 059 */ 060 // CHECKSTYLE:OFF 061 // Data abstraction coupling is "to high". but this is necessary for proper 062 // layout. 063 public final class Mtable extends AbstractTableElement implements 064 MathMLTableElement { 065 // CHECKSTYLE:ON 066 067 /** 068 * The XML element from this class. 069 */ 070 public static final String ELEMENT = "mtable"; 071 072 /** Attribute for columnalign. */ 073 static final String ATTR_COLUMNALIGN = "columnalign"; 074 075 /** Attribute for rowalign. */ 076 static final String ATTR_ROWALIGN = "rowalign"; 077 078 /** Attribute for groupalign. */ 079 static final String ATTR_GROUPALIGN = "groupalign"; 080 081 /** attribute for rowlines. */ 082 private static final String ATTR_ROWLINES = "rowlines"; 083 084 /** attribute for columnlines. */ 085 private static final String ATTR_COLUMNLINES = "columnlines"; 086 087 /** attribute for align. */ 088 private static final String ATTR_ALIGN = "align"; 089 090 /** attribute for alignmentscope. */ 091 private static final String ATTR_ALIGNMENTSCOPE = "alignmentscope"; 092 093 /** attribute for columnwidth. */ 094 private static final String ATTR_COLUMNWIDTH = "columnwidth"; 095 096 /** attribute for width. */ 097 private static final String ATTR_WIDTH = "width"; 098 099 /** attribute for rowspacing. */ 100 private static final String ATTR_ROWSPACING = "rowspacing"; 101 102 /** attribute for columnspacing. */ 103 private static final String ATTR_COLUMNSPACING = "columnspacing"; 104 105 /** attribute for frame. */ 106 private static final String ATTR_FRAME = "frame"; 107 108 /** attribute for framespacing. */ 109 private static final String ATTR_FRAMESPACING = "framespacing"; 110 111 /** attribute for equalrows. */ 112 private static final String ATTR_EQUALROWS = "equalrows"; 113 114 /** attribute for equalcolumns. */ 115 private static final String ATTR_EQUALCOLUMNS = "equalcolumns"; 116 117 /** attribute for displaystyle. */ 118 private static final String ATTR_DISPLAYSTYLE = "displaystyle"; 119 120 /** attribute for side. */ 121 private static final String ATTR_SIDE = "side"; 122 123 /** attribute for minlabelspacing. */ 124 private static final String ATTR_MINLABELSPACING = "minlabelspacing"; 125 126 /** value for no lines. */ 127 private static final String VALUE_NONE = "none"; 128 129 /** value for dashed lines. */ 130 private static final String VALUE_DASHED = "dashed"; 131 132 /** value for solid lines. */ 133 private static final String VALUE_SOLID = "solid"; 134 135 private static final long serialVersionUID = 1L; 136 137 /** 138 * Default column spacing. 139 */ 140 private static final String DEFAULT_COLUMNSPACING = "0.8em"; 141 142 /** 143 * Default row spacing. 144 */ 145 private static final String DEFAULT_ROWSPACING = "1.0ex"; 146 147 /** 148 * Default frame spacing. 149 */ 150 private static final String DEFAULT_FRAMESPACING = "0.4em 0.5ex"; 151 152 private static final String VALUE_AUTO = "auto"; 153 154 /** 155 * Logger for this class 156 */ 157 private static final Log LOGGER = LogFactory.getLog(Mtable.class); 158 159 /** 160 * Class for line types. 161 */ 162 public enum LineType { 163 /** No lines. */ 164 NONE, 165 /** Solid line. */ 166 SOLID, 167 /** Dashed line. */ 168 DASHED; 169 170 /** 171 * Parse a string and return a linetype. 172 * 173 * @param s 174 * the string to parse 175 * @return a line type for this string type 176 */ 177 public static LineType parseLineType(final String s) { 178 final LineType retVal; 179 if (s.equalsIgnoreCase(Mtable.VALUE_SOLID)) { 180 retVal = SOLID; 181 } else if (s.equalsIgnoreCase(Mtable.VALUE_DASHED)) { 182 retVal = DASHED; 183 } else { 184 retVal = NONE; 185 } 186 return retVal; 187 } 188 }; 189 190 /** 191 * Class for alignment types. 192 */ 193 private static final class VAlign { 194 195 /** Align to top. */ 196 static final int TOP = 0; 197 198 /** Align to bottom. */ 199 static final int BOTTOM = 1; 200 201 /** Align to center. */ 202 static final int CENTER = 2; 203 204 /** Align to baseline. */ 205 static final int BASELINE = 3; 206 207 /** Align to axis. */ 208 static final int AXIS = 4; 209 210 static final String VALUE_TOP = "top"; 211 212 static final String VALUE_BOTTOM = "bottom"; 213 214 static final String VALUE_CENTER = "center"; 215 216 static final String VALUE_BASELINE = "baseline"; 217 218 static final String VALUE_AXIS = "axis"; 219 220 static final VAlign BASELINE_ALIGN = new VAlign(Mtable.VAlign.BASELINE, 221 0); 222 223 private static final String INVALID_VERTICAL_ALIGNMENT_VALUE = "Invalid vertical alignment value: "; 224 225 private final int valign; 226 227 private final int alignTo; 228 229 private VAlign(final int align, final int relativeTo) { 230 this.valign = align; 231 this.alignTo = relativeTo; 232 } 233 234 /** 235 * Parse a string and return a alignment. 236 * 237 * @param s 238 * the string to parse 239 * @return an alignment for this string type 240 */ 241 public static VAlign parseString(final String s) { 242 if ((s == null) || (s.length() == 0)) { 243 return null; 244 } 245 final int align; 246 int relativeTo = 0; 247 final String s2 = s.trim().toLowerCase(Locale.ENGLISH); 248 final String s3; 249 if (s2.startsWith(Mtable.VAlign.VALUE_TOP)) { 250 align = Mtable.VAlign.TOP; 251 s3 = s2.substring(Mtable.VAlign.VALUE_TOP.length()).trim(); 252 } else if (s2.startsWith(Mtable.VAlign.VALUE_BOTTOM)) { 253 align = Mtable.VAlign.BOTTOM; 254 s3 = s2.substring(Mtable.VAlign.VALUE_BOTTOM.length()).trim(); 255 } else if (s2.startsWith(Mtable.VAlign.VALUE_CENTER)) { 256 align = Mtable.VAlign.CENTER; 257 s3 = s2.substring(Mtable.VAlign.VALUE_CENTER.length()).trim(); 258 } else if (s2.startsWith(Mtable.VAlign.VALUE_BASELINE)) { 259 align = Mtable.VAlign.BASELINE; 260 s3 = s2.substring(Mtable.VAlign.VALUE_BASELINE.length()).trim(); 261 } else if (s2.startsWith(Mtable.VAlign.VALUE_AXIS)) { 262 align = Mtable.VAlign.AXIS; 263 s3 = s2.substring(Mtable.VAlign.VALUE_AXIS.length()).trim(); 264 } else { 265 Mtable.LOGGER 266 .warn(Mtable.VAlign.INVALID_VERTICAL_ALIGNMENT_VALUE 267 + s); 268 align = Mtable.VAlign.BASELINE; 269 s3 = "0"; 270 } 271 if (s3.length() > 0) { 272 try { 273 relativeTo = Integer.parseInt(s3); 274 } catch (final NumberFormatException nfe) { 275 Mtable.LOGGER 276 .warn(Mtable.VAlign.INVALID_VERTICAL_ALIGNMENT_VALUE 277 + s); 278 } 279 } 280 return new VAlign(align, relativeTo); 281 } 282 283 public int getAlign() { 284 return this.valign; 285 } 286 287 public int getRelative() { 288 return this.alignTo; 289 } 290 } 291 292 /** 293 * Default constructor. Sets MathML Namespace. 294 * 295 * @param qname 296 * Qualified name. 297 * @param odoc 298 * Owner Document. 299 */ 300 public Mtable(final String qname, final AbstractDocument odoc) { 301 super(qname, odoc); 302 303 this.setDefaultMathAttribute(Mtable.ATTR_ALIGN, 304 Mtable.VAlign.VALUE_AXIS); 305 this.setDefaultMathAttribute(Mtable.ATTR_ROWALIGN, 306 Mtable.VAlign.VALUE_BASELINE); 307 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNALIGN, 308 HAlign.ALIGN_CENTER); 309 this.setDefaultMathAttribute(Mtable.ATTR_GROUPALIGN, "{left}"); 310 this 311 .setDefaultMathAttribute(Mtable.ATTR_ALIGNMENTSCOPE, 312 Constants.TRUE); 313 this 314 .setDefaultMathAttribute(Mtable.ATTR_COLUMNWIDTH, 315 Mtable.VALUE_AUTO); 316 this.setDefaultMathAttribute(Mtable.ATTR_WIDTH, Mtable.VALUE_AUTO); 317 this.setDefaultMathAttribute(Mtable.ATTR_ROWSPACING, 318 Mtable.DEFAULT_ROWSPACING); 319 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNSPACING, 320 Mtable.DEFAULT_COLUMNSPACING); 321 this.setDefaultMathAttribute(Mtable.ATTR_ROWLINES, Mtable.VALUE_NONE); 322 this 323 .setDefaultMathAttribute(Mtable.ATTR_COLUMNLINES, 324 Mtable.VALUE_NONE); 325 this.setDefaultMathAttribute(Mtable.ATTR_FRAME, Mtable.VALUE_NONE); 326 this.setDefaultMathAttribute(Mtable.ATTR_FRAMESPACING, 327 Mtable.DEFAULT_FRAMESPACING); 328 this.setDefaultMathAttribute(Mtable.ATTR_EQUALROWS, Constants.FALSE); 329 this.setDefaultMathAttribute(Mtable.ATTR_EQUALCOLUMNS, Constants.FALSE); 330 this.setDefaultMathAttribute(Mtable.ATTR_DISPLAYSTYLE, Constants.FALSE); 331 this.setDefaultMathAttribute(Mtable.ATTR_SIDE, HAlign.ALIGN_RIGHT); 332 this.setDefaultMathAttribute(Mtable.ATTR_MINLABELSPACING, 333 Mtable.DEFAULT_COLUMNSPACING); 334 } 335 336 /** {@inheritDoc} */ 337 @Override 338 protected Node newNode() { 339 return new Mtable(this.nodeName, this.ownerDocument); 340 } 341 342 /** {@inheritDoc} */ 343 @Override 344 public LayoutContext getChildLayoutContext(final int childNum, 345 final LayoutContext context) { 346 return new InlineLayoutContext(this 347 .applyLocalAttributesToContext(context)); 348 } 349 350 private float getFramespacingh(final LayoutContext now) { 351 if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) { 352 return 0; 353 } 354 final String spacing = this.getSpaceArrayEntry(this.getFramespacing(), 355 0); 356 return AttributesHelper.convertSizeToPt(spacing, now, 357 AttributesHelper.PT); 358 } 359 360 private float getFramespacingv(final LayoutContext now) { 361 if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) { 362 return 0; 363 } 364 final String spacing = this.getSpaceArrayEntry(this.getFramespacing(), 365 1); 366 return AttributesHelper.convertSizeToPt(spacing, now, 367 AttributesHelper.PT); 368 } 369 370 /** {@inheritDoc} */ 371 public String getRowlines() { 372 return this.getMathAttribute(Mtable.ATTR_ROWLINES); 373 } 374 375 /** {@inheritDoc} */ 376 public void setRowlines(final String rowlines) { 377 this.setAttribute(Mtable.ATTR_ROWLINES, rowlines); 378 } 379 380 /** {@inheritDoc} */ 381 public String getColumnlines() { 382 return this.getMathAttribute(Mtable.ATTR_COLUMNLINES); 383 } 384 385 /** {@inheritDoc} */ 386 public void setColumnlines(final String columnlines) { 387 this.setAttribute(Mtable.ATTR_COLUMNLINES, columnlines); 388 } 389 390 private LineType getRowLine(final int row) { 391 return Mtable.LineType.parseLineType(this.getSpaceArrayEntry(this 392 .getRowlines(), row)); 393 } 394 395 private LineType getColumnLine(final int col) { 396 return Mtable.LineType.parseLineType(this.getSpaceArrayEntry(this 397 .getColumnlines(), col)); 398 } 399 400 private LineType getFrameAsLineType() { 401 return Mtable.LineType.parseLineType(this.getFrame()); 402 } 403 404 /** 405 * Gets an entry in a white-space separated string. 406 * <p> 407 * If the entry requested is beyond the index, the last entry is returned. 408 * 409 * @todo This method is probably useful for other attribute values. Examine, 410 * and move to a more common place. (like AttrHelper) 411 * @param string 412 * the string in which to look. 413 * @param index 414 * index of the element (0-based) 415 * @return the element at that index 416 */ 417 private String getSpaceArrayEntry(final String string, final int index) { 418 final String[] array; 419 if (string == null) { 420 array = new String[0]; 421 } else { 422 array = string.split("\\s"); 423 } 424 int cur = -1; 425 String last = ""; 426 for (final String s : array) { 427 if (s.length() > 0) { 428 cur++; 429 if (cur == index) { 430 return s; 431 } 432 last = s; 433 } 434 } 435 return last; 436 } 437 438 /** {@inheritDoc} */ 439 public String getColumnwidth() { 440 return this.getMathAttribute(Mtable.ATTR_COLUMNWIDTH); 441 } 442 443 /** {@inheritDoc} */ 444 public void setColumnwidth(final String columnwidth) { 445 this.setAttribute(Mtable.ATTR_COLUMNWIDTH, columnwidth); 446 } 447 448 /** {@inheritDoc} */ 449 public String getWidth() { 450 return this.getMathAttribute(Mtable.ATTR_WIDTH); 451 } 452 453 /** {@inheritDoc} */ 454 public void setWidth(final String width) { 455 this.setAttribute(Mtable.ATTR_WIDTH, width); 456 } 457 458 /** {@inheritDoc} */ 459 public String getAlign() { 460 return this.getMathAttribute(Mtable.ATTR_ALIGN); 461 } 462 463 /** {@inheritDoc} */ 464 public void setAlign(final String align) { 465 this.setAttribute(Mtable.ATTR_ALIGN, align); 466 } 467 468 /** {@inheritDoc} */ 469 public String getAlignmentscope() { 470 return this.getMathAttribute(Mtable.ATTR_ALIGNMENTSCOPE); 471 } 472 473 /** {@inheritDoc} */ 474 public void setAlignmentscope(final String alignmentscope) { 475 this.setAttribute(Mtable.ATTR_ALIGNMENTSCOPE, alignmentscope); 476 } 477 478 /** {@inheritDoc} */ 479 public String getRowspacing() { 480 return this.getMathAttribute(Mtable.ATTR_ROWSPACING); 481 } 482 483 /** {@inheritDoc} */ 484 public void setRowspacing(final String rowspacing) { 485 this.setAttribute(Mtable.ATTR_ROWSPACING, rowspacing); 486 } 487 488 /** {@inheritDoc} */ 489 public String getColumnspacing() { 490 return this.getMathAttribute(Mtable.ATTR_COLUMNSPACING); 491 } 492 493 /** {@inheritDoc} */ 494 public void setColumnspacing(final String columnspacing) { 495 this.setAttribute(Mtable.ATTR_COLUMNSPACING, columnspacing); 496 } 497 498 /** {@inheritDoc} */ 499 public String getFrame() { 500 return this.getMathAttribute(Mtable.ATTR_FRAME); 501 } 502 503 /** {@inheritDoc} */ 504 public void setFrame(final String frame) { 505 this.setAttribute(Mtable.ATTR_FRAME, frame); 506 } 507 508 /** {@inheritDoc} */ 509 public String getFramespacing() { 510 return this.getMathAttribute(Mtable.ATTR_FRAMESPACING); 511 } 512 513 /** {@inheritDoc} */ 514 public void setFramespacing(final String framespacing) { 515 this.setAttribute(Mtable.ATTR_FRAMESPACING, framespacing); 516 } 517 518 /** {@inheritDoc} */ 519 public String getEqualrows() { 520 return this.getMathAttribute(Mtable.ATTR_EQUALROWS); 521 } 522 523 /** {@inheritDoc} */ 524 public void setEqualrows(final String equalrows) { 525 this.setAttribute(Mtable.ATTR_EQUALROWS, equalrows); 526 } 527 528 /** {@inheritDoc} */ 529 public String getEqualcolumns() { 530 return this.getMathAttribute(Mtable.ATTR_EQUALCOLUMNS); 531 } 532 533 /** {@inheritDoc} */ 534 public void setEqualcolumns(final String equalcolumns) { 535 this.setAttribute(Mtable.ATTR_EQUALCOLUMNS, equalcolumns); 536 } 537 538 /** {@inheritDoc} */ 539 public String getDisplaystyle() { 540 return this.getMathAttribute(Mtable.ATTR_DISPLAYSTYLE); 541 } 542 543 /** {@inheritDoc} */ 544 public void setDisplaystyle(final String displaystyle) { 545 this.setAttribute(Mtable.ATTR_DISPLAYSTYLE, displaystyle); 546 } 547 548 /** {@inheritDoc} */ 549 public String getSide() { 550 return this.getMathAttribute(Mtable.ATTR_SIDE); 551 } 552 553 /** {@inheritDoc} */ 554 public void setSide(final String side) { 555 this.setAttribute(Mtable.ATTR_SIDE, side); 556 } 557 558 /** {@inheritDoc} */ 559 public String getMinlabelspacing() { 560 return this.getMathAttribute(Mtable.ATTR_MINLABELSPACING); 561 } 562 563 /** {@inheritDoc} */ 564 public void setMinlabelspacing(final String minlabelspacing) { 565 this.setAttribute(Mtable.ATTR_MINLABELSPACING, minlabelspacing); 566 } 567 568 /** {@inheritDoc} */ 569 public MathMLNodeList getRows() { 570 // TODO: Implement 571 return null; 572 } 573 574 /** {@inheritDoc} */ 575 public MathMLTableRowElement insertEmptyRow(final int index) { 576 // TODO: Implement 577 return null; 578 } 579 580 /** {@inheritDoc} */ 581 public MathMLLabeledRowElement insertEmptyLabeledRow(final int index) { 582 // TODO: Implement 583 return null; 584 } 585 586 /** {@inheritDoc} */ 587 public MathMLTableRowElement getRow(final int index) { 588 // TODO: Implement 589 return null; 590 } 591 592 /** {@inheritDoc} */ 593 public MathMLTableRowElement insertRow(final int index, 594 final MathMLTableRowElement newRow) { 595 // TODO: Implement 596 return null; 597 } 598 599 /** {@inheritDoc} */ 600 public MathMLTableRowElement setRow(final int index, 601 final MathMLTableRowElement newRow) { 602 // TODO: Implement 603 return null; 604 } 605 606 /** {@inheritDoc} */ 607 public void deleteRow(final int index) { 608 // TODO: Implement 609 } 610 611 /** {@inheritDoc} */ 612 public MathMLTableRowElement removeRow(final int index) { 613 // TODO: Implement 614 return null; 615 } 616 617 /** {@inheritDoc} */ 618 public void deleteRow(final long index) { 619 // TODO Auto-generated method stub 620 621 } 622 623 /** {@inheritDoc} */ 624 public MathMLTableRowElement getRow(final long index) { 625 // TODO Auto-generated method stub 626 return null; 627 } 628 629 /** {@inheritDoc} */ 630 public MathMLLabeledRowElement insertEmptyLabeledRow(final long index) { 631 // TODO Auto-generated method stub 632 return null; 633 } 634 635 /** {@inheritDoc} */ 636 public MathMLTableRowElement insertEmptyRow(final long index) { 637 // TODO Auto-generated method stub 638 return null; 639 } 640 641 /** {@inheritDoc} */ 642 public MathMLTableRowElement insertRow(final long index, 643 final MathMLTableRowElement newRow) { 644 // TODO Auto-generated method stub 645 return null; 646 } 647 648 /** {@inheritDoc} */ 649 public MathMLTableRowElement removeRow(final long index) { 650 // TODO Auto-generated method stub 651 return null; 652 } 653 654 /** {@inheritDoc} */ 655 public MathMLTableRowElement setRow(final long index, 656 final MathMLTableRowElement newRow) { 657 // TODO Auto-generated method stub 658 return null; 659 } 660 661 /** {@inheritDoc} */ 662 // CHECKSTYLE:OFF 663 // Function is too long. Unfortunately it has to be for proper layout 664 @Override 665 public void layoutStageInvariant(final LayoutView view, 666 final LayoutInfo info, final LayoutStage stage, 667 final LayoutContext context) { 668 // CHECKSTYLE:ON 669 final Graphics2D g = view.getGraphics(); 670 final LayoutContext now = this.applyLocalAttributesToContext(context); 671 final List<LayoutableNode> children = this.getChildrenToLayout(); 672 final LayoutInfo[] rowInfos = new LayoutInfo[children.size()]; 673 final LayoutableNode[] rowChild = new LayoutableNode[children.size()]; 674 float y = 0; 675 int rows = 0; 676 677 // Layout Rows vertically, calculate height of the table. 678 final float vFrameSpacing = this.getFramespacingv(now); 679 float height = vFrameSpacing; 680 for (final LayoutableNode child : children) { 681 rowChild[rows] = child; 682 final LayoutInfo mtrInfo = view.getInfo(child); 683 y += mtrInfo.getAscentHeight(stage); 684 rowInfos[rows] = mtrInfo; 685 rows++; 686 mtrInfo.moveTo(0, y, stage); 687 y += mtrInfo.getDescentHeight(stage); 688 height = y; 689 y += AttributesHelper.convertSizeToPt(this.getSpaceArrayEntry(this 690 .getRowspacing(), rows), now, AttributesHelper.PT); 691 } 692 height += vFrameSpacing; 693 694 final float verticalShift = this.shiftTableVertically(stage, context, 695 g, rowInfos, rows, height); 696 697 final List<LayoutableNode>[] mtdChildren = this 698 .createListOfMtdChildren(rowChild, rows); 699 this.stretchAndAlignMtds(view, mtdChildren, rowInfos, rows, stage); 700 701 final List<Float> columnwidth = this.calculateBasicColumnWidth(view, 702 stage, rows, mtdChildren); 703 704 // TODO This is where Alignment-Groups should be calculated 705 706 final float totalWidth = this.layoutColumnsHorizontally(view, stage, 707 now, rows, mtdChildren, columnwidth); 708 709 this.setRowWidth(stage, rowInfos, rows, totalWidth); 710 711 this.addRowLines(info, rowInfos, rows, totalWidth, stage, now); 712 this.addColumnLines(info, columnwidth, verticalShift, height, now); 713 this.addFrame(info, totalWidth, verticalShift, height, now); 714 715 final float hFrameSpacing = this.getFramespacingh(now); 716 final Dimension2D borderLeftTop = new Dimension2DImpl(hFrameSpacing, 717 vFrameSpacing); 718 final Dimension2D borderRightBottom = new Dimension2DImpl( 719 hFrameSpacing, vFrameSpacing); 720 ElementListSupport.fillInfoFromChildren(view, info, this, stage, 721 borderLeftTop, borderRightBottom); 722 } 723 724 private void addFrame(final LayoutInfo info, final float width, 725 final float verticalShift, final float height, 726 final LayoutContext now) { 727 final LineType lineType = this.getFrameAsLineType(); 728 final boolean solid = Mtable.LineType.SOLID.equals(lineType); 729 final boolean dashed = Mtable.LineType.DASHED.equals(lineType); 730 if (dashed || solid) { 731 final float lineWidth = GraphicsSupport.lineWidth(now); 732 final float lineInset = lineWidth / 2.0f; 733 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR); 734 final List<GraphicsObject> go = info.getGraphicObjects(); 735 final float vFrameSpacing = this.getFramespacingv(now); 736 737 final float left = lineInset; 738 final float right = width - lineInset; 739 final float top = verticalShift + lineInset - vFrameSpacing; 740 final float bottom = height + verticalShift - lineInset; 741 go.add(new LineObject(left, top, right, top, lineWidth, color, 742 dashed)); 743 go.add(new LineObject(left, bottom, right, bottom, lineWidth, 744 color, dashed)); 745 go.add(new LineObject(left, top, left, bottom, lineWidth, color, 746 dashed)); 747 go.add(new LineObject(right, top, right, bottom, lineWidth, color, 748 dashed)); 749 } 750 } 751 752 private void addRowLines(final LayoutInfo info, 753 final LayoutInfo[] rowInfos, final int rows, final float width, 754 final LayoutStage stage, final LayoutContext now) { 755 final float lineWidth = GraphicsSupport.lineWidth(now); 756 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR); 757 758 final float inFrameStart = this.getFramespacingh(now); 759 for (int row = 0; row < rows - 1; row++) { 760 final LineType lineType = this.getRowLine(row); 761 final boolean solid = Mtable.LineType.SOLID.equals(lineType); 762 final boolean dashed = Mtable.LineType.DASHED.equals(lineType); 763 if (dashed || solid) { 764 final float y = (rowInfos[row].getPosY(stage) 765 + rowInfos[row].getDescentHeight(stage) 766 + rowInfos[row + 1].getPosY(stage) - rowInfos[row + 1] 767 .getAscentHeight(stage)) / 2.0f; 768 info.getGraphicObjects().add( 769 new LineObject(inFrameStart, y, width - inFrameStart, 770 y, lineWidth, color, dashed)); 771 } 772 } 773 } 774 775 private void addColumnLines(final LayoutInfo info, 776 final List<Float> columnwidth, final float verticalShift, 777 final float height, final LayoutContext now) { 778 final float lineWidth = GraphicsSupport.lineWidth(now); 779 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR); 780 float x = this.getFramespacingh(now); 781 782 final float inFrameStart = this.getFramespacingv(now); 783 final float colsm1 = columnwidth.size() - 1; 784 for (int col = 0; col < colsm1; col++) { 785 final LineType lineType = this.getColumnLine(col); 786 final boolean solid = Mtable.LineType.SOLID.equals(lineType); 787 final boolean dashed = Mtable.LineType.DASHED.equals(lineType); 788 if (dashed || solid) { 789 final float halfSpace = this.getSpaceAfterColumn(now, col) / 2.0f; 790 x += columnwidth.get(col) + halfSpace; 791 info.getGraphicObjects().add( 792 new LineObject(x, verticalShift, x, height 793 + verticalShift - inFrameStart, lineWidth, 794 color, dashed)); 795 x += halfSpace; 796 } 797 } 798 } 799 800 private void stretchAndAlignMtds(final LayoutView view, 801 final List<LayoutableNode>[] mtdChildren, 802 final LayoutInfo[] rowInfos, final int rows, final LayoutStage stage) { 803 for (int i = 0; i < rows; i++) { 804 final float rowAscent = rowInfos[i].getAscentHeight(stage); 805 final float rowDescent = rowInfos[i].getDescentHeight(stage); 806 for (final LayoutableNode n : mtdChildren[i]) { 807 final LayoutInfo mtdInfo = view.getInfo(n); 808 809 final VAlign valign = this.getVAlign((JEuclidElement) n, i); 810 final float verticalShift; 811 if (valign.getAlign() == Mtable.VAlign.TOP) { 812 verticalShift = -rowAscent + mtdInfo.getAscentHeight(stage); 813 } else if (valign.getAlign() == Mtable.VAlign.BOTTOM) { 814 verticalShift = rowDescent 815 - mtdInfo.getDescentHeight(stage); 816 } else if (valign.getAlign() == Mtable.VAlign.CENTER) { 817 verticalShift = (-rowAscent + rowDescent 818 + mtdInfo.getAscentHeight(stage) - mtdInfo 819 .getDescentHeight(stage)) / 2.0f; 820 } else if (valign.getAlign() == Mtable.VAlign.AXIS) { 821 // TODO: This uses center instead of axis. 822 verticalShift = (-rowAscent + rowDescent 823 + mtdInfo.getAscentHeight(stage) - mtdInfo 824 .getDescentHeight(stage)) / 2.0f; 825 } else { 826 // BASELINE 827 verticalShift = 0.0f; 828 } 829 mtdInfo.shiftVertically(verticalShift, stage); 830 mtdInfo.setStretchAscent(rowAscent + verticalShift); 831 mtdInfo.setStretchDescent(rowDescent - verticalShift); 832 } 833 } 834 } 835 836 private float shiftTableVertically(final LayoutStage stage, 837 final LayoutContext context, final Graphics2D g, 838 final LayoutInfo[] rowInfos, final int rows, final float height) { 839 // Shift table by given vertical alignment 840 // final String alignStr = this.getAlign(); 841 // AlignmentType align = 842 // Mtable.AlignmentType.parseAlignmentType(alignStr); 843 // TODO: Proper vertical alignment; 844 // This is "axis" alignment. 845 final float verticalShift = -this.getMiddleShift(g, context) - height 846 / 2.0f; 847 848 for (int i = 0; i < rows; i++) { 849 rowInfos[i].shiftVertically(verticalShift, stage); 850 } 851 return verticalShift; 852 } 853 854 @SuppressWarnings("unchecked") 855 private List<LayoutableNode>[] createListOfMtdChildren( 856 final LayoutableNode[] rowChild, final int rows) { 857 final List<LayoutableNode>[] mtdChildren = new List[rows]; 858 for (int i = 0; i < rows; i++) { 859 if (rowChild[i] instanceof MathMLTableRowElement) { 860 mtdChildren[i] = rowChild[i].getChildrenToLayout(); 861 } else { 862 mtdChildren[i] = new ArrayList<LayoutableNode>(1); 863 mtdChildren[i].add(rowChild[i]); 864 } 865 } 866 return mtdChildren; 867 } 868 869 private List<Float> calculateBasicColumnWidth(final LayoutView view, 870 final LayoutStage stage, final int rows, 871 final List<LayoutableNode>[] mtdChildren) { 872 final List<Float> columnwidth = new ArrayList<Float>(); 873 for (int i = 0; i < rows; i++) { 874 int missing = mtdChildren[i].size() - columnwidth.size(); 875 while (missing > 0) { 876 columnwidth.add(0.0f); 877 missing--; 878 } 879 int col = 0; 880 for (final LayoutableNode n : mtdChildren[i]) { 881 final float width = Math.max(columnwidth.get(col), view 882 .getInfo(n).getWidth(stage)); 883 columnwidth.set(col, width); 884 col++; 885 } 886 } 887 if (Boolean.parseBoolean(this.getEqualcolumns())) { 888 this.makeEqual(columnwidth); 889 } 890 return columnwidth; 891 } 892 893 private void makeEqual(final List<Float> columnwidth) { 894 float maxWidth = 0.0f; 895 for (final Float width : columnwidth) { 896 maxWidth = Math.max(width, maxWidth); 897 } 898 final int cols = columnwidth.size(); 899 for (int i = 0; i < cols; i++) { 900 columnwidth.set(i, maxWidth); 901 } 902 } 903 904 private void setRowWidth(final LayoutStage stage, 905 final LayoutInfo[] rowInfos, final int rows, final float totalWidth) { 906 for (int i = 0; i < rows; i++) { 907 rowInfos[i].setWidth(totalWidth, stage); 908 } 909 } 910 911 private float layoutColumnsHorizontally(final LayoutView view, 912 final LayoutStage stage, final LayoutContext now, final int rows, 913 final List<LayoutableNode>[] mtdChildren, 914 final List<Float> columnwidth) { 915 final float hFrameSpacing = this.getFramespacingh(now); 916 float totalWidth = hFrameSpacing; 917 for (int i = 0; i < rows; i++) { 918 float x = hFrameSpacing; 919 int col = 0; 920 for (final LayoutableNode n : mtdChildren[i]) { 921 final LayoutInfo mtdInfo = view.getInfo(n); 922 final HAlign halign = this.getHAlign((JEuclidElement) n, col); 923 final float colwi = columnwidth.get(col); 924 final float xo = halign.getHAlignOffset(stage, mtdInfo, colwi); 925 mtdInfo.moveTo(x + xo, mtdInfo.getPosY(stage), stage); 926 // mtdInfo.setWidth(colwi, stage); 927 mtdInfo.setStretchWidth(colwi); 928 x += colwi; 929 totalWidth = Math.max(totalWidth, x); 930 x += this.getSpaceAfterColumn(now, col); 931 col++; 932 } 933 } 934 return totalWidth + hFrameSpacing; 935 } 936 937 private float getSpaceAfterColumn(final LayoutContext now, final int col) { 938 final float columnSpace = AttributesHelper.convertSizeToPt(this 939 .getSpaceArrayEntry(this.getColumnspacing(), col), now, 940 AttributesHelper.PT); 941 return columnSpace; 942 } 943 944 private HAlign getHAlign(final JEuclidElement n, final int col) { 945 assert n != null; 946 final HAlign retVal; 947 if (n instanceof MathMLTableCellElement) { 948 final MathMLTableCellElement cell = (MathMLTableCellElement) n; 949 final String alignString = cell.getColumnalign(); 950 final HAlign halign = HAlign.parseString(alignString, null); 951 if (halign == null) { 952 retVal = this.getHAlign(n.getParent(), col); 953 } else { 954 retVal = halign; 955 } 956 } else if (n instanceof MathMLTableRowElement) { 957 final MathMLTableRowElement rowE = (MathMLTableRowElement) n; 958 final String alignArray = rowE.getColumnalign(); 959 if ((alignArray != null) && (alignArray.length() > 0)) { 960 retVal = HAlign.parseString(this.getSpaceArrayEntry(alignArray, 961 col), HAlign.CENTER); 962 } else { 963 retVal = this.getHAlign(n.getParent(), col); 964 } 965 } else if (n instanceof MathMLTableElement) { 966 final MathMLTableElement table = (MathMLTableElement) n; 967 final String alignArray = table.getColumnalign(); 968 if ((alignArray != null) && (alignArray.length() > 0)) { 969 retVal = HAlign.parseString(this.getSpaceArrayEntry(alignArray, 970 col), HAlign.CENTER); 971 } else { 972 retVal = HAlign.CENTER; 973 } 974 } else { 975 retVal = this.getHAlign(n.getParent(), col); 976 } 977 return retVal; 978 } 979 980 private VAlign getVAlign(final JEuclidElement n, final int row) { 981 assert n != null; 982 final VAlign retVal; 983 if (n instanceof MathMLTableCellElement) { 984 final MathMLTableCellElement cell = (MathMLTableCellElement) n; 985 final String alignString = cell.getRowalign(); 986 final Mtable.VAlign valign = Mtable.VAlign.parseString(alignString); 987 if (valign == null) { 988 retVal = this.getVAlign(n.getParent(), row); 989 } else { 990 retVal = valign; 991 } 992 } else if (n instanceof MathMLTableRowElement) { 993 final MathMLTableRowElement rowE = (MathMLTableRowElement) n; 994 final String alignString = rowE.getRowalign(); 995 final Mtable.VAlign valign = Mtable.VAlign.parseString(alignString); 996 if (valign == null) { 997 retVal = this.getVAlign(n.getParent(), row); 998 } else { 999 retVal = valign; 1000 } 1001 } else if (n instanceof MathMLTableElement) { 1002 final MathMLTableElement table = (MathMLTableElement) n; 1003 final String alignArray = table.getRowalign(); 1004 if ((alignArray != null) && (alignArray.length() > 0)) { 1005 retVal = Mtable.VAlign.parseString(this.getSpaceArrayEntry( 1006 alignArray, row)); 1007 } else { 1008 retVal = Mtable.VAlign.BASELINE_ALIGN; 1009 } 1010 } else { 1011 retVal = this.getVAlign(n.getParent(), row); 1012 } 1013 return retVal; 1014 } 1015 1016 }