Coverage Report - net.sourceforge.jeuclid.elements.presentation.script.AbstractUnderOver
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractUnderOver
85%
55/64
64%
18/28
1,722
 
 1  
 /*
 2  
  * Copyright 2007 - 2007 JEuclid, http://jeuclid.sf.net
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 /* $Id: AbstractUnderOver.java,v 2986a8eeaebc 2009/09/24 12:53:08 max $ */
 18  
 
 19  
 package net.sourceforge.jeuclid.elements.presentation.script;
 20  
 
 21  
 import java.awt.geom.Dimension2D;
 22  
 
 23  
 import net.sourceforge.jeuclid.LayoutContext;
 24  
 import net.sourceforge.jeuclid.context.Display;
 25  
 import net.sourceforge.jeuclid.context.InlineLayoutContext;
 26  
 import net.sourceforge.jeuclid.context.Parameter;
 27  
 import net.sourceforge.jeuclid.context.RelativeScriptlevelLayoutContext;
 28  
 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
 29  
 import net.sourceforge.jeuclid.elements.JEuclidElement;
 30  
 import net.sourceforge.jeuclid.elements.support.Dimension2DImpl;
 31  
 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
 32  
 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
 33  
 import net.sourceforge.jeuclid.layout.LayoutInfo;
 34  
 import net.sourceforge.jeuclid.layout.LayoutStage;
 35  
 import net.sourceforge.jeuclid.layout.LayoutView;
 36  
 
 37  
 import org.apache.batik.dom.AbstractDocument;
 38  
 import org.w3c.dom.mathml.MathMLElement;
 39  
 import org.w3c.dom.mathml.MathMLOperatorElement;
 40  
 import org.w3c.dom.mathml.MathMLUnderOverElement;
 41  
 
 42  
 /**
 43  
  * Implementation and helper methods for munder, mover, and munderover.
 44  
  * <p>
 45  
  * TODO: some operators should "default" to being an accent, but currently they
 46  
  * don't
 47  
  * 
 48  
  * @version $Revision: 2986a8eeaebc $
 49  
  */
 50  3971
 public abstract class AbstractUnderOver extends AbstractJEuclidElement
 51  
         implements MathMLUnderOverElement {
 52  
 
 53  
     /**
 54  
      * Space between base and under/over for accents.
 55  
      */
 56  
     public static final String UNDER_OVER_SPACE = "0.1ex";
 57  
 
 58  
     /** Space for non-accents multiplied by this value. */
 59  
     public static final float NON_ACCENT_MULTIPLIER = 2.5f;
 60  
 
 61  
     /** attribute for accent property. */
 62  
     public static final String ATTR_ACCENT = "accent";
 63  
 
 64  
     /** attribute for accentunder property. */
 65  
     public static final String ATTR_ACCENTUNDER = "accentunder";
 66  
 
 67  
     /** No attributes, so just use 1. */
 68  
     private static final long serialVersionUID = 1L;
 69  
 
 70  
     /**
 71  
      * Default constructor. Sets MathML Namespace.
 72  
      * 
 73  
      * @param qname
 74  
      *            Qualified name.
 75  
      * @param odoc
 76  
      *            Owner Document.
 77  
      */
 78  
     public AbstractUnderOver(final String qname, final AbstractDocument odoc) {
 79  10868
         super(qname, odoc);
 80  10868
     }
 81  
 
 82  
     /** {@inheritDoc} */
 83  
     public String getAccent() {
 84  
         // TODO: Accent also depends on the content. See spec 3.4.4 - 3.4.6
 85  17138
         return this.getMathAttribute(AbstractUnderOver.ATTR_ACCENT);
 86  
     }
 87  
 
 88  
     /**
 89  
      * returns the accent property as boolean.
 90  
      * 
 91  
      * @return accent
 92  
      */
 93  
     protected boolean getAccentAsBoolean() {
 94  17138
         return Boolean.parseBoolean(this.getAccent());
 95  
     }
 96  
 
 97  
     /**
 98  
      * @param context
 99  
      *            LayoutContext
 100  
      * @return true if limits are moved (behave like under/over).
 101  
      */
 102  
     private boolean limitsAreMoved(final LayoutContext now) {
 103  10868
         return (!this.getAccentAsBoolean())
 104  
                 && (this.getBase() instanceof MathMLOperatorElement)
 105  
                 && Boolean
 106  
                         .parseBoolean(((MathMLOperatorElement) this.getBase())
 107  
                                 .getMovablelimits())
 108  
                 && (Display.INLINE.equals(now.getParameter(Parameter.DISPLAY)));
 109  
     }
 110  
 
 111  
     /** {@inheritDoc} */
 112  
     public String getAccentunder() {
 113  
         // TODO: Accent also depends on the content. See spec 3.4.4 - 3.4.6
 114  5434
         return this.getMathAttribute(AbstractUnderOver.ATTR_ACCENTUNDER);
 115  
     }
 116  
 
 117  
     /** {@inheritDoc} */
 118  
     @Override
 119  
     public LayoutContext getChildLayoutContext(final int childNum,
 120  
             final LayoutContext context) {
 121  19646
         final LayoutContext now = this.applyLocalAttributesToContext(context);
 122  19646
         if (childNum == 0) {
 123  7942
             return now;
 124  
         } else {
 125  
             // TODO: Should depend on type and accent
 126  11704
             return new RelativeScriptlevelLayoutContext(
 127  
                     new InlineLayoutContext(now), 1);
 128  
         }
 129  
     }
 130  
 
 131  
     /**
 132  
      * returns the accentunder property as boolean.
 133  
      * 
 134  
      * @return accentunder
 135  
      */
 136  
     protected boolean getAccentunderAsBoolean() {
 137  5434
         return Boolean.parseBoolean(this.getAccentunder());
 138  
     }
 139  
 
 140  
     /** {@inheritDoc} */
 141  
     public JEuclidElement getBase() {
 142  30305
         return this.getMathElement(0);
 143  
     }
 144  
 
 145  
     /** {@inheritDoc} */
 146  
     public abstract JEuclidElement getOverscript();
 147  
 
 148  
     /** {@inheritDoc} */
 149  
     public abstract JEuclidElement getUnderscript();
 150  
 
 151  
     /** {@inheritDoc} */
 152  
     public void setAccent(final String accent) {
 153  0
         this.setAttribute(AbstractUnderOver.ATTR_ACCENT, accent);
 154  0
     }
 155  
 
 156  
     /** {@inheritDoc} */
 157  
     public void setAccentunder(final String accentunder) {
 158  0
         this.setAttribute(AbstractUnderOver.ATTR_ACCENTUNDER, accentunder);
 159  0
     }
 160  
 
 161  
     /** {@inheritDoc} */
 162  
     public void setBase(final MathMLElement base) {
 163  0
         this.setMathElement(0, base);
 164  0
     }
 165  
 
 166  
     /** {@inheritDoc} */
 167  
     @Override
 168  
     public boolean hasChildPostscripts(final JEuclidElement child,
 169  
             final LayoutContext context) {
 170  2926
         return this.limitsAreMoved(context) && child.isSameNode(this.getBase());
 171  
     }
 172  
 
 173  
     /** {@inheritDoc} */
 174  
     @Override
 175  
     protected void layoutStageInvariant(final LayoutView view,
 176  
             final LayoutInfo info, final LayoutStage stage,
 177  
             final LayoutContext context) {
 178  7942
         final LayoutContext now = this.applyLocalAttributesToContext(context);
 179  7942
         if (this.limitsAreMoved(now)) {
 180  0
             ScriptSupport.layout(view, info, stage, now, this, this.getBase(),
 181  
                     this.getUnderscript(), this.getOverscript(), null, null);
 182  
         } else {
 183  7942
             this.layoutUnderOver(view, info, stage, now);
 184  
         }
 185  7942
     }
 186  
 
 187  
     private void layoutUnderOver(final LayoutView view, final LayoutInfo info,
 188  
             final LayoutStage stage, final LayoutContext now) {
 189  
 
 190  7942
         final JEuclidElement base = this.getBase();
 191  7942
         final JEuclidElement under = this.getUnderscript();
 192  7942
         final JEuclidElement over = this.getOverscript();
 193  
 
 194  7942
         final LayoutInfo baseInfo = view.getInfo(base);
 195  
         final LayoutInfo underInfo;
 196  
         final LayoutInfo overInfo;
 197  
 
 198  7942
         float width = baseInfo.getWidth(stage);
 199  
 
 200  7942
         final float extraShift = AttributesHelper.convertSizeToPt(
 201  
                 AbstractUnderOver.UNDER_OVER_SPACE, now, AttributesHelper.PT);
 202  
 
 203  7942
         if (under == null) {
 204  2508
             underInfo = null;
 205  
         } else {
 206  5434
             underInfo = view.getInfo(under);
 207  5434
             width = Math.max(width, underInfo.getWidth(stage));
 208  
         }
 209  7942
         if (over == null) {
 210  1672
             overInfo = null;
 211  
         } else {
 212  6270
             overInfo = view.getInfo(over);
 213  6270
             width = Math.max(width, overInfo.getWidth(stage));
 214  
         }
 215  7942
         final float middle = width / 2.0f;
 216  
 
 217  7942
         baseInfo.moveTo(middle - baseInfo.getHorizontalCenterOffset(stage), 0,
 218  
                 stage);
 219  
 
 220  7942
         if (under != null) {
 221  5434
             this.positionUnder(stage, baseInfo, underInfo, extraShift, middle);
 222  
         }
 223  7942
         if (over != null) {
 224  6270
             this.positionOver(stage, baseInfo, overInfo, extraShift, middle);
 225  
         }
 226  
 
 227  7942
         final Dimension2D borderLeftTop = new Dimension2DImpl(0.0f, 0.0f);
 228  7942
         final Dimension2D borderRightBottom = new Dimension2DImpl(0.0f, 0.0f);
 229  7942
         ElementListSupport.fillInfoFromChildren(view, info, this, stage,
 230  
                 borderLeftTop, borderRightBottom);
 231  7942
         info.setStretchWidth(width);
 232  7942
         info.setStretchAscent(baseInfo.getStretchAscent());
 233  7942
         info.setStretchDescent(baseInfo.getStretchDescent());
 234  7942
     }
 235  
 
 236  
     private void positionUnder(final LayoutStage stage,
 237  
             final LayoutInfo baseInfo, final LayoutInfo underInfo,
 238  
             final float extraShift, final float middle) {
 239  
         final float underextra;
 240  5434
         if (this.getAccentunderAsBoolean()) {
 241  0
             underextra = extraShift;
 242  
         } else {
 243  5434
             underextra = extraShift * AbstractUnderOver.NON_ACCENT_MULTIPLIER;
 244  
         }
 245  5434
         final float y = baseInfo.getDescentHeight(stage)
 246  
                 + underInfo.getAscentHeight(stage) + underextra;
 247  5434
         underInfo.moveTo(middle - underInfo.getHorizontalCenterOffset(stage),
 248  
                 y, stage);
 249  5434
     }
 250  
 
 251  
     private void positionOver(final LayoutStage stage,
 252  
             final LayoutInfo baseInfo, final LayoutInfo overInfo,
 253  
             final float extraShift, final float middle) {
 254  
         final float overextra;
 255  6270
         if (this.getAccentAsBoolean()) {
 256  0
             overextra = extraShift;
 257  
         } else {
 258  6270
             overextra = extraShift * AbstractUnderOver.NON_ACCENT_MULTIPLIER;
 259  
         }
 260  6270
         final float y = baseInfo.getAscentHeight(stage)
 261  
                 + overInfo.getDescentHeight(stage) + overextra;
 262  6270
         overInfo.moveTo(middle - overInfo.getHorizontalCenterOffset(stage), -y,
 263  
                 stage);
 264  6270
     }
 265  
 }