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