ParserPane.java
001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002  *
003  * Copyright 2000-2013,  Michael Meyling <mime@qedeq.org>.
004  *
005  * "Hilbert II" is free software; you can redistribute
006  * it and/or modify it under the terms of the GNU General Public
007  * License as published by the Free Software Foundation; either
008  * version 2 of the License, or (at your option) any later version.
009  *
010  * This program is distributed in the hope that it will be useful,
011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013  * GNU General Public License for more details.
014  */
015 
016 package org.qedeq.gui.se.pane;
017 
018 import java.awt.Color;
019 import java.awt.Container;
020 import java.awt.Font;
021 import java.awt.event.ActionEvent;
022 import java.awt.event.ActionListener;
023 import java.awt.event.ComponentAdapter;
024 import java.awt.event.ComponentEvent;
025 import java.awt.event.MouseAdapter;
026 import java.awt.event.MouseEvent;
027 import java.io.File;
028 import java.io.IOException;
029 import java.util.List;
030 
031 import javax.swing.AbstractAction;
032 import javax.swing.JFrame;
033 import javax.swing.JMenu;
034 import javax.swing.JMenuBar;
035 import javax.swing.JMenuItem;
036 import javax.swing.JOptionPane;
037 import javax.swing.JScrollPane;
038 import javax.swing.JSplitPane;
039 import javax.swing.JViewport;
040 import javax.xml.parsers.ParserConfigurationException;
041 
042 import org.qedeq.base.io.IoUtility;
043 import org.qedeq.base.io.ResourceLoaderUtility;
044 import org.qedeq.base.io.TextInput;
045 import org.qedeq.base.trace.Trace;
046 import org.qedeq.base.utility.StringUtility;
047 import org.qedeq.base.utility.YodaUtility;
048 import org.qedeq.gui.se.element.CPTextArea;
049 import org.qedeq.gui.se.util.GuiHelper;
050 import org.qedeq.kernel.bo.KernelContext;
051 import org.qedeq.kernel.bo.module.InternalKernelServices;
052 import org.qedeq.kernel.bo.module.ModuleLabels;
053 import org.qedeq.kernel.bo.parser.MathParser;
054 import org.qedeq.kernel.bo.parser.ParserException;
055 import org.qedeq.kernel.bo.parser.Term;
056 import org.qedeq.kernel.bo.service.Element2LatexImpl;
057 import org.qedeq.kernel.bo.service.Element2Utf8Impl;
058 import org.qedeq.kernel.se.base.list.Element;
059 import org.qedeq.kernel.se.common.SourceFileExceptionList;
060 import org.qedeq.kernel.xml.handler.parser.LoadXmlOperatorListUtility;
061 import org.qedeq.kernel.xml.parser.BasicParser;
062 import org.xml.sax.SAXException;
063 
064 
065 /**
066  * Transform formulas into  QEDEQ syntax formulas.
067  *
068  @author  Michael Meyling
069  */
070 public class ParserPane extends JFrame {
071 
072     /** This class. */
073     private static final Class CLASS = ParserPane.class;
074 
075     /** Source to parse. */
076     private CPTextArea source = new CPTextArea(true);
077 
078     /** Parse result. */
079     private CPTextArea resultField = new CPTextArea(false);
080 
081     /** Error messages. */
082     private CPTextArea error = new CPTextArea(false);
083 
084     /** Make source scrollable. */
085     private JScrollPane sourceScroller = new JScrollPane();
086 
087     /** Split between source and result. */
088     private JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
089 
090     /** Menu for copy and paste. */
091     private JMenuBar menu = new JMenuBar();
092 
093     /** List of {@link org.qedeq.kernel.parser.Operator}s. */
094     private final List operators;
095 
096     /** Error position within source file. */
097     private int errorPosition = -1;
098 
099     /** Split between previous split and error pane. */
100     private JSplitPane globalPane;
101 
102     /** File that contains operator definitions. */
103     private final File resourceFile;
104 
105     /** Use this parser. */
106     private final MathParser parser;
107 
108 
109     public ParserPane(final String name, final MathParser parser, final String title,
110             final String resourceName, final String samplethrows SourceFileExceptionList {
111         // LATER mime 20080131: hard coded window, change to FormLayout
112         super(title);
113         this.parser = parser;
114         source.setText(sample);
115         final String resourceDirectoryName = "config";
116         try {
117             resourceFile = ResourceLoaderUtility.getResourceFile(
118                 KernelContext.getInstance().getConfig().getBasisDirectory(), resourceDirectoryName,
119                 resourceName).getCanonicalFile();
120         catch (final IOException e) {     // should not occur
121             throw new RuntimeException(e);
122         }
123         // LATER mime 20100906: change name and loading mechanism (don't use source directory for file!!!)
124         try {
125             operators = LoadXmlOperatorListUtility.getOperatorList(
126                 (InternalKernelServicesYodaUtility.getFieldValue(KernelContext.getInstance()"services"),
127                 resourceFile);
128         catch (NoSuchFieldException e) {  // programming error
129             throw new RuntimeException(e);
130         }
131         setupView(name);
132         updateView();
133     }
134 
135     /**
136      * Assembles the GUI components of the panel.
137      *
138      @param   name    Name of transformation source.
139      */
140     private final void setupView(final String name) {
141         final Container pane = getContentPane();
142         source.setDragEnabled(true);
143         source.setFont(new Font("monospaced", Font.PLAIN, pane.getFont().getSize()));
144         source.setAutoscrolls(true);
145         source.setCaretPosition(0);
146         source.setEditable(true);
147         source.getCaret().setVisible(false);
148         source.setLineWrap(true);
149         source.setWrapStyleWord(true);
150         source.setFocusable(true);
151 
152         resultField.setFont(new Font("monospaced", Font.PLAIN, pane.getFont().getSize()));
153         resultField.setAutoscrolls(true);
154         resultField.setCaretPosition(0);
155         resultField.setEditable(false);
156         resultField.getCaret().setVisible(false);
157         resultField.setFocusable(true);
158         final JMenuItem item = new JMenuItem("Show as Text");
159         item.addActionListener(new ActionListener() {
160             public void actionPerformed(final ActionEvent e) {
161                 final String text = resultField.getText().trim();
162                 if (text.length() == 0) {
163                     return;
164                 }
165                 ModuleLabels labels = new ModuleLabels();
166                 Element2LatexImpl converter = new Element2LatexImpl(labels);
167                 Element2Utf8Impl textConverter = new Element2Utf8Impl(converter);
168                 Element[] elements = null;
169                 try {
170                     elements = BasicParser.createElements(text);
171                 catch (final ParserConfigurationException e1) {
172                     Trace.fatal(CLASS, "setupView$actionPerformed""Parser configuration error",
173                         e1);
174                     return;
175                 catch (final SAXException e1) {
176                     // ignore
177                     return;
178                 }
179                 final StringBuffer result = new StringBuffer();
180                 for (int i = 0; i < elements.length; i++) {
181                     final String[] parsed = textConverter.getUtf8(elements[i]120);
182                     for (int j = 0; j < parsed.length; j++) {
183                         result.append(parsed[j"\n");
184                     }
185                     result.append("\n");
186                 }
187                 final TextPaneWindow window = new TextPaneWindow("QEDEQ formulas as unicode text",
188                     GuiHelper.readImageIcon("oil/" + QedeqGuiConfig.getInstance().getIconSize()
189                     "/apps/education-mathematics.png"), result.toString());
190                 window.setVisible(true);
191             }
192         });
193         resultField.addMenuItem(item);
194 
195         error.setFont(new Font("monospaced", Font.PLAIN, pane.getFont().getSize()));
196         error.setForeground(Color.RED);
197         error.setAutoscrolls(true);
198         error.setCaretPosition(0);
199         error.setEditable(false);
200         error.getCaret().setVisible(false);
201         error.setFocusable(true);
202         error.addMouseListener(new MouseAdapter() {
203             public void mouseClicked(final MouseEvent e) {
204                 updateView();
205             }
206 
207         });
208 
209         final JViewport qedeqPort = sourceScroller.getViewport();
210         qedeqPort.add(source);
211 
212         final JScrollPane resultScroller = new JScrollPane();
213         final JViewport resultPort = resultScroller.getViewport();
214         resultPort.add(resultField);
215 
216         final JScrollPane errorScroller = new JScrollPane();
217         final JViewport errorPort = errorScroller.getViewport();
218         errorPort.add(error);
219 
220         splitPane.setTopComponent(sourceScroller);
221         splitPane.setBottomComponent(resultScroller);
222         splitPane.setResizeWeight(0);
223         splitPane.setOneTouchExpandable(true);
224 
225         error.setText("");
226 
227         globalPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
228         globalPane.setTopComponent(splitPane);
229         globalPane.setBottomComponent(errorScroller);
230         globalPane.setResizeWeight(1);
231         globalPane.setOneTouchExpandable(true);
232 
233         pane.add(globalPane);
234 
235         addComponentListener(new ComponentAdapter() {
236             public void componentHidden(final ComponentEvent e) {
237                 Trace.trace(CLASS, this, "componentHidden", e);
238             }
239             public void componentShown(final ComponentEvent e) {
240                 Trace.trace(CLASS, this, "componentShown", e);
241             }
242         });
243 
244         menu.removeAll();
245 
246 /*
247         final JMenu fileMenu = new JMenu("File");
248         fileMenu.setMnemonic('F');
249         {
250             final JMenuItem transform = new JMenuItem("Load");
251             transform.setMnemonic('L');
252             transform.addActionListener(new AbstractAction() {
253                 public final void actionPerformed(final ActionEvent action) {
254                 }
255             });
256             fileMenu.add(transform);
257         }
258         menu.add(fileMenu);
259         setJMenuBar(menu);
260 */
261         final JMenu transformMenu = new JMenu("Transform");
262         transformMenu.setMnemonic('T');
263         {
264             final JMenuItem transform = new JMenuItem(name + " to QEDEQ");
265             transform.setMnemonic('Q');
266             transform.addActionListener(new AbstractAction() {
267                 public final void actionPerformed(final ActionEvent action) {
268                     resultField.setText(printMath(source.getText()));
269                     updateView();
270                 }
271             });
272             transformMenu.add(transform);
273         }
274 //** LATER mime 20071230: add conversion from QEDEQ into LaTeX
275         /*
276         {
277             final JMenuItem transform = new JMenuItem("QEDEQ to LaTeX");
278             transform.setMnemonic('L');
279             transform.addActionListener(new AbstractAction() {
280                 public final void actionPerformed(final ActionEvent action) {
281                     La
282                     System.out.println(qedeq.getText());
283                     result.setText(printMath(qedeq.getText()));
284                     updateView();
285                 }
286             });
287             transformMenu.add(transform);
288         }
289 */
290         {
291             final JMenuItem doSwitch = new JMenuItem("switch content");
292             doSwitch.setMnemonic('S');
293             doSwitch.addActionListener(new AbstractAction() {
294                 public final void actionPerformed(final ActionEvent action) {
295                     final String text = source.getText();
296                     source.setText(resultField.getText());
297                     resultField.setText(text);
298                     updateView();
299                 }
300             });
301             transformMenu.add(doSwitch);
302         }
303         menu.add(transformMenu);
304 
305         final JMenu helpMenu = new JMenu("Help");
306         helpMenu.setMnemonic('H');
307         {
308             final JMenuItem about = new JMenuItem("About");
309             about.setMnemonic('A');
310             about.addActionListener(new AbstractAction() {
311                 public final void actionPerformed(final ActionEvent action) {
312                     JOptionPane.showMessageDialog(ParserPane.this,
313                         "This dialog enables to transform textual input into the QEDEQ format.\n"
314                         "The operators and their QEDEQ counterparts are defined int the file:\n"
315                         + resourceFile,
316                         "About", JOptionPane.INFORMATION_MESSAGE);
317                 }
318             });
319             helpMenu.add(about);
320         }
321         menu.add(helpMenu);
322 
323         setJMenuBar(menu);
324         setSize(500800);
325     }
326 
327     /**
328      * Set line wrap.
329      *
330      @param   wrap    Line wrap?
331      */
332     public void setLineWrap(final boolean wrap) {
333         source.setLineWrap(wrap);
334     }
335 
336     /**
337      * Get line wrap.
338      *
339      @return  Line wrap?
340      */
341     public boolean getLineWrap() {
342         return source.getLineWrap();
343     }
344 
345     /**
346      * Update from model.
347      */
348     public synchronized void updateView() {
349         final String method = "updateView()";
350         Trace.begin(CLASS, this, method);
351 
352         if (errorPosition >= 0) {
353             // reserve 3 text lines for error description
354             globalPane.setDividerLocation(globalPane.getHeight()
355                 - globalPane.getDividerSize()
356                 - error.getFontMetrics(error.getFont()).getHeight() 4);
357         else {
358             error.setText("");
359             globalPane.setDividerLocation(this.getHeight());
360         }
361         this.repaint();
362     }
363 
364 
365 
366 // not used any longer
367 /*
368     private final int findCaretPosition(final int i) {
369         if (i == 1) {
370             return 0;
371         }
372         final String s = qedeq.getText();
373         int j = 0;
374         int k = 0;
375         for (; j < s.length(); j++) {
376             if (s.charAt(j) == '\n') {
377                 k++;
378             }
379             if (k == i - 1) {
380                 return j + 1;
381             }
382         }
383         return 0;
384     }
385 */
386 
387     private String printMath(final String text)  {
388         final StringBuffer buffer = new StringBuffer(text);
389         final TextInput input = new TextInput(buffer);
390         parser.setParameters(input, operators);
391         final StringBuffer out = new StringBuffer();
392         errorPosition = -1;
393         try {
394             Term term = null;
395             do {
396                 term = parser.readTerm();
397                 if (term != null) {
398                     out.append(term.getQedeqXml()).append("\n");
399                     System.out.println(term.getQedeqXml());
400                 }
401             while (term != null || !parser.eof());
402         catch (ParserException e) {
403             e.printStackTrace(System.out);
404             final StringBuffer result = new StringBuffer();
405             errorPosition = input.getPosition();
406             result.append(input.getRow() ":" + input.getColumn() ":" "\n");
407             result.append(e.getMessage() "\n");
408             result.append(input.getLine().replace('\t'' ').replace('\015', ' '"\n");
409             final StringBuffer pointer = StringUtility.getSpaces(input.getColumn());
410             pointer.append('^');
411             result.append(pointer);
412             System.out.println(result.toString());
413             error.setText(result.toString());
414         catch (Exception e) {
415             e.printStackTrace(System.out);
416             final StringBuffer result = new StringBuffer();
417             errorPosition = input.getPosition();
418             result.append(input.getRow() ":" + input.getColumn() ":" "\n");
419             result.append(e.getMessage() "\n");
420             result.append(input.getLine().replace('\t'' ').replace('\015', ' '"\n");
421             final StringBuffer pointer = StringUtility.getSpaces(input.getColumn());
422             pointer.append('^');
423             result.append(pointer);
424             System.out.println(result.toString());
425             error.setText(result.toString());
426         }
427         IoUtility.close(input);  // to satisfy checkstyle
428         return out.toString();
429     }
430 
431 
432 
433 }