001 /*
002 * Copyright 2007 - 2007 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: AbstractRoot.java,v bc1d5fde7b73 2009/06/01 14:40:54 maxberger $ */
018
019 package net.sourceforge.jeuclid.elements.presentation.general;
020
021 import java.awt.Color;
022 import java.awt.FontMetrics;
023 import java.awt.Graphics2D;
024 import java.util.List;
025
026 import net.sourceforge.jeuclid.LayoutContext;
027 import net.sourceforge.jeuclid.context.Parameter;
028 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
029 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
030 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
031 import net.sourceforge.jeuclid.layout.GraphicsObject;
032 import net.sourceforge.jeuclid.layout.LayoutInfo;
033 import net.sourceforge.jeuclid.layout.LayoutStage;
034 import net.sourceforge.jeuclid.layout.LayoutView;
035 import net.sourceforge.jeuclid.layout.LayoutableNode;
036 import net.sourceforge.jeuclid.layout.LineObject;
037
038 import org.apache.batik.dom.AbstractDocument;
039 import org.w3c.dom.mathml.MathMLRadicalElement;
040
041 /**
042 * common superclass for root like elements (root, sqrt).
043 *
044 * @version $Revision: bc1d5fde7b73 $
045 */
046 public abstract class AbstractRoot extends AbstractJEuclidElement implements
047 MathMLRadicalElement {
048
049 private static final String EXTRA_SPACE = "0.1ex";
050
051 private static final String ROOT_WIDTH = "0.5em";
052
053 /**
054 * Default constructor. Sets MathML Namespace.
055 *
056 * @param qname
057 * Qualified name.
058 * @param odoc
059 * Owner Document.
060 */
061 public AbstractRoot(final String qname, final AbstractDocument odoc) {
062 super(qname, odoc);
063 }
064
065 /**
066 * retrieve the content of this radical element.
067 *
068 * @return A List<MathElement> with the contents for this element.
069 */
070 protected abstract List<LayoutableNode> getContent();
071
072 /** {@inheritDoc} */
073 // CHECKSTYLE:OFF
074 // This function is too long, but it depends on too many parameters.
075 @Override
076 protected void layoutStageInvariant(final LayoutView view,
077 final LayoutInfo info, final LayoutStage stage,
078 final LayoutContext context) {
079 // CHECKSTYLE:ON
080
081 // Basic Calculations
082 final Graphics2D g = view.getGraphics();
083 final LayoutContext now = this.applyLocalAttributesToContext(context);
084 final float middleShift = this.getMiddleShift(g, context);
085 final float linethickness = GraphicsSupport.lineWidth(now);
086 final float extraSpace = AttributesHelper.convertSizeToPt(
087 AbstractRoot.EXTRA_SPACE, now, "");
088 final float rootwidth = AttributesHelper.convertSizeToPt(
089 AbstractRoot.ROOT_WIDTH, context, "");
090 final Color color = (Color) now.getParameter(Parameter.MATHCOLOR);
091 float xPos = linethickness;
092 final LayoutableNode index = (LayoutableNode) this.getIndex();
093 final List<GraphicsObject> graphicObjects = info.getGraphicObjects();
094 graphicObjects.clear();
095
096 // Draw Index
097 float indexAscent;
098 if (index == null) {
099 indexAscent = 0.0f;
100 } else {
101 final LayoutInfo indexInfo = view.getInfo(index);
102 final float indexPos = middleShift + linethickness / 2.0f
103 + extraSpace + indexInfo.getDescentHeight(stage);
104 indexInfo.moveTo(xPos, -indexPos, stage);
105 xPos += indexInfo.getWidth(stage);
106 graphicObjects.add(new LineObject(linethickness, -middleShift,
107 xPos, -middleShift, linethickness, color));
108 indexAscent = indexPos + indexInfo.getAscentHeight(stage);
109 }
110
111 // Skip Root Space
112 xPos += rootwidth;
113
114 // Draw Content below Root
115 final float contentStartX = xPos;
116 final FontMetrics metrics = this
117 .getFontMetrics(view.getGraphics(), now);
118 float maxAscent = metrics.getAscent();
119 float maxDescent = metrics.getDescent();
120 for (final LayoutableNode child : this.getContent()) {
121 final LayoutInfo childInfo = view.getInfo(child);
122 childInfo.moveTo(xPos, 0, stage);
123 maxAscent = Math.max(maxAscent, childInfo.getAscentHeight(stage));
124 maxDescent = Math
125 .max(maxDescent, childInfo.getDescentHeight(stage));
126 xPos += childInfo.getWidth(stage);
127 }
128 xPos += 2 * extraSpace;
129 final float topLinePos = maxAscent + 2 * extraSpace + linethickness
130 / 2.0f;
131
132 // Fill in Info
133 info.setAscentHeight(Math.max(topLinePos + linethickness / 2.0f,
134 indexAscent), stage);
135 info.setDescentHeight(maxDescent + linethickness / 2.0f, stage);
136 info.setHorizontalCenterOffset(xPos / 2.0f, stage);
137 info.setWidth(xPos + linethickness, stage);
138 info.setStretchAscent(maxAscent);
139 info.setStretchDescent(maxDescent);
140
141 // Add Root Glyph
142 graphicObjects.add(new LineObject(contentStartX - rootwidth,
143 -middleShift, contentStartX - rootwidth / 2.0f, maxDescent,
144 linethickness, color));
145 graphicObjects.add(new LineObject(contentStartX - rootwidth / 2.0f,
146 maxDescent, contentStartX, -topLinePos, linethickness, color));
147 graphicObjects.add(new LineObject(contentStartX, -topLinePos, xPos,
148 -topLinePos, linethickness, color));
149 }
150 }