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 }