View Javadoc

1   /*
2    * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  /* $Id: MainFrame.java,v 0b66106c7ff7 2010/08/06 15:35:06 max $ */
18  
19  package net.sourceforge.jeuclid.app.mathviewer;
20  
21  import java.awt.BorderLayout;
22  import java.awt.Point;
23  import java.awt.Toolkit;
24  import java.awt.datatransfer.DataFlavor;
25  import java.awt.datatransfer.StringSelection;
26  import java.awt.datatransfer.Transferable;
27  import java.awt.event.ActionEvent;
28  import java.awt.event.ActionListener;
29  import java.awt.event.KeyEvent;
30  import java.io.File;
31  
32  import javax.swing.JCheckBoxMenuItem;
33  import javax.swing.JDialog;
34  import javax.swing.JFrame;
35  import javax.swing.JMenu;
36  import javax.swing.JMenuBar;
37  import javax.swing.JMenuItem;
38  import javax.swing.JOptionPane;
39  import javax.swing.JPanel;
40  import javax.swing.JPopupMenu;
41  import javax.swing.JScrollPane;
42  import javax.swing.JSplitPane;
43  import javax.swing.KeyStroke;
44  import javax.swing.ScrollPaneConstants;
45  import javax.swing.event.DocumentEvent;
46  import javax.swing.event.DocumentListener;
47  
48  import net.sourceforge.jeuclid.MathMLSerializer;
49  import net.sourceforge.jeuclid.biparser.BiTree;
50  import net.sourceforge.jeuclid.biparser.NonIncrementalElementException;
51  import net.sourceforge.jeuclid.biparser.ReparseException;
52  import net.sourceforge.jeuclid.biparser.SAXBiParser;
53  import net.sourceforge.jeuclid.biparser.TextPosition;
54  import net.sourceforge.jeuclid.context.LayoutContextImpl;
55  import net.sourceforge.jeuclid.context.Parameter;
56  import net.sourceforge.jeuclid.swing.CursorListener;
57  import net.sourceforge.jeuclid.swing.JMathComponent;
58  
59  import org.apache.batik.util.gui.xmleditor.XMLContext;
60  import org.apache.batik.util.gui.xmleditor.XMLEditorKit;
61  import org.apache.batik.util.gui.xmleditor.XMLTextEditor;
62  import org.w3c.dom.Document;
63  import org.w3c.dom.Node;
64  
65  /**
66   * Main frame for the MathViewer application.
67   * 
68   * @version $Revision: 0b66106c7ff7 $
69   */
70  // CHECKSTYLE:OFF
71  public class MainFrame extends JFrame implements CursorListener {
72      // CHECKSTYLE:OFF
73  
74      private static final int DEFAULT_HEIGHT = 400;
75  
76      private static final int DEFAULT_WIDTH = 700;
77  
78      private static final FileIO FILEIO = FileIO.getInstance();
79  
80      // /**
81      // * Logger for this class
82      // */
83      // currently unused.
84      // private static final Log LOGGER = LogFactory.getLog(MainFrame.class);
85  
86      private static final long serialVersionUID = 1L;
87  
88      private static final float FONT_SIZE_MULTIPLICATOR = 1.20f;
89  
90      private JPanel jContentPane;
91  
92      private JMenuBar jJMenuBar;
93  
94      private JMenu fileMenu;
95  
96      private JMenu editMenu;
97  
98      private JMenu helpMenu;
99  
100     private JMenuItem exitMenuItem;
101 
102     private JMenuItem unformattedCopyMenuItem;
103 
104     private JMenuItem formattedCopyMenuItem;
105 
106     private JMenuItem pasteMenuItem;
107 
108     private JMenuItem aboutMenuItem;
109 
110     private JMenuItem openMenuItem;
111 
112     private JDialog aboutDialog;
113 
114     private JSplitPane splitPane;
115 
116     private JScrollPane scrollPane;
117 
118     private JScrollPane scrollPane2;
119 
120     private XMLTextEditor xmlEditor;
121 
122     private JMathComponent mathComponent;
123 
124     private BiTree biTree;
125 
126     private JMenu viewMenu;
127 
128     private JMenuItem refreshMenuItem;
129 
130     private JMenuItem biggerMenuItem;
131 
132     private JMenuItem smallerMenuItem;
133 
134     private JMenuItem exportMenuItem;
135 
136     private JCheckBoxMenuItem aliasMenuItem;
137 
138     private JCheckBoxMenuItem debugMenuItem;
139 
140     // ==================================================
141     // context menu elements
142     // ==================================================
143 
144     private JPopupMenu contextPopupMenu;
145 
146     private JMenu insertMenu;
147 
148     private JMenu greekMenu;
149 
150     private JMenu logicsMenu;
151 
152     private JMenu symbolsMenu;
153 
154     private JMenuItem c_refreshMenuItem;
155 
156     private JMenuItem tableMenuItem;
157 
158     private JMenuItem polynomMenuItem;
159 
160     private JMenuItem orMenuItem;
161 
162     private JMenuItem andMenuItem;
163 
164     private JMenuItem notMenuItem;
165 
166     private JMenuItem alphaMenuItem;
167 
168     private JMenuItem betaMenuItem;
169 
170     private JMenuItem gammaMenuItem;
171 
172     private JMenuItem deltaMenuItem;
173 
174     private JMenuItem omegaMenuItem;
175 
176     private JMenuItem existsMenuItem;
177 
178     private JMenuItem forallMenuItem;
179 
180     /**
181      * This is the default constructor.
182      */
183     public MainFrame() {
184         super();
185         this.initialize();
186     }
187 
188     @Override
189     public void updateCursorPosition(final Node node) {
190         final TextPosition result = this.biTree.searchNode(node);
191         if (result != null
192                 && result.getTotalOffset() < this.getXMLEditor().getText()
193                         .length()) {
194             this.getXMLEditor().requestFocusInWindow();
195             this.getXMLEditor().setCaretPosition(result.getTotalOffset());
196             this.getXMLEditor().setSelectionStart(result.getTotalOffset());
197             this.getXMLEditor().setSelectionEnd(
198                     result.getTotalOffset() + result.getLength());
199         }
200     }
201 
202     /**
203      * This method initializes this
204      * 
205      * @return void
206      */
207     private void initialize() {
208         this.setJMenuBar(this.getJJMenuBar());
209         this.setSize(MainFrame.DEFAULT_WIDTH, MainFrame.DEFAULT_HEIGHT);
210         this.setContentPane(this.getJContentPane());
211         this.setTitle(Messages.getString("MathViewer.windowTitle")); //$NON-NLS-1$
212         this.setLocationByPlatform(true);
213     }
214 
215     /**
216      * This method initializes jContentPane
217      * 
218      * @return javax.swing.JPanel
219      */
220     private JPanel getJContentPane() {
221         if (this.jContentPane == null) {
222             this.jContentPane = new JPanel();
223             this.jContentPane.setLayout(new BorderLayout());
224             this.jContentPane.add(this.getSplitPane(), BorderLayout.CENTER);
225         }
226         return this.jContentPane;
227     }
228 
229     /**
230      * This method initializes jJMenuBar
231      * 
232      * @return javax.swing.JMenuBar
233      */
234     private JMenuBar getJJMenuBar() {
235         if (this.jJMenuBar == null) {
236             this.jJMenuBar = new JMenuBar();
237             this.jJMenuBar.add(this.getFileMenu());
238             this.jJMenuBar.add(this.getEditMenu());
239             this.jJMenuBar.add(this.getViewMenu());
240             if (!MathViewer.OSX) {
241                 // This will need to be changed once the Help menu contains
242                 // more that just the About item.
243                 this.jJMenuBar.add(this.getHelpMenu());
244             }
245         }
246         return this.jJMenuBar;
247     }
248 
249     /**
250      * This method initializes jMenu
251      * 
252      * @return javax.swing.JMenu
253      */
254     private JMenu getFileMenu() {
255         if (this.fileMenu == null) {
256             this.fileMenu = new JMenu();
257             this.fileMenu.setText(Messages.getString("MathViewer.FileMenu")); //$NON-NLS-1$
258             this.fileMenu.add(this.getOpenMenuItem());
259             this.fileMenu.add(this.getExportMenuItem());
260             if (!MathViewer.OSX) {
261                 this.fileMenu.add(this.getExitMenuItem());
262             }
263         }
264         return this.fileMenu;
265     }
266 
267     /**
268      * This method initializes jMenu
269      * 
270      * @return javax.swing.JMenu
271      */
272     private JMenu getEditMenu() {
273         if (this.editMenu == null) {
274             this.editMenu = new JMenu();
275             this.editMenu.setText(Messages.getString("MathViewer.EditMenu")); //$NON-NLS-1$
276             this.editMenu.add(this.getUnformattedCopyMenuItem());
277             this.editMenu.add(this.getFormattedCopyMenuItem());
278             this.editMenu.add(this.getPasteMenuItem());
279         }
280         return this.editMenu;
281     }
282 
283     /**
284      * This method initializes jMenu
285      * 
286      * @return javax.swing.JMenu
287      */
288     private JMenu getHelpMenu() {
289         if (this.helpMenu == null) {
290             this.helpMenu = new JMenu();
291             this.helpMenu.setText(Messages.getString("MathViewer.helpMenu")); //$NON-NLS-1$
292             // If there are more items, please modify getJJMenuBar to always
293             // display the help menu and this function to not display about on
294             // OS X
295             this.helpMenu.add(this.getAboutMenuItem());
296         }
297         return this.helpMenu;
298     }
299 
300     /**
301      * This method initializes jMenuItem
302      * 
303      * @return javax.swing.JMenuItem
304      */
305     private JMenuItem getExitMenuItem() {
306         if (this.exitMenuItem == null) {
307             this.exitMenuItem = new JMenuItem();
308             this.exitMenuItem.setText(Messages.getString("MathViewer.exit")); //$NON-NLS-1$
309             this.exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(
310                     KeyEvent.VK_Q, Toolkit.getDefaultToolkit()
311                             .getMenuShortcutKeyMask(), true));
312 
313             this.exitMenuItem.addActionListener(new ActionListener() {
314                 public void actionPerformed(final ActionEvent e) {
315                     System.exit(0);
316                 }
317             });
318         }
319         return this.exitMenuItem;
320     }
321 
322     private JMenuItem getUnformattedCopyMenuItem() {
323         if (this.unformattedCopyMenuItem == null) {
324             this.unformattedCopyMenuItem = new JMenuItem();
325             this.unformattedCopyMenuItem.setText(Messages
326                     .getString("MathViewer.unformattedCopyFull")); //$NON-NLS-1$
327             // this.unformattedCopyMenuItem.setAccelerator(KeyStroke
328             // .getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit()
329             // .getMenuShortcutKeyMask(), true));
330 
331             this.unformattedCopyMenuItem
332                     .addActionListener(new ActionListener() {
333                         public void actionPerformed(final ActionEvent e) {
334                             MainFrame.this.copyFullToClipboard(false);
335                         }
336                     });
337         }
338         return this.unformattedCopyMenuItem;
339     }
340 
341     private JMenuItem getFormattedCopyMenuItem() {
342         if (this.formattedCopyMenuItem == null) {
343             this.formattedCopyMenuItem = new JMenuItem();
344             this.formattedCopyMenuItem.setText(Messages
345                     .getString("MathViewer.formattedCopyFull")); //$NON-NLS-1$
346             // this.formattedCopyMenuItem.setAccelerator(KeyStroke.getKeyStroke(
347             // KeyEvent.VK_C, Toolkit.getDefaultToolkit()
348             // .getMenuShortcutKeyMask()
349             // | InputEvent.SHIFT_DOWN_MASK, true));
350 
351             this.formattedCopyMenuItem.addActionListener(new ActionListener() {
352                 public void actionPerformed(final ActionEvent e) {
353                     MainFrame.this.copyFullToClipboard(true);
354                 }
355             });
356         }
357         return this.formattedCopyMenuItem;
358     }
359 
360     /**
361      * This method initializes jMenuItem
362      * 
363      * @return javax.swing.JMenuItem
364      */
365     private JMenuItem getPasteMenuItem() {
366         if (this.pasteMenuItem == null) {
367             this.pasteMenuItem = new JMenuItem();
368             this.pasteMenuItem.setText(Messages
369                     .getString("MathViewer.pasteFull")); //$NON-NLS-1$
370             // this.pasteMenuItem.setAccelerator(KeyStroke.getKeyStroke(
371             // KeyEvent.VK_V, Toolkit.getDefaultToolkit()
372             // .getMenuShortcutKeyMask(), true));
373 
374             this.pasteMenuItem.addActionListener(new ActionListener() {
375                 public void actionPerformed(final ActionEvent e) {
376                     MainFrame.this.pasteFullFromClipboard();
377                 }
378             });
379         }
380         return this.pasteMenuItem;
381     }
382 
383     /**
384      * This method initializes jMenuItem
385      * 
386      * @return javax.swing.JMenuItem
387      */
388     private JMenuItem getAboutMenuItem() {
389         if (this.aboutMenuItem == null) {
390             this.aboutMenuItem = new JMenuItem();
391             this.aboutMenuItem.setText(Messages
392                     .getString("MathViewer.aboutMenuItem")); //$NON-NLS-1$
393             this.aboutMenuItem.addActionListener(new ActionListener() {
394                 public void actionPerformed(final ActionEvent e) {
395                     MainFrame.this.displayAbout();
396                 }
397             });
398         }
399         return this.aboutMenuItem;
400     }
401 
402     /**
403      * Display the about dialog.
404      */
405     public void displayAbout() {
406         final JDialog aDialog = MainFrame.this.getAboutDialog();
407         aDialog.pack();
408         final Point loc = MainFrame.this.getLocation();
409         loc.translate((MainFrame.this.getWidth() - aDialog.getWidth()) / 2, 0);
410         aDialog.setLocation(loc);
411         aDialog.setVisible(true);
412 
413     }
414 
415     /**
416      * This method initializes aboutDialog
417      * 
418      * @return javax.swing.JDialog
419      */
420     private JDialog getAboutDialog() {
421         if (this.aboutDialog == null) {
422             this.aboutDialog = new AboutDialog(this);
423         }
424         return this.aboutDialog;
425     }
426 
427     /**
428      * This method initializes jMenuItem
429      * 
430      * @return javax.swing.JMenuItem
431      */
432     private JMenuItem getOpenMenuItem() {
433         if (this.openMenuItem == null) {
434             this.openMenuItem = new JMenuItem();
435             this.openMenuItem.setText(Messages.getString("MathViewer.open")); //$NON-NLS-1$
436             this.openMenuItem.setAccelerator(KeyStroke.getKeyStroke(
437                     KeyEvent.VK_O, Toolkit.getDefaultToolkit()
438                             .getMenuShortcutKeyMask(), true));
439             this.openMenuItem
440                     .addActionListener(new java.awt.event.ActionListener() {
441                         public void actionPerformed(
442                                 final java.awt.event.ActionEvent e) {
443                             MainFrame.this.openFile();
444                         }
445                     });
446         }
447         return this.openMenuItem;
448     }
449 
450     /**
451      * Try to load a given file into this frame.
452      * 
453      * @param f
454      *            reference to the file.
455      */
456     public void loadFile(final File f) {
457         final Document doc = MainFrame.FILEIO.loadFile(this, f);
458         if (doc == null) {
459             this.getXMLEditor().setText("");
460         } else {
461             this.getXMLEditor().setText(
462                     MathMLSerializer.serializeDocument(doc, false, false));
463         }
464         this.updateFromTextArea();
465     }
466 
467     /**
468      * carries out the actual file-open procedure.
469      */
470     protected void openFile() {
471         final File file = MainFrame.FILEIO.selectFileToOpen(this);
472         this.loadFile(file);
473     }
474 
475     /**
476      * This method initializes splitPane
477      * 
478      * @return {@link JSplitPane}
479      */
480     private JSplitPane getSplitPane() {
481         if (this.splitPane == null) {
482             this.splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
483                     this.getScrollPane(), this.getScrollPane2());
484             this.splitPane.setOneTouchExpandable(true);
485             this.splitPane.setResizeWeight(1.0);
486         }
487         return this.splitPane;
488     }
489 
490     private void setText(final String text) {
491         this.xmlEditor.setText(text);
492         try {
493             this.biTree = SAXBiParser.getInstance().parse(text);
494         } catch (NonIncrementalElementException e) {
495             this.biTree = null;
496             this.getMathComponent().setContent(text);
497         }
498         if (this.biTree != null) {
499             this.biTree.createDOMTree();
500             this.mathComponent.setDocument(this.biTree.getDocument());
501         }
502     }
503 
504     /**
505      * This method initializes xmlEditor
506      * 
507      * @return {@link XMLTextEditor}
508      */
509     private XMLTextEditor getXMLEditor() {
510         if (this.xmlEditor == null) {
511             this.xmlEditor = new XMLTextEditor();
512             this.xmlEditor.setEditorKit(new XMLEditorKit(new XMLContext()));
513             /*
514              * this.xmlEditor.setText("<?xml version='1.0'?>" + Helper.nl() +
515              * "<math xmlns='http://www.w3.org/1998/Math/MathML'>" + Helper.nl()
516              * + "</math>");
517              */
518             this.setText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
519                     + Helper.nl()
520                     // DOCTYPE for W3C compliance obviously not
521                     // supported
522                     // +
523                     // "<!DOCTYPE math PUBLIC -//W3C//DTD MathML 2.0//EN' "
524                     // +
525                     // "'http://www.w3.org/Math/DTD/mathml2/mathml2.dtd'>"
526                     // + Helper.nl()
527                     + "<math xmlns='http://www.w3.org/1998/Math/MathML'>"
528                     + Helper.nl() + "<mrow>" + Helper.nl() + "<mi>a</mi>"
529                     + Helper.nl() + "<msup><mi>x</mi><mn>2</mn></msup>"
530                     + Helper.nl() + "<mo>+</mo><mi>b</mi>" + Helper.nl()
531                     + "<mi>x</mi><mo>+</mo><mi>c</mi>" + Helper.nl()
532                     + "<mo>=</mo><mo>0</mo>" + Helper.nl() + "</mrow>"
533                     + Helper.nl() + "</math>");
534 
535             this.xmlEditor.setEditable(true);
536             this.xmlEditor.setComponentPopupMenu(this.getContextPopupMenu());
537             this.xmlEditor.getDocument().addDocumentListener(
538                     new DocumentListener() {
539                         public void changedUpdate(
540                                 final DocumentEvent documentevent) {
541                             MainFrame.this.updateFromTextArea(documentevent);
542                         }
543 
544                         public void insertUpdate(
545                                 final DocumentEvent documentevent) {
546                             MainFrame.this.updateFromTextArea(documentevent);
547                         }
548 
549                         public void removeUpdate(
550                                 final DocumentEvent documentevent) {
551                             MainFrame.this.updateFromTextArea(documentevent);
552                         }
553                     });
554             // this.updateFromTextArea();
555         }
556 
557         return this.xmlEditor;
558     }
559 
560     private String normalize(final String text) {
561         // workaround for some problems with OS dependency
562         // pane.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty,
563         // "\n");
564         return text.replace("\r\n", "\n");
565     }
566 
567     /**
568      * Set the content from a String containing the MathML content.
569      * 
570      * @param text
571      *            the content to set.
572      * @param documentEvent
573      *            documentEvent which triggered the change.
574      */
575     private void setContent(final DocumentEvent documentEvent, final String text) {
576         DocumentEvent.EventType type;
577         if (this.biTree == null || this.biTree.getRoot() == null) {
578             this.getMathComponent().setContent(text);
579         } else {
580 
581             type = documentEvent.getType();
582 
583             try {
584                 if (type == DocumentEvent.EventType.INSERT) {
585                     this.biTree.insert(documentEvent.getOffset(),
586                             documentEvent.getLength(), text);
587 
588                 } else if (type == DocumentEvent.EventType.REMOVE) {
589                     this.biTree.remove(documentEvent.getOffset(),
590                             documentEvent.getLength(), text);
591 
592                 } else {
593                     // Other types of events are unsupported.
594                     this.getMathComponent().setContent(text);
595                 }
596             } catch (final ReparseException ex) {
597                 this.getMathComponent().setContent(text);
598             } catch (NonIncrementalElementException e) {
599                 this.biTree = null;
600                 this.getMathComponent().setContent(text);
601             }
602         }
603         this.getMathComponent().revalidate();
604         this.getMathComponent().repaint();
605     }
606 
607     private void updateFromTextArea(final DocumentEvent documentevent) {
608         try {
609             final String txt = this.normalize(this.getXMLEditor().getText());
610             this.setContent(documentevent, txt);
611 
612             // CHECKSTYLE:OFF
613             // in this case, we want to explicitly provide catch-all error
614             // handling.
615         } catch (final RuntimeException e) {
616             // CHECKSTYLE:ON
617         }
618     }
619 
620     private void updateFromTextArea() {
621         try {
622             final String txt = this.normalize(this.getXMLEditor().getText());
623             this.setText(txt);
624 
625             // CHECKSTYLE:OFF
626             // in this case, we want to explicitly provide catch-all error
627             // handling.
628         } catch (final RuntimeException e) {
629             // CHECKSTYLE:ON
630         }
631     }
632 
633     /**
634      * This method initializes scrollPane
635      * 
636      * @return javax.swing.JScrollPane
637      */
638     private JScrollPane getScrollPane() {
639         if (this.scrollPane == null) {
640             this.scrollPane = new JScrollPane();
641             this.scrollPane.setViewportView(this.getMathComponent());
642 
643             if (MathViewer.OSX) {
644                 this.scrollPane
645                         .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
646                 this.scrollPane
647                         .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
648             }
649         }
650         return this.scrollPane;
651     }
652 
653     /**
654      * This method initializes scrollPane2
655      * 
656      * @return javax.swing.JScrollPane
657      */
658     private JScrollPane getScrollPane2() {
659         if (this.scrollPane2 == null) {
660             this.scrollPane2 = new JScrollPane();
661             this.scrollPane2.setViewportView(this.getXMLEditor());
662 
663             if (MathViewer.OSX) {
664                 this.scrollPane2
665                         .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
666                 this.scrollPane2
667                         .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
668             }
669         }
670         return this.scrollPane2;
671     }
672 
673     /**
674      * This method initializes mathComponent.
675      * 
676      * @return net.sourceforge.jeuclid.swing.JMathComponent
677      */
678     public JMathComponent getMathComponent() {
679         if (this.mathComponent == null) {
680             this.mathComponent = new JMathComponent(this);
681             this.mathComponent
682                     .setContent("<math><mtext>" //$NON-NLS-1$
683                             + Messages.getString("MathViewer.noFileLoaded") + "</mtext></math>"); //$NON-NLS-1$ //$NON-NLS-2$
684             this.mathComponent.setFocusable(true);
685         }
686         return this.mathComponent;
687     }
688 
689     /**
690      * This method initializes viewMenu
691      * 
692      * @return javax.swing.JMenu
693      */
694     private JMenu getViewMenu() {
695         if (this.viewMenu == null) {
696             this.viewMenu = new JMenu();
697             this.viewMenu.setText(Messages.getString("MathViewer.viewMenu")); //$NON-NLS-1$
698             this.viewMenu.add(this.getRefreshMenuItem());
699             this.viewMenu.add(this.getBiggerMenuItem());
700             this.viewMenu.add(this.getSmallerMenuItem());
701             this.viewMenu.add(this.getAliasMenuItem());
702             this.viewMenu.add(this.getDebugMenuItem());
703             if (!MathViewer.OSX) {
704                 this.viewMenu.add(this.getViewModifyParams());
705             }
706         }
707         return this.viewMenu;
708     }
709 
710     private JMenuItem getViewModifyParams() {
711         final JMenuItem mi = new JMenuItem(
712                 Messages.getString("MathViewer.viewModifyParams"));
713         mi.addActionListener(new ActionListener() {
714             public void actionPerformed(final ActionEvent e) {
715                 MainFrame.this.displaySettings();
716             }
717         });
718         return mi;
719     }
720 
721     /**
722      * Display the settings dialog.
723      */
724     public void displaySettings() {
725         new ParametersDialog(MainFrame.this).setVisible(true);
726         MainFrame.this.debugMenuItem
727                 .setSelected(((Boolean) MainFrame.this.mathComponent
728                         .getParameters().getParameter(Parameter.DEBUG))
729                         .booleanValue());
730         MainFrame.this.aliasMenuItem
731                 .setSelected(((Boolean) MainFrame.this.mathComponent
732                         .getParameters().getParameter(Parameter.ANTIALIAS))
733                         .booleanValue());
734 
735     }
736 
737     /**
738      * This method initializes refreshMenuItem
739      * 
740      * @return javax.swing.JMenuItem
741      */
742     private JMenuItem getRefreshMenuItem() {
743         if (this.refreshMenuItem == null) {
744             this.refreshMenuItem = new JMenuItem();
745             this.refreshMenuItem.setText(Messages
746                     .getString("MathViewer.textRefresh"));
747             this.refreshMenuItem.setAccelerator(KeyStroke.getKeyStroke(
748                     KeyEvent.VK_Y, Toolkit.getDefaultToolkit()
749                             .getMenuShortcutKeyMask(), true));
750             this.refreshMenuItem
751                     .addActionListener(new java.awt.event.ActionListener() {
752                         public void actionPerformed(
753                                 final java.awt.event.ActionEvent e) {
754                             MainFrame.this.updateFromTextArea();
755                         }
756                     });
757         }
758         return this.refreshMenuItem;
759     }
760 
761     /**
762      * This method initializes biggerMenuItem
763      * 
764      * @return javax.swing.JMenuItem
765      */
766     private JMenuItem getBiggerMenuItem() {
767         if (this.biggerMenuItem == null) {
768             this.biggerMenuItem = new JMenuItem();
769             this.biggerMenuItem.setText(Messages
770                     .getString("MathViewer.textBigger")); //$NON-NLS-1$
771             this.biggerMenuItem.setAccelerator(KeyStroke.getKeyStroke(
772             /*
773              * KeyEvent.VK_ADD, Toolkit.getDefaultToolkit()
774              * .getMenuShortcutKeyMask(), true));
775              */
776             KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit()
777                     .getMenuShortcutKeyMask(), true));
778             this.biggerMenuItem
779                     .addActionListener(new java.awt.event.ActionListener() {
780                         public void actionPerformed(
781                                 final java.awt.event.ActionEvent e) {
782                             final JMathComponent jmc = MainFrame.this
783                                     .getMathComponent();
784                             jmc.setFontSize(jmc.getFontSize()
785                                     * MainFrame.FONT_SIZE_MULTIPLICATOR);
786                         }
787                     });
788         }
789         return this.biggerMenuItem;
790     }
791 
792     /**
793      * This method initializes smallerMenuItem
794      * 
795      * @return javax.swing.JMenuItem
796      */
797     private JMenuItem getSmallerMenuItem() {
798         if (this.smallerMenuItem == null) {
799             this.smallerMenuItem = new JMenuItem();
800             this.smallerMenuItem.setText(Messages
801                     .getString("MathViewer.textSmaller")); //$NON-NLS-1$
802             this.smallerMenuItem.setAccelerator(KeyStroke.getKeyStroke(
803             /*
804              * KeyEvent.VK_SUBTRACT, Toolkit.getDefaultToolkit()
805              * .getMenuShortcutKeyMask(), true));
806              */
807             KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit()
808                     .getMenuShortcutKeyMask(), true));
809 
810             this.smallerMenuItem
811                     .addActionListener(new java.awt.event.ActionListener() {
812                         public void actionPerformed(
813                                 final java.awt.event.ActionEvent e) {
814                             final JMathComponent jmc = MainFrame.this
815                                     .getMathComponent();
816                             jmc.setFontSize(jmc.getFontSize()
817                                     / MainFrame.FONT_SIZE_MULTIPLICATOR);
818                         }
819                     });
820         }
821         return this.smallerMenuItem;
822     }
823 
824     /**
825      * This method initializes exportMenuItem.
826      * 
827      * @return javax.swing.JMenuItem
828      */
829     private JMenuItem getExportMenuItem() {
830         if (this.exportMenuItem == null) {
831             this.exportMenuItem = new JMenuItem();
832             this.exportMenuItem
833                     .setText(Messages.getString("MathViewer.export")); //$NON-NLS-1$
834             this.exportMenuItem.setAccelerator(KeyStroke.getKeyStroke(
835                     KeyEvent.VK_S, Toolkit.getDefaultToolkit()
836                             .getMenuShortcutKeyMask(), true));
837             this.exportMenuItem
838                     .addActionListener(new java.awt.event.ActionListener() {
839                         public void actionPerformed(
840                                 final java.awt.event.ActionEvent e) {
841                             MainFrame.this.exportFile();
842                         }
843                     });
844         }
845         return this.exportMenuItem;
846     }
847 
848     /**
849      * Carries out the actual export File operation.
850      */
851     protected void exportFile() {
852         MainFrame.FILEIO.saveDocument(this, this.getMathComponent()
853                 .getDocument(), this.getMathComponent().getParameters());
854     }
855 
856     /**
857      * This method initializes aliasMenuItem
858      * 
859      * @return javax.swing.JCheckBoxMenuItem
860      */
861     private JCheckBoxMenuItem getAliasMenuItem() {
862         if (this.aliasMenuItem == null) {
863             this.aliasMenuItem = new JCheckBoxMenuItem();
864             this.aliasMenuItem.setText(Messages.getString("MathViewer.alias")); //$NON-NLS-1$
865             this.aliasMenuItem.setSelected((Boolean) LayoutContextImpl
866                     .getDefaultLayoutContext()
867                     .getParameter(Parameter.ANTIALIAS));
868             this.aliasMenuItem
869                     .addItemListener(new java.awt.event.ItemListener() {
870                         public void itemStateChanged(
871                                 final java.awt.event.ItemEvent e) {
872                             MainFrame.this.getMathComponent().setParameter(
873                                     Parameter.ANTIALIAS,
874                                     MainFrame.this.aliasMenuItem.isSelected());
875                         }
876                     });
877         }
878         return this.aliasMenuItem;
879     }
880 
881     /**
882      * This method initializes debugMenuItem
883      * 
884      * @return javax.swing.JCheckBoxMenuItem
885      */
886     private JCheckBoxMenuItem getDebugMenuItem() {
887         if (this.debugMenuItem == null) {
888             this.debugMenuItem = new JCheckBoxMenuItem();
889             this.debugMenuItem.setText(Messages.getString("MathViewer.debug")); //$NON-NLS-1$
890             this.debugMenuItem.setSelected((Boolean) LayoutContextImpl
891                     .getDefaultLayoutContext().getParameter(Parameter.DEBUG));
892             this.debugMenuItem
893                     .addItemListener(new java.awt.event.ItemListener() {
894                         public void itemStateChanged(
895                                 final java.awt.event.ItemEvent e) {
896                             MainFrame.this.getMathComponent().setParameter(
897                                     Parameter.DEBUG,
898                                     MainFrame.this.debugMenuItem.isSelected());
899                         }
900                     });
901         }
902         return this.debugMenuItem;
903     }
904 
905     private void pasteFullFromClipboard() {
906         final Transferable content = Toolkit.getDefaultToolkit()
907                 .getSystemClipboard().getContents(null);
908         if (content != null
909                 && content.isDataFlavorSupported(DataFlavor.stringFlavor)) {
910             try {
911                 final String newContent = (String) content
912                         .getTransferData(DataFlavor.stringFlavor);
913                 this.getMathComponent().setContent(newContent);
914                 this.getXMLEditor().setText(newContent);
915                 // CHECKSTYLE:OFF
916                 // in this case, we want to explicitly provide catch-all error
917                 // handling.
918             } catch (final Exception e) {
919                 // CHECKSTYLE:ON
920                 JOptionPane.showMessageDialog(
921                         this,
922                         new String[] {
923                                 Messages.getString("MathViewer.pasteFailure"),
924                                 e.toString(), },
925                         Messages.getString("MathViewer.error"),
926                         JOptionPane.ERROR_MESSAGE);
927             }
928         }
929     }
930 
931     private void copyFullToClipboard(final boolean formatted) {
932         Toolkit.getDefaultToolkit()
933                 .getSystemClipboard()
934                 .setContents(
935                         new StringSelection(MathMLSerializer.serializeDocument(
936                                 this.mathComponent.getDocument(), false,
937                                 formatted)), null);
938     }
939 
940     private JMenuItem getCRefreshMenuItem() {
941         if (this.c_refreshMenuItem == null) {
942             this.c_refreshMenuItem = new JMenuItem();
943             this.c_refreshMenuItem.setText(Messages
944                     .getString("MathViewer.cRefreshMenuItem")); //$NON-NLS-1$
945             this.c_refreshMenuItem.setAccelerator(KeyStroke.getKeyStroke(
946                     KeyEvent.VK_F10, Toolkit.getDefaultToolkit()
947                             .getMenuShortcutKeyMask(), true));
948             this.c_refreshMenuItem.addActionListener(new ActionListener() {
949                 public void actionPerformed(final ActionEvent e) {
950                     MainFrame.this.updateFromTextArea();
951                 }
952             });
953         }
954         return this.c_refreshMenuItem;
955     }
956 
957     private JMenuItem getTableMenuItem() {
958         if (this.tableMenuItem == null) {
959             this.tableMenuItem = new JMenuItem();
960             this.tableMenuItem.setText(Messages
961                     .getString("MathViewer.tableMenuItem")); //$NON-NLS-1$
962             this.tableMenuItem.addActionListener(new ActionListener() {
963                 public void actionPerformed(final ActionEvent e) {
964                     final InsertTableDialog dlg = new InsertTableDialog(
965                             MainFrame.this, true);
966                     dlg.setVisible(true);
967 
968                     if (dlg.getMathMLText() != null) {
969                         MainFrame.this.insertMacro(dlg.getMathMLText());
970                     }
971                 }
972             });
973         }
974         return this.tableMenuItem;
975     }
976 
977     private JMenuItem getPolynomMenuItem() {
978         if (this.polynomMenuItem == null) {
979             this.polynomMenuItem = new JMenuItem();
980             this.polynomMenuItem.setText(Messages
981                     .getString("MathViewer.polynomMenuItem")); //$NON-NLS-1$
982             this.polynomMenuItem.addActionListener(new ActionListener() {
983                 public void actionPerformed(final ActionEvent e) {
984                     final InsertPolynomDialog dlg = new InsertPolynomDialog(
985                             MainFrame.this, true);
986                     dlg.setVisible(true);
987                     if (dlg.getMathMLText() != null) {
988                         MainFrame.this.insertMacro(dlg.getMathMLText());
989                     }
990                 }
991             });
992         }
993         return this.polynomMenuItem;
994     }
995 
996     private JMenuItem getOrMenuItem() {
997         if (this.orMenuItem == null) {
998             this.orMenuItem = new JMenuItem();
999             this.orMenuItem
1000                     .setText(Messages.getString("MathViewer.orMenuItem")); //$NON-NLS-1$
1001             this.orMenuItem.addActionListener(new ActionListener() {
1002                 public void actionPerformed(final ActionEvent e) {
1003                     MainFrame.this
1004                             .insertMacro("<apply><or/><ci>a</ci><ci>b</ci></apply>");
1005                 }
1006             });
1007         }
1008         return this.orMenuItem;
1009     }
1010 
1011     private JMenuItem getAndMenuItem() {
1012         if (this.andMenuItem == null) {
1013             this.andMenuItem = new JMenuItem();
1014             this.andMenuItem.setText(Messages
1015                     .getString("MathViewer.andMenuItem")); //$NON-NLS-1$
1016             this.andMenuItem.addActionListener(new ActionListener() {
1017                 public void actionPerformed(final ActionEvent e) {
1018                     MainFrame.this
1019                             .insertMacro("<apply><and/><ci>a</ci><ci>b</ci></apply>");
1020                 }
1021             });
1022         }
1023         return this.andMenuItem;
1024     }
1025 
1026     private JMenuItem getNotMenuItem() {
1027         if (this.notMenuItem == null) {
1028             this.notMenuItem = new JMenuItem();
1029             this.notMenuItem.setText(Messages
1030                     .getString("MathViewer.notMenuItem")); //$NON-NLS-1$
1031             this.notMenuItem.addActionListener(new ActionListener() {
1032                 public void actionPerformed(final ActionEvent e) {
1033                     MainFrame.this
1034                             .insertMacro("<apply><not/><ci>a</ci></apply>");
1035                 }
1036             });
1037         }
1038         return this.notMenuItem;
1039     }
1040 
1041     private JMenuItem getAlphaMenuItem() {
1042         if (this.alphaMenuItem == null) {
1043             this.alphaMenuItem = new JMenuItem();
1044             this.alphaMenuItem.setText(Messages
1045                     .getString("MathViewer.alphaMenuItem")); //$NON-NLS-1$
1046             this.alphaMenuItem.addActionListener(new ActionListener() {
1047                 public void actionPerformed(final ActionEvent e) {
1048                     MainFrame.this.insertMacro("<mi>&#x003b1;</mi>");
1049                 }
1050             });
1051         }
1052         return this.alphaMenuItem;
1053     }
1054 
1055     private JMenuItem getBetaMenuItem() {
1056         if (this.betaMenuItem == null) {
1057             this.betaMenuItem = new JMenuItem();
1058             this.betaMenuItem.setText(Messages
1059                     .getString("MathViewer.betaMenuItem")); //$NON-NLS-1$
1060             this.betaMenuItem.addActionListener(new ActionListener() {
1061                 public void actionPerformed(final ActionEvent e) {
1062                     MainFrame.this.insertMacro("<mi>&#x003b2;</mi>");
1063                 }
1064             });
1065         }
1066         return this.betaMenuItem;
1067     }
1068 
1069     private JMenuItem getGammaMenuItem() {
1070         if (this.gammaMenuItem == null) {
1071             this.gammaMenuItem = new JMenuItem();
1072             this.gammaMenuItem.setText(Messages
1073                     .getString("MathViewer.gammaMenuItem")); //$NON-NLS-1$
1074             this.gammaMenuItem.addActionListener(new ActionListener() {
1075                 public void actionPerformed(final ActionEvent e) {
1076                     MainFrame.this.insertMacro("<mi>&#x003b3;</mi>");
1077                 }
1078             });
1079         }
1080         return this.gammaMenuItem;
1081     }
1082 
1083     private JMenuItem getDeltaMenuItem() {
1084         if (this.deltaMenuItem == null) {
1085             this.deltaMenuItem = new JMenuItem();
1086             this.deltaMenuItem.setText(Messages
1087                     .getString("MathViewer.deltaMenuItem")); //$NON-NLS-1$
1088             this.deltaMenuItem.addActionListener(new ActionListener() {
1089                 public void actionPerformed(final ActionEvent e) {
1090                     MainFrame.this.insertMacro("<mi>&#x003b4;</mi>");
1091                 }
1092             });
1093         }
1094         return this.deltaMenuItem;
1095     }
1096 
1097     private JMenuItem getOmegaMenuItem() {
1098         if (this.omegaMenuItem == null) {
1099             this.omegaMenuItem = new JMenuItem();
1100             this.omegaMenuItem.setText(Messages
1101                     .getString("MathViewer.omegaMenuItem")); //$NON-NLS-1$
1102             this.omegaMenuItem.addActionListener(new ActionListener() {
1103                 public void actionPerformed(final ActionEvent e) {
1104                     MainFrame.this.insertMacro("<mi>&#x003c9;</mi>");
1105                 }
1106             });
1107         }
1108         return this.omegaMenuItem;
1109     }
1110 
1111     private JMenuItem getExistsMenuItem() {
1112         if (this.existsMenuItem == null) {
1113             this.existsMenuItem = new JMenuItem();
1114             this.existsMenuItem.setText(Messages
1115                     .getString("MathViewer.existsMenuItem")); //$NON-NLS-1$
1116             this.existsMenuItem.addActionListener(new ActionListener() {
1117                 public void actionPerformed(final ActionEvent e) {
1118                     MainFrame.this.insertMacro("<apply><exists/></apply>");
1119                 }
1120             });
1121         }
1122         return this.existsMenuItem;
1123     }
1124 
1125     private JMenuItem getForAllMenuItem() {
1126         if (this.forallMenuItem == null) {
1127             this.forallMenuItem = new JMenuItem();
1128             this.forallMenuItem.setText(Messages
1129                     .getString("MathViewer.forallMenuItem")); //$NON-NLS-1$
1130             this.forallMenuItem.addActionListener(new ActionListener() {
1131                 public void actionPerformed(final ActionEvent e) {
1132                     MainFrame.this.insertMacro("<apply><forall/></apply>");
1133                 }
1134             });
1135         }
1136         return this.forallMenuItem;
1137     }
1138 
1139     private JMenu getGreekMenu() {
1140         if (this.greekMenu == null) {
1141             this.greekMenu = new JMenu();
1142             this.greekMenu.setText(Messages.getString("MathViewer.GreekMenu")); //$NON-NLS-1$
1143             this.greekMenu.add(this.getAlphaMenuItem());
1144             this.greekMenu.add(this.getBetaMenuItem());
1145             this.greekMenu.add(this.getGammaMenuItem());
1146             this.greekMenu.add(this.getDeltaMenuItem());
1147             this.greekMenu.add(this.getOmegaMenuItem());
1148         }
1149         return this.greekMenu;
1150     }
1151 
1152     private JMenu getLogicsMenu() {
1153         if (this.logicsMenu == null) {
1154             this.logicsMenu = new JMenu();
1155             this.logicsMenu
1156                     .setText(Messages.getString("MathViewer.LogicsMenu")); //$NON-NLS-1$
1157             this.logicsMenu.add(this.getAndMenuItem());
1158             this.logicsMenu.add(this.getOrMenuItem());
1159             this.logicsMenu.add(this.getNotMenuItem());
1160         }
1161         return this.logicsMenu;
1162     }
1163 
1164     private JMenu getSymbolsMenu() {
1165         if (this.symbolsMenu == null) {
1166             this.symbolsMenu = new JMenu();
1167             this.symbolsMenu.setText(Messages
1168                     .getString("MathViewer.SymbolsMenu")); //$NON-NLS-1$
1169             this.symbolsMenu.add(this.getForAllMenuItem());
1170             this.symbolsMenu.add(this.getExistsMenuItem());
1171         }
1172         return this.symbolsMenu;
1173     }
1174 
1175     private JMenu getInsertMenu() {
1176         if (this.insertMenu == null) {
1177             this.insertMenu = new JMenu();
1178             this.insertMenu
1179                     .setText(Messages.getString("MathViewer.InsertMenu")); //$NON-NLS-1$
1180             this.insertMenu.add(this.getTableMenuItem());
1181             this.insertMenu.add(this.getPolynomMenuItem());
1182             this.insertMenu.add(this.getGreekMenu());
1183             this.insertMenu.add(this.getLogicsMenu());
1184             this.insertMenu.add(this.getSymbolsMenu());
1185         }
1186         return this.insertMenu;
1187     }
1188 
1189     private JPopupMenu getContextPopupMenu() {
1190         if (this.contextPopupMenu == null) {
1191             this.contextPopupMenu = new JPopupMenu();
1192             this.contextPopupMenu.add(this.getCRefreshMenuItem());
1193             this.contextPopupMenu.add(this.getInsertMenu());
1194         }
1195         return this.contextPopupMenu;
1196     }
1197 
1198     private void insertMacro(final String macroText) {
1199         final int pos = this.getXMLEditor().getCaretPosition();
1200         String s1 = this.getXMLEditor().getText().substring(0, pos);
1201         final String s2 = this.getXMLEditor().getText().substring(pos);
1202         s1 += macroText + s2;
1203         this.getXMLEditor().setText(s1);
1204         this.updateFromTextArea();
1205     }
1206 }