1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sourceforge.jeuclid.elements.presentation.table;
20
21 import java.awt.BasicStroke;
22 import java.awt.Graphics2D;
23 import java.awt.Stroke;
24 import java.awt.geom.Line2D;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Vector;
28
29 import net.sourceforge.jeuclid.MathBase;
30 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
31 import net.sourceforge.jeuclid.elements.JEuclidElement;
32 import net.sourceforge.jeuclid.elements.presentation.token.Mn;
33 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
34 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
35
36 import org.w3c.dom.DOMException;
37 import org.w3c.dom.mathml.MathMLLabeledRowElement;
38 import org.w3c.dom.mathml.MathMLNodeList;
39 import org.w3c.dom.mathml.MathMLTableElement;
40 import org.w3c.dom.mathml.MathMLTableRowElement;
41
42
43
44
45
46
47
48
49 public class Mtable extends AbstractJEuclidElement implements
50 MathMLTableElement {
51
52
53 public static final String ATTR_ROWLINES = "rowlines";
54
55
56 public static final String ATTR_COLUMNLINES = "columnlines";
57
58
59 public static final String ATTR_ALIGN = "align";
60
61
62 public static final String ATTR_ALIGNMENTSCOPE = "alignmentscope";
63
64
65 public static final String ATTR_COLUMNWIDTH = "columnwidth";
66
67
68 public static final String ATTR_WIDTH = "width";
69
70
71 public static final String ATTR_ROWSPACING = "rowspacing";
72
73
74 public static final String ATTR_COLUMNSPACING = "columnspacing";
75
76
77 public static final String ATTR_FRAME = "frame";
78
79
80 public static final String ATTR_FRAMESPACING = "framespacing";
81
82
83 public static final String ATTR_EQUALROWS = "equalrows";
84
85
86 public static final String ATTR_EQUALCOLUMNS = "equalcolumns";
87
88
89 public static final String ATTR_DISPLAYSTYLE = "displaystyle";
90
91
92 public static final String ATTR_SIDE = "side";
93
94
95 public static final String ATTR_MINLABELSPACING = "minlabelspacing";
96
97
98 public static final String VALUE_NONE = "none";
99
100
101 public static final String VALUE_DASHED = "dashed";
102
103
104 public static final String VALUE_SOLID = "solid";
105
106
107
108
109 public static final String ELEMENT = "mtable";
110
111
112
113
114 public static final int ALIGN_TOP = 0;
115
116
117
118
119 public static final int ALIGN_BOTTOM = 1;
120
121
122 public static final String ATTR_ROWALIGN = "rowalign";
123
124
125 public static final String ATTR_COLUMNALIGN = "columnalign";
126
127
128 public static final String ATTR_GROUPALIGN = "groupalign";
129
130
131
132
133 public static final String DEFAULT_COLUMNSPACING = "0.8em";
134
135
136
137
138 public static final String DEFAULT_ROWSPACING = "1.0ex";
139
140
141
142
143 public static final int ALIGN_CENTER = 2;
144
145
146
147
148 public static final int ALIGN_BASELINE = 3;
149
150
151
152
153 public static final int ALIGN_AXIS = 4;
154
155
156
157
158 public static final int ALIGN_LEFT = 5;
159
160
161
162
163 public static final int ALIGN_RIGHT = 6;
164
165
166
167
168 public static final int ALIGN_MARK = 11;
169
170
171
172
173 public static final int ALIGN_DECIMALPOINT = 7;
174
175
176
177
178 public static final int WIDTH_AUTO = -1;
179
180
181
182
183 public static final int WIDTH_FIT = -2;
184
185
186
187
188 private static final String DEFAULT_FRAMESPACING = "0.4em 0.5ex";
189
190
191
192
193 public enum LineType {
194
195 NONE,
196
197 SOLID,
198
199 DASHED;
200
201
202
203
204
205
206
207
208 public static LineType parseLineType(final String s) {
209 final LineType retVal;
210 if (s.equalsIgnoreCase(Mtable.VALUE_NONE)) {
211 retVal = NONE;
212 } else if (s.equalsIgnoreCase(Mtable.VALUE_DASHED)) {
213 retVal = DASHED;
214 } else {
215 retVal = SOLID;
216 }
217 return retVal;
218 }
219 };
220
221
222
223
224 public enum AlignmentType {
225
226 TOP,
227
228 BOTTOM,
229
230 CENTER,
231
232 BASELINE,
233
234 AXIS,
235
236 LEFT,
237
238 RIGHT,
239
240 DECIMALPOINT,
241
242 MARK;
243
244
245
246
247
248
249
250
251 public static AlignmentType parseAlignmentType(final String s) {
252 final AlignmentType retVal;
253 if ("top".equalsIgnoreCase(s)) {
254 retVal = Mtable.AlignmentType.TOP;
255 } else if ("bottom".equalsIgnoreCase(s)) {
256 retVal = Mtable.AlignmentType.BOTTOM;
257 } else if ("baseline".equalsIgnoreCase(s)) {
258 retVal = Mtable.AlignmentType.BASELINE;
259 } else if ("axis".equalsIgnoreCase(s)) {
260 retVal = Mtable.AlignmentType.AXIS;
261 } else if ("left".equalsIgnoreCase(s)) {
262 retVal = Mtable.AlignmentType.LEFT;
263 } else if ("right".equalsIgnoreCase(s)) {
264 retVal = Mtable.AlignmentType.RIGHT;
265 } else if ("decimalpoint".equalsIgnoreCase(s)) {
266 retVal = Mtable.AlignmentType.DECIMALPOINT;
267 } else {
268 retVal = Mtable.AlignmentType.CENTER;
269 }
270 return retVal;
271 }
272 }
273
274
275
276
277
278
279
280 public Mtable(final MathBase base) {
281 super(base);
282 this.setDefaultMathAttribute(Mtable.ATTR_ALIGN, "axis");
283 this.setDefaultMathAttribute(Mtable.ATTR_ROWALIGN, "baseline");
284 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNALIGN, "center");
285 this.setDefaultMathAttribute(Mtable.ATTR_GROUPALIGN, "{left}");
286 this.setDefaultMathAttribute(Mtable.ATTR_ALIGNMENTSCOPE,
287 MathBase.TRUE);
288 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNWIDTH, "auto");
289 this.setDefaultMathAttribute(Mtable.ATTR_WIDTH, "auto");
290 this.setDefaultMathAttribute(Mtable.ATTR_ROWSPACING,
291 Mtable.DEFAULT_ROWSPACING);
292 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNSPACING,
293 Mtable.DEFAULT_COLUMNSPACING);
294 this.setDefaultMathAttribute(Mtable.ATTR_ROWLINES, Mtable.VALUE_NONE);
295 this.setDefaultMathAttribute(Mtable.ATTR_COLUMNLINES,
296 Mtable.VALUE_NONE);
297 this.setDefaultMathAttribute(Mtable.ATTR_FRAME, Mtable.VALUE_NONE);
298 this.setDefaultMathAttribute(Mtable.ATTR_FRAMESPACING,
299 Mtable.DEFAULT_FRAMESPACING);
300 this.setDefaultMathAttribute(Mtable.ATTR_EQUALROWS, MathBase.FALSE);
301 this
302 .setDefaultMathAttribute(Mtable.ATTR_EQUALCOLUMNS,
303 MathBase.FALSE);
304 this
305 .setDefaultMathAttribute(Mtable.ATTR_DISPLAYSTYLE,
306 MathBase.FALSE);
307 this.setDefaultMathAttribute(Mtable.ATTR_SIDE, "right");
308 this.setDefaultMathAttribute(Mtable.ATTR_MINLABELSPACING, "0.8em");
309 }
310
311
312 @Override
313 public boolean isChildBlock(final JEuclidElement child) {
314 return false;
315 }
316
317
318
319
320
321 protected float getFramespacingh() {
322 if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) {
323 return 0;
324 }
325 final String spacing = this.getSpaceArrayEntry(
326 this.getFramespacing(), 0);
327 return AttributesHelper.convertSizeToPt(spacing, this,
328 AttributesHelper.PT);
329 }
330
331
332
333
334
335 protected float getFramespacingv() {
336 if (Mtable.LineType.NONE.equals(this.getFrameAsLineType())) {
337 return 0;
338 }
339 final String spacing = this.getSpaceArrayEntry(
340 this.getFramespacing(), 1);
341 return AttributesHelper.convertSizeToPt(spacing, this,
342 AttributesHelper.PT);
343 }
344
345
346
347
348
349
350
351
352
353
354
355 @Override
356 public void paint(final Graphics2D g, float posX, float posY) {
357 super.paint(g, posX, posY);
358 posX = posX + this.getFramespacingh();
359 posY = posY + this.getFramespacingv();
360
361 int i;
362 int j;
363 final float[] maxrowascentheight = new float[this
364 .getMathElementCount()];
365 final float[] maxrowdescentheight = new float[this
366 .getMathElementCount()];
367
368 for (i = 0; i < this.getMathElementCount(); i++) {
369 maxrowascentheight[i] = this.getMaxRowAscentHeight(g, i);
370 maxrowdescentheight[i] = this.getMaxRowDescentHeight(g, i);
371 }
372
373 final int maxcolumns = this.getMaxColumnCount();
374 final boolean isAlignGroupsExist = this.getMaxGroupAlignCount() == 0 ? false
375 : true;
376 final float[] maxcolumnwidth = new float[maxcolumns];
377
378 for (i = 0; i < maxcolumns; i++) {
379 maxcolumnwidth[i] = this.getMaxColumnWidth(g, i);
380 }
381
382 final float x1 = posX;
383 float x = x1;
384
385 posY = posY - this.getAscentHeight(g);
386 final float startY = posY;
387
388 final List<Float> rowlines = new Vector<Float>();
389 final List<Float> columnlines = new Vector<Float>(maxcolumns);
390
391 for (i = 0; i < this.getMathElementCount(); i++) {
392 final JEuclidElement row = this.getMathElement(i);
393 posY += maxrowascentheight[i];
394
395 x = x1;
396 for (j = 0; (j < maxcolumns) && (j < row.getMathElementCount()); j++) {
397 if (isAlignGroupsExist
398 && this.getAlignGroups((Mtd) row.getMathElement(j)).length > 0) {
399
400 row.getMathElement(j).paint(g, x, posY);
401 } else {
402
403
404 final float xx = x + maxcolumnwidth[j] / 2
405 - row.getMathElement(j).getWidth(g) / 2;
406 row.getMathElement(j).paint(g, xx, posY);
407 }
408 final float currentColSpacing = this.getColumnspacing(j);
409 x += maxcolumnwidth[j];
410 if ((i == 0) && (j < maxcolumns - 1)) {
411
412
413 columnlines.add(x + currentColSpacing / 2.0f);
414 }
415 x += currentColSpacing;
416 }
417
418 posY += maxrowdescentheight[i];
419 final float currentRowSpacing = this.getRowspacing(i);
420 if (i < (this.getMathElementCount() - 1)) {
421 rowlines.add(posY + currentRowSpacing / 2.0f);
422 }
423 posY += currentRowSpacing;
424 }
425 int col = 0;
426 final Stroke oldStroke = g.getStroke();
427 final float lineWidth = GraphicsSupport.lineWidth(this);
428 final float dashWidth = 3.0f * lineWidth;
429 final Stroke solidStroke = new BasicStroke(lineWidth);
430 final Stroke dashedStroke = new BasicStroke(lineWidth,
431 BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, lineWidth,
432 new float[] { dashWidth, dashWidth }, 0);
433 for (final float lineX : columnlines) {
434 final LineType lt = this.getColumnLine(col);
435 col++;
436 if (Mtable.LineType.SOLID.equals(lt)) {
437 g.setStroke(solidStroke);
438 } else if (Mtable.LineType.DASHED.equals(lt)) {
439 g.setStroke(dashedStroke);
440 }
441 if (!Mtable.LineType.NONE.equals(lt)) {
442 g.draw(new Line2D.Float(lineX, startY, lineX, posY));
443 }
444 }
445 int row = 0;
446 for (final float lineY : rowlines) {
447
448
449 final LineType lt = this.getRowLine(row);
450 row++;
451
452
453 if (Mtable.LineType.SOLID.equals(lt)) {
454 g.setStroke(solidStroke);
455 } else if (Mtable.LineType.DASHED.equals(lt)) {
456 g.setStroke(dashedStroke);
457 }
458 if (!Mtable.LineType.NONE.equals(lt)) {
459 g.draw(new Line2D.Float(x1, lineY, x, lineY));
460 }
461 }
462 g.setStroke(oldStroke);
463 }
464
465
466
467
468
469
470
471
472 private float getMaxRowAscentHeight(final Graphics2D g, final int row) {
473 if (row >= this.getMathElementCount()) {
474 return 0;
475 }
476 final JEuclidElement child = this.getMathElement(row);
477 float height = 0;
478
479 for (int i = 0; i < child.getMathElementCount(); i++) {
480 height = Math.max(height, child.getMathElement(i)
481 .getAscentHeight(g));
482 }
483 return height;
484 }
485
486
487
488
489
490
491
492
493 private float getMaxRowDescentHeight(final Graphics2D g, final int row) {
494 if (row >= this.getMathElementCount()) {
495 return 0;
496 }
497
498 final JEuclidElement child = this.getMathElement(row);
499 float height = 0;
500
501 for (int i = 0; i < child.getMathElementCount(); i++) {
502 height = Math.max(height, child.getMathElement(i)
503 .getDescentHeight(g));
504 }
505 return height;
506 }
507
508
509
510
511
512
513
514
515 private float getMaxColumnWidth(final Graphics2D g, final int column) {
516 float width = 0;
517
518 for (int i = 0; i < this.getMathElementCount(); i++) {
519 final JEuclidElement child = this.getMathElement(i);
520
521 if (column < child.getMathElementCount()) {
522 width = Math.max(width, child.getMathElement(column)
523 .getWidth(g));
524 }
525 }
526 return width;
527 }
528
529
530
531
532
533
534 private int getMaxColumnCount() {
535 int count = 0;
536
537 for (int i = 0; i < this.getMathElementCount(); i++) {
538 final JEuclidElement child = this.getMathElement(i);
539 count = Math.max(count, child.getMathElementCount());
540 }
541 return count;
542 }
543
544
545 @Override
546 public float calculateWidth(final Graphics2D g) {
547 this.calculateAlignmentGroups(g);
548 float width = 0;
549 final int maxcolumns = this.getMaxColumnCount();
550
551 for (int i = 0; i < maxcolumns; i++) {
552 width = width + this.getMaxColumnWidth(g, i);
553 if (i + 1 < maxcolumns) {
554 width = width + this.getColumnspacing(i);
555 }
556 }
557 width = width + this.getFramespacingh() * 2;
558 return width;
559 }
560
561 private float calculateActualHeight(final Graphics2D g) {
562 float height = 0;
563 final int mec = this.getMathElementCount();
564 for (int i = 0; i < mec; i++) {
565 height = height + this.getMaxRowAscentHeight(g, i)
566 + this.getMaxRowDescentHeight(g, i);
567 if (i + 1 < mec) {
568 height = height + this.getRowspacing(i);
569 }
570 }
571 height = height + this.getFramespacingv() * 2;
572 return height;
573 }
574
575
576 @Override
577 public float calculateAscentHeight(final Graphics2D g) {
578 final AlignmentType align = Mtable.AlignmentType
579 .parseAlignmentType(this.getAlign());
580 if (Mtable.AlignmentType.BOTTOM.equals(align)) {
581 return this.calculateActualHeight(g);
582 } else if (Mtable.AlignmentType.TOP.equals(align)) {
583 return this.getRowCount() > 0 ? this.getMaxRowAscentHeight(g, 0)
584 : 0;
585 } else if (Mtable.AlignmentType.AXIS.equals(align)) {
586
587 return (this.calculateActualHeight(g) + 1) / 2;
588 }
589
590
591 return (this.calculateActualHeight(g) + 1) / 2
592 + this.getMiddleShift(g);
593 }
594
595
596 @Override
597 public float calculateDescentHeight(final Graphics2D g) {
598 final Mtable.AlignmentType align = Mtable.AlignmentType
599 .parseAlignmentType(this.getAlign());
600 if (Mtable.AlignmentType.BOTTOM.equals(align)) {
601 return 0;
602 } else if (Mtable.AlignmentType.TOP.equals(align)) {
603 return this.calculateActualHeight(g)
604 - (this.getRowCount() > 0 ? this.getMaxRowAscentHeight(g,
605 0) : 0);
606 } else if (Mtable.AlignmentType.AXIS.equals(align)) {
607
608 return (this.calculateActualHeight(g) + 1) / 2;
609 }
610 final float b = this.getMiddleShift(g);
611
612 final float c = (this.calculateActualHeight(g) + 1) / 2;
613 return c - b;
614 }
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630 public List<Mtable.AlignmentType> getGroupAlign(final Mtd cell) {
631 final List<Mtable.AlignmentType> result = new Vector<Mtable.AlignmentType>();
632
633 String groupAlign;
634
635 if (cell == null) {
636 return result;
637 }
638 final String cellGroupAlign = cell.getGroupalign();
639 if (cellGroupAlign == null || cellGroupAlign.length() == 0) {
640 groupAlign = ((Mtr) cell.getParent()).getGroupalign();
641 } else {
642 groupAlign = cell.getGroupalign();
643 }
644
645 if (groupAlign == null) {
646 groupAlign = this.getGroupalign();
647 }
648
649 if (groupAlign != null) {
650
651 final String[] gAlign = groupAlign.split("\\w");
652 for (final String value : gAlign) {
653 if (value.length() > 0) {
654 result
655 .add(Mtable.AlignmentType
656 .parseAlignmentType(value));
657 }
658 }
659 }
660
661 return result;
662 }
663
664
665
666
667
668
669 private int getMaxGroupAlignCount() {
670 int result = 0;
671 final int rowsCount = this.getRowCount();
672 final int columnsCount = this.getMaxColumnCount();
673 int tmpLength = 0;
674
675 for (int column = 0; column < columnsCount; column++) {
676 for (int row = 0; row < rowsCount; row++) {
677 Mtd cell = null;
678 try {
679 cell = this.getCell(row, column);
680 } catch (final Exception e) {
681 return 0;
682 }
683
684 if (cell != null) {
685 tmpLength = cell.getAlignGroups().size();
686 if (result < tmpLength) {
687 result = tmpLength;
688 }
689 }
690 }
691 }
692
693 return result;
694 }
695
696
697
698
699
700
701 private int getRowCount() {
702 return this.getMathElementCount();
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717 private Mtd getCell(final int row, final int column) throws Exception {
718 final int rowsCount = this.getRowCount();
719 final int columnsCount = this.getMaxColumnCount();
720 Mtd cell = null;
721
722 if (row > rowsCount - 1 || column > columnsCount - 1) {
723 return cell;
724 }
725
726 final JEuclidElement theRow = this.getMathElement(row);
727 if (column < theRow.getMathElementCount()) {
728 if (theRow.getMathElement(column) instanceof Mtd) {
729 cell = (Mtd) theRow.getMathElement(column);
730 } else {
731 throw new Exception(
732 "This table doesn't contain <mtr> and <mtd> tags.");
733 }
734 }
735
736 return cell;
737 }
738
739
740
741
742
743
744
745
746 private Maligngroup[] getAlignGroups(final Mtd cell) {
747 Maligngroup[] result;
748
749 final List<Maligngroup> list = cell.getAlignGroups();
750
751 if (list.size() == 0) {
752 result = new Maligngroup[0];
753 } else {
754
755 result = new Maligngroup[list.size()];
756 for (int i = 0; i < list.size(); i++) {
757 result[i] = (list.get(i));
758 }
759 }
760
761 return result;
762 }
763
764
765
766
767 private static final int WHOLE_WIDTH = 0;
768
769
770
771
772 private static final int LEFT_WIDTH = 1;
773
774
775
776
777 private static final int RIGHT_WIDTH = 2;
778
779
780
781
782
783
784
785
786 protected void calculateAlignmentGroups(final Graphics2D g) {
787 final int rowsCount = this.getRowCount();
788 final int columnsCount = this.getMaxColumnCount();
789 final int MAX_WIDTH_IN_COLUMN = rowsCount;
790 final int maxGroupAlignCount = this.getMaxGroupAlignCount();
791 if (maxGroupAlignCount == 0) {
792 return;
793 }
794
795
796
797
798
799
800
801 final float[][][][] alignwidths = new float[columnsCount][3][rowsCount + 1][maxGroupAlignCount];
802
803 final boolean[][] usesMarks = new boolean[columnsCount][this
804 .getMaxGroupAlignCount()];
805
806 Maligngroup[] aligngroups;
807
808 List<Mtable.AlignmentType> groupalignvalues;
809
810 List<JEuclidElement> elements;
811 for (int col = 0; col < columnsCount; col++) {
812
813 for (int row = 0; row < rowsCount; row++) {
814 Mtd cell = null;
815 try {
816 cell = this.getCell(row, col);
817 } catch (final Exception e) {
818 cell = null;
819 }
820 if (cell != null) {
821 aligngroups = this.getAlignGroups(cell);
822 groupalignvalues = this.getGroupAlign(cell);
823 if (groupalignvalues.size() == 0) {
824
825
826 groupalignvalues = new Vector<Mtable.AlignmentType>(
827 aligngroups.length);
828 for (final Maligngroup element : aligngroups) {
829 groupalignvalues.add(Mtable.AlignmentType.LEFT);
830 }
831 }
832 if (aligngroups.length == 0
833 || aligngroups.length < groupalignvalues.size()) {
834 continue;
835
836 }
837 for (int alignIndex = 0; alignIndex < groupalignvalues
838 .size(); alignIndex++) {
839
840 elements = Maligngroup
841 .getElementsOfAlignGroup(aligngroups[alignIndex]);
842 alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex] = Maligngroup
843 .getElementsWholeWidth(g, elements);
844
845 if (alignwidths[col][Mtable.WHOLE_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] < alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex]) {
846 alignwidths[col][Mtable.WHOLE_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] = alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex];
847 }
848
849 if (aligngroups[alignIndex].getMark() != null) {
850 usesMarks[col][alignIndex] = true;
851 final float leftPart = this.getWidthTillMark(g,
852 elements.iterator());
853
854 alignwidths[col][Mtable.LEFT_WIDTH][row][alignIndex] = leftPart;
855
856 alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex] = alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex]
857 - leftPart;
858
859 if (alignwidths[col][Mtable.LEFT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] < leftPart) {
860 alignwidths[col][Mtable.LEFT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] = leftPart;
861 }
862
863 if (alignwidths[col][Mtable.RIGHT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] < alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex]) {
864 alignwidths[col][Mtable.RIGHT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] = alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex];
865 }
866 } else {
867
868
869 alignwidths[col][Mtable.LEFT_WIDTH][row][alignIndex] = 0;
870 alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex] = alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex];
871
872 if (groupalignvalues.get(alignIndex).equals(
873 Mtable.AlignmentType.DECIMALPOINT)) {
874
875
876
877 final float tillPoint = this
878 .getWidthTillPoint(g, elements
879 .iterator());
880 final float pointWidth = this.getPointWidth(
881 g, elements.iterator());
882
883 alignwidths[col][Mtable.LEFT_WIDTH][row][alignIndex] = tillPoint;
884
885 if (alignwidths[col][Mtable.LEFT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] < tillPoint) {
886 alignwidths[col][Mtable.LEFT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] = tillPoint;
887 }
888
889 alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex] = alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex]
890 - tillPoint - pointWidth;
891
892 if (alignwidths[col][Mtable.RIGHT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] < alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex]) {
893 alignwidths[col][Mtable.RIGHT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex] = alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex];
894 }
895 }
896 }
897 }
898 }
899 }
900 }
901
902
903 Mtable.AlignmentType alignOfTheGroup = Mtable.AlignmentType.LEFT;
904 float currentWidth = 0;
905 float maxWidth = 0;
906 float leftWidth = 0;
907 float leftMaxWidth = 0;
908 float rightWidth = 0;
909 float rightMaxWidth = 0;
910 Maligngroup group = null;
911 Maligngroup nextGroup = null;
912 for (int col = 0; col < columnsCount; col++) {
913 for (int row = 0; row < rowsCount; row++) {
914 Mtd cell = null;
915 try {
916 cell = this.getCell(row, col);
917 } catch (final Exception e) {
918 cell = null;
919 }
920
921 if (cell != null) {
922 aligngroups = this.getAlignGroups(cell);
923 groupalignvalues = this.getGroupAlign(cell);
924 if (groupalignvalues.size() == 0) {
925
926
927 groupalignvalues = new Vector<Mtable.AlignmentType>(
928 aligngroups.length);
929 for (final Maligngroup element : aligngroups) {
930 groupalignvalues.add(Mtable.AlignmentType.LEFT);
931 }
932 }
933 if (aligngroups.length == 0
934 || aligngroups.length < groupalignvalues.size()) {
935 continue;
936 }
937 for (int alignIndex = 0; alignIndex < groupalignvalues
938 .size(); alignIndex++) {
939
940
941 alignOfTheGroup = groupalignvalues.get(alignIndex);
942 currentWidth = alignwidths[col][Mtable.WHOLE_WIDTH][row][alignIndex];
943 maxWidth = alignwidths[col][Mtable.WHOLE_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex];
944 leftWidth = alignwidths[col][Mtable.LEFT_WIDTH][row][alignIndex];
945 leftMaxWidth = alignwidths[col][Mtable.LEFT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex];
946 rightWidth = alignwidths[col][Mtable.RIGHT_WIDTH][row][alignIndex];
947 rightMaxWidth = alignwidths[col][Mtable.RIGHT_WIDTH][MAX_WIDTH_IN_COLUMN][alignIndex];
948 group = aligngroups[alignIndex];
949 if (usesMarks[col][alignIndex]) {
950 alignOfTheGroup = Mtable.AlignmentType.MARK;
951 }
952 if (alignIndex < groupalignvalues.size() - 1) {
953 nextGroup = aligngroups[alignIndex + 1];
954 }
955 switch (alignOfTheGroup) {
956 case RIGHT:
957 group.width += maxWidth - currentWidth;
958 break;
959 case LEFT:
960 if (alignIndex < groupalignvalues.size() - 1) {
961 nextGroup.width += maxWidth - currentWidth;
962 }
963 break;
964 case CENTER:
965 group.width += (maxWidth - currentWidth) / 2;
966 if (alignIndex < groupalignvalues.size() - 1) {
967 nextGroup.width += (maxWidth - currentWidth) / 2;
968 }
969 break;
970 case DECIMALPOINT:
971 case MARK:
972 group.width += (leftMaxWidth - leftWidth);
973 if (alignIndex < groupalignvalues.size() - 1) {
974 nextGroup.width += rightMaxWidth - rightWidth;
975 }
976 break;
977 default:
978 group.width += maxWidth - currentWidth;
979 }
980 }
981 }
982 }
983 }
984 }
985
986
987
988
989
990
991 private class ChildIterator implements Iterator {
992
993 private final org.w3c.dom.NodeList nodeList;
994
995 private int pos;
996
997 protected ChildIterator(final org.w3c.dom.NodeList nl) {
998 this.nodeList = nl;
999 }
1000
1001 public boolean hasNext() {
1002 return this.pos < this.nodeList.getLength();
1003 }
1004
1005 public Object next() {
1006 this.pos++;
1007 return this.nodeList.item(this.pos - 1);
1008 }
1009
1010 public void remove() {
1011
1012 }
1013
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 private float getWidthTillPoint(final Graphics2D g,
1025 final Iterator elements) {
1026 float result = 0;
1027
1028 JEuclidElement element = null;
1029 for (; elements.hasNext();) {
1030 element = (JEuclidElement) elements.next();
1031 if (element instanceof Mn) {
1032 return result + ((Mn) element).getWidthTillPoint(g);
1033 } else {
1034 if (!this.containsNumber(element)) {
1035 result += element.getWidth(g);
1036 } else {
1037 result += this.getWidthTillPoint(g, new ChildIterator(
1038 this.getChildNodes()));
1039
1040 }
1041 }
1042 }
1043
1044 return result;
1045 }
1046
1047
1048
1049
1050
1051 private boolean containsNumber(final JEuclidElement element) {
1052 return this.containsElement(element, Mn.ELEMENT);
1053 }
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063 private float getPointWidth(final Graphics2D g, final Iterator iterator) {
1064 float result = 0;
1065
1066 for (; iterator.hasNext();) {
1067 final JEuclidElement element = (JEuclidElement) iterator.next();
1068 if (element instanceof Mn) {
1069 result = ((Mn) element).getPointWidth(g);
1070 break;
1071 }
1072 }
1073
1074 return result;
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084 private float getWidthTillMark(final Graphics2D g, final Iterator elements) {
1085 float result = 0;
1086
1087 JEuclidElement element = null;
1088 for (; elements.hasNext();) {
1089 element = (JEuclidElement) elements.next();
1090 if (element instanceof Malignmark) {
1091 return result;
1092 } else {
1093 if (!this.containsMark(element)) {
1094 result += element.getWidth(g);
1095 } else {
1096 result += this.getWidthTillMark(g, new ChildIterator(this
1097 .getChildNodes()));
1098 }
1099 }
1100 }
1101
1102 return result;
1103 }
1104
1105
1106
1107
1108
1109
1110
1111
1112 private boolean containsMark(final JEuclidElement element) {
1113 return this.containsElement(element, Malignmark.ELEMENT);
1114 }
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126 private boolean containsElement(final JEuclidElement container,
1127 final String searchName) {
1128 if (container.getTagName().equals(searchName)) {
1129 return true;
1130 }
1131
1132 for (int i = 0; i < container.getMathElementCount(); i++) {
1133 if (this.containsElement(container.getMathElement(i), searchName)) {
1134 return true;
1135 }
1136 }
1137
1138 return false;
1139 }
1140
1141
1142 public String getTagName() {
1143 return Mtable.ELEMENT;
1144 }
1145
1146
1147 public String getRowlines() {
1148 return this.getMathAttribute(Mtable.ATTR_ROWLINES);
1149 }
1150
1151
1152 public void setRowlines(final String rowlines) {
1153 this.setAttribute(Mtable.ATTR_ROWLINES, rowlines);
1154 }
1155
1156
1157 public String getColumnlines() {
1158 return this.getMathAttribute(Mtable.ATTR_COLUMNLINES);
1159 }
1160
1161
1162 public void setColumnlines(final String columnlines) {
1163 this.setAttribute(Mtable.ATTR_COLUMNLINES, columnlines);
1164 }
1165
1166 private LineType getRowLine(final int row) {
1167 return Mtable.LineType.parseLineType(this.getSpaceArrayEntry(this
1168 .getRowlines(), row));
1169 }
1170
1171 private LineType getColumnLine(final