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: ElementListSupport.java,v d02878fc1d01 2009/09/08 12:35:02 max $ */
018    
019    package net.sourceforge.jeuclid.elements.support;
020    
021    import java.awt.Color;
022    import java.awt.geom.Dimension2D;
023    import java.util.ArrayList;
024    import java.util.List;
025    
026    import net.sourceforge.jeuclid.layout.FillRectObject;
027    import net.sourceforge.jeuclid.layout.GraphicsObject;
028    import net.sourceforge.jeuclid.layout.LayoutInfo;
029    import net.sourceforge.jeuclid.layout.LayoutStage;
030    import net.sourceforge.jeuclid.layout.LayoutView;
031    import net.sourceforge.jeuclid.layout.LayoutableNode;
032    
033    import org.w3c.dom.Node;
034    
035    /**
036     * Class to support Lists of MathElements.
037     * <p>
038     * This class can be used by all elements that have some kind of a list of
039     * children that they need to handle in a row-like manner.
040     * 
041     * @version $Revision: d02878fc1d01 $
042     */
043    public final class ElementListSupport {
044    
045        private ElementListSupport() {
046            // Utility class.
047        }
048    
049        /**
050         * Creates a list of children for the given Element.
051         * 
052         * @param parent
053         *            the parent element.
054         * @return list of Children.
055         */
056        public static List<Node> createListOfChildren(final Node parent) {
057            final org.w3c.dom.NodeList childList = parent.getChildNodes();
058            final int len = childList.getLength();
059            final List<Node> children = new ArrayList<Node>(len);
060            for (int i = 0; i < len; i++) {
061                final Node child = childList.item(i);
062                children.add(child);
063            }
064            return children;
065    
066        }
067    
068        /**
069         * Creates a list of layoutable children for the given Element.
070         * 
071         * @param parent
072         *            the parent element.
073         * @return list of Children.
074         */
075        public static List<LayoutableNode> createListOfLayoutChildren(
076                final Node parent) {
077            final org.w3c.dom.NodeList childList = parent.getChildNodes();
078            final int len = childList.getLength();
079            final List<LayoutableNode> children = new ArrayList<LayoutableNode>(len);
080            for (int i = 0; i < len; i++) {
081                final Node child = childList.item(i);
082                if (child instanceof LayoutableNode) {
083                    children.add((LayoutableNode) child);
084                }
085            }
086            return children;
087    
088        }
089    
090        /**
091         * @param view
092         *            View Object
093         * @param info
094         *            Info to fill
095         * @param parent
096         *            Current Node
097         * @param stage
098         *            Stage to load Info From
099         * @param borderLeftTop
100         *            border around element.
101         * @param borderRightBottom
102         *            border around element.
103         */
104        public static void fillInfoFromChildren(final LayoutView view,
105                final LayoutInfo info, final Node parent, final LayoutStage stage,
106                final Dimension2D borderLeftTop, final Dimension2D borderRightBottom) {
107            float ascentHeight = (float) borderLeftTop.getHeight();
108            float descentHeight = (float) borderRightBottom.getHeight();
109            final float startX = (float) borderLeftTop.getWidth();
110            float width = startX;
111            for (final LayoutableNode child : ElementListSupport
112                    .createListOfLayoutChildren(parent)) {
113                final LayoutInfo childInfo = view.getInfo(child);
114                ascentHeight = Math.max(ascentHeight, -childInfo.getPosY(stage)
115                        + childInfo.getAscentHeight(stage));
116                descentHeight = Math.max(descentHeight, childInfo.getPosY(stage)
117                        + childInfo.getDescentHeight(stage));
118                width = Math.max(width, childInfo.getPosX(stage)
119                        + childInfo.getWidth(stage));
120            }
121            info.setAscentHeight(ascentHeight + (float) borderLeftTop.getHeight(),
122                    stage);
123            info.setDescentHeight(descentHeight
124                    + (float) borderRightBottom.getHeight(), stage);
125            info.setHorizontalCenterOffset((width + startX) / 2.0f, stage);
126            info.setWidth(width + (float) borderRightBottom.getWidth(), stage);
127        }
128    
129        /**
130         * @param view
131         *            View Object
132         * @param info
133         *            Info to fill
134         * @param children
135         *            Children to layout
136         * @param stage
137         *            Stage to load Info From
138         */
139        public static void layoutSequential(final LayoutView view,
140                final LayoutInfo info, final List<LayoutableNode> children,
141                final LayoutStage stage) {
142            float ascentHeight = 0.0f;
143            float descentHeight = 0.0f;
144            float posX = 0.0f;
145            float stretchAscent = 0.0f;
146            float stretchDescent = 0.0f;
147    
148            for (final LayoutableNode child : children) {
149                final LayoutInfo childInfo = view.getInfo(child);
150                ascentHeight = Math.max(ascentHeight, childInfo
151                        .getAscentHeight(stage));
152                descentHeight = Math.max(descentHeight, childInfo
153                        .getDescentHeight(stage));
154                stretchAscent = Math.max(stretchAscent, childInfo
155                        .getStretchAscent());
156                stretchDescent = Math.max(stretchDescent, childInfo
157                        .getStretchDescent());
158                childInfo.moveTo(posX, 0.0f, stage);
159                posX += childInfo.getWidth(stage);
160            }
161            info.setAscentHeight(ascentHeight, stage);
162            info.setDescentHeight(descentHeight, stage);
163            info.setStretchAscent(stretchAscent);
164            info.setStretchDescent(stretchDescent);
165            info.setHorizontalCenterOffset(posX / 2.0f, stage);
166            info.setWidth(posX, stage);
167        }
168    
169        /**
170         * Add a background Rectangle for the given background color.
171         * 
172         * @param backgroundColor
173         *            background color (may be null)
174         * @param info
175         *            LayoutInfo object to add to. Must already be completely
176         *            rendered (stage 2)
177         * @param useCeil
178         *            if true, the {@link Math#ceil(double)} will be used to avoid
179         *            anti-aliasing artifacts.
180         */
181        public static void addBackground(final Color backgroundColor,
182                final LayoutInfo info, final boolean useCeil) {
183            if (backgroundColor != null) {
184                final GraphicsObject fillObject;
185                if (useCeil) {
186                    fillObject = new FillRectObject(backgroundColor, (float) Math
187                            .ceil(info.getAscentHeight(LayoutStage.STAGE2)),
188                            (float) Math.ceil(info
189                                    .getDescentHeight(LayoutStage.STAGE2)),
190                            (float) Math.ceil(info.getWidth(LayoutStage.STAGE2)));
191                } else {
192                    fillObject = new FillRectObject(backgroundColor, info
193                            .getAscentHeight(LayoutStage.STAGE2), info
194                            .getDescentHeight(LayoutStage.STAGE2), info
195                            .getWidth(LayoutStage.STAGE2));
196    
197                }
198    
199                info.getGraphicObjects().add(0, fillObject);
200            }
201    
202        }
203    }