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