001    /*
002     * Copyright 2002 - 2008 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: MathVariant.java,v e6bd6c2d9bf4 2008/11/28 15:02:26 maxberger $ */
018    
019    package net.sourceforge.jeuclid.elements.support.attributes;
020    
021    import java.awt.Font;
022    import java.io.Serializable;
023    import java.util.HashMap;
024    import java.util.HashSet;
025    import java.util.List;
026    import java.util.Locale;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import net.sourceforge.jeuclid.LayoutContext;
031    import net.sourceforge.jeuclid.context.Parameter;
032    import net.sourceforge.jeuclid.elements.support.text.CharacterMapping;
033    import net.sourceforge.jeuclid.font.FontFactory;
034    
035    import org.apache.commons.logging.Log;
036    import org.apache.commons.logging.LogFactory;
037    
038    /**
039     * Class to represent and use MathVariants.
040     * 
041     * @version $Revision: e6bd6c2d9bf4 $
042     */
043    public final class MathVariant implements Serializable {
044    
045        /**
046         * Mathvariant constant. Bold style.
047         */
048        public static final MathVariant BOLD = new MathVariant(Font.BOLD,
049                FontFamily.SERIF);
050    
051        /**
052         * Mathvariant constant. Bold fraktur style.
053         */
054        public static final MathVariant BOLD_FRAKTUR = new MathVariant(Font.BOLD,
055                FontFamily.FRAKTUR);
056    
057        /**
058         * Mathvariant constant. Bold-italic style.
059         */
060        public static final MathVariant BOLD_ITALIC = new MathVariant(Font.BOLD
061                | Font.ITALIC, FontFamily.SERIF);
062    
063        /**
064         * Mathvariant constant. Bold sans-serif style.
065         */
066        public static final MathVariant BOLD_SANS_SERIF = new MathVariant(
067                Font.BOLD, FontFamily.SANSSERIF);
068    
069        /**
070         * Mathvariant constant. Bold script style.
071         */
072        public static final MathVariant BOLD_SCRIPT = new MathVariant(Font.BOLD,
073                FontFamily.SCRIPT);
074    
075        /**
076         * Mathvariant constant. Double struck style.
077         */
078        public static final MathVariant DOUBLE_STRUCK = new MathVariant(
079                Font.PLAIN, FontFamily.DOUBLE_STRUCK);
080    
081        /**
082         * Mathvariant constant. Fraktur style.
083         */
084        public static final MathVariant FRAKTUR = new MathVariant(Font.PLAIN,
085                FontFamily.FRAKTUR);
086    
087        /**
088         * Mathvariant constant. Italic style.
089         */
090        public static final MathVariant ITALIC = new MathVariant(Font.ITALIC,
091                FontFamily.SERIF);
092    
093        /**
094         * Mathvariant constant. Monospace style.
095         */
096        public static final MathVariant MONOSPACE = new MathVariant(Font.PLAIN,
097                FontFamily.MONOSPACED);
098    
099        /**
100         * Mathvariant constant. Normal style.
101         */
102        public static final MathVariant NORMAL = new MathVariant(Font.PLAIN,
103                FontFamily.SERIF);
104    
105        /**
106         * Mathvariant constant. Sans-serif style.
107         */
108        public static final MathVariant SANS_SERIF = new MathVariant(Font.PLAIN,
109                FontFamily.SANSSERIF);
110    
111        /**
112         * Mathvariant constant. Bold italic sans-serif style.
113         */
114        public static final MathVariant SANS_SERIF_BOLD_ITALIC = new MathVariant(
115                Font.BOLD | Font.ITALIC, FontFamily.SANSSERIF);
116    
117        /**
118         * Mathvariant constant. Italic sans-serif style.
119         */
120        public static final MathVariant SANS_SERIF_ITALIC = new MathVariant(
121                Font.ITALIC, FontFamily.SANSSERIF);
122    
123        /**
124         * Mathvariant constant. Script style.
125         */
126        public static final MathVariant SCRIPT = new MathVariant(Font.PLAIN,
127                FontFamily.SCRIPT);
128    
129        private static final Map<String, MathVariant> ATTRIBUTEMAP = new HashMap<String, MathVariant>();
130    
131        private static final Map<FontFamily, Parameter> PARAMFORFONT = new HashMap<FontFamily, Parameter>();
132    
133        /**
134         * 
135         */
136        private static final long serialVersionUID = 1L;
137    
138        /**
139         * Logger for this class.
140         */
141        private static final Log LOGGER = LogFactory
142                .getLog(CharacterMapping.class);
143    
144        private static final Set<Integer> WARNED = new HashSet<Integer>();
145    
146        private final int awtStyle;
147    
148        private final FontFamily fontFamily;
149    
150        /**
151         * Creates a Mathvariant with the given AWT-Style and font-family.
152         * 
153         * @param awtstyle
154         *            the awt Style
155         * @param family
156         *            the font family
157         */
158        public MathVariant(final int awtstyle, final FontFamily family) {
159            this.awtStyle = awtstyle;
160            this.fontFamily = family;
161        };
162    
163        /**
164         * Creates a Mathvariant object from an attribute value.
165         * 
166         * @param variant
167         *            the string representation of the attribute value
168         * @return a mathVariant object or null if none is found.
169         */
170        public static MathVariant stringToMathVariant(final String variant) {
171            synchronized (MathVariant.ATTRIBUTEMAP) {
172                // Needs to be initialized late due to chicken-egg problem.
173                if (MathVariant.ATTRIBUTEMAP.isEmpty()) {
174                    MathVariant.ATTRIBUTEMAP.put("normal", MathVariant.NORMAL);
175                    MathVariant.ATTRIBUTEMAP.put("bold", MathVariant.BOLD);
176                    MathVariant.ATTRIBUTEMAP.put("italic", MathVariant.ITALIC);
177                    MathVariant.ATTRIBUTEMAP.put("bold-italic",
178                            MathVariant.BOLD_ITALIC);
179                    MathVariant.ATTRIBUTEMAP.put("double-struck",
180                            MathVariant.DOUBLE_STRUCK);
181                    MathVariant.ATTRIBUTEMAP.put("bold-fraktur",
182                            MathVariant.BOLD_FRAKTUR);
183                    MathVariant.ATTRIBUTEMAP.put("script", MathVariant.SCRIPT);
184                    MathVariant.ATTRIBUTEMAP.put("bold-script",
185                            MathVariant.BOLD_SCRIPT);
186                    MathVariant.ATTRIBUTEMAP.put("fraktur", MathVariant.FRAKTUR);
187                    MathVariant.ATTRIBUTEMAP.put("sans-serif",
188                            MathVariant.SANS_SERIF);
189                    MathVariant.ATTRIBUTEMAP.put("bold-sans-serif",
190                            MathVariant.BOLD_SANS_SERIF);
191                    MathVariant.ATTRIBUTEMAP.put("sans-serif-italic",
192                            MathVariant.SANS_SERIF_ITALIC);
193                    MathVariant.ATTRIBUTEMAP.put("sans-serif-bold-italic",
194                            MathVariant.SANS_SERIF_BOLD_ITALIC);
195                    MathVariant.ATTRIBUTEMAP.put("monospace",
196                            MathVariant.MONOSPACE);
197                }
198                return MathVariant.ATTRIBUTEMAP.get(variant
199                        .toLowerCase(Locale.ENGLISH));
200            }
201        }
202    
203        /**
204         * Create a font for the given attributes.
205         * 
206         * @param size
207         *            size of the font to create
208         * @param codepoint
209         *            a character that must exist in this font
210         * @param context
211         *            LayoutContext to use.
212         * @param force
213         *            if true will always return a font, otherwise will return
214         *            null.
215         * @return a font object.
216         */
217        @SuppressWarnings("unchecked")
218        public Font createFont(final float size, final int codepoint,
219                final LayoutContext context, final boolean force) {
220    
221            final Parameter theParam = MathVariant.PARAMFORFONT
222                    .get(this.fontFamily);
223            final Font font = FontFactory.getInstance().getFont(
224                    (List<String>) context.getParameter(theParam), codepoint,
225                    this.awtStyle, size);
226            if (force && font == null) {
227                if (!MathVariant.WARNED.contains(codepoint)) {
228                    MathVariant.WARNED.add(codepoint);
229                    final String hexString = Integer.toHexString(codepoint);
230                    MathVariant.LOGGER
231                            .warn("No font available to display character "
232                                    + hexString);
233                    MathVariant.LOGGER
234                            .info("Find a font at  http://www.fileformat.info/info/unicode/char/"
235                                    + hexString
236                                    + "/fontsupport.htm or "
237                                    + "http://www.alanwood.net/unicode/search.html");
238                }
239                return FontFactory.getInstance().getFont(FontFactory.SANSSERIF,
240                        this.awtStyle, size);
241            }
242            return font;
243        }
244    
245        /**
246         * @return the awtStyle
247         */
248        public int getAwtStyle() {
249            return this.awtStyle;
250        }
251    
252        /**
253         * @return the fontFamily
254         */
255        public FontFamily getFontFamily() {
256            return this.fontFamily;
257        }
258    
259        static {
260            MathVariant.PARAMFORFONT.put(FontFamily.SERIF, Parameter.FONTS_SERIF);
261            MathVariant.PARAMFORFONT.put(FontFamily.SANSSERIF,
262                    Parameter.FONTS_SANSSERIF);
263            MathVariant.PARAMFORFONT.put(FontFamily.MONOSPACED,
264                    Parameter.FONTS_MONOSPACED);
265            MathVariant.PARAMFORFONT.put(FontFamily.SCRIPT,
266                    Parameter.FONTS_SCRIPT);
267            MathVariant.PARAMFORFONT.put(FontFamily.FRAKTUR,
268                    Parameter.FONTS_FRAKTUR);
269            MathVariant.PARAMFORFONT.put(FontFamily.DOUBLE_STRUCK,
270                    Parameter.FONTS_DOUBLESTRUCK);
271        }
272    
273        /** {@inheritDoc} */
274        @Override
275        public int hashCode() {
276            final int prime = 31;
277            int result;
278            if (this.fontFamily == null) {
279                result = 0;
280            } else {
281                result = this.fontFamily.hashCode();
282            }
283            result = prime * result + this.awtStyle;
284            return result;
285        }
286    
287        /** {@inheritDoc} */
288        @Override
289        public boolean equals(final Object obj) {
290            if (this == obj) {
291                return true;
292            }
293            if (obj == null) {
294                return false;
295            }
296            if (this.getClass() != obj.getClass()) {
297                return false;
298            }
299            final MathVariant other = (MathVariant) obj;
300            if (this.awtStyle != other.awtStyle) {
301                return false;
302            }
303            if (this.fontFamily == null) {
304                if (other.fontFamily != null) {
305                    return false;
306                }
307            } else if (!this.fontFamily.equals(other.fontFamily)) {
308                return false;
309            }
310            return true;
311        }
312    
313        /** {@inheritDoc} */
314        @Override
315        public String toString() {
316            final StringBuilder b = new StringBuilder();
317            b.append('[');
318            b.append(this.fontFamily);
319            if (this.awtStyle > 0) {
320                b.append(' ');
321            }
322            if ((this.awtStyle & Font.BOLD) > 0) {
323                b.append('B');
324            }
325            if ((this.awtStyle & Font.ITALIC) > 0) {
326                b.append('I');
327            }
328            b.append(']');
329            return b.toString();
330        }
331    }