001 /*
002 * Copyright 2002 - 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: JMathComponent.java 433 2007-08-20 11:59:25Z maxberger $ */
018
019 package net.sourceforge.jeuclid.swing;
020
021 import java.awt.Color;
022 import java.awt.Dimension;
023 import java.awt.Font;
024 import java.io.IOException;
025 import java.util.Map;
026
027 import javax.swing.JComponent;
028 import javax.swing.SwingConstants;
029 import javax.swing.UIManager;
030 import javax.xml.parsers.ParserConfigurationException;
031
032 import net.sourceforge.jeuclid.MathBase;
033 import net.sourceforge.jeuclid.MathMLParserSupport;
034 import net.sourceforge.jeuclid.MathMLSerializer;
035 import net.sourceforge.jeuclid.ParameterKey;
036 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
037
038 import org.w3c.dom.Document;
039 import org.xml.sax.SAXException;
040
041 /**
042 * Displays MathML content in a Swing Component.
043 * <p>
044 * There are two properties which expose the actual content, accessible though
045 * {@link #getDocument()} / {@link #setDocument(Document)} for content already
046 * available as a DOM model, and {@link #getContent()} and
047 * {@link #setContent(String)} for content available as a String.
048 * <p>
049 * This class exposes most of the rendering parameters as standard bean
050 * attributes. If you need to set additional attributes, you may use the
051 * {@link #setParameter(ParameterKey, String)} function.
052 * <p>
053 * Please use only the attributes exposed through the attached
054 * {@link JMathComponentBeanInfo} class. Additional attributes, such as
055 * {@link #getFont()} and {@link #setFont(Font)} are provided for Swing
056 * compatibility, but they may not work exactly as expected.
057 *
058 * @see net.sourceforge.jeuclid.awt.MathComponent
059 * @author Unknown
060 * @author Max Berger
061 * @version $Revision: 433 $
062 */
063 public class JMathComponent extends JComponent implements SwingConstants {
064
065 private static final String DEFAULT_DOCUMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
066 + "<math mode=\"display\">\n"
067 + " <mrow>\n"
068 + " <munderover>\n"
069 + " <mo>∫</mo>\n"
070 + " <mn>1</mn>\n"
071 + " <mi>x</mi>\n"
072 + " </munderover>\n"
073 + " <mfrac>\n"
074 + " <mi>dt</mi>\n"
075 + " <mi>t</mi>\n"
076 + " </mfrac>\n" + " </mrow>\n" + "</math>";
077
078 private static final String FONT_SEPARATOR = ",";
079
080 /**
081 * Logger for this class
082 */
083 // currently unused.
084 // private static final Log LOGGER =
085 // LogFactory.getLog(JMathComponent.class);
086 /** */
087 private static final long serialVersionUID = 1L;
088
089 private static final String UI_CLASS_ID = "MathComponentUI";
090
091 private Document document;
092
093 private int horizontalAlignment = SwingConstants.CENTER;
094
095 private final Map<ParameterKey, String> parameters = MathBase
096 .getDefaultParameters();
097
098 private int verticalAlignment = SwingConstants.CENTER;
099
100 /**
101 * Default constructor.
102 */
103 public JMathComponent() {
104 this.updateUI();
105 this.fontCompat();
106 this.setContent(JMathComponent.DEFAULT_DOCUMENT);
107 }
108
109 /**
110 * Provide compatibility for standard get/setFont() operations.
111 */
112 private void fontCompat() {
113 final String fontName = this.getFontsSerif().split(
114 JMathComponent.FONT_SEPARATOR)[0];
115 final float fontSize = this.getFontSize();
116 super.setFont(new Font(fontName, 0, (int) fontSize));
117 }
118
119 /**
120 * Tries to return the content as a String.
121 * <p>
122 * This transforms the internal DOM tree back into a string, which may is
123 * not guaranteed to be the literally same as the original content.
124 * However, it will represent the same XML document.
125 *
126 * @return the content string.
127 */
128 public String getContent() {
129 return MathMLSerializer.serializeDocument(this.getDocument(), false,
130 false);
131 }
132
133 /**
134 * @return the document
135 */
136 public Document getDocument() {
137 return this.document;
138 }
139
140 /**
141 * Font list for Doublestruck. Please see
142 * {@link ParameterKey#FontsDoublestruck} for an explanation of this
143 * parameter.
144 *
145 * @return The list for Doublestruck.
146 * @see ParameterKey#FontsDoublestruck
147 */
148 public String getFontsDoublestruck() {
149 return this.parameters.get(ParameterKey.FontsDoublestruck);
150 }
151
152 /**
153 * Font list for Fraktur. Please see {@link ParameterKey#FontsFraktur} for
154 * an explanation of this parameter.
155 *
156 * @return The list for Fraktur.
157 * @see ParameterKey#FontsFraktur
158 */
159 public String getFontsFraktur() {
160 return this.parameters.get(ParameterKey.FontsFraktur);
161 }
162
163 /**
164 * @return the fontSize
165 */
166 public float getFontSize() {
167 return Float.parseFloat(this.parameters.get(ParameterKey.FontSize));
168 }
169
170 /**
171 * Font list for Monospaced. Please see
172 * {@link ParameterKey#FontsMonospaced} for an explanation of this
173 * parameter.
174 *
175 * @return The list for monospaced.
176 * @see ParameterKey#FontsMonospaced
177 */
178 public String getFontsMonospaced() {
179 return this.parameters.get(ParameterKey.FontsMonospaced);
180 }
181
182 /**
183 * Font list for Sans-Serif. Please see {@link ParameterKey#FontsSanserif}
184 * for an explanation of this parameter.
185 *
186 * @return The list for sansserif.
187 * @see ParameterKey#FontsSanserif
188 */
189 public String getFontsSanserif() {
190 return this.parameters.get(ParameterKey.FontsSanserif);
191 }
192
193 /**
194 * Font list for Script. Please see {@link ParameterKey#FontsScript} for
195 * an explanation of this parameter.
196 *
197 * @return The list for Script.
198 * @see ParameterKey#FontsScript
199 */
200 public String getFontsScript() {
201 return this.parameters.get(ParameterKey.FontsScript);
202 }
203
204 /**
205 * Font list for Serif (the default MathML font). Please see
206 * {@link ParameterKey#FontsSerif} for an explanation of this parameter.
207 *
208 * @return The list for serif.
209 * @see ParameterKey#FontsSerif
210 */
211 public String getFontsSerif() {
212 return this.parameters.get(ParameterKey.FontsSerif);
213 }
214
215 /** {@inheritDoc} */
216 @Override
217 public Color getForeground() {
218 return AttributesHelper.stringToColor(this.parameters
219 .get(ParameterKey.ForegroundColor), Color.BLACK);
220 }
221
222 /**
223 * Horizontal alignment, as defined by
224 * {@link javax.swing.JLabel#getHorizontalAlignment()}.
225 * <p>
226 * Supported are: {@link SwingConstants#LEADING},
227 * {@link SwingConstants#LEFT}, {@link SwingConstants#CENTER},
228 * {@link SwingConstants#TRAILING}, {@link SwingConstants#RIGHT}.
229 *
230 * @return the horizontalAlignment
231 * @see javax.swing.JLabel#getHorizontalAlignment()
232 */
233 public int getHorizontalAlignment() {
234 return this.horizontalAlignment;
235 }
236
237 /**
238 * Gets the preferred size of this component.
239 *
240 * @return A dimension object indicating this component's preferred size.
241 */
242 @Override
243 public Dimension getPreferredSize() {
244 return this.getMinimumSize();
245 }
246
247 /**
248 * @return the UI implementation.
249 */
250 public MathComponentUI getUI() {
251 return (MathComponentUI) this.ui;
252 }
253
254 /**
255 * @return The default UI class
256 */
257 @Override
258 public String getUIClassID() {
259 return JMathComponent.UI_CLASS_ID;
260 }
261
262 /**
263 * Vertical alignment, as defined by
264 * {@link javax.swing.JLabel#getVerticalAlignment()}.
265 * <p>
266 * Supported are: {@link SwingConstants#TOP},
267 * {@link SwingConstants#CENTER}, {@link SwingConstants#BOTTOM}.
268 *
269 * @return the verticalAlignment
270 * @see javax.swing.JLabel#getVerticalAlignment()
271 */
272 public int getVerticalAlignment() {
273 return this.verticalAlignment;
274 }
275
276 private void reval() {
277 this.repaint();
278 this.revalidate();
279 }
280
281 /** {@inheritDoc} */
282 @Override
283 public void setBackground(final Color c) {
284 super.setBackground(c);
285 this.reval();
286 }
287
288 /**
289 * Set the content from a String containing the MathML content.
290 *
291 * @param contentString
292 * the content to set.
293 */
294 public void setContent(final String contentString) {
295 try {
296 this.setDocument(MathMLParserSupport.parseString(contentString));
297 } catch (final SAXException e) {
298 throw new RuntimeException(e);
299 } catch (final ParserConfigurationException e) {
300 throw new RuntimeException(e);
301 } catch (final IOException e) {
302 throw new RuntimeException(e);
303 }
304 }
305
306 /**
307 * Enables, or disables the debug mode.
308 *
309 * @param dbg
310 * Debug mode.
311 */
312 public void setDebug(final boolean dbg) {
313 this.parameterChange(ParameterKey.DebugMode, Boolean.toString(dbg));
314 }
315
316 /**
317 * @param doc
318 * the document to set
319 */
320 public void setDocument(final Document doc) {
321 final Document oldValue = this.document;
322 this.firePropertyChange("document", oldValue, doc);
323 this.document = doc;
324 if (doc != oldValue) {
325 this.revalidate();
326 this.repaint();
327 }
328 }
329
330 /**
331 * Font emulator for standard component behaviour.
332 * <p>
333 * Emulates the standard setFont function by setting the font Size and
334 * adding the font to the front of the serif font list.
335 * <p>
336 * Please use the separate setters if possible.
337 *
338 * @param f
339 * font to set.
340 * @see #setFontSize(float)
341 * @see #setFontsSerif(String)
342 * @deprecated
343 */
344 @Deprecated
345 @Override
346 public void setFont(final Font f) {
347 super.setFont(f);
348 this.setFontSize(f.getSize2D());
349 this.setFontsSerif(f.getFamily() + JMathComponent.FONT_SEPARATOR
350 + this.getFontsSerif());
351 }
352
353 /**
354 * Font list for Doublestruck. Please see
355 * {@link ParameterKey#FontsDoublestruck} for an explanation of this
356 * parameter.
357 *
358 * @param newFonts
359 * new list for Doublestruck (comma seraparated).
360 * @see ParameterKey#FontsDoublestruck
361 */
362 public void setFontsDoublestruck(final String newFonts) {
363 this.parameterChange(ParameterKey.FontsDoublestruck, newFonts);
364 }
365
366 /**
367 * Font list for Fraktur. Please see {@link ParameterKey#FontsFraktur} for
368 * an explanation of this parameter.
369 *
370 * @param newFonts
371 * new list for Fraktur (comma seraparated).
372 * @see ParameterKey#FontsFraktur
373 */
374 public void setFontsFraktur(final String newFonts) {
375 this.parameterChange(ParameterKey.FontsFraktur, newFonts);
376 }
377
378 private void parameterChange(final ParameterKey key, final String newValue) {
379 final String oldValue = this.parameters.get(key);
380 this.parameters.put(key, newValue);
381 this.firePropertyChange(key.name(), oldValue, this.parameters
382 .get(key));
383 this.revalidate();
384 this.repaint();
385 }
386
387 /**
388 * sets the font size used.
389 *
390 * @param fontSize
391 * the font size.
392 */
393 public void setFontSize(final float fontSize) {
394 this.parameterChange(ParameterKey.FontSize, Float.toString(fontSize));
395 }
396
397 /**
398 * Font list for Monospaced. Please see
399 * {@link ParameterKey#FontsMonospaced} for an explanation of this
400 * parameter.
401 *
402 * @param newFonts
403 * new list for Monospaced (comma seraparated).
404 * @see ParameterKey#FontsMonospaced
405 */
406 public void setFontsMonospaced(final String newFonts) {
407 this.parameterChange(ParameterKey.FontsMonospaced, newFonts);
408 }
409
410 /**
411 * Font list for Sans-Serif. Please see {@link ParameterKey#FontsSanserif}
412 * for an explanation of this parameter.
413 *
414 * @param newFonts
415 * new list for sansserif (comma seraparated).
416 * @see ParameterKey#FontsSanserif
417 */
418 public void setFontsSanserif(final String newFonts) {
419 this.parameterChange(ParameterKey.FontsSanserif, newFonts);
420 }
421
422 /**
423 * Font list for Script. Please see {@link ParameterKey#FontsScript} for
424 * an explanation of this parameter.
425 *
426 * @param newFonts
427 * new list for Script (comma seraparated).
428 * @see ParameterKey#FontsScript
429 */
430 public void setFontsScript(final String newFonts) {
431 this.parameterChange(ParameterKey.FontsScript, newFonts);
432 }
433
434 /**
435 * Font list for Serif (the default MathML font). Please see
436 * {@link ParameterKey#FontsSerif} for an explanation of this parameter.
437 *
438 * @param newFonts
439 * new list for serif (comma seraparated).
440 * @see ParameterKey#FontsSerif
441 */
442 public void setFontsSerif(final String newFonts) {
443 this.parameterChange(ParameterKey.FontsSerif, newFonts);
444 this.fontCompat();
445 }
446
447 /** {@inheritDoc} */
448 @Override
449 public void setForeground(final Color fg) {
450 super.setForeground(fg);
451 final String colorAsHex = AttributesHelper.colorTOsRGBString(fg);
452 this.parameterChange(ParameterKey.ForegroundColor, colorAsHex);
453 }
454
455 /**
456 * Horizontal alignment, as defined by
457 * {@link javax.swing.JLabel#setHorizontalAlignment(int)}.
458 * <p>
459 * Supported are: {@link SwingConstants#LEADING},
460 * {@link SwingConstants#LEFT}, {@link SwingConstants#CENTER},
461 * {@link SwingConstants#TRAILING}, {@link SwingConstants#RIGHT}.
462 *
463 * @param hAlignment
464 * the horizontalAlignment to set
465 * @see javax.swing.JLabel#setHorizontalAlignment(int)
466 */
467 public void setHorizontalAlignment(final int hAlignment) {
468 this.horizontalAlignment = hAlignment;
469 }
470
471 /** {@inheritDoc} */
472 @Override
473 public void setOpaque(final boolean opaque) {
474 super.setOpaque(opaque);
475 this.reval();
476 }
477
478 /**
479 * Sets a generic JEuclid rendering parameter. Please see
480 * {@link ParameterKey} for a list of possible values.
481 *
482 * @param key
483 * the parameter to set.
484 * @param value
485 * the value to set it to.
486 */
487 public final void setParameter(final ParameterKey key, final String value) {
488 this.parameterChange(key, value);
489 }
490
491 /**
492 * Vertical alignment, as defined by
493 * {@link javax.swing.JLabel#setVerticalAlignment(int)}.
494 * <p>
495 * Supported are: {@link SwingConstants#TOP},
496 * {@link SwingConstants#CENTER}, {@link SwingConstants#BOTTOM}.
497 *
498 * @param vAlignment
499 * the verticalAlignment to set
500 * @see javax.swing.JLabel#setVerticalAlignment(int)
501 */
502 public void setVerticalAlignment(final int vAlignment) {
503 this.verticalAlignment = vAlignment;
504 }
505
506 /** {@inheritDoc} */
507 @Override
508 public void updateUI() {
509 if (UIManager.get(this.getUIClassID()) != null) {
510 this.setUI(UIManager.getUI(this));
511 } else {
512 this.setUI(new MathComponentUI());
513 }
514 }
515
516 /**
517 * @return the parameters
518 */
519 public Map<ParameterKey, String> getParameters() {
520 return this.parameters;
521 }
522
523 }