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.general;
20
21 import java.awt.Color;
22 import java.awt.geom.Dimension2D;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.Stack;
31
32 import net.sourceforge.jeuclid.LayoutContext;
33 import net.sourceforge.jeuclid.context.Parameter;
34 import net.sourceforge.jeuclid.elements.AbstractElementWithDelegates;
35 import net.sourceforge.jeuclid.elements.JEuclidElement;
36 import net.sourceforge.jeuclid.elements.presentation.AbstractContainer;
37 import net.sourceforge.jeuclid.elements.support.Dimension2DImpl;
38 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
39 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
40 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
41 import net.sourceforge.jeuclid.layout.GraphicsObject;
42 import net.sourceforge.jeuclid.layout.LayoutInfo;
43 import net.sourceforge.jeuclid.layout.LayoutStage;
44 import net.sourceforge.jeuclid.layout.LayoutView;
45 import net.sourceforge.jeuclid.layout.LayoutableNode;
46 import net.sourceforge.jeuclid.layout.LineObject;
47
48 import org.apache.batik.dom.AbstractDocument;
49 import org.apache.commons.logging.Log;
50 import org.apache.commons.logging.LogFactory;
51 import org.w3c.dom.Node;
52 import org.w3c.dom.mathml.MathMLEncloseElement;
53
54
55
56
57
58
59 public final class Menclose extends AbstractElementWithDelegates implements
60 MathMLEncloseElement {
61
62
63
64
65 public static final String ELEMENT = "menclose";
66
67
68 public static final String ATTR_NOTATION = "notation";
69
70 private static final String LONGDIV = "longdiv";
71
72
73
74
75
76 private abstract static class AbstractRowLikeNotation extends
77 AbstractContainer {
78
79
80
81
82 private static final long serialVersionUID = 1L;
83
84
85
86
87
88
89
90
91
92 public AbstractRowLikeNotation(final String qname,
93 final AbstractDocument odoc) {
94 super(qname, odoc);
95 }
96
97
98 @Override
99 protected void layoutStageInvariant(final LayoutView view,
100 final LayoutInfo info, final LayoutStage stage,
101 final LayoutContext context) {
102 final LayoutContext now = this
103 .applyLocalAttributesToContext(context);
104 final Dimension2D borderLeftTop = this.getBorderLeftTop(now);
105 final float borderLeft = (float) borderLeftTop.getWidth();
106 if (borderLeft > 0.0f) {
107 view.getInfo((LayoutableNode) this.getFirstChild()).moveTo(
108 borderLeft, 0, stage);
109 }
110 ElementListSupport.fillInfoFromChildren(view, info, this, stage,
111 borderLeftTop, this.getBorderRightBottom(now));
112 this.enclHook(info, stage, this.applyLocalAttributesToContext(now));
113 }
114
115
116
117
118
119
120
121
122 protected Dimension2D getBorderLeftTop(final LayoutContext now) {
123 return new Dimension2DImpl(0.0f, 0.0f);
124 }
125
126
127
128
129
130
131
132
133 protected Dimension2D getBorderRightBottom(final LayoutContext now) {
134 return new Dimension2DImpl(0.0f, 0.0f);
135 }
136
137
138
139
140
141
142
143
144
145
146
147 protected abstract void enclHook(final LayoutInfo info,
148 final LayoutStage stage, final LayoutContext now);
149 }
150
151
152
153
154
155
156 private static final class Longdiv extends Menclose.AbstractRowLikeNotation {
157 private static final long serialVersionUID = 1L;
158
159
160
161
162
163
164
165
166
167 public Longdiv(final String qname, final AbstractDocument odoc) {
168 super(qname, odoc);
169 }
170
171 @Override
172 protected Node newNode() {
173 return new Longdiv(this.nodeName, this.ownerDocument);
174 }
175
176
177 @Override
178 protected Dimension2D getBorderLeftTop(final LayoutContext now) {
179 final float lineSpace = GraphicsSupport.lineWidth(now) * 2;
180 return new Dimension2DImpl(AttributesHelper.convertSizeToPt(
181 "0.25em", now, null)
182 + lineSpace, lineSpace);
183 }
184
185
186 @Override
187 protected void enclHook(final LayoutInfo info, final LayoutStage stage,
188 final LayoutContext now) {
189 final List<GraphicsObject> graphicObjects = info
190 .getGraphicObjects();
191 graphicObjects.clear();
192 final float lineWidth = GraphicsSupport.lineWidth(now);
193 final float top = info.getAscentHeight(stage) + lineWidth;
194 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
195 graphicObjects.add(new LineObject(lineWidth, -top, lineWidth, info
196 .getDescentHeight(stage), lineWidth, color));
197 graphicObjects.add(new LineObject(lineWidth, -top, info
198 .getWidth(stage), -top, lineWidth, color));
199 }
200 }
201
202
203
204
205
206 private static final class Updiagonalstrike extends
207 Menclose.AbstractRowLikeNotation {
208
209 private static final long serialVersionUID = 1L;
210
211
212
213
214
215
216
217
218
219 public Updiagonalstrike(final String qname, final AbstractDocument odoc) {
220 super(qname, odoc);
221 }
222
223 @Override
224 protected Node newNode() {
225 return new Updiagonalstrike(this.nodeName, this.ownerDocument);
226 }
227
228
229 @Override
230 protected void enclHook(final LayoutInfo info, final LayoutStage stage,
231 final LayoutContext now) {
232
233 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
234 final float lineWidth = GraphicsSupport.lineWidth(now);
235 info.setGraphicsObject(new LineObject(0, info
236 .getDescentHeight(stage), info.getWidth(stage), -info
237 .getAscentHeight(stage), lineWidth, color));
238 }
239
240 }
241
242
243
244
245
246 private static final class Downdiagonalstrike extends
247 Menclose.AbstractRowLikeNotation {
248
249 private static final long serialVersionUID = 1L;
250
251
252
253
254
255
256
257
258
259 public Downdiagonalstrike(final String qname,
260 final AbstractDocument odoc) {
261 super(qname, odoc);
262 }
263
264 @Override
265 protected Node newNode() {
266 return new Downdiagonalstrike(this.nodeName, this.ownerDocument);
267 }
268
269
270 @Override
271 protected void enclHook(final LayoutInfo info, final LayoutStage stage,
272 final LayoutContext now) {
273
274 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
275 final float lineWidth = GraphicsSupport.lineWidth(now);
276 info.setGraphicsObject(new LineObject(0, -info
277 .getAscentHeight(stage), info.getWidth(stage), info
278 .getDescentHeight(stage), lineWidth, color));
279 }
280 }
281
282 private static final class Actuarial extends
283 Menclose.AbstractRowLikeNotation {
284 private static final long serialVersionUID = 1L;
285
286
287
288
289
290
291
292
293
294 public Actuarial(final String qname, final AbstractDocument odoc) {
295 super(qname, odoc);
296 }
297
298 @Override
299 protected Node newNode() {
300 return new Actuarial(this.nodeName, this.ownerDocument);
301 }
302
303
304 @Override
305 protected Dimension2D getBorderLeftTop(final LayoutContext now) {
306 final float lineSpace = GraphicsSupport.lineWidth(now) * 2;
307 return new Dimension2DImpl(0.0f, lineSpace);
308 }
309
310
311 @Override
312 protected Dimension2D getBorderRightBottom(final LayoutContext now) {
313 final float lineSpace = GraphicsSupport.lineWidth(now) * 2;
314 return new Dimension2DImpl(lineSpace, 0.0f);
315 }
316
317
318 @Override
319 protected void enclHook(final LayoutInfo info, final LayoutStage stage,
320 final LayoutContext now) {
321 final List<GraphicsObject> graphicObjects = info
322 .getGraphicObjects();
323 graphicObjects.clear();
324 final float lineWidth = GraphicsSupport.lineWidth(now);
325 final float top = info.getAscentHeight(stage) + lineWidth;
326 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
327 graphicObjects.add(new LineObject(0, -top, info.getWidth(stage)
328 - lineWidth, -top, lineWidth, color));
329 graphicObjects.add(new LineObject(info.getWidth(stage) - lineWidth,
330 -top, info.getWidth(stage) - lineWidth, info
331 .getDescentHeight(stage), lineWidth, color));
332 }
333
334 }
335
336
337
338
339 private static final Log LOGGER = LogFactory.getLog(Menclose.class);
340
341 private static final Map<String, Constructor<?>> IMPL_CLASSES = new HashMap<String, Constructor<?>>();;
342
343 private static final long serialVersionUID = 1L;
344
345
346
347
348
349
350
351
352
353 public Menclose(final String qname, final AbstractDocument odoc) {
354 super(qname, odoc);
355
356 this.setDefaultMathAttribute(Menclose.ATTR_NOTATION, Menclose.LONGDIV);
357 }
358
359
360 @Override
361 protected Node newNode() {
362 return new Menclose(this.nodeName, this.ownerDocument);
363 }
364
365
366
367
368 public String getNotation() {
369 return this.getMathAttribute(Menclose.ATTR_NOTATION);
370 }
371
372
373
374
375
376
377
378 public void setNotation(final String notation) {
379 this.setAttribute(Menclose.ATTR_NOTATION, notation);
380 }
381
382
383 @Override
384 protected List<LayoutableNode> createDelegates() {
385 final Stack<Constructor<?>> notationImpls = this.parseNotations();
386 JEuclidElement lastChild = this.ensureSingleChild();
387 lastChild = this.createStackOfDelegates(notationImpls, lastChild);
388 return Collections.singletonList((LayoutableNode) lastChild);
389 }
390
391 private JEuclidElement createStackOfDelegates(
392 final Stack<Constructor<?>> notationImpls,
393 final JEuclidElement oldChild) {
394 JEuclidElement lastChild = oldChild;
395 while (!notationImpls.isEmpty()) {
396 final Constructor<?> con = notationImpls.pop();
397 try {
398 final JEuclidElement element = (JEuclidElement) con
399 .newInstance("saklsdiwet:menclosechild",
400 this.ownerDocument);
401 element.appendChild(lastChild);
402 lastChild = element;
403 } catch (final InstantiationException e) {
404 Menclose.LOGGER.warn(e);
405 } catch (final IllegalAccessException e) {
406 Menclose.LOGGER.warn(e);
407 } catch (final InvocationTargetException e) {
408 Menclose.LOGGER.warn(e);
409 }
410 }
411 return lastChild;
412 }
413
414
415
416
417
418
419
420 private JEuclidElement ensureSingleChild() {
421 final JEuclidElement lastChild;
422 if (this.getMathElementCount() == 1) {
423 lastChild = this.getMathElement(0);
424 } else {
425 lastChild = (JEuclidElement) this.ownerDocument
426 .createElement(Mrow.ELEMENT);
427 for (final Node child : ElementListSupport
428 .createListOfChildren(this)) {
429 lastChild.appendChild(child);
430 }
431 }
432 return lastChild;
433 }
434
435 private Stack<Constructor<?>> parseNotations() {
436 final String[] notations = this.getNotation().split(" ");
437 final Stack<Constructor<?>> notationImpls = new Stack<Constructor<?>>();
438 for (final String curNotation : notations) {
439 final Constructor<?> con = Menclose.IMPL_CLASSES.get(curNotation
440 .toLowerCase(Locale.ENGLISH));
441 if (con == null) {
442 if (curNotation.length() > 0) {
443 Menclose.LOGGER.info("Unsupported notation for menclose: "
444 + curNotation);
445 }
446 } else {
447 notationImpls.push(con);
448 }
449 }
450 return notationImpls;
451 }
452
453 static {
454 try {
455 Menclose.IMPL_CLASSES.put("radical", Msqrt.class.getConstructor(
456 String.class, AbstractDocument.class));
457 Menclose.IMPL_CLASSES.put(Menclose.LONGDIV, Menclose.Longdiv.class
458 .getConstructor(String.class, AbstractDocument.class));
459 Menclose.IMPL_CLASSES.put("updiagonalstrike",
460 Menclose.Updiagonalstrike.class.getConstructor(
461 String.class, AbstractDocument.class));
462 Menclose.IMPL_CLASSES.put("downdiagonalstrike",
463 Menclose.Downdiagonalstrike.class.getConstructor(
464 String.class, AbstractDocument.class));
465 Menclose.IMPL_CLASSES.put("actuarial", Menclose.Actuarial.class
466 .getConstructor(String.class, AbstractDocument.class));
467 } catch (final NoSuchMethodException e) {
468 Menclose.LOGGER.fatal(e);
469 }
470 }
471 }