package de.unisiegen.gtitool.ui.logic; import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.Stack; import java.util.TreeSet; import javax.imageio.ImageIO; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.ListSelectionModel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.EventListenerList; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import org.jgraph.event.GraphSelectionEvent; import org.jgraph.event.GraphSelectionListener; import org.jgraph.graph.GraphSelectionModel; import de.unisiegen.gtitool.core.entities.Alphabet; import de.unisiegen.gtitool.core.entities.DefaultRegexAlphabet; import de.unisiegen.gtitool.core.entities.Symbol; import de.unisiegen.gtitool.core.entities.listener.ModifyStatusChangedListener; import de.unisiegen.gtitool.core.entities.regex.LeafNode; import de.unisiegen.gtitool.core.entities.regex.RegexNode; import de.unisiegen.gtitool.core.exceptions.RegexException; import de.unisiegen.gtitool.core.exceptions.RegexParseException; import de.unisiegen.gtitool.core.exceptions.RegexValidationException; import de.unisiegen.gtitool.core.exceptions.CoreException.ErrorType; import de.unisiegen.gtitool.core.exceptions.alphabet.AlphabetException; import de.unisiegen.gtitool.core.exceptions.grammar.GrammarException; import de.unisiegen.gtitool.core.machines.Machine.MachineType; import de.unisiegen.gtitool.core.preferences.listener.ColorChangedAdapter; import de.unisiegen.gtitool.core.preferences.listener.LanguageChangedListener; import de.unisiegen.gtitool.core.regex.DefaultRegex; import de.unisiegen.gtitool.core.regex.DefaultRegex.RegexType; import de.unisiegen.gtitool.core.storage.Modifyable; import de.unisiegen.gtitool.core.storage.exceptions.StoreException; import de.unisiegen.gtitool.core.util.ObjectPair; import de.unisiegen.gtitool.ui.convert.Converter; import de.unisiegen.gtitool.ui.i18n.Messages; import de.unisiegen.gtitool.ui.jgraph.DefaultNodeView; import de.unisiegen.gtitool.ui.jgraph.JGTIGraph; import de.unisiegen.gtitool.ui.latex.LatexExporter; import de.unisiegen.gtitool.ui.logic.MainWindow.ButtonState; import de.unisiegen.gtitool.ui.logic.interfaces.EditorPanel; import de.unisiegen.gtitool.ui.logic.interfaces.LogicClass; import de.unisiegen.gtitool.ui.model.ConsoleColumnModel; import de.unisiegen.gtitool.ui.model.DefaultModel; import de.unisiegen.gtitool.ui.model.DefaultRegexModel; import de.unisiegen.gtitool.ui.model.RegexConsoleTableModel; import de.unisiegen.gtitool.ui.netbeans.MainWindowForm; import de.unisiegen.gtitool.ui.netbeans.RegexPanelForm; import de.unisiegen.gtitool.ui.preferences.PreferenceManager; import de.unisiegen.gtitool.ui.redoundo.RegexUndoItem; import de.unisiegen.gtitool.ui.storage.Storage; import de.unisiegen.gtitool.ui.style.listener.ParseableChangedListener; /** * @author Simon Meurer */ public final class RegexPanel implements LogicClass < RegexPanelForm >, EditorPanel { /** * A {@link DocumentListener} for RegexTexts. */ public class TextDocumentListener implements DocumentListener { /** * {@inheritDoc} * * @see DocumentListener#changedUpdate(DocumentEvent) */ public void changedUpdate ( @SuppressWarnings ( "unused" ) DocumentEvent e ) { // Nothing to do here. } /** * {@inheritDoc} * * @see DocumentListener#insertUpdate(DocumentEvent) */ public void insertUpdate ( DocumentEvent arg0 ) { try { getUndohistory ().push ( new RegexUndoItem ( getCurrentContent () ) ); getRedohistory ().clear (); setCurrentContent ( arg0.getDocument ().getText ( 0, arg0.getDocument ().getLength () ) ); } catch ( BadLocationException e ) { e.printStackTrace (); System.exit ( 1 ); } updateRedoUndoButtons (); } /** * {@inheritDoc} * * @see DocumentListener#removeUpdate(DocumentEvent) */ public void removeUpdate ( DocumentEvent arg0 ) { try { getUndohistory ().push ( new RegexUndoItem ( getCurrentContent () ) ); getRedohistory ().clear (); setCurrentContent ( arg0.getDocument ().getText ( 0, arg0.getDocument ().getLength () ) ); } catch ( BadLocationException e ) { e.printStackTrace (); System.exit ( 1 ); } updateRedoUndoButtons (); } } /** * The current Regex String. */ private String currentContent = ""; //$NON-NLS-1$ /** * The {@link TextDocumentListener} */ private TextDocumentListener docListener = new TextDocumentListener (); /** * The {@link RegexConsoleTableModel} for the error table. */ private RegexConsoleTableModel errorTableModel; /** * The {@link File} for this {@link RegexPanel}. */ private File file; /** * The {@link RegexPanelForm} */ private RegexPanelForm gui; /** * The {@link JGTIGraph} for this Panel */ private JGTIGraph jGTIGraph; /** * The {@link EventListenerList}. */ private EventListenerList listenerList = new EventListenerList (); /** * The {@link MainWindowForm} */ private MainWindowForm mainWindowForm; /** * The {@link DefaultRegexModel}. */ private DefaultRegexModel model; /** * The name of this {@link GrammarPanel}. */ private String name = null; /** * The redo history implemented as a {@link Stack} */ private Stack < RegexUndoItem > redohistory = new Stack < RegexUndoItem > (); /** * The undo history implemented as a {@link Stack} */ private Stack < RegexUndoItem > undohistory = new Stack < RegexUndoItem > (); /** * The {@link RegexConsoleTableModel} for the warning table. */ private RegexConsoleTableModel warningTableModel; /** * Allocates a new {@link RegexPanel} * * @param mainWindowForm The {@link MainWindowForm} * @param file The {@link File} * @param model The {@link DefaultRegexModel} */ public RegexPanel ( MainWindowForm mainWindowForm, DefaultRegexModel model, File file ) { this.mainWindowForm = mainWindowForm; this.file = file; this.model = model; this.gui = new RegexPanelForm ( this ); if ( this.model.getRegex ().getRegexNode () != null ) { this.gui.styledRegexParserPanel.setText ( this.model.getRegex () .getRegexString () ); } else { this.gui.styledRegexParserPanel.setText ( this.model .getInitialRegexString () ); } this.gui.jGTIPanelInfo.setVisible ( this.mainWindowForm .getJCheckBoxMenuItemRegexInfo ().getState () ); if ( getRegex ().getRegexNode () != null ) { getRegex ().getRegexNode ().setShowPositions ( this.gui.jGTIPanelInfo.isVisible () ); } initializeJGraph (); setVisibleConsole ( this.mainWindowForm.getJCheckBoxMenuItemConsole () .getState () ); this.gui.jGTISplitPaneConsole.setDividerLocation ( 0.5 ); this.gui.styledRegexParserPanel.setAlphabet ( model.getRegex () .getAlphabet () ); PreferenceManager.getInstance ().addLanguageChangedListener ( this ); PreferenceManager.getInstance ().addColorChangedListener ( new ColorChangedAdapter () { /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexComment(java.awt.Color) */ @Override public void colorChangedRegexComment ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().styledRegexParserPanel.repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexMarkedNode(java.awt.Color) */ @Override public void colorChangedRegexMarkedNode ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexPosition(java.awt.Color) */ @Override public void colorChangedRegexPosition ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexSelectedNode(java.awt.Color) */ @Override public void colorChangedRegexSelectedNode ( @SuppressWarnings ( "unused" ) Color newColor ) { getJGTIGraph ().repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexSymbol(java.awt.Color) */ @Override public void colorChangedRegexSymbol ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexToken(java.awt.Color) */ @Override public void colorChangedRegexToken ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().repaint (); } /** * {@inheritDoc} * * @see ColorChangedAdapter#colorChangedRegexToolTip(java.awt.Color) */ @Override public void colorChangedRegexToolTip ( @SuppressWarnings ( "unused" ) Color newColor ) { getGUI ().repaint (); } } ); this.gui.styledRegexParserPanel .addParseableChangedListener ( new ParseableChangedListener < RegexNode > () { /** * {@inheritDoc} * * @see ParseableChangedListener#parseableChanged(de.unisiegen.gtitool.core.entities.Entity) */ public void parseableChanged ( RegexNode newEntity ) { changeRegex ( newEntity ); } } ); initialize (); if ( model.getRegex ().getRegexNode () != null ) { this.currentContent = model.getRegex ().getRegexString (); try { validate (); changeRegex ( model.getRegex ().getRegexNode () ); } catch ( RegexValidationException exc ) { boolean ok = true; for ( RegexException e : exc.getRegexException () ) { if ( e.getType ().equals ( ErrorType.ERROR ) ) { ok = false; break; } } if ( ok ) { changeRegex ( model.getRegex ().getRegexNode () ); } } } this.gui.styledRegexParserPanel.getDocument ().addDocumentListener ( this.docListener ); } /** * Add a new Error * * @param regexException The {@link GrammarException} containing the data */ public final void addError ( RegexException regexException ) { this.errorTableModel.addRow ( regexException ); } /** * {@inheritDoc} * * @see Modifyable#addModifyStatusChangedListener(ModifyStatusChangedListener) */ public final void addModifyStatusChangedListener ( ModifyStatusChangedListener listener ) { this.listenerList.add ( ModifyStatusChangedListener.class, listener ); } /** * Adds a {@link RegexUndoItem} * * @param item The {@link RegexUndoItem} */ public void addUndoItem ( RegexUndoItem item ) { this.undohistory.add ( item ); } /** * Add a new Error * * @param regexException The {@link GrammarException} containing the data */ public final void addWarning ( RegexException regexException ) { this.warningTableModel.addRow ( regexException ); } /** * Changes the Regex * * @param newRegexNode The new {@link RegexNode} */ public void changeRegex ( RegexNode newRegexNode ) { if ( newRegexNode != null ) { this.model.changeRegexNode ( newRegexNode, this.gui.styledRegexParserPanel.getText () ); if ( !newRegexNode.isInCoreSyntax () ) { getMainWindow ().addButtonState ( ButtonState.ENABLED_TO_CORE_SYNTAX ); } else { getMainWindow () .removeButtonState ( ButtonState.ENABLED_TO_CORE_SYNTAX ); } getMainWindow ().addButtonState ( ButtonState.ENABLED_PRINT ); getMainWindow ().addButtonState ( ButtonState.ENABLED_EXPORT_PICTURE ); getMainWindow ().addButtonState ( ButtonState.ENABLED_TO_LATEX ); getMainWindow ().addButtonState ( ButtonState.ENABLED_CONVERT_TO ); getMainWindow ().addButtonState ( ButtonState.ENABLED_CONVERT_TO_SOURCE_REGEX ); if ( this.model.getRegex ().getRegexNode () != null ) { this.model.getRegex ().getRegexNode ().setShowPositions ( this.gui.jGTIPanelInfo.isVisible () ); } initializeJGraph (); this.gui.jGTIScrollPaneGraph.setViewportView ( this.jGTIGraph ); this.model.createTree (); updateRegexNodeInfo (); } else { initializeJGraph (); this.gui.jGTIScrollPaneGraph.setViewportView ( this.jGTIGraph ); getMainWindow ().removeButtonState ( ButtonState.ENABLED_CONVERT_TO ); getMainWindow ().removeButtonState ( ButtonState.ENABLED_PRINT ); getMainWindow ().removeButtonState ( ButtonState.ENABLED_EXPORT_PICTURE ); getMainWindow ().removeButtonState ( ButtonState.ENABLED_TO_LATEX ); getMainWindow ().removeButtonState ( ButtonState.ENABLED_TO_CORE_SYNTAX ); } fireModifyStatusChanged ( false ); } /** * {@inheritDoc} * * @see EditorPanel#clearValidationMessages() */ public void clearValidationMessages () { this.gui.jGTITabbedPaneConsole.setTitleAt ( 0, Messages .getString ( "RegexPanel.Error" ) ); //$NON-NLS-1$ this.gui.jGTITabbedPaneConsole.setTitleAt ( 1, Messages .getString ( "RegexPanel.Warning" ) ); //$NON-NLS-1$ this.errorTableModel.clearData (); this.warningTableModel.clearData (); } /** * Let the listeners know that the modify status has changed. * * @param forceModify True if the modify is forced, otherwise false. */ public final void fireModifyStatusChanged ( boolean forceModify ) { clearValidationMessages (); ModifyStatusChangedListener [] listeners = this.listenerList .getListeners ( ModifyStatusChangedListener.class ); if ( forceModify ) { for ( ModifyStatusChangedListener current : listeners ) { current.modifyStatusChanged ( true ); } } else { boolean newModifyStatus = isModified (); for ( ModifyStatusChangedListener current : listeners ) { current.modifyStatusChanged ( newModifyStatus ); } } } /** * {@inheritDoc} * * @see EditorPanel#getConverter() */ public Converter getConverter () { return new ConvertRegexToMachineDialog ( this.mainWindowForm, this ); } /** * Returns the currentContent. * * @return The currentContent. * @see #currentContent */ public String getCurrentContent () { return this.currentContent; } /** * {@inheritDoc} * * @see EditorPanel#getFile() */ public File getFile () { return this.file; } /** * {@inheritDoc} * * @see EditorPanel#getFileEnding() */ public String getFileEnding () { return "." + RegexType.REGEX.getFileEnding (); //$NON-NLS-1$ } /** * {@inheritDoc} * * @see LogicClass#getGUI() */ public RegexPanelForm getGUI () { return this.gui; } /** * Returns the jGTIGraph. * * @return The jGTIGraph. * @see #jGTIGraph */ public JGTIGraph getJGTIGraph () { return this.jGTIGraph; } /** * {@inheritDoc} * * @see EditorPanel#getJTabbedPaneConsole() */ public JTabbedPane getJTabbedPaneConsole () { return this.gui.jGTITabbedPaneConsole; } /** * Returns the {@link MainWindow}. * * @return The {@link MainWindow}. * @see #mainWindowForm */ public final MainWindow getMainWindow () { return this.mainWindowForm.getLogic (); } /** * Returns the mainWindowForm. * * @return The mainWindowForm. * @see #mainWindowForm */ public MainWindowForm getMainWindowForm () { return this.mainWindowForm; } /** * Returns the {@link DefaultModel}. * * @return The {@link DefaultModel}. * @see #model */ public DefaultModel getModel () { return this.model; } /** * {@inheritDoc} * * @see EditorPanel#getName() */ public final String getName () { return this.file == null ? this.name : this.file.getName (); } /** * {@inheritDoc} * * @see EditorPanel#getPanel() */ public JPanel getPanel () { return this.gui; } /** * Returns the redohistory. * * @return The redohistory. * @see #redohistory */ public Stack < RegexUndoItem > getRedohistory () { return this.redohistory; } /** * Returns the regex. * * @return The regex. */ public DefaultRegex getRegex () { return this.model.getRegex (); } /** * Returns the undohistory. * * @return The undohistory. * @see #undohistory */ public Stack < RegexUndoItem > getUndohistory () { return this.undohistory; } /** * {@inheritDoc} * * @see EditorPanel#handleExchange() */ public void handleExchange () { this.model.setActualRegexString ( this.gui.styledRegexParserPanel .getText () ); ExchangeDialog exchangeDialog = new ExchangeDialog ( this.mainWindowForm .getLogic (), this.model.getElement (), this.file ); exchangeDialog.show (); } /** * Handles the export picture event. */ public final void handleExportPicture () { FileFilter fileFilter = new FileFilter () { @Override public boolean accept ( File acceptedFile ) { if ( acceptedFile.isDirectory () ) { return true; } if ( acceptedFile.getName ().toLowerCase ().matches ( ".+\\.png" ) ) //$NON-NLS-1$ { return true; } return false; } @Override public String getDescription () { return Messages.getString ( "RegexPanel.ExportPicturePNG" ) //$NON-NLS-1$ + " (*.png)"; //$NON-NLS-1$ } }; SaveDialog saveDialog = new SaveDialog ( this.mainWindowForm, PreferenceManager.getInstance ().getWorkingPath (), fileFilter, fileFilter ); saveDialog.show (); if ( ( !saveDialog.isConfirmed () ) || ( saveDialog.getSelectedFile () == null ) ) { return; } if ( saveDialog.getSelectedFile ().exists () ) { ConfirmDialog confirmDialog = new ConfirmDialog ( this.mainWindowForm, Messages.getString ( "RegexPanel.FileExists", saveDialog //$NON-NLS-1$ .getSelectedFile ().getName () ), Messages .getString ( "RegexPanel.ExportPicture" ), true, false, true, //$NON-NLS-1$ false, false ); confirmDialog.show (); if ( confirmDialog.isNotConfirmed () ) { return; } } String filename = saveDialog.getSelectedFile ().toString ().toLowerCase () .matches ( ".+\\.png" ) ? saveDialog.getSelectedFile ().toString () //$NON-NLS-1$ : saveDialog.getSelectedFile ().toString () + ".png"; //$NON-NLS-1$ PreferenceManager.getInstance ().setWorkingPath ( saveDialog.getCurrentDirectory ().getAbsolutePath () ); Rectangle usedBounds = this.jGTIGraph.getUsedBounds (); int inset = 20; int width = usedBounds.width + 2 * inset; int height = usedBounds.height + 2 * inset; BufferedImage image = new BufferedImage ( width, height, BufferedImage.TYPE_INT_RGB ); Graphics graphics = image.getGraphics (); graphics.fillRect ( 0, 0, width, height ); this.jGTIGraph.paintAll ( graphics ); graphics.dispose (); try { ImageIO.write ( image, "PNG", new File ( filename ) ); //$NON-NLS-1$ } catch ( IOException exc ) { InfoDialog infoDialog = new InfoDialog ( this.mainWindowForm, Messages .getString ( "RegexPanel.ExportPictureError" ), Messages//$NON-NLS-1$ .getString ( "RegexPanel.ExportPictureErrorTitle" ) );//$NON-NLS-1$ infoDialog.show (); } } /** * {@inheritDoc} * * @see EditorPanel#handleRedo() */ public void handleRedo () { if ( isRedoAble () ) { performRedo (); this.gui.repaint (); updateRedoUndoButtons (); } } /** * {@inheritDoc} * * @see EditorPanel#handleSave() */ public File handleSave () { if ( this.file == null ) { return handleSaveAs (); } try { this.model.setActualRegexString ( this.gui.styledRegexParserPanel .getText () ); Storage.getInstance ().store ( this.model, this.file ); } catch ( StoreException e ) { InfoDialog infoDialog = new InfoDialog ( this.mainWindowForm, e .getMessage (), Messages.getString ( "RegexPanel.Save" ) ); //$NON-NLS-1$ infoDialog.show (); } resetModify (); fireModifyStatusChanged ( false ); this.model.setInitialRegexString ( this.gui.styledRegexParserPanel .getText () ); return this.file; } /** * {@inheritDoc} * * @see EditorPanel#handleSaveAs() */ public File handleSaveAs () { try { FileFilter fileFilter = new FileFilter () { @Override public boolean accept ( File acceptedFile ) { if ( acceptedFile.isDirectory () ) { return true; } if ( acceptedFile.getName ().toLowerCase ().matches ( ".+\\." //$NON-NLS-1$ + RegexType.REGEX.getFileEnding () ) ) { return true; } return false; } @Override public String getDescription () { return Messages.getString ( "NewDialog." //$NON-NLS-1$ + RegexType.REGEX.toString () ) + " (*." //$NON-NLS-1$ + RegexType.REGEX.getFileEnding () + ")"; //$NON-NLS-1$ } }; SaveDialog saveDialog = new SaveDialog ( this.mainWindowForm, PreferenceManager.getInstance ().getWorkingPath (), fileFilter, fileFilter ); saveDialog.show (); if ( ( !saveDialog.isConfirmed () ) || ( saveDialog.getSelectedFile () == null ) ) { return null; } if ( saveDialog.getSelectedFile ().exists () ) { ConfirmDialog confirmDialog = new ConfirmDialog ( this.mainWindowForm, Messages.getString ( "RegexPanel.FileExists", saveDialog.getSelectedFile () //$NON-NLS-1$ .getName () ), Messages.getString ( "RegexPanel.Save" ), //$NON-NLS-1$ true, false, true, false, false ); confirmDialog.show (); if ( confirmDialog.isNotConfirmed () ) { return null; } } String filename = saveDialog.getSelectedFile ().toString ().matches ( ".+\\." + RegexType.REGEX.getFileEnding () ) ? saveDialog //$NON-NLS-1$ .getSelectedFile ().toString () : saveDialog.getSelectedFile () .toString () + "." + RegexType.REGEX.getFileEnding (); //$NON-NLS-1$ this.model.setActualRegexString ( this.gui.styledRegexParserPanel .getText () ); Storage.getInstance ().store ( this.model, new File ( filename ) ); PreferenceManager.getInstance ().setWorkingPath ( saveDialog.getCurrentDirectory ().getAbsolutePath () ); this.file = new File ( filename ); } catch ( StoreException e ) { InfoDialog infoDialog = new InfoDialog ( this.mainWindowForm, e .getMessage (), Messages.getString ( "RegexPanel.Save" ) ); //$NON-NLS-1$ infoDialog.show (); } resetModify (); fireModifyStatusChanged ( false ); this.model.setInitialRegexString ( this.gui.styledRegexParserPanel .getText () ); return this.file; } /** * Handles the to Core Syntax */ public void handleToCoreSyntaxButtonClicked () { if ( this.errorTableModel.getRowCount () == 0 ) { DefaultRegex newRegex = new DefaultRegex ( this.model.getRegex () .getAlphabet () ); newRegex.setRegexNode ( this.model.getRegex ().getRegexNode () .toCoreSyntax ( true ), this.model.getRegex ().getRegexNode () .toCoreSyntax ( true ).toPrettyString ().toString () ); getMainWindow ().handleNew ( new DefaultRegexModel ( newRegex ) ); } } /** * Handle the DFA button clicked * * @param evt Unused */ public void handleToDFAButton ( @SuppressWarnings ( "unused" ) ActionEvent evt ) { if ( this.errorTableModel.getRowCount () == 0 ) { ConvertRegexToMachineDialog converter = new ConvertRegexToMachineDialog ( this.mainWindowForm, this ); converter.convert ( RegexType.REGEX, MachineType.DFA, false, false ); } } /** * Handles Click on the toLatexButton */ public void handleToLatexButtonClicked () { if ( this.errorTableModel.getRowCount () == 0 ) { FileFilter ff = new FileFilter () { @Override public boolean accept ( File acceptedFile ) { if ( acceptedFile.isDirectory () ) { return true; } if ( acceptedFile.getName ().toLowerCase ().matches ( ".+\\." //$NON-NLS-1$ + "tex" ) ) //$NON-NLS-1$ { return true; } return false; } @Override public String getDescription () { return Messages.getString ( "Latex.FileDescription" ) //$NON-NLS-1$ + " (*.tex)"; //$NON-NLS-1$ } }; SaveDialog sd = new SaveDialog ( getMainWindowForm (), PreferenceManager .getInstance ().getWorkingPath (), ff, ff ); sd.show (); if ( sd.getSelectedFile () != null ) { String filename = sd.getSelectedFile ().toString ().matches ( ".+\\.tex" ) ? sd //$NON-NLS-1$ .getSelectedFile ().toString () : sd.getSelectedFile ().toString () + ".tex"; //$NON-NLS-1$ LatexExporter.buildLatexFile ( this.model.toLatexString (), new File ( filename ) ); } } } /** * Handles the Click on the NFA Button * * @param evt */ public void handleToNFAButton ( @SuppressWarnings ( "unused" ) ActionEvent evt ) { if ( this.errorTableModel.getRowCount () == 0 ) { ConvertRegexToMachineDialog converter = new ConvertRegexToMachineDialog ( this.mainWindowForm, this ); converter.convert ( RegexType.REGEX, MachineType.ENFA, false, false ); } } /** * {@inheritDoc} * * @see EditorPanel#handleToolbarEditDocument() */ public void handleToolbarEditDocument () { AlphabetDialog alphabetDialog = new AlphabetDialog ( this.mainWindowForm, this, getRegex () ); alphabetDialog.show (); initializeAlphabet (); } /** * {@inheritDoc} * * @see EditorPanel#handleUndo() */ public void handleUndo () { if ( isUndoAble () ) { performUndo (); this.gui.repaint (); updateRedoUndoButtons (); } } /** * Initialize */ private void initialize () { this.errorTableModel = new RegexConsoleTableModel (); this.warningTableModel = new RegexConsoleTableModel (); this.gui.jGTITableWarnings.setModel ( this.warningTableModel ); this.gui.jGTITableWarnings.setColumnModel ( new ConsoleColumnModel () ); this.gui.jGTITableWarnings.getTableHeader ().setReorderingAllowed ( false ); this.gui.jGTITableErrors.setModel ( this.errorTableModel ); this.gui.jGTITableErrors.setColumnModel ( new ConsoleColumnModel () ); this.gui.jGTITableErrors.getTableHeader ().setReorderingAllowed ( false ); initializeAlphabet (); initializeSecondView (); this.gui.jGTITableWarnings .setSelectionMode ( ListSelectionModel.SINGLE_SELECTION ); this.gui.jGTITableWarnings.getSelectionModel ().addListSelectionListener ( new ListSelectionListener () { public void valueChanged ( @SuppressWarnings ( "unused" ) ListSelectionEvent event ) { // Nothing to do here } } ); this.gui.jGTIScrollPaneGraph.setViewportView ( this.jGTIGraph ); } /** * Initializes the Alphabet */ public void initializeAlphabet () { this.gui.styledRegexParserPanel.parse (); this.gui.styledRegexAlphabetParserPanel.setText ( this.model.getRegex () .getAlphabet ().toClassPrettyString () ); } /** * Initializes the JGraph */ public void initializeJGraph () { this.model.initializeGraph (); this.jGTIGraph = this.model.getJGTIGraph (); this.jGTIGraph.setMoveable ( false ); this.jGTIGraph.getSelectionModel ().setSelectionMode ( GraphSelectionModel.SINGLE_GRAPH_SELECTION ); this.jGTIGraph.addGraphSelectionListener ( new GraphSelectionListener () { /** * @see org.jgraph.event.GraphSelectionListener#valueChanged(org.jgraph.event.GraphSelectionEvent) */ public void valueChanged ( @SuppressWarnings ( "unused" ) GraphSelectionEvent e ) { updateRegexNodeInfo (); } } ); } /** * Initializes the second view . */ private final void initializeSecondView () { MouseListener mouseListener = new MouseAdapter () { @SuppressWarnings ( "synthetic-access" ) @Override public void mouseReleased ( MouseEvent event ) { RegexPanel.this.mainWindowForm.getLogic () .handleSecondViewMouseReleased ( event ); } }; MouseMotionListener mouseMotionListener = new MouseMotionAdapter () { @SuppressWarnings ( "synthetic-access" ) @Override public void mouseDragged ( MouseEvent event ) { RegexPanel.this.mainWindowForm.getLogic () .handleSecondViewMouseReleased ( event ); } }; this.jGTIGraph.addMouseListener ( mouseListener ); this.jGTIGraph.addMouseMotionListener ( mouseMotionListener ); this.gui.jGTIScrollPaneGraph.getHorizontalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneGraph.getVerticalScrollBar ().addMouseListener ( mouseListener ); this.gui.styledRegexAlphabetParserPanel.addMouseListener ( mouseListener ); this.gui.styledRegexParserPanel.addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jGTITextAreaFirstpos .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jGTITextAreaFollowpos .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jGTITextAreaLastpos .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jGTITextAreaNullable .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneFirstpos.getHorizontalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneFirstpos.getVerticalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneFollowpos.getHorizontalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneFollowpos.getVerticalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneLastpos.getHorizontalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneLastpos.getVerticalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneNullable.getHorizontalScrollBar () .addMouseListener ( mouseListener ); this.gui.regexNodeInfoPanel.jScrollPaneNullable.getVerticalScrollBar () .addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneNodeInfo.getHorizontalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneNodeInfo.getVerticalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTITabbedPaneConsole.addMouseListener ( mouseListener ); this.gui.jGTITableErrors.addMouseListener ( mouseListener ); this.gui.jGTITableErrors.getTableHeader () .addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneErrors.getHorizontalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneErrors.getVerticalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTITableWarnings.addMouseListener ( mouseListener ); this.gui.jGTITableWarnings.getTableHeader ().addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneWarnings.getHorizontalScrollBar ().addMouseListener ( mouseListener ); this.gui.jGTIScrollPaneWarnings.getVerticalScrollBar ().addMouseListener ( mouseListener ); } /** * {@inheritDoc} * * @see Modifyable#isModified() */ public boolean isModified () { if ( this.model.getInitialRegexString () == null ) { return true; } return !this.model.getInitialRegexString ().equals ( this.gui.styledRegexParserPanel.getText () ) || this.model.getRegex ().getAlphabet ().isModified () || ( this.file == null ); } /** * {@inheritDoc} * * @see EditorPanel#isRedoAble() */ public boolean isRedoAble () { return !this.redohistory.isEmpty (); } /** * {@inheritDoc} * * @see EditorPanel#isUndoAble() */ public boolean isUndoAble () { return !this.undohistory.isEmpty (); } /** * {@inheritDoc} * * @see LanguageChangedListener#languageChanged() */ public void languageChanged () { this.gui.jGTITabbedPaneConsole.setTitleAt ( 0, Messages .getString ( "RegexPanel.Error" ) ); //$NON-NLS-1$ this.gui.jGTITabbedPaneConsole.setTitleAt ( 1, Messages .getString ( "RegexPanel.Warning" ) ); //$NON-NLS-1$ this.gui.jGTILabelAlphabet.setText ( Messages .getString ( "RegexPanel.AlphabetTitle" ) ); //$NON-NLS-1$ this.gui.jGTILabelGraph.setText ( Messages .getString ( "RegexPanel.GraphTitle" ) ); //$NON-NLS-1$ this.gui.jGTILabelInfo.setText ( Messages .getString ( "RegexPanel.InformationTitle" ) ); //$NON-NLS-1$ this.gui.jGTILabelRegex.setText ( Messages .getString ( "RegexPanel.RegexTitle" ) ); //$NON-NLS-1$ } /** * Preforms the {@link Alphabet} change. * * @param oldAlphabet The old {@link Alphabet}. * @param newAlphabet The new {@link Alphabet}. */ public final void performAlphabetChange ( Alphabet oldAlphabet, Alphabet newAlphabet ) { TreeSet < Symbol > symbolsToAdd = new TreeSet < Symbol > (); TreeSet < Symbol > symbolsToRemove = new TreeSet < Symbol > (); for ( Symbol current : newAlphabet ) { if ( !oldAlphabet.contains ( current ) ) { symbolsToAdd.add ( current ); } } for ( Symbol current : oldAlphabet ) { if ( !newAlphabet.contains ( current ) ) { symbolsToRemove.add ( current ); } } try { oldAlphabet.add ( symbolsToAdd ); oldAlphabet.remove ( symbolsToRemove ); } catch ( AlphabetException exc ) { exc.printStackTrace (); System.exit ( 1 ); } fireModifyStatusChanged ( false ); } /** * Preforms the redo step */ private void performRedo () { try { Document document = this.gui.styledRegexParserPanel.getDocument (); document.removeDocumentListener ( this.docListener ); RegexUndoItem item = this.redohistory.peek (); if ( item.getRegexString () != null ) { this.undohistory.push ( new RegexUndoItem ( document.getText ( 0, document.getLength () ) ) ); document.remove ( 0, document.getLength () ); document.insertString ( 0, this.redohistory.pop ().getRegexString (), null ); } else { this.undohistory .push ( new RegexUndoItem ( new DefaultRegexAlphabet ( this.gui.styledRegexAlphabetParserPanel.getParsedObject () .get () ) ) ); DefaultRegexAlphabet a = this.redohistory.pop ().getLastAlphabet (); performAlphabetChange ( getRegex ().getAlphabet (), a ); this.gui.styledRegexAlphabetParserPanel.setText ( a ); } document.addDocumentListener ( this.docListener ); } catch ( BadLocationException e ) { e.printStackTrace (); System.exit ( 1 ); } catch ( AlphabetException exc ) { exc.printStackTrace (); } } /** * Performs the undo step */ private void performUndo () { try { Document document = this.gui.styledRegexParserPanel.getDocument (); document.removeDocumentListener ( this.docListener ); String doctext = document.getText ( 0, document.getLength () ); RegexUndoItem item = this.undohistory.peek (); if ( item.getRegexString () != null ) { String historytext = this.undohistory.pop ().getRegexString (); document.remove ( 0, document.getLength () ); document.insertString ( 0, historytext, null ); this.redohistory.add ( new RegexUndoItem ( doctext ) ); this.currentContent = historytext; } else { DefaultRegexAlphabet a = this.undohistory.pop ().getLastAlphabet (); this.redohistory .add ( new RegexUndoItem ( new DefaultRegexAlphabet ( this.gui.styledRegexAlphabetParserPanel.getParsedObject () .get () ) ) ); performAlphabetChange ( getRegex ().getAlphabet (), a ); this.gui.styledRegexAlphabetParserPanel.setText ( a ); } document.addDocumentListener ( this.docListener ); } catch ( BadLocationException e ) { e.printStackTrace (); System.exit ( 1 ); } catch ( AlphabetException exc ) { exc.printStackTrace (); } } /** * {@inheritDoc} * * @see Modifyable#removeModifyStatusChangedListener(ModifyStatusChangedListener) */ public final void removeModifyStatusChangedListener ( ModifyStatusChangedListener listener ) { this.listenerList.remove ( ModifyStatusChangedListener.class, listener ); } /** * {@inheritDoc} * * @see Modifyable#resetModify() */ public void resetModify () { this.model.setInitialRegexString ( this.gui.styledRegexParserPanel .getText () ); this.model.getRegex ().getAlphabet ().resetModify (); } /** * Sets the currentContent. * * @param currentContent The currentContent to set. * @see #currentContent */ public void setCurrentContent ( String currentContent ) { this.currentContent = currentContent; } /** * {@inheritDoc} * * @see EditorPanel#setName(java.lang.String) */ public void setName ( String name ) { this.name = name; } /** * {@inheritDoc} * * @see EditorPanel#setVisibleConsole(boolean) */ public void setVisibleConsole ( boolean visible ) { if ( visible ) { this.gui.jGTISplitPaneConsole .setRightComponent ( this.gui.jGTITabbedPaneConsole ); this.gui.jGTISplitPaneConsole.setDividerSize ( 3 ); this.gui.jGTISplitPaneConsole.setDividerLocation ( this.mainWindowForm .getHeight () - 322 ); } else { this.gui.jGTISplitPaneConsole.setRightComponent ( null ); this.gui.jGTISplitPaneConsole.setDividerSize ( 0 ); } } /** * Updates the Redo and Undo button */ public void updateRedoUndoButtons () { if ( isUndoAble () ) { this.mainWindowForm.getLogic () .addButtonState ( ButtonState.ENABLED_UNDO ); } else { this.mainWindowForm.getLogic ().removeButtonState ( ButtonState.ENABLED_UNDO ); } if ( isRedoAble () ) { this.mainWindowForm.getLogic () .addButtonState ( ButtonState.ENABLED_REDO ); } else { this.mainWindowForm.getLogic ().removeButtonState ( ButtonState.ENABLED_REDO ); } } /** * Updates the RegexNode infos */ protected void updateRegexNodeInfo () { if ( this.jGTIGraph.getSelectionCell () instanceof DefaultNodeView ) { this.gui.regexNodeInfoPanel.jGTITextAreaNullable.setEnabled ( true ); this.gui.regexNodeInfoPanel.jGTITextAreaFirstpos.setEnabled ( true ); this.gui.regexNodeInfoPanel.jGTITextAreaLastpos.setEnabled ( true ); this.gui.regexNodeInfoPanel.jGTITextAreaFollowpos.setEnabled ( true ); RegexNode node = ( ( DefaultNodeView ) this.jGTIGraph.getSelectionCell () ) .getNode (); this.gui.regexNodeInfoPanel.jGTITextAreaNullable.setText ( String .valueOf ( node.nullable () ) ); String firstpos = "{"; //$NON-NLS-1$ for ( LeafNode n : node.firstPos () ) { firstpos += n.getPosition (); if ( node.firstPos ().indexOf ( n ) != node.firstPos ().size () - 1 ) { firstpos += "; "; //$NON-NLS-1$ } } firstpos += "}"; //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaFirstpos.setText ( firstpos ); String lastpos = "{"; //$NON-NLS-1$ for ( LeafNode n : node.lastPos () ) { lastpos += n.getPosition (); if ( node.lastPos ().indexOf ( n ) != node.lastPos ().size () - 1 ) { lastpos += "; "; //$NON-NLS-1$ } } lastpos += "}"; //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaLastpos.setText ( lastpos ); String followpos = "{"; //$NON-NLS-1$ boolean first = true; LinkedList < ObjectPair < LeafNode, LeafNode > > follow = new LinkedList < ObjectPair < LeafNode, LeafNode > > (); follow.addAll ( node.followPos () ); Collections.sort ( follow, new Comparator < ObjectPair < LeafNode, LeafNode > > () { /** * @see java.util.Comparator#compare(java.lang.Object, * java.lang.Object) */ public int compare ( ObjectPair < LeafNode, LeafNode > o1, ObjectPair < LeafNode, LeafNode > o2 ) { int p1 = o1.getFirst ().getPosition () - o2.getFirst ().getPosition (); if ( p1 != 0 ) { return p1; } return o1.getSecond ().getPosition () - o2.getSecond ().getPosition (); } } ); for ( ObjectPair < LeafNode, LeafNode > pair : follow ) { if ( !first ) { followpos += "; "; //$NON-NLS-1$ } followpos += "(" + pair.getFirst ().getPosition () + ", " //$NON-NLS-1$ //$NON-NLS-2$ + pair.getSecond ().getPosition () + ")"; //$NON-NLS-1$ first = false; } followpos += "}"; //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaFollowpos.setText ( followpos ); } else { this.gui.regexNodeInfoPanel.jGTITextAreaNullable.setText ( "" ); //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaFirstpos.setText ( "" ); //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaFollowpos.setText ( "" ); //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaLastpos.setText ( "" ); //$NON-NLS-1$ this.gui.regexNodeInfoPanel.jGTITextAreaNullable.setEnabled ( false ); this.gui.regexNodeInfoPanel.jGTITextAreaFirstpos.setEnabled ( false ); this.gui.regexNodeInfoPanel.jGTITextAreaLastpos.setEnabled ( false ); this.gui.regexNodeInfoPanel.jGTITextAreaFollowpos.setEnabled ( false ); } } /** * Validates the Panel * * @throws RegexValidationException When validation goes wrong */ public void validate () throws RegexValidationException { ArrayList < RegexException > list = new ArrayList < RegexException > (); if ( this.gui.styledRegexParserPanel.parse () == null ) { list.add ( new RegexParseException () ); } try { getRegex ().validate (); } catch ( RegexValidationException exc ) { list.addAll ( exc.getRegexException () ); } if ( !list.isEmpty () ) { throw new RegexValidationException ( list ); } } }