001 /*
002 * Copyright 2002 - 2009 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: AbstractJEuclidElement.java,v 62d8defc665e 2009/09/25 14:22:59 max $ */
018
019 package net.sourceforge.jeuclid.elements;
020
021 import java.awt.Color;
022 import java.awt.Font;
023 import java.awt.FontMetrics;
024 import java.awt.Graphics2D;
025 import java.util.HashMap;
026 import java.util.HashSet;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.Set;
030
031 import net.sourceforge.jeuclid.LayoutContext;
032 import net.sourceforge.jeuclid.context.StyleAttributeLayoutContext;
033 import net.sourceforge.jeuclid.elements.presentation.token.Mo;
034 import net.sourceforge.jeuclid.elements.presentation.token.Mtext;
035 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
036 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
037 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
038 import net.sourceforge.jeuclid.elements.support.attributes.MathVariant;
039 import net.sourceforge.jeuclid.elements.support.text.TextContent;
040 import net.sourceforge.jeuclid.layout.LayoutInfo;
041 import net.sourceforge.jeuclid.layout.LayoutStage;
042 import net.sourceforge.jeuclid.layout.LayoutView;
043 import net.sourceforge.jeuclid.layout.LayoutableNode;
044
045 import org.apache.batik.dom.AbstractDocument;
046 import org.apache.batik.dom.GenericElementNS;
047 import org.apache.batik.dom.events.DOMMutationEvent;
048 import org.w3c.dom.Attr;
049 import org.w3c.dom.Node;
050 import org.w3c.dom.events.Event;
051 import org.w3c.dom.mathml.MathMLElement;
052 import org.w3c.dom.mathml.MathMLMathElement;
053 import org.w3c.dom.mathml.MathMLNodeList;
054
055 /**
056 * The basic class for all math elements. Every element class inherits from this
057 * class. It provides basic functionality for drawing.
058 *
059 * @version $Revision: 62d8defc665e $
060 */
061 // CHECKSTYLE:OFF
062 public abstract class AbstractJEuclidElement extends
063 // CHECKSTYLE:ON
064 GenericElementNS implements JEuclidElement {
065
066 /** Constant for mathvariant attribute. */
067 public static final String ATTR_MATHVARIANT = "mathvariant";
068
069 /** Constant for mathcolor attribute. */
070 public static final String ATTR_MATHCOLOR = "mathcolor";
071
072 /** Constant for mathsize attribute. */
073 public static final String ATTR_MATHSIZE = "mathsize";
074
075 /** Constant for fontfamily attribute. */
076 public static final String ATTR_DEPRECATED_FONTFAMILY = "fontfamily";
077
078 /** Constant for fontstyle attribute. */
079 public static final String ATTR_DEPRECATED_FONTSTYLE = "fontstyle";
080
081 /** Constant for fontweight attribute. */
082 public static final String ATTR_DEPRECATED_FONTWEIGHT = "fontweight";
083
084 /** Constant for fontsize attribute. */
085 public static final String ATTR_DEPRECATED_FONTSIZE = "fontsize";
086
087 /** Constant for color attribute. */
088 public static final String ATTR_DEPRECATED_COLOR = "color";
089
090 /** Constant for background attribute. */
091 public static final String ATTR_DEPRECATED_BACKGROUND = "background";
092
093 /** Constant for class attribute. */
094 public static final String ATTR_CLASS = "class";
095
096 /** Constant for style attribute. */
097 public static final String ATTR_STYLE = "style";
098
099 /** Constant for id attribute. */
100 public static final String ATTR_ID = "id";
101
102 /** Constant for href attribute. */
103 public static final String ATTR_HREF = "xlink:href";
104
105 /** Constant for xref attribute. */
106 public static final String ATTR_XREF = "xref";
107
108 /** The mathbackground attribute. */
109 public static final String ATTR_MATHBACKGROUND = "mathbackground";
110
111 /**
112 * largest value for all trivial spaces (= spaces that can be ignored /
113 * shortened).
114 */
115 public static final int TRIVIAL_SPACE_MAX = 0x20;
116
117 /**
118 * The URI from MathML.
119 */
120 public static final String URI = "http://www.w3.org/1998/Math/MathML";
121
122 private static final float MIDDLE_SHIFT = 0.38f;
123
124 // /**
125 // * Logger for this class
126 // */
127 // private static final Log LOGGER = LogFactory
128 // .getLog(AbstractJEuclidElement.class);
129
130 private static final Set<String> DEPRECATED_ATTRIBUTES = new HashSet<String>();
131
132 /**
133 * Reference to the element acting as parent if there is no parent.
134 */
135 private JEuclidElement fakeParent;
136
137 private final Map<String, String> defaultMathAttributes = new HashMap<String, String>();
138
139 /**
140 * Default constructor. Sets MathML Namespace.
141 *
142 * @param qname
143 * Qualified name.
144 * @param odoc
145 * Owner Document.
146 */
147 public AbstractJEuclidElement(final String qname,
148 final AbstractDocument odoc) {
149 super(AbstractJEuclidElement.URI, qname, odoc);
150 }
151
152 /**
153 * Constructor to explicitly set the namespace.
154 *
155 * @param nsUri
156 * Namespace URI.
157 * @param qname
158 * Qualified name.
159 * @param odoc
160 * Owner Document.
161 */
162 public AbstractJEuclidElement(final String nsUri, final String qname,
163 final AbstractDocument odoc) {
164 super(nsUri, qname, odoc);
165 }
166
167 /**
168 * Gets the used font. Everything regardes font, processed by MathBase
169 * object.
170 *
171 * @param context
172 * LayoutContext to use.
173 * @return Font Font object.
174 */
175 public Font getFont(final LayoutContext context) {
176 final String content = this.getText();
177 final char aChar;
178 if (content.length() > 0) {
179 aChar = content.charAt(0);
180 } else {
181 aChar = 'A';
182 }
183 return this.getMathvariantAsVariant().createFont(
184 GraphicsSupport.getFontsizeInPoint(context), aChar,
185 this.applyLocalAttributesToContext(context), true);
186
187 }
188
189 /** {@inheritDoc} */
190 public MathVariant getMathvariantAsVariant() {
191 // TODO: Support deprecated variant names
192 String setMv = this.getMathAttribute(
193 AbstractJEuclidElement.ATTR_MATHVARIANT, false);
194
195 JEuclidElement parent = this.getParent();
196 while ((setMv == null) && (parent != null)) {
197 // element is not set, try to inherit
198 if (parent instanceof AbstractJEuclidElement) {
199 setMv = ((AbstractJEuclidElement) parent).getMathAttribute(
200 AbstractJEuclidElement.ATTR_MATHVARIANT, false);
201 }
202 parent = parent.getParent();
203 }
204 if (setMv == null) {
205 setMv = this.defaultMathAttributes
206 .get(AbstractJEuclidElement.ATTR_MATHVARIANT);
207 }
208 MathVariant variant;
209 if (setMv == null) {
210 variant = MathVariant.NORMAL;
211 } else {
212 variant = MathVariant.stringToMathVariant(setMv);
213 if (variant == null) {
214 variant = MathVariant.NORMAL;
215 }
216 }
217 return variant;
218 }
219
220 // /**
221 // * Setting size of child of the element.
222 // *
223 // * @param child
224 // * Child element
225 // * @param childpos
226 // * Position of the child element
227 // */
228 //
229 // private void setChildSize(AbstractMathElement child, int childpos) {
230 //
231 // float childSize = (float) Math.pow(getScriptSizeMultiplier(), child
232 // .getAbsoluteScriptLevel());
233 //
234 // child.multipleFont(m_font, (float) Math.pow(getScriptSizeMultiplier(),
235 // child.getAbsoluteScriptLevel()));
236 // System.out.println(child.toString() + " "
237 // + child.getAbsoluteScriptLevel() + " "
238 // + getScriptSizeMultiplier() + " " + childSize);
239 //
240 // child.setScriptSizeMultiplier(getScriptSizeMultiplier());
241 //
242 // if (this instanceof MathMultiScripts) {
243 // if (childpos > 0) {
244 // child.multipleFont(m_font, getScriptSizeMultiplier());
245 // child.setDisplayStyle(false);
246 // child.setInheritSisplayStyle(false);
247 // }
248 // } else if (this instanceof MathOver) {
249 // if (childpos == 1) {
250 // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
251 // getMathElement(0))
252 // .getMoveableLimits())
253 // || (!((MathOver) this).getAccent())) {
254 // child.multipleFont(m_font, getScriptSizeMultiplier());
255 // child.setDisplayStyle(false);
256 // child.setInheritSisplayStyle(false);
257 // }
258 // }
259 // } else if (this instanceof MathUnder) {
260 // if (childpos == 1) {
261 // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
262 // getMathElement(0))
263 // .getMoveableLimits())
264 // || (!((MathUnder) this).getAccentUnder())) {
265 // child.multipleFont(m_font, getScriptSizeMultiplier());
266 // child.setDisplayStyle(false);
267 // child.setInheritSisplayStyle(false);
268 // }
269 // }
270 // } else if (this instanceof MathUnderOver) {
271 // if (childpos > 0) {
272 // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
273 // getMathElement(0))
274 // .getMoveableLimits())
275 // || ((childpos == 1) && (!((MathUnderOver) this)
276 // .getAccentUnder()))
277 // || ((childpos == 2) && (!((MathUnderOver) this)
278 // .getAccent()))) {
279 // child.multipleFont(m_font, getScriptSizeMultiplier());
280 // child.setDisplayStyle(false);
281 // child.setInheritSisplayStyle(false);
282 // }
283 // }
284 // } else if (this instanceof MathRoot) {
285 // if (childpos == 1) {
286 // child.multipleFont(m_font, (float) Math.pow(
287 // getScriptSizeMultiplier(), 2));
288 // child.setDisplayStyle(false);
289 // child.setInheritSisplayStyle(false);
290 // }
291 // } else if (this instanceof MathSub) {
292 // if (childpos == 1) {
293 // child.multipleFont(m_font, getScriptSizeMultiplier());
294 // child.setDisplayStyle(false);
295 // child.setInheritSisplayStyle(false);
296 // }
297 // } else if (this instanceof MathSup) {
298 // if (childpos == 1) {
299 // child.multipleFont(m_font, getScriptSizeMultiplier());
300 // child.setDisplayStyle(false);
301 // child.setInheritSisplayStyle(false);
302 // }
303 // } else if (this instanceof MathSubSup) {
304 // if (childpos > 0) {
305 // child.multipleFont(m_font, getScriptSizeMultiplier());
306 // child.setDisplayStyle(false);
307 // child.setInheritSisplayStyle(false);
308 // }
309 // } else if (this instanceof MathStyle) {
310 // // child.multipleFont(m_font, (float) Math.pow(
311 // // getScriptSizeMultiplier(), ((MathStyle) this)
312 // // .getScriptlevel()));
313 // } else {
314 // child.setFont(m_font);
315 // }
316 // }
317
318 /**
319 * Add a math element as a child.
320 *
321 * @param child
322 * Math element object.
323 */
324 public final void addMathElement(final MathMLElement child) {
325 if (child != null) {
326 this.appendChild(child);
327 }
328 }
329
330 /**
331 * Gets a child from this element.
332 * <p>
333 * Please note, that unlike the MathML DOM model functions this function
334 * uses a 0-based index.
335 *
336 * @param index
337 * Index of the child (0-based).
338 * @return The child MathElement object.
339 */
340 protected JEuclidElement getMathElement(final int index) {
341 final List<Node> childList = ElementListSupport
342 .createListOfChildren(this);
343 int count = 0;
344 for (final Node n : childList) {
345 if (n instanceof JEuclidElement) {
346 if (count == index) {
347 return (JEuclidElement) n;
348 }
349 count++;
350 }
351 }
352 for (; count < index; count++) {
353 this.appendChild(this.ownerDocument.createElement(Mtext.ELEMENT));
354 }
355 final JEuclidElement last = (JEuclidElement) this.ownerDocument
356 .createElement(Mtext.ELEMENT);
357 this.appendChild(last);
358 return last;
359 }
360
361 /**
362 * Sets a specific child to the newElement, creating other subelements as
363 * necessary.
364 *
365 * @param index
366 * the index to set (0=the first child)
367 * @param newElement
368 * new element to be set as child.
369 */
370 protected void setMathElement(final int index,
371 final MathMLElement newElement) {
372 final org.w3c.dom.NodeList childList = this.getChildNodes();
373 while (childList.getLength() < index) {
374 this.appendChild(this.getOwnerDocument().createTextNode(""));
375 }
376 if (childList.getLength() == index) {
377 this.addMathElement(newElement);
378 } else {
379 this.replaceChild(newElement, childList.item(index));
380 }
381 }
382
383 /** {@inheritDoc} */
384 public int getIndexOfMathElement(final JEuclidElement element) {
385 final org.w3c.dom.NodeList childList = this.getChildNodes();
386 for (int i = 0; i < childList.getLength(); i++) {
387 if (childList.item(i).equals(element)) {
388 return i;
389 }
390 }
391 return -1;
392 }
393
394 /** {@inheritDoc} */
395 public int getMathElementCount() {
396 final List<Node> childList = ElementListSupport
397 .createListOfChildren(this);
398 int count = 0;
399 for (final Node n : childList) {
400 if (n instanceof JEuclidElement) {
401 count++;
402 }
403 }
404 return count;
405 }
406
407 /**
408 * Returns the text content of this element.
409 *
410 * @return Text content.
411 */
412 public String getText() {
413 return TextContent.getText(this);
414 }
415
416 /** {@inheritDoc} */
417 public void setFakeParent(final JEuclidElement parent) {
418 this.fakeParent = parent;
419 }
420
421 private JEuclidNode getParentAsJEuclidNode() {
422 final Node parentNode = this.getParentNode();
423 final JEuclidNode theParent;
424 if (parentNode instanceof JEuclidNode) {
425 theParent = (JEuclidNode) parentNode;
426 } else {
427 theParent = null;
428 }
429 if (theParent == null) {
430 return this.fakeParent;
431 } else {
432 return theParent;
433 }
434
435 }
436
437 /** {@inheritDoc} */
438 public JEuclidElement getParent() {
439 final JEuclidNode parentNode = this.getParentAsJEuclidNode();
440 if (parentNode instanceof JEuclidElement) {
441 return (JEuclidElement) parentNode;
442 } else {
443 return null;
444 }
445 }
446
447 /**
448 * Sets value of mathvariant attribute (style of the element).
449 *
450 * @param mathvariant
451 * Value of mathvariant.
452 */
453 public void setMathvariant(final String mathvariant) {
454 this.setAttribute(AbstractJEuclidElement.ATTR_MATHVARIANT, mathvariant);
455 }
456
457 /**
458 * Returns value of mathvariant attribute (style of the element).
459 *
460 * @return Value of mathvariant.
461 */
462 public String getMathvariant() {
463 return this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHVARIANT);
464 }
465
466 /**
467 * Gets the font metrics of the used font.
468 *
469 * @return Font metrics.
470 * @param context
471 * LayoutContext to use.
472 * @param g
473 * Graphics2D context to use.
474 */
475 public FontMetrics getFontMetrics(final Graphics2D g,
476 final LayoutContext context) {
477 return g.getFontMetrics(this.getFont(context));
478 }
479
480 /**
481 * Sets value of math color attribute.
482 *
483 * @param mathcolor
484 * Color object.
485 */
486 public void setMathcolor(final String mathcolor) {
487 this.setAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR, mathcolor);
488 }
489
490 /**
491 * Returns value of mathcolor attribute.
492 *
493 * @return Color as string.
494 */
495 public String getMathcolor() {
496 String color;
497 color = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR);
498 if (color == null) {
499 color = this
500 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR);
501 }
502 return color;
503 }
504
505 /**
506 * Retrieve the mathsize attribute.
507 *
508 * @return the mathsize attribute.
509 */
510 public String getMathsize() {
511 String size;
512 size = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHSIZE);
513 if (size == null) {
514 size = this
515 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE);
516 }
517 return size;
518
519 }
520
521 /**
522 * Sets mathsize to a new value.
523 *
524 * @param mathsize
525 * value of mathsize.
526 */
527 public void setMathsize(final String mathsize) {
528 this.setAttribute(AbstractJEuclidElement.ATTR_MATHSIZE, mathsize);
529 }
530
531 /**
532 * Sets default values for math attributes. Default values are returned
533 * through getMathAttribute, but not stored in the actual DOM tree. This is
534 * necessary to support proper serialization.
535 *
536 * @param key
537 * the attribute to set.
538 * @param value
539 * value of the attribute.
540 */
541 protected void setDefaultMathAttribute(final String key, final String value) {
542 this.defaultMathAttributes.put(key, value);
543 }
544
545 /**
546 * retrieve an attribute from the MathML or default name space, returning
547 * the default value if the attribute is not set.
548 *
549 * @param attrName
550 * the name of the attribute
551 * @return attribute value or null if not set.
552 * @see #getMathAttribute(String, boolean)
553 */
554 protected String getMathAttribute(final String attrName) {
555 return this.getMathAttribute(attrName, true);
556 }
557
558 /**
559 * retrieve an attribute from the MathML or default name space.
560 *
561 * @param attrName
562 * the name of the attribute
563 * @param useDefault
564 * is true, the default value is used if the attribute is not
565 * set.
566 * @return attribute value or null if not set.
567 * @see #getMathAttribute(String)
568 */
569 protected String getMathAttribute(final String attrName,
570 final boolean useDefault) {
571 final String attrValue;
572 Attr attr = this.getAttributeNodeNS(AbstractJEuclidElement.URI,
573 attrName);
574 if (attr == null) {
575 attr = this.getAttributeNode(attrName);
576 }
577 if (attr == null) {
578 if (useDefault) {
579 attrValue = this.getDefaultMathAttribute(attrName);
580 } else {
581 attrValue = null;
582 }
583 } else {
584 attrValue = attr.getValue().trim();
585 }
586 return attrValue;
587 }
588
589 /**
590 * Retrieves the previously stored default value for this attribute.
591 *
592 * @param attrName
593 * name of the Attribute
594 * @return value set by {@link #setDefaultMathAttribute(String, String)} or
595 * null if not set.
596 */
597 private String getDefaultMathAttribute(final String attrName) {
598 return this.defaultMathAttributes.get(attrName);
599 }
600
601 /**
602 * Returns value of mathbackground attribute.
603 *
604 * @return Color as string.
605 */
606 public String getMathbackground() {
607 String color;
608 color = this
609 .getMathAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND);
610 if (color == null) {
611 color = this
612 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND);
613 }
614 return color;
615 }
616
617 /**
618 * Sets the value of the machbackground attribute.
619 *
620 * @param mathbackground
621 * a string to be used as background color.
622 */
623 public void setMathbackground(final String mathbackground) {
624 this.setAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND,
625 mathbackground);
626 }
627
628 /**
629 * Returns the distance of the baseline and the middleline.
630 *
631 * @return Distance baseline - middleline.
632 * @param context
633 * Layout Context to use
634 * @param g
635 * Graphics2D context to use.
636 */
637 public float getMiddleShift(final Graphics2D g, final LayoutContext context) {
638 return this.getFontMetrics(g, context).getAscent()
639 * AbstractJEuclidElement.MIDDLE_SHIFT;
640 }
641
642 /** {@inheritDoc} */
643 public String getClassName() {
644 return this.getAttribute(AbstractJEuclidElement.ATTR_CLASS);
645 }
646
647 /** {@inheritDoc} */
648 public void setClassName(final String className) {
649 this.setAttribute(AbstractJEuclidElement.ATTR_CLASS, className);
650 }
651
652 /** {@inheritDoc} */
653 public String getMathElementStyle() {
654 return this.getAttribute(AbstractJEuclidElement.ATTR_STYLE);
655 }
656
657 /** {@inheritDoc} */
658 public void setMathElementStyle(final String mathElementStyle) {
659 this.setAttribute(AbstractJEuclidElement.ATTR_STYLE, mathElementStyle);
660 }
661
662 /** {@inheritDoc} */
663 @Override
664 public String getId() {
665 return this.getAttribute(AbstractJEuclidElement.ATTR_ID);
666 }
667
668 /** {@inheritDoc} */
669 public void setId(final String id) {
670 this.setAttribute(AbstractJEuclidElement.ATTR_ID, id);
671 }
672
673 /** {@inheritDoc} */
674 public String getXref() {
675 return this.getAttribute(AbstractJEuclidElement.ATTR_XREF);
676 }
677
678 /** {@inheritDoc} */
679 public void setXref(final String xref) {
680 this.setAttribute(AbstractJEuclidElement.ATTR_XREF, xref);
681 }
682
683 /** {@inheritDoc} */
684 public String getHref() {
685 return this.getAttribute(AbstractJEuclidElement.ATTR_HREF);
686 }
687
688 /** {@inheritDoc} */
689 public void setHref(final String href) {
690 this.setAttribute(AbstractJEuclidElement.ATTR_HREF, href);
691 }
692
693 /** {@inheritDoc} */
694 public MathMLMathElement getOwnerMathElement() {
695 JEuclidElement node = this.getParent();
696 while (node != null) {
697 if (node instanceof MathMLMathElement) {
698 return (MathMLMathElement) node;
699 }
700 node = node.getParent();
701 }
702 return null;
703 }
704
705 /** {@inheritDoc} */
706 public boolean hasChildPrescripts(final JEuclidElement child) {
707 return false;
708 }
709
710 /** {@inheritDoc} */
711 public boolean hasChildPostscripts(final JEuclidElement child,
712 final LayoutContext context) {
713 return false;
714 }
715
716 /**
717 * Returns the children as a MathML NodeList.
718 *
719 * @return a list of children
720 */
721 public MathMLNodeList getContents() {
722 return (MathMLNodeList) this.getChildNodes();
723 }
724
725 /** {@inheritDoc} */
726 public LayoutContext getChildLayoutContext(final int childNum,
727 final LayoutContext context) {
728 return this.applyLocalAttributesToContext(context);
729 }
730
731 /**
732 * Retrieve the LayoutContext valid for the current node.
733 *
734 * @param context
735 * external context.
736 * @return the current layout context.
737 */
738 public LayoutContext applyLocalAttributesToContext(
739 final LayoutContext context) {
740 // TODO: Theoretically this only applies all to presentation token
741 // elements except mspace and mglyph, and on no other elements except
742 // mstyle 3.2.2
743 return this.applyStyleAttributes(context);
744 }
745
746 /**
747 * Apply Style attributed specified in 3.2.2 to a layout context.
748 *
749 * @param applyTo
750 * the context to apply to
751 * @return a context which has the style attributes changed accordingly. May
752 * be the original context if nothing has changed.
753 */
754 private LayoutContext applyStyleAttributes(final LayoutContext applyTo) {
755 LayoutContext retVal = applyTo;
756
757 // Variant is not inherited and therefore not part of the context.
758
759 final String msize = this.getMathsize();
760
761 final Color foreground;
762 final String colorString = this.getMathcolor();
763 if (colorString == null) {
764 foreground = null;
765 } else {
766 foreground = AttributesHelper.stringToColor(colorString,
767 Color.BLACK);
768 }
769
770 // Background is handled differently and does not need to go into
771 // context.
772
773 if ((msize != null) || (foreground != null)) {
774 retVal = new StyleAttributeLayoutContext(applyTo, msize, foreground);
775 }
776
777 return retVal;
778 }
779
780 /** {@inheritDoc} */
781 public List<LayoutableNode> getChildrenToLayout() {
782 final List<LayoutableNode> l = ElementListSupport
783 .createListOfLayoutChildren(this);
784 return l;
785 }
786
787 /** {@inheritDoc} */
788 public List<LayoutableNode> getChildrenToDraw() {
789 final List<LayoutableNode> l = ElementListSupport
790 .createListOfLayoutChildren(this);
791 return l;
792 }
793
794 /**
795 * Layout for elements which are stage independent.
796 * <p>
797 * This function will layout an element which is layed out the same no
798 * matter what stage it is in. This is the case for most elements.
799 * <p>
800 * Notable exceptions are mo and tables.
801 *
802 * @param view
803 * View Object for this layout.
804 * @param info
805 * An info object which will be filled during layout.
806 * @param stage
807 * current layout stage.
808 * @param context
809 * current LayoutContext.
810 */
811 protected void layoutStageInvariant(final LayoutView view,
812 final LayoutInfo info, final LayoutStage stage,
813 final LayoutContext context) {
814 ElementListSupport.layoutSequential(view, info, this
815 .getChildrenToLayout(), stage);
816 }
817
818 /** {@inheritDoc} */
819 public void layoutStage1(final LayoutView view, final LayoutInfo info,
820 final LayoutStage childMinStage, final LayoutContext context) {
821 this.layoutStageInvariant(view, info, LayoutStage.STAGE1, context);
822
823 // TODO: This should be done in a better way.
824 if (this.getMathbackground() == null) {
825 info.setLayoutStage(childMinStage);
826 } else {
827 info.setLayoutStage(LayoutStage.STAGE1);
828 }
829 }
830
831 /** {@inheritDoc} */
832 public void layoutStage2(final LayoutView view, final LayoutInfo info,
833 final LayoutContext context) {
834 this.layoutStageInvariant(view, info, LayoutStage.STAGE2, context);
835
836 // TODO: put in own function, ensure this is also called from
837 // subclasses.
838 final String background = this.getMathbackground();
839 final Color backgroundColor = AttributesHelper.stringToColor(
840 background, null);
841 ElementListSupport.addBackground(backgroundColor, info, false);
842 info.setLayoutStage(LayoutStage.STAGE2);
843 }
844
845 static {
846 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
847 .add(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR);
848 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
849 .add(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND);
850 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
851 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE);
852 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
853 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTWEIGHT);
854 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
855 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSTYLE);
856 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
857 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTFAMILY);
858
859 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES.add(Mo.ATTR_MOVEABLEWRONG);
860 }
861
862 /**
863 * Override this function to get notified whenever the contents of this
864 * element have changed.
865 */
866 protected void changeHook() {
867 // Override me!
868 }
869
870 /** {@inheritDoc} */
871 @Override
872 public boolean dispatchEvent(final Event evt) {
873 if (evt instanceof DOMMutationEvent) {
874 this.changeHook();
875 }
876 return super.dispatchEvent(evt);
877 }
878 }