001 /*
002 * Copyright 2002 - 2009 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: Mfenced.java,v 34009469c57a 2009/08/07 13:21:37 max $ */
018
019 package net.sourceforge.jeuclid.elements.presentation.general;
020
021 import java.util.ArrayList;
022 import java.util.List;
023
024 import net.sourceforge.jeuclid.Constants;
025 import net.sourceforge.jeuclid.elements.AbstractElementWithDelegates;
026 import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
027 import net.sourceforge.jeuclid.elements.presentation.token.Mo;
028 import net.sourceforge.jeuclid.elements.support.operatordict.OperatorDictionary;
029 import net.sourceforge.jeuclid.layout.LayoutableNode;
030
031 import org.apache.batik.dom.AbstractDocument;
032 import org.w3c.dom.Node;
033 import org.w3c.dom.mathml.MathMLFencedElement;
034
035 /**
036 * The class represents the mfenced element.
037 *
038 * @version $Revision: 34009469c57a $
039 */
040 public final class Mfenced extends AbstractElementWithDelegates implements
041 MathMLFencedElement {
042
043 /** The separators attribute. */
044 public static final String ATTR_SEPARATORS = "separators";
045
046 /** The close attribute. */
047 public static final String ATTR_CLOSE = "close";
048
049 /** The open attribute. */
050 public static final String ATTR_OPEN = "open";
051
052 /**
053 * The XML element from this class.
054 */
055 public static final String ELEMENT = "mfenced";
056
057 private static final String FENCE_SPACE = "0.2em";
058
059 private static final long serialVersionUID = 1L;
060
061 /**
062 * Default constructor. Sets MathML Namespace.
063 *
064 * @param qname
065 * Qualified name.
066 * @param odoc
067 * Owner Document.
068 */
069 public Mfenced(final String qname, final AbstractDocument odoc) {
070 super(qname, odoc);
071 this.setDefaultMathAttribute(Mfenced.ATTR_OPEN, "(");
072 this.setDefaultMathAttribute(Mfenced.ATTR_CLOSE, ")");
073 this.setDefaultMathAttribute(Mfenced.ATTR_SEPARATORS, ",");
074 }
075
076 /** {@inheritDoc} */
077 @Override
078 protected Node newNode() {
079 return new Mfenced(this.nodeName, this.ownerDocument);
080 }
081
082 /**
083 * @return opening delimiter
084 */
085 public String getOpen() {
086 return this.getMathAttribute(Mfenced.ATTR_OPEN);
087 }
088
089 /**
090 * Set the opening delimiter.
091 *
092 * @param open
093 * Delimiter
094 */
095 public void setOpen(final String open) {
096 this.setAttribute(Mfenced.ATTR_OPEN, open);
097 }
098
099 /**
100 * @return Return the closing delimiter
101 */
102 public String getClose() {
103 return this.getMathAttribute(Mfenced.ATTR_CLOSE);
104 }
105
106 /**
107 * Set the closing delimiter.
108 *
109 * @param close
110 * New close delimeter
111 */
112 public void setClose(final String close) {
113 this.setAttribute(Mfenced.ATTR_CLOSE, close);
114 }
115
116 /**
117 * Return the separators.
118 *
119 * @return separators
120 */
121 public String getSeparators() {
122 final StringBuilder retVal = new StringBuilder();
123 final String attValue = this.getMathAttribute(Mfenced.ATTR_SEPARATORS);
124 if (attValue != null) {
125 for (int i = 0; i < attValue.length(); i++) {
126 final char c = attValue.charAt(i);
127 if (c > AbstractJEuclidElement.TRIVIAL_SPACE_MAX) {
128 retVal.append(c);
129 }
130 }
131 }
132 return retVal.toString();
133 }
134
135 /**
136 * Set the separators.
137 *
138 * @param separators
139 * New separators
140 */
141 public void setSeparators(final String separators) {
142 this.setAttribute(Mfenced.ATTR_SEPARATORS, separators);
143 }
144
145 /** {@inheritDoc} */
146 @Override
147 protected List<LayoutableNode> createDelegates() {
148 final int contentCount = this.getMathElementCount();
149 final List<LayoutableNode> retVal = new ArrayList<LayoutableNode>(
150 2 * contentCount + 1);
151
152 final Mo opOpen = this.createFenceOperator();
153 opOpen.setForm(OperatorDictionary.FORM_PREFIX);
154 opOpen.setTextContent(this.getOpen());
155
156 retVal.add(opOpen);
157 final String sep = this.getSeparators();
158 final boolean haveSep = (sep != null) && (sep.length() > 0);
159
160 for (int i = 0; i < contentCount; i++) {
161 retVal.add(this.getMathElement(i));
162
163 if (haveSep && (i < (contentCount - 1))) {
164 final Mo opSep = (Mo) this.getOwnerDocument().createElement(
165 Mo.ELEMENT);
166 opSep.setSeparator(Constants.TRUE);
167 if (i < sep.length()) {
168 opSep.setTextContent(String.valueOf(sep.charAt(i)));
169 } else {
170 opSep.setTextContent(String.valueOf(sep
171 .charAt(sep.length() - 1)));
172 }
173 retVal.add(opSep);
174 }
175 }
176 final Mo opClose = this.createFenceOperator();
177 opClose.setForm(OperatorDictionary.FORM_POSTFIX);
178 opClose.setTextContent(this.getClose());
179 retVal.add(opClose);
180
181 return retVal;
182 }
183
184 private Mo createFenceOperator() {
185 final Mo opOpen = (Mo) this.getOwnerDocument()
186 .createElement(Mo.ELEMENT);
187 opOpen.setFence(Constants.TRUE);
188 opOpen.setStretchy(Constants.TRUE);
189 opOpen.setRspace(Mfenced.FENCE_SPACE);
190 opOpen.setLspace(Mfenced.FENCE_SPACE);
191 opOpen.setSymmetric(Constants.FALSE);
192 return opOpen;
193 }
194
195 }