Coverage Report - net.sourceforge.jeuclid.elements.presentation.table.Mtable
 
Classes in this File Line Coverage Branch Coverage Complexity
Mtable
64%
198/309
58%
61/104
1,863
Mtable$LineType
80%
8/10
50%
2/4
1,863
Mtable$VAlign
51%
18/35
50%
8/16
1,863
 
 1  
 /*
 2  
  * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 /* $Id: Mtable.java,v bc1d5fde7b73 2009/06/01 14:40:54 maxberger $ */
 18  
 
 19  
 package net.sourceforge.jeuclid.elements.presentation.table;
 20  
 
 21  
 import java.awt.Color;
 22  
 import java.awt.Graphics2D;
 23  
 import java.awt.geom.Dimension2D;
 24  
 import java.util.ArrayList;
 25  
 import java.util.List;
 26  
 import java.util.Locale;
 27  
 
 28  
 import net.sourceforge.jeuclid.Constants;
 29  
 import net.sourceforge.jeuclid.LayoutContext;
 30  
 import net.sourceforge.jeuclid.context.InlineLayoutContext;
 31  
 import net.sourceforge.jeuclid.context.Parameter;
 32  
 import net.sourceforge.jeuclid.elements.JEuclidElement;
 33  
 import net.sourceforge.jeuclid.elements.support.Dimension2DImpl;
 34  
 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
 35  
 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
 36  
 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
 37  
 import net.sourceforge.jeuclid.elements.support.attributes.HAlign;
 38  
 import net.sourceforge.jeuclid.layout.GraphicsObject;
 39  
 import net.sourceforge.jeuclid.layout.LayoutInfo;
 40  
 import net.sourceforge.jeuclid.layout.LayoutStage;
 41  
 import net.sourceforge.jeuclid.layout.LayoutView;
 42  
 import net.sourceforge.jeuclid.layout.LayoutableNode;
 43  
 import net.sourceforge.jeuclid.layout.LineObject;
 44  
 
 45  
 import org.apache.batik.dom.AbstractDocument;
 46  
 import org.apache.commons.logging.Log;
 47  
 import org.apache.commons.logging.LogFactory;
 48  
 import org.w3c.dom.Node;
 49  
 import org.w3c.dom.mathml.MathMLLabeledRowElement;
 50  
 import org.w3c.dom.mathml.MathMLNodeList;
 51  
 import org.w3c.dom.mathml.MathMLTableCellElement;
 52  
 import org.w3c.dom.mathml.MathMLTableElement;
 53  
 import org.w3c.dom.mathml.MathMLTableRowElement;
 54  
 
 55  
 /**
 56  
  * This class presents a table.
 57  
  * 
 58  
  * @version $Revision: bc1d5fde7b73 $
 59  
  */
 60  
 // CHECKSTYLE:OFF
 61  
 // Data abstraction coupling is "to high". but this is necessary for proper
 62  
 // layout.
 63  209
 public final class Mtable extends AbstractTableElement implements
 64  
         MathMLTableElement {
 65  
     // CHECKSTYLE:ON
 66  
 
 67  
     /**
 68  
      * The XML element from this class.
 69  
      */
 70  
     public static final String ELEMENT = "mtable";
 71  
 
 72  
     /** Attribute for columnalign. */
 73  
     static final String ATTR_COLUMNALIGN = "columnalign";
 74  
 
 75  
     /** Attribute for rowalign. */
 76  
     static final String ATTR_ROWALIGN = "rowalign";
 77  
 
 78  
     /** Attribute for groupalign. */
 79  
     static final String ATTR_GROUPALIGN = "groupalign";
 80  
 
 81  
     /** attribute for rowlines. */
 82  
     private static final String ATTR_ROWLINES = "rowlines";
 83  
 
 84  
     /** attribute for columnlines. */
 85  
     private static final String ATTR_COLUMNLINES = "columnlines";
 86  
 
 87  
     /** attribute for align. */
 88  
     private static final String ATTR_ALIGN = "align";
 89  
 
 90  
     /** attribute for alignmentscope. */
 91  
     private static final String ATTR_ALIGNMENTSCOPE = "alignmentscope";
 92  
 
 93  
     /** attribute for columnwidth. */
 94  
     private static final String ATTR_COLUMNWIDTH = "columnwidth";
 95  
 
 96  
     /** attribute for width. */
 97  
     private static final String ATTR_WIDTH = "width";
 98  
 
 99  
     /** 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  209
     private static final Log LOGGER = LogFactory.getLog(Mtable.class);
 158  
 
 159  
     /**
 160  
      * Class for line types.
 161  
      */
 162  836
     public enum LineType {
 163  
         /** No lines. */
 164  209
         NONE,
 165  
         /** Solid line. */
 166  209
         SOLID,
 167  
         /** Dashed line. */
 168  209
         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  14839
             if (s.equalsIgnoreCase(Mtable.VALUE_SOLID)) {
 180  0
                 retVal = SOLID;
 181  14839
             } else if (s.equalsIgnoreCase(Mtable.VALUE_DASHED)) {
 182  0
                 retVal = DASHED;
 183  
             } else {
 184  14839
                 retVal = NONE;
 185  
             }
 186  14839
             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  209
         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  6479
         private VAlign(final int align, final int relativeTo) {
 230  6479
             this.valign = align;
 231  6479
             this.alignTo = relativeTo;
 232  6479
         }
 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  18810
             if ((s == null) || (s.length() == 0)) {
 243  12540
                 return null;
 244  
             }
 245  
             final int align;
 246  6270
             int relativeTo = 0;
 247  6270
             final String s2 = s.trim().toLowerCase(Locale.ENGLISH);
 248  
             final String s3;
 249  6270
             if (s2.startsWith(Mtable.VAlign.VALUE_TOP)) {
 250  0
                 align = Mtable.VAlign.TOP;
 251  0
                 s3 = s2.substring(Mtable.VAlign.VALUE_TOP.length()).trim();
 252  6270
             } else if (s2.startsWith(Mtable.VAlign.VALUE_BOTTOM)) {
 253  0
                 align = Mtable.VAlign.BOTTOM;
 254  0
                 s3 = s2.substring(Mtable.VAlign.VALUE_BOTTOM.length()).trim();
 255  6270
             } else if (s2.startsWith(Mtable.VAlign.VALUE_CENTER)) {
 256  0
                 align = Mtable.VAlign.CENTER;
 257  0
                 s3 = s2.substring(Mtable.VAlign.VALUE_CENTER.length()).trim();
 258  6270
             } else if (s2.startsWith(Mtable.VAlign.VALUE_BASELINE)) {
 259  6270
                 align = Mtable.VAlign.BASELINE;
 260  6270
                 s3 = s2.substring(Mtable.VAlign.VALUE_BASELINE.length()).trim();
 261  0
             } else if (s2.startsWith(Mtable.VAlign.VALUE_AXIS)) {
 262  0
                 align = Mtable.VAlign.AXIS;
 263  0
                 s3 = s2.substring(Mtable.VAlign.VALUE_AXIS.length()).trim();
 264  
             } else {
 265  0
                 Mtable.LOGGER
 266  
                         .warn(Mtable.VAlign.INVALID_VERTICAL_ALIGNMENT_VALUE
 267  
                                 + s);
 268  0
                 align = Mtable.VAlign.BASELINE;
 269  0
                 s3 = "0";
 270  
             }
 271  6270
             if (s3.length() > 0) {
 272  
                 try {
 273  0
                     relativeTo = Integer.parseInt(s3);
 274  0
                 } catch (final NumberFormatException nfe) {
 275  0
                     Mtable.LOGGER
 276  
                             .warn(Mtable.VAlign.INVALID_VERTICAL_ALIGNMENT_VALUE
 277  
                                     + s);
 278  0
                 }
 279  
             }
 280  6270
             return new VAlign(align, relativeTo);
 281  
         }
 282  
 
 283  
         public int getAlign() {
 284  25080
             return this.valign;
 285  
         }
 286  
 
 287  
         public int getRelative() {
 288  0
             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  3971
         super(qname, odoc);
 302  
 
 303  3971
         this.setDefaultMathAttribute(Mtable.ATTR_ALIGN,
 304  
                 Mtable.VAlign.VALUE_AXIS);
 305  3971
         this.setDefaultMathAttribute(Mtable.ATTR_ROWALIGN,
 306  
                 Mtable.VAlign.VALUE_BASELINE);
 307  3971
         this.setDefaultMathAttribute(Mtable.ATTR_COLUMNALIGN,
 308  
                 HAlign.ALIGN_CENTER);
 309  3971
         this.setDefaultMathAttribute(Mtable.ATTR_GROUPALIGN, "{left}");
 310  3971
         this
 311  
                 .setDefaultMathAttribute(Mtable.ATTR_ALIGNMENTSCOPE,
 312  
                         Constants.TRUE);
 313  3971
         this
 314  
                 .setDefaultMathAttribute(Mtable.ATTR_COLUMNWIDTH,
 315  
                         Mtable.VALUE_AUTO);
 316  3971
         this.setDefaultMathAttribute(Mtable.ATTR_WIDTH, Mtable.VALUE_AUTO);
 317  3971
         this.setDefaultMathAttribute(Mtable.ATTR_ROWSPACING,
 318  
                 Mtable.DEFAULT_ROWSPACING);
 319  3971
         this.setDefaultMathAttribute(Mtable.ATTR_COLUMNSPACING,
 320  
                 Mtable.DEFAULT_COLUMNSPACING);
 321  3971
         this.setDefaultMathAttribute(Mtable.ATTR_ROWLINES, Mtable.VALUE_NONE);
 322  3971
         this
 323  
                 .setDefaultMathAttribute(Mtable.ATTR_COLUMNLINES,
 324  
                         Mtable.VALUE_NONE);
 325  3971
         this.setDefaultMathAttribute(Mtable.ATTR_FRAME, Mtable.VALUE_NONE);
 326  3971
         this.setDefaultMathAttribute(Mtable.ATTR_FRAMESPACING,
 327  
                 Mtable.DEFAULT_FRAMESPACING);
 328  3971
         this.setDefaultMathAttribute(Mtable.ATTR_EQUALROWS, Constants.FALSE);
 329  3971
         this.setDefaultMathAttribute(Mtable.ATTR_EQUALCOLUMNS, Constants.FALSE);
 330  3971
         this.setDefaultMathAttribute(Mtable.ATTR_DISPLAYSTYLE, Constants.FALSE);
 331  3971
         this.setDefaultMathAttribute(Mtable.ATTR_SIDE, HAlign.ALIGN_RIGHT);
 332  3971
         this.setDefaultMathAttribute(Mtable.ATTR_MINLABELSPACING,
 333  
                 Mtable.DEFAULT_COLUMNSPACING);
 334  3971
     }
 335  
 
 336  
     /** {@inheritDoc} */
 337  
     @Override
 338  
     protected Node newNode() {
 339  0
         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  3553
         return new InlineLayoutContext(this
 347  
                 .applyLocalAttributesToContext(context));
 348  
     }
 349  
 
 350  
     private float getFramespacingh(final LayoutContext now) {
 351  6688
         if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) {
 352  6688
             return 0;
 353  
         }
 354  0
         final String spacing = this.getSpaceArrayEntry(this.getFramespacing(),
 355  
                 0);
 356  0
         return AttributesHelper.convertSizeToPt(spacing, now,
 357  
                 AttributesHelper.PT);
 358  
     }
 359  
 
 360  
     private float getFramespacingv(final LayoutContext now) {
 361  3344
         if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) {
 362  3344
             return 0;
 363  
         }
 364  0
         final String spacing = this.getSpaceArrayEntry(this.getFramespacing(),
 365  
                 1);
 366  0
         return AttributesHelper.convertSizeToPt(spacing, now,
 367  
                 AttributesHelper.PT);
 368  
     }
 369  
 
 370  
     /** {@inheritDoc} */
 371  
     public String getRowlines() {
 372  1881
         return this.getMathAttribute(Mtable.ATTR_ROWLINES);
 373  
     }
 374  
 
 375  
     /** {@inheritDoc} */
 376  
     public void setRowlines(final String rowlines) {
 377  0
         this.setAttribute(Mtable.ATTR_ROWLINES, rowlines);
 378  0
     }
 379  
 
 380  
     /** {@inheritDoc} */
 381  
     public String getColumnlines() {
 382  1254
         return this.getMathAttribute(Mtable.ATTR_COLUMNLINES);
 383  
     }
 384  
 
 385  
     /** {@inheritDoc} */
 386  
     public void setColumnlines(final String columnlines) {
 387  0
         this.setAttribute(Mtable.ATTR_COLUMNLINES, columnlines);
 388  0
     }
 389  
 
 390  
     private LineType getRowLine(final int row) {
 391  1881
         return Mtable.LineType.parseLineType(this.getSpaceArrayEntry(this
 392  
                 .getRowlines(), row));
 393  
     }
 394  
 
 395  
     private LineType getColumnLine(final int col) {
 396  1254
         return Mtable.LineType.parseLineType(this.getSpaceArrayEntry(this
 397  
                 .getColumnlines(), col));
 398  
     }
 399  
 
 400  
     private LineType getFrameAsLineType() {
 401  11704
         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  19228
         if (string == null) {
 420  0
             array = new String[0];
 421  
         } else {
 422  19228
             array = string.split("\\s");
 423  
         }
 424  19228
         int cur = -1;
 425  19228
         String last = "";
 426  29051
         for (final String s : array) {
 427  19228
             if (s.length() > 0) {
 428  19228
                 cur++;
 429  19228
                 if (cur == index) {
 430  9405
                     return s;
 431  
                 }
 432  9823
                 last = s;
 433  
             }
 434  
         }
 435  9823
         return last;
 436  
     }
 437  
 
 438  
     /** {@inheritDoc} */
 439  
     public String getColumnwidth() {
 440  0
         return this.getMathAttribute(Mtable.ATTR_COLUMNWIDTH);
 441  
     }
 442  
 
 443  
     /** {@inheritDoc} */
 444  
     public void setColumnwidth(final String columnwidth) {
 445  0
         this.setAttribute(Mtable.ATTR_COLUMNWIDTH, columnwidth);
 446  0
     }
 447  
 
 448  
     /** {@inheritDoc} */
 449  
     public String getWidth() {
 450  0
         return this.getMathAttribute(Mtable.ATTR_WIDTH);
 451  
     }
 452  
 
 453  
     /** {@inheritDoc} */
 454  
     public void setWidth(final String width) {
 455  0
         this.setAttribute(Mtable.ATTR_WIDTH, width);
 456  0
     }
 457  
 
 458  
     /** {@inheritDoc} */
 459  
     public String getAlign() {
 460  0
         return this.getMathAttribute(Mtable.ATTR_ALIGN);
 461  
     }
 462  
 
 463  
     /** {@inheritDoc} */
 464  
     public void setAlign(final String align) {
 465  0
         this.setAttribute(Mtable.ATTR_ALIGN, align);
 466  0
     }
 467  
 
 468  
     /** {@inheritDoc} */
 469  
     public String getAlignmentscope() {
 470  0
         return this.getMathAttribute(Mtable.ATTR_ALIGNMENTSCOPE);
 471  
     }
 472  
 
 473  
     /** {@inheritDoc} */
 474  
     public void setAlignmentscope(final String alignmentscope) {
 475  0
         this.setAttribute(Mtable.ATTR_ALIGNMENTSCOPE, alignmentscope);
 476  0
     }
 477  
 
 478  
     /** {@inheritDoc} */
 479  
     public String getRowspacing() {
 480  3553
         return this.getMathAttribute(Mtable.ATTR_ROWSPACING);
 481  
     }
 482  
 
 483  
     /** {@inheritDoc} */
 484  
     public void setRowspacing(final String rowspacing) {
 485  0
         this.setAttribute(Mtable.ATTR_ROWSPACING, rowspacing);
 486  0
     }
 487  
 
 488  
     /** {@inheritDoc} */
 489  
     public String getColumnspacing() {
 490  6270
         return this.getMathAttribute(Mtable.ATTR_COLUMNSPACING);
 491  
     }
 492  
 
 493  
     /** {@inheritDoc} */
 494  
     public void setColumnspacing(final String columnspacing) {
 495  0
         this.setAttribute(Mtable.ATTR_COLUMNSPACING, columnspacing);
 496  0
     }
 497  
 
 498  
     /** {@inheritDoc} */
 499  
     public String getFrame() {
 500  11704
         return this.getMathAttribute(Mtable.ATTR_FRAME);
 501  
     }
 502  
 
 503  
     /** {@inheritDoc} */
 504  
     public void setFrame(final String frame) {
 505  0
         this.setAttribute(Mtable.ATTR_FRAME, frame);
 506  0
     }
 507  
 
 508  
     /** {@inheritDoc} */
 509  
     public String getFramespacing() {
 510  0
         return this.getMathAttribute(Mtable.ATTR_FRAMESPACING);
 511  
     }
 512  
 
 513  
     /** {@inheritDoc} */
 514  
     public void setFramespacing(final String framespacing) {
 515  0
         this.setAttribute(Mtable.ATTR_FRAMESPACING, framespacing);
 516  0
     }
 517  
 
 518  
     /** {@inheritDoc} */
 519  
     public String getEqualrows() {
 520  0
         return this.getMathAttribute(Mtable.ATTR_EQUALROWS);
 521  
     }
 522  
 
 523  
     /** {@inheritDoc} */
 524  
     public void setEqualrows(final String equalrows) {
 525  0
         this.setAttribute(Mtable.ATTR_EQUALROWS, equalrows);
 526  0
     }
 527  
 
 528  
     /** {@inheritDoc} */
 529  
     public String getEqualcolumns() {
 530  1672
         return this.getMathAttribute(Mtable.ATTR_EQUALCOLUMNS);
 531  
     }
 532  
 
 533  
     /** {@inheritDoc} */
 534  
     public void setEqualcolumns(final String equalcolumns) {
 535  0
         this.setAttribute(Mtable.ATTR_EQUALCOLUMNS, equalcolumns);
 536  0
     }
 537  
 
 538  
     /** {@inheritDoc} */
 539  
     public String getDisplaystyle() {
 540  0
         return this.getMathAttribute(Mtable.ATTR_DISPLAYSTYLE);
 541  
     }
 542  
 
 543  
     /** {@inheritDoc} */
 544  
     public void setDisplaystyle(final String displaystyle) {
 545  0
         this.setAttribute(Mtable.ATTR_DISPLAYSTYLE, displaystyle);
 546  0
     }
 547  
 
 548  
     /** {@inheritDoc} */
 549  
     public String getSide() {
 550  0
         return this.getMathAttribute(Mtable.ATTR_SIDE);
 551  
     }
 552  
 
 553  
     /** {@inheritDoc} */
 554  
     public void setSide(final String side) {
 555  0
         this.setAttribute(Mtable.ATTR_SIDE, side);
 556  0
     }
 557  
 
 558  
     /** {@inheritDoc} */
 559  
     public String getMinlabelspacing() {
 560  0
         return this.getMathAttribute(Mtable.ATTR_MINLABELSPACING);
 561  
     }
 562  
 
 563  
     /** {@inheritDoc} */
 564  
     public void setMinlabelspacing(final String minlabelspacing) {
 565  0
         this.setAttribute(Mtable.ATTR_MINLABELSPACING, minlabelspacing);
 566  0
     }
 567  
 
 568  
     /** {@inheritDoc} */
 569  
     public MathMLNodeList getRows() {
 570  
         // TODO: Implement
 571  0
         return null;
 572  
     }
 573  
 
 574  
     /** {@inheritDoc} */
 575  
     public MathMLTableRowElement insertEmptyRow(final int index) {
 576  
         // TODO: Implement
 577  0
         return null;
 578  
     }
 579  
 
 580  
     /** {@inheritDoc} */
 581  
     public MathMLLabeledRowElement insertEmptyLabeledRow(final int index) {
 582  
         // TODO: Implement
 583  0
         return null;
 584  
     }
 585  
 
 586  
     /** {@inheritDoc} */
 587  
     public MathMLTableRowElement getRow(final int index) {
 588  
         // TODO: Implement
 589  0
         return null;
 590  
     }
 591  
 
 592  
     /** {@inheritDoc} */
 593  
     public MathMLTableRowElement insertRow(final int index,
 594  
             final MathMLTableRowElement newRow) {
 595  
         // TODO: Implement
 596  0
         return null;
 597  
     }
 598  
 
 599  
     /** {@inheritDoc} */
 600  
     public MathMLTableRowElement setRow(final int index,
 601  
             final MathMLTableRowElement newRow) {
 602  
         // TODO: Implement
 603  0
         return null;
 604  
     }
 605  
 
 606  
     /** {@inheritDoc} */
 607  
     public void deleteRow(final int index) {
 608  
         // TODO: Implement
 609  0
     }
 610  
 
 611  
     /** {@inheritDoc} */
 612  
     public MathMLTableRowElement removeRow(final int index) {
 613  
         // TODO: Implement
 614  0
         return null;
 615  
     }
 616  
 
 617  
     /** {@inheritDoc} */
 618  
     public void deleteRow(final long index) {
 619  
         // TODO Auto-generated method stub
 620  
 
 621  0
     }
 622  
 
 623  
     /** {@inheritDoc} */
 624  
     public MathMLTableRowElement getRow(final long index) {
 625  
         // TODO Auto-generated method stub
 626  0
         return null;
 627  
     }
 628  
 
 629  
     /** {@inheritDoc} */
 630  
     public MathMLLabeledRowElement insertEmptyLabeledRow(final long index) {
 631  
         // TODO Auto-generated method stub
 632  0
         return null;
 633  
     }
 634  
 
 635  
     /** {@inheritDoc} */
 636  
     public MathMLTableRowElement insertEmptyRow(final long index) {
 637  
         // TODO Auto-generated method stub
 638  0
         return null;
 639  
     }
 640  
 
 641  
     /** {@inheritDoc} */
 642  
     public MathMLTableRowElement insertRow(final long index,
 643  
             final MathMLTableRowElement newRow) {
 644  
         // TODO Auto-generated method stub
 645  0
         return null;
 646  
     }
 647  
 
 648  
     /** {@inheritDoc} */
 649  
     public MathMLTableRowElement removeRow(final long index) {
 650  
         // TODO Auto-generated method stub
 651  0
         return null;
 652  
     }
 653  
 
 654  
     /** {@inheritDoc} */
 655  
     public MathMLTableRowElement setRow(final long index,
 656  
             final MathMLTableRowElement newRow) {
 657  
         // TODO Auto-generated method stub
 658  0
         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  1672
         final Graphics2D g = view.getGraphics();
 670  1672
         final LayoutContext now = this.applyLocalAttributesToContext(context);
 671  1672
         final List<LayoutableNode> children = this.getChildrenToLayout();
 672  1672
         final LayoutInfo[] rowInfos = new LayoutInfo[children.size()];
 673  1672
         final LayoutableNode[] rowChild = new LayoutableNode[children.size()];
 674  1672
         float y = 0;
 675  1672
         int rows = 0;
 676  
 
 677  
         // Layout Rows vertically, calculate height of the table.
 678  1672
         final float vFrameSpacing = this.getFramespacingv(now);
 679  1672
         float height = vFrameSpacing;
 680  1672
         for (final LayoutableNode child : children) {
 681  3553
             rowChild[rows] = child;
 682  3553
             final LayoutInfo mtrInfo = view.getInfo(child);
 683  3553
             y += mtrInfo.getAscentHeight(stage);
 684  3553
             rowInfos[rows] = mtrInfo;
 685  3553
             rows++;
 686  3553
             mtrInfo.moveTo(0, y, stage);
 687  3553
             y += mtrInfo.getDescentHeight(stage);
 688  3553
             height = y;
 689  3553
             y += AttributesHelper.convertSizeToPt(this.getSpaceArrayEntry(this
 690  
                     .getRowspacing(), rows), now, AttributesHelper.PT);
 691  3553
         }
 692  1672
         height += vFrameSpacing;
 693  
 
 694  1672
         final float verticalShift = this.shiftTableVertically(stage, context,
 695  
                 g, rowInfos, rows, height);
 696  
 
 697  1672
         final List<LayoutableNode>[] mtdChildren = this
 698  
                 .createListOfMtdChildren(rowChild, rows);
 699  1672
         this.stretchAndAlignMtds(view, mtdChildren, rowInfos, rows, stage);
 700  
 
 701  1672
         final List<Float> columnwidth = this.calculateBasicColumnWidth(view,
 702  
                 stage, rows, mtdChildren);
 703  
 
 704  
         // TODO This is where Alignment-Groups should be calculated
 705  
 
 706  1672
         final float totalWidth = this.layoutColumnsHorizontally(view, stage,
 707  
                 now, rows, mtdChildren, columnwidth);
 708  
 
 709  1672
         this.setRowWidth(stage, rowInfos, rows, totalWidth);
 710  
 
 711  1672
         this.addRowLines(info, rowInfos, rows, totalWidth, stage, now);
 712  1672
         this.addColumnLines(info, columnwidth, verticalShift, height, now);
 713  1672
         this.addFrame(info, totalWidth, verticalShift, height, now);
 714  
 
 715  1672
         final float hFrameSpacing = this.getFramespacingh(now);
 716  1672
         final Dimension2D borderLeftTop = new Dimension2DImpl(hFrameSpacing,
 717  
                 vFrameSpacing);
 718  1672
         final Dimension2D borderRightBottom = new Dimension2DImpl(
 719  
                 hFrameSpacing, vFrameSpacing);
 720  1672
         ElementListSupport.fillInfoFromChildren(view, info, this, stage,
 721  
                 borderLeftTop, borderRightBottom);
 722  1672
     }
 723  
 
 724  
     private void addFrame(final LayoutInfo info, final float width,
 725  
             final float verticalShift, final float height,
 726  
             final LayoutContext now) {
 727  1672
         final LineType lineType = this.getFrameAsLineType();
 728  1672
         final boolean solid = Mtable.LineType.SOLID.equals(lineType);
 729  1672
         final boolean dashed = Mtable.LineType.DASHED.equals(lineType);
 730  1672
         if (dashed || solid) {
 731  0
             final float lineWidth = GraphicsSupport.lineWidth(now);
 732  0
             final float lineInset = lineWidth / 2.0f;
 733  0
             final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
 734  0
             final List<GraphicsObject> go = info.getGraphicObjects();
 735  0
             final float vFrameSpacing = this.getFramespacingv(now);
 736  
 
 737  0
             final float left = lineInset;
 738  0
             final float right = width - lineInset;
 739  0
             final float top = verticalShift + lineInset - vFrameSpacing;
 740  0
             final float bottom = height + verticalShift - lineInset;
 741  0
             go.add(new LineObject(left, top, right, top, lineWidth, color,
 742  
                     dashed));
 743  0
             go.add(new LineObject(left, bottom, right, bottom, lineWidth,
 744  
                     color, dashed));
 745  0
             go.add(new LineObject(left, top, left, bottom, lineWidth, color,
 746  
                     dashed));
 747  0
             go.add(new LineObject(right, top, right, bottom, lineWidth, color,
 748  
                     dashed));
 749  
         }
 750  1672
     }
 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  1672
         final float lineWidth = GraphicsSupport.lineWidth(now);
 756  1672
         final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
 757  
 
 758  1672
         final float inFrameStart = this.getFramespacingh(now);
 759  3553
         for (int row = 0; row < rows - 1; row++) {
 760  1881
             final LineType lineType = this.getRowLine(row);
 761  1881
             final boolean solid = Mtable.LineType.SOLID.equals(lineType);
 762  1881
             final boolean dashed = Mtable.LineType.DASHED.equals(lineType);
 763  1881
             if (dashed || solid) {
 764  0
                 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  0
                 info.getGraphicObjects().add(
 769  
                         new LineObject(inFrameStart, y, width - inFrameStart,
 770  
                                 y, lineWidth, color, dashed));
 771  
             }
 772  
         }
 773  1672
     }
 774  
 
 775  
     private void addColumnLines(final LayoutInfo info,
 776  
             final List<Float> columnwidth, final float verticalShift,
 777  
             final float height, final LayoutContext now) {
 778  1672
         final float lineWidth = GraphicsSupport.lineWidth(now);
 779  1672
         final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
 780  1672
         float x = this.getFramespacingh(now);
 781  
 
 782  1672
         final float inFrameStart = this.getFramespacingv(now);
 783  1672
         final float colsm1 = columnwidth.size() - 1;
 784  2926
         for (int col = 0; col < colsm1; col++) {
 785  1254
             final LineType lineType = this.getColumnLine(col);
 786  1254
             final boolean solid = Mtable.LineType.SOLID.equals(lineType);
 787  1254
             final boolean dashed = Mtable.LineType.DASHED.equals(lineType);
 788  1254
             if (dashed || solid) {
 789  0
                 final float halfSpace = this.getSpaceAfterColumn(now, col) / 2.0f;
 790  0
                 x += columnwidth.get(col) + halfSpace;
 791  0
                 info.getGraphicObjects().add(
 792  
                         new LineObject(x, verticalShift, x, height
 793  
                                 + verticalShift - inFrameStart, lineWidth,
 794  
                                 color, dashed));
 795  0
                 x += halfSpace;
 796  
             }
 797  
         }
 798  1672
     }
 799  
 
 800  
     private void stretchAndAlignMtds(final LayoutView view,
 801  
             final List<LayoutableNode>[] mtdChildren,
 802  
             final LayoutInfo[] rowInfos, final int rows, final LayoutStage stage) {
 803  5225
         for (int i = 0; i < rows; i++) {
 804  3553
             final float rowAscent = rowInfos[i].getAscentHeight(stage);
 805  3553
             final float rowDescent = rowInfos[i].getDescentHeight(stage);
 806  3553
             for (final LayoutableNode n : mtdChildren[i]) {
 807  6270
                 final LayoutInfo mtdInfo = view.getInfo(n);
 808  
 
 809  6270
                 final VAlign valign = this.getVAlign((JEuclidElement) n, i);
 810  
                 final float verticalShift;
 811  6270
                 if (valign.getAlign() == Mtable.VAlign.TOP) {
 812  0
                     verticalShift = -rowAscent + mtdInfo.getAscentHeight(stage);
 813  6270
                 } else if (valign.getAlign() == Mtable.VAlign.BOTTOM) {
 814  0
                     verticalShift = rowDescent
 815  
                             - mtdInfo.getDescentHeight(stage);
 816  6270
                 } else if (valign.getAlign() == Mtable.VAlign.CENTER) {
 817  0
                     verticalShift = (-rowAscent + rowDescent
 818  
                             + mtdInfo.getAscentHeight(stage) - mtdInfo
 819  
                             .getDescentHeight(stage)) / 2.0f;
 820  6270
                 } else if (valign.getAlign() == Mtable.VAlign.AXIS) {
 821  
                     // TODO: This uses center instead of axis.
 822  0
                     verticalShift = (-rowAscent + rowDescent
 823  
                             + mtdInfo.getAscentHeight(stage) - mtdInfo
 824  
                             .getDescentHeight(stage)) / 2.0f;
 825  
                 } else {
 826  
                     // BASELINE
 827  6270
                     verticalShift = 0.0f;
 828  
                 }
 829  6270
                 mtdInfo.shiftVertically(verticalShift, stage);
 830  6270
                 mtdInfo.setStretchAscent(rowAscent + verticalShift);
 831  6270
                 mtdInfo.setStretchDescent(rowDescent - verticalShift);
 832  6270
             }
 833  
         }
 834  1672
     }
 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  1672
         final float verticalShift = -this.getMiddleShift(g, context) - height
 846  
                 / 2.0f;
 847  
 
 848  5225
         for (int i = 0; i < rows; i++) {
 849  3553
             rowInfos[i].shiftVertically(verticalShift, stage);
 850  
         }
 851  1672
         return verticalShift;
 852  
     }
 853  
 
 854  
     @SuppressWarnings("unchecked")
 855  
     private List<LayoutableNode>[] createListOfMtdChildren(
 856  
             final LayoutableNode[] rowChild, final int rows) {
 857  1672
         final List<LayoutableNode>[] mtdChildren = new List[rows];
 858  5225
         for (int i = 0; i < rows; i++) {
 859  3553
             if (rowChild[i] instanceof MathMLTableRowElement) {
 860  3553
                 mtdChildren[i] = rowChild[i].getChildrenToLayout();
 861  
             } else {
 862  0
                 mtdChildren[i] = new ArrayList<LayoutableNode>(1);
 863  0
                 mtdChildren[i].add(rowChild[i]);
 864  
             }
 865  
         }
 866  1672
         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  1672
         final List<Float> columnwidth = new ArrayList<Float>();
 873  5225
         for (int i = 0; i < rows; i++) {
 874  3553
             int missing = mtdChildren[i].size() - columnwidth.size();
 875  6479
             while (missing > 0) {
 876  2926
                 columnwidth.add(0.0f);
 877  2926
                 missing--;
 878  
             }
 879  3553
             int col = 0;
 880  3553
             for (final LayoutableNode n : mtdChildren[i]) {
 881  6270
                 final float width = Math.max(columnwidth.get(col), view
 882  
                         .getInfo(n).getWidth(stage));
 883  6270
                 columnwidth.set(col, width);
 884  6270
                 col++;
 885  6270
             }
 886  
         }
 887  1672
         if (Boolean.parseBoolean(this.getEqualcolumns())) {
 888  0
             this.makeEqual(columnwidth);
 889  
         }
 890  1672
         return columnwidth;
 891  
     }
 892  
 
 893  
     private void makeEqual(final List<Float> columnwidth) {
 894  0
         float maxWidth = 0.0f;
 895  0
         for (final Float width : columnwidth) {
 896  0
             maxWidth = Math.max(width, maxWidth);
 897  
         }
 898  0
         final int cols = columnwidth.size();
 899  0
         for (int i = 0; i < cols; i++) {
 900  0
             columnwidth.set(i, maxWidth);
 901  
         }
 902  0
     }
 903  
 
 904  
     private void setRowWidth(final LayoutStage stage,
 905  
             final LayoutInfo[] rowInfos, final int rows, final float totalWidth) {
 906  5225
         for (int i = 0; i < rows; i++) {
 907  3553
             rowInfos[i].setWidth(totalWidth, stage);
 908  
         }
 909  1672
     }
 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  1672
         final float hFrameSpacing = this.getFramespacingh(now);
 916  1672
         float totalWidth = hFrameSpacing;
 917  5225
         for (int i = 0; i < rows; i++) {
 918  3553
             float x = hFrameSpacing;
 919  3553
             int col = 0;
 920  3553
             for (final LayoutableNode n : mtdChildren[i]) {
 921  6270
                 final LayoutInfo mtdInfo = view.getInfo(n);
 922  6270
                 final HAlign halign = this.getHAlign((JEuclidElement) n, col);
 923  6270
                 final float colwi = columnwidth.get(col);
 924  6270
                 final float xo = halign.getHAlignOffset(stage, mtdInfo, colwi);
 925  6270
                 mtdInfo.moveTo(x + xo, mtdInfo.getPosY(stage), stage);
 926  
                 // mtdInfo.setWidth(colwi, stage);
 927  6270
                 mtdInfo.setStretchWidth(colwi);
 928  6270
                 x += colwi;
 929  6270
                 totalWidth = Math.max(totalWidth, x);
 930  6270
                 x += this.getSpaceAfterColumn(now, col);
 931  6270
                 col++;
 932  6270
             }
 933  
         }
 934  1672
         return totalWidth + hFrameSpacing;
 935  
     }
 936  
 
 937  
     private float getSpaceAfterColumn(final LayoutContext now, final int col) {
 938  6270
         final float columnSpace = AttributesHelper.convertSizeToPt(this
 939  
                 .getSpaceArrayEntry(this.getColumnspacing(), col), now,
 940  
                 AttributesHelper.PT);
 941  6270
         return columnSpace;
 942  
     }
 943  
 
 944  
     private HAlign getHAlign(final JEuclidElement n, final int col) {
 945  6270
         assert n != null;
 946  
         final HAlign retVal;
 947  6270
         if (n instanceof MathMLTableCellElement) {
 948  6270
             final MathMLTableCellElement cell = (MathMLTableCellElement) n;
 949  6270
             final String alignString = cell.getColumnalign();
 950  6270
             final HAlign halign = HAlign.parseString(alignString, null);
 951  6270
             if (halign == null) {
 952  0
                 retVal = this.getHAlign(n.getParent(), col);
 953  
             } else {
 954  6270
                 retVal = halign;
 955  
             }
 956  6270
         } else if (n instanceof MathMLTableRowElement) {
 957  0
             final MathMLTableRowElement rowE = (MathMLTableRowElement) n;
 958  0
             final String alignArray = rowE.getColumnalign();
 959  0
             if ((alignArray != null) && (alignArray.length() > 0)) {
 960  0
                 retVal = HAlign.parseString(this.getSpaceArrayEntry(alignArray,
 961  
                         col), HAlign.CENTER);
 962  
             } else {
 963  0
                 retVal = this.getHAlign(n.getParent(), col);
 964  
             }
 965  0
         } else if (n instanceof MathMLTableElement) {
 966  0
             final MathMLTableElement table = (MathMLTableElement) n;
 967  0
             final String alignArray = table.getColumnalign();
 968  0
             if ((alignArray != null) && (alignArray.length() > 0)) {
 969  0
                 retVal = HAlign.parseString(this.getSpaceArrayEntry(alignArray,
 970  
                         col), HAlign.CENTER);
 971  
             } else {
 972  0
                 retVal = HAlign.CENTER;
 973  
             }
 974  0
         } else {
 975  0
             retVal = this.getHAlign(n.getParent(), col);
 976  
         }
 977  6270
         return retVal;
 978  
     }
 979  
 
 980  
     private VAlign getVAlign(final JEuclidElement n, final int row) {
 981  18810
         assert n != null;
 982  
         final VAlign retVal;
 983  18810
         if (n instanceof MathMLTableCellElement) {
 984  6270
             final MathMLTableCellElement cell = (MathMLTableCellElement) n;
 985  6270
             final String alignString = cell.getRowalign();
 986  6270
             final Mtable.VAlign valign = Mtable.VAlign.parseString(alignString);
 987  6270
             if (valign == null) {
 988  6270
                 retVal = this.getVAlign(n.getParent(), row);
 989  
             } else {
 990  0
                 retVal = valign;
 991  
             }
 992  6270
         } else if (n instanceof MathMLTableRowElement) {
 993  6270
             final MathMLTableRowElement rowE = (MathMLTableRowElement) n;
 994  6270
             final String alignString = rowE.getRowalign();
 995  6270
             final Mtable.VAlign valign = Mtable.VAlign.parseString(alignString);
 996  6270
             if (valign == null) {
 997  6270
                 retVal = this.getVAlign(n.getParent(), row);
 998  
             } else {
 999  0
                 retVal = valign;
 1000  
             }
 1001  6270
         } else if (n instanceof MathMLTableElement) {
 1002  6270
             final MathMLTableElement table = (MathMLTableElement) n;
 1003  6270
             final String alignArray = table.getRowalign();
 1004  6270
             if ((alignArray != null) && (alignArray.length() > 0)) {
 1005  6270
                 retVal = Mtable.VAlign.parseString(this.getSpaceArrayEntry(
 1006  
                         alignArray, row));
 1007  
             } else {
 1008  0
                 retVal = Mtable.VAlign.BASELINE_ALIGN;
 1009  
             }
 1010  6270
         } else {
 1011  0
             retVal = this.getVAlign(n.getParent(), row);
 1012  
         }
 1013  18810
         return retVal;
 1014  
     }
 1015  
 
 1016  
 }