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