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.script;
20
21 import java.awt.geom.Dimension2D;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import net.sourceforge.jeuclid.LayoutContext;
26 import net.sourceforge.jeuclid.elements.JEuclidElement;
27 import net.sourceforge.jeuclid.elements.support.Dimension2DImpl;
28 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
29 import net.sourceforge.jeuclid.elements.support.MathMLNodeListImpl;
30 import net.sourceforge.jeuclid.layout.LayoutInfo;
31 import net.sourceforge.jeuclid.layout.LayoutStage;
32 import net.sourceforge.jeuclid.layout.LayoutView;
33
34 import org.w3c.dom.Node;
35 import org.w3c.dom.mathml.MathMLElement;
36 import org.w3c.dom.mathml.MathMLMultiScriptsElement;
37 import org.w3c.dom.mathml.MathMLNodeList;
38
39
40
41
42
43
44
45 public final class Mmultiscripts extends AbstractScriptElement implements
46 MathMLMultiScriptsElement {
47
48
49
50 public static final String ELEMENT = "mmultiscripts";
51
52 private static final long serialVersionUID = 1L;
53
54
55
56
57
58
59
60 private static final int STATE_POSTSUB = 0;
61
62 private static final int STATE_POSTSUPER = 1;
63
64 private static final int STATE_PRESUB = 2;
65
66 private static final int STATE_PRESUPER = 3;
67
68 private final List<JEuclidElement> postsubscripts = new ArrayList<JEuclidElement>();
69
70 private final List<JEuclidElement> postsuperscripts = new ArrayList<JEuclidElement>();
71
72 private final List<JEuclidElement> presubscripts = new ArrayList<JEuclidElement>();
73
74 private final List<JEuclidElement> presuperscripts = new ArrayList<JEuclidElement>();
75
76 private boolean inRewriteChildren;
77
78
79
80
81 public Mmultiscripts() {
82 super();
83 this.inRewriteChildren = false;
84 }
85
86
87 @Override
88 protected Node newNode() {
89 return new Mmultiscripts();
90 }
91
92
93 @Override
94 public void changeHook() {
95 super.changeHook();
96 if (!this.inRewriteChildren) {
97 this.parseChildren();
98 }
99 }
100
101 private void parseChildren() {
102 this.presubscripts.clear();
103 this.presuperscripts.clear();
104 this.postsubscripts.clear();
105 this.postsuperscripts.clear();
106 final org.w3c.dom.NodeList childList = this.getChildNodes();
107 int state = Mmultiscripts.STATE_POSTSUB;
108 final int len = childList.getLength();
109 for (int i = 1; i < len; i++) {
110 final Node child = childList.item(i);
111 if (child instanceof Mprescripts) {
112 state = Mmultiscripts.STATE_PRESUB;
113 } else if (child instanceof JEuclidElement) {
114 final JEuclidElement jchild = (JEuclidElement) child;
115 if (state == Mmultiscripts.STATE_POSTSUB) {
116 this.postsubscripts.add(jchild);
117 state = Mmultiscripts.STATE_POSTSUPER;
118 } else if (state == Mmultiscripts.STATE_POSTSUPER) {
119 this.postsuperscripts.add(jchild);
120 state = Mmultiscripts.STATE_POSTSUB;
121 } else if (state == Mmultiscripts.STATE_PRESUB) {
122 this.presubscripts.add(jchild);
123 state = Mmultiscripts.STATE_PRESUPER;
124 } else {
125 this.presuperscripts.add(jchild);
126 state = Mmultiscripts.STATE_PRESUB;
127 }
128 }
129 }
130 if (this.postsuperscripts.size() < this.postsubscripts.size()) {
131 this.postsuperscripts.add((JEuclidElement) this.getOwnerDocument()
132 .createElement(None.ELEMENT));
133 }
134 if (this.presuperscripts.size() < this.presubscripts.size()) {
135 this.presuperscripts.add((JEuclidElement) this.getOwnerDocument()
136 .createElement(None.ELEMENT));
137 }
138 }
139
140
141 @Override
142 protected void layoutStageInvariant(final LayoutView view,
143 final LayoutInfo info, final LayoutStage stage,
144 final LayoutContext context) {
145 final JEuclidElement base = this.getBase();
146 final LayoutInfo baseInfo = view.getInfo(base);
147 final LayoutContext now = this.applyLocalAttributesToContext(context);
148
149 final String subScriptshift = this.getSubscriptshift();
150 final String superScriptshift = this.getSuperscriptshift();
151
152 final ScriptSupport.ShiftInfo totalShiftInfo = this
153 .calculateTotalShift(view, stage, baseInfo, now,
154 subScriptshift, superScriptshift);
155 float posX = 0.0f;
156 final float subBaselineShift = totalShiftInfo.getSubShift();
157 final float superBaselineShift = totalShiftInfo.getSuperShift();
158 for (int i = 0; i < this.presubscripts.size(); i++) {
159 final LayoutInfo subInfo = view.getInfo(this.presubscripts.get(i));
160 final LayoutInfo superInfo = view.getInfo(this.presuperscripts
161 .get(i));
162 subInfo.moveTo(posX, subBaselineShift, stage);
163 superInfo.moveTo(posX, -superBaselineShift, stage);
164 posX += Math
165 .max(subInfo.getWidth(stage), superInfo.getWidth(stage));
166 }
167 baseInfo.moveTo(posX, 0.0f, stage);
168 posX += baseInfo.getWidth(stage);
169 for (int i = 0; i < this.postsubscripts.size(); i++) {
170 final LayoutInfo subInfo = view.getInfo(this.postsubscripts.get(i));
171 final LayoutInfo superInfo = view.getInfo(this.postsuperscripts
172 .get(i));
173 subInfo.moveTo(posX, subBaselineShift, stage);
174 superInfo.moveTo(posX, -superBaselineShift, stage);
175 posX += Math
176 .max(subInfo.getWidth(stage), superInfo.getWidth(stage));
177 }
178
179 final Dimension2D noborder = new Dimension2DImpl(0.0f, 0.0f);
180 ElementListSupport.fillInfoFromChildren(view, info, this, stage,
181 noborder, noborder);
182 }
183
184 private ScriptSupport.ShiftInfo calculateTotalShift(final LayoutView view,
185 final LayoutStage stage, final LayoutInfo baseInfo,
186 final LayoutContext now, final String subScriptshift,
187 final String superScriptshift) {
188 final ScriptSupport.ShiftInfo totalShiftInfo = new ScriptSupport.ShiftInfo(
189 0.0f, 0.0f);
190
191 for (int i = 0; i < this.presubscripts.size(); i++) {
192 final LayoutInfo subInfo = view.getInfo(this.presubscripts.get(i));
193 final LayoutInfo superInfo = view.getInfo(this.presuperscripts
194 .get(i));
195 final ScriptSupport.ShiftInfo shiftInfo = ScriptSupport
196 .calculateScriptShfits(stage, now, subScriptshift,
197 superScriptshift, baseInfo, subInfo, superInfo);
198 totalShiftInfo.max(shiftInfo);
199 }
200 for (int i = 0; i < this.postsubscripts.size(); i++) {
201 final LayoutInfo subInfo = view.getInfo(this.postsubscripts.get(i));
202 final LayoutInfo superInfo = view.getInfo(this.postsuperscripts
203 .get(i));
204 final ScriptSupport.ShiftInfo shiftInfo = ScriptSupport
205 .calculateScriptShfits(stage, now, subScriptshift,
206 superScriptshift, baseInfo, subInfo, superInfo);
207 totalShiftInfo.max(shiftInfo);
208 }
209 return totalShiftInfo;
210 }
211
212
213 @Override
214 public boolean hasChildPrescripts(final JEuclidElement child) {
215 return child.isSameNode(this.getBase())
216 && this.getNumprescriptcolumns() > 0;
217 }
218
219
220 @Override
221 public boolean hasChildPostscripts(final JEuclidElement child,
222 final LayoutContext context) {
223 return child.isSameNode(this.getBase())
224 && this.getNumscriptcolumns() > 0;
225 }
226
227
228 public JEuclidElement getBase() {
229 final JEuclidElement base = this.getMathElement(0);
230 if (base == null) {
231 return (JEuclidElement) this.getOwnerDocument().createElement(
232 None.ELEMENT);
233 } else {
234 return base;
235 }
236 }
237
238
239 public void setBase(final MathMLElement base) {
240 this.setMathElement(0, base);
241 }
242
243
244 public int getNumprescriptcolumns() {
245 return this.presubscripts.size();
246 }
247
248
249 public int getNumscriptcolumns() {
250 return this.postsubscripts.size();
251 }
252
253
254 public MathMLElement getPreSubScript(final int colIndex) {
255 return this.presubscripts.get(colIndex - 1);
256 }
257
258
259 public MathMLElement getPreSuperScript(final int colIndex) {
260 return this.presuperscripts.get(colIndex - 1);
261 }
262
263
264 public MathMLNodeList getPrescripts() {
265 final int presubsize = this.presubscripts.size();
266 final List<Node> list = new ArrayList<Node>(2 * presubsize);
267 for (int i = 0; i < presubsize; i++) {
268 list.add(this.presubscripts.get(i));
269 list.add(this.presuperscripts.get(i));
270 }
271 return new MathMLNodeListImpl(list);
272 }
273
274
275 public MathMLNodeList getScripts() {
276 final int postsubsize = this.postsubscripts.size();
277 final List<Node> list = new ArrayList<Node>(2 * postsubsize);
278 for (int i = 0; i < postsubsize; i++) {
279 list.add(this.postsubscripts.get(i));
280 list.add(this.postsuperscripts.get(i));
281 }
282 return new MathMLNodeListImpl(list);
283 }
284
285
286 public MathMLElement getSubScript(final int colIndex) {
287 if ((colIndex < 1) || (colIndex > this.postsubscripts.size())) {
288 return null;
289 }
290 return this.postsubscripts.get(colIndex - 1);
291 }
292
293
294 public MathMLElement getSuperScript(final int colIndex) {
295 if ((colIndex < 1) || (colIndex > this.postsuperscripts.size())) {
296 return null;
297 }
298 return this.postsuperscripts.get(colIndex - 1);
299 }
300
301 private void rewriteChildren() {
302 this.inRewriteChildren = true;
303
304 final org.w3c.dom.NodeList childList = this.getChildNodes();
305 final int len = childList.getLength();
306
307 for (int i = 1; i < len; i++) {
308 this.removeChild(childList.item(1));
309 }
310 if (len == 0) {
311 this.addMathElement((JEuclidElement) this.getOwnerDocument()
312 .createElement(None.ELEMENT));
313 }
314 for (int i = 0; i < this.postsubscripts.size(); i++) {
315 this.addMathElement(this.postsubscripts.get(i));
316 this.addMathElement(this.postsuperscripts.get(i));
317 }
318 final int numprescripts = this.presubscripts.size();
319 if (numprescripts > 0) {
320 this.addMathElement((Mprescripts) this.getOwnerDocument()
321 .createElement(Mprescripts.ELEMENT));
322 for (int i = 0; i < numprescripts; i++) {
323 this.addMathElement(this.presubscripts.get(i));
324 this.addMathElement(this.presuperscripts.get(i));
325 }
326 }
327 this.inRewriteChildren = false;
328 }
329
330
331 public MathMLElement insertPreSubScriptBefore(final int colIndex,
332 final MathMLElement newScript) {
333 final int targetIndex;
334 if (colIndex == 0) {
335 targetIndex = this.presubscripts.size();
336 } else {
337 targetIndex = colIndex - 1;
338 }
339 this.presubscripts.add(targetIndex, (JEuclidElement) newScript);
340 this.presuperscripts.add(targetIndex, (JEuclidElement) this
341 .getOwnerDocument().createElement(None.ELEMENT));
342 this.rewriteChildren();
343 return newScript;
344 }
345
346
347 public MathMLElement insertPreSuperScriptBefore(final int colIndex,
348 final MathMLElement newScript) {
349 final int targetIndex;
350 if (colIndex == 0) {
351 targetIndex = this.presubscripts.size();
352 } else {
353 targetIndex = colIndex - 1;
354 }
355 this.presubscripts.add(targetIndex, (JEuclidElement) this
356 .getOwnerDocument().createElement(None.ELEMENT));
357 this.presuperscripts.add(targetIndex, (JEuclidElement) newScript);
358 this.rewriteChildren();
359 return newScript;
360 }
361
362
363 public MathMLElement insertSubScriptBefore(final int colIndex,
364 final MathMLElement newScript) {
365 final int targetIndex;
366 if (colIndex == 0) {
367 targetIndex = this.postsubscripts.size();
368 } else {
369 targetIndex = colIndex - 1;
370 }
371 this.postsubscripts.add(targetIndex, (JEuclidElement) newScript);
372 this.postsuperscripts.add(targetIndex, (JEuclidElement) this
373 .getOwnerDocument().createElement(None.ELEMENT));
374 this.rewriteChildren();
375 return newScript;
376 }
377
378
379 public MathMLElement insertSuperScriptBefore(final int colIndex,
380 final MathMLElement newScript) {
381 final int targetIndex;
382 if (colIndex == 0) {
383 targetIndex = this.postsubscripts.size();
384 } else {
385 targetIndex = colIndex - 1;
386 }
387 this.postsubscripts.add(targetIndex, (JEuclidElement) this
388 .getOwnerDocument().createElement(None.ELEMENT));
389 this.postsuperscripts.add(targetIndex, (JEuclidElement) newScript);
390 this.rewriteChildren();
391 return newScript;
392 }
393
394
395 public MathMLElement setPreSubScriptAt(final int colIndex,
396 final MathMLElement newScript) {
397 final int targetCol = colIndex - 1;
398 if (targetCol == this.presubscripts.size()) {
399 return this.insertPreSubScriptBefore(0, newScript);
400 } else {
401 this.presubscripts.set(targetCol, (JEuclidElement) newScript);
402 this.rewriteChildren();
403 return newScript;
404 }
405 }
406
407
408 public MathMLElement setPreSuperScriptAt(final int colIndex,
409 final MathMLElement newScript) {
410 final int targetCol = colIndex - 1;
411 if (targetCol == this.presuperscripts.size()) {
412 return this.insertPreSuperScriptBefore(0, newScript);
413 } else {
414 this.presuperscripts.set(targetCol, (JEuclidElement) newScript);
415 this.rewriteChildren();
416 return newScript;
417 }
418 }
419
420
421 public MathMLElement setSubScriptAt(final int colIndex,
422 final MathMLElement newScript) {
423 final int targetCol = colIndex - 1;
424 if (targetCol == this.postsubscripts.size()) {
425 return this.insertSubScriptBefore(0, newScript);
426 } else {
427 this.postsubscripts.set(targetCol, (JEuclidElement) newScript);
428 this.rewriteChildren();
429 return newScript;
430 }
431 }
432
433
434 public MathMLElement setSuperScriptAt(final int colIndex,
435 final MathMLElement newScript) {
436 final int targetCol = colIndex - 1;
437 if (targetCol == this.postsuperscripts.size()) {
438 return this.insertSuperScriptBefore(0, newScript);
439 } else {
440 this.postsuperscripts.set(targetCol, (JEuclidElement) newScript);
441 this.rewriteChildren();
442 return newScript;
443 }
444 }
445
446 }