package de.unisiegen.gtitool.ui.logic; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import javax.swing.AbstractListModel; import javax.swing.JFrame; import javax.swing.ListModel; import de.unisiegen.gtitool.core.entities.DefaultProduction; import de.unisiegen.gtitool.core.entities.NonterminalSymbol; import de.unisiegen.gtitool.core.entities.NonterminalSymbolSet; import de.unisiegen.gtitool.core.entities.Production; import de.unisiegen.gtitool.core.entities.ProductionWord; import de.unisiegen.gtitool.core.entities.TerminalSymbolSet; import de.unisiegen.gtitool.core.parser.style.renderer.PrettyStringListCellRenderer; import de.unisiegen.gtitool.ui.logic.interfaces.LogicClass; import de.unisiegen.gtitool.ui.model.DefaultGrammarModel; import de.unisiegen.gtitool.ui.netbeans.ProductionDialogForm; import de.unisiegen.gtitool.ui.redoundo.ProductionChangedItem; import de.unisiegen.gtitool.ui.redoundo.RedoUndoHandler; import de.unisiegen.gtitool.ui.redoundo.RedoUndoItem; import de.unisiegen.gtitool.ui.style.listener.ParseableChangedListener; /** * The logic class for the create new production dialog. * * @author Benjamin Mies * @author Christian Fehler * @version $Id$ */ public final class ProductionDialog implements LogicClass < ProductionDialogForm > { /** * The nonterminal symbol {@link ListModel}. * * @author Benjamin Mies */ public final class SymbolListModel extends AbstractListModel implements Iterable < NonterminalSymbol > { /** * The serial version uid. */ private static final long serialVersionUID = -3937680826576568992L; /** * The item list. */ private ArrayList < NonterminalSymbol > list; /** * Allocates a new {@link SymbolListModel}. */ public SymbolListModel () { this.list = new ArrayList < NonterminalSymbol > (); } /** * Adds the given item. * * @param pItem The item to add. */ public final void add ( NonterminalSymbol pItem ) { this.list.add ( pItem ); Collections.sort ( this.list ); fireContentsChanged ( this, 0, this.list.size () - 1 ); } /** * Clears the model. */ public final void clear () { int size = this.list.size (); this.list.clear (); fireIntervalRemoved ( this, 0, size - 1 < 0 ? 0 : size - 1 ); } /** * Returns the value at the specified index. * * @param index The requested index. * @return The value at the specified index. * @see ListModel#getElementAt(int) */ public final Object getElementAt ( int index ) { if ( ( index < 0 ) || ( index >= this.list.size () ) ) { throw new IllegalArgumentException ( "index incorrect" ); //$NON-NLS-1$ } return this.list.get ( index ); } /** * Returns the list of {@link NonterminalSymbol}s. * * @return the list of {@link NonterminalSymbol}s. */ public ArrayList < NonterminalSymbol > getList () { return this.list; } /** * Returns the length of the list. * * @return The length of the list. * @see ListModel#getSize() */ public final int getSize () { return this.list.size (); } /** * {@inheritDoc} * * @see Iterable#iterator() */ public final Iterator < NonterminalSymbol > iterator () { return this.list.iterator (); } /** * Removes the item with the given index. * * @param index The item index. */ public final void remove ( int index ) { this.list.remove ( index ); fireIntervalRemoved ( this, index, index ); } /** * Removes the given item. * * @param pItem The item to remove. */ public final void remove ( NonterminalSymbol pItem ) { int index = this.list.indexOf ( pItem ); this.list.remove ( pItem ); fireIntervalRemoved ( this, index, index ); } } /** * The {@link ProductionDialogForm}. */ private ProductionDialogForm gui; /** * The parent frame. */ private JFrame parent; /** * The {@link SymbolListModel} for teh nonterminal symbols */ private SymbolListModel listModel = new SymbolListModel (); /** * The old production, if we are in configure mode. */ private Production oldProduction; /** * The {@link DefaultGrammarModel}. */ private DefaultGrammarModel model; /** * The {@link RedoUndoHandler}. */ private RedoUndoHandler redoUndoHandler; /** * Creates a new {@link ProductionDialog}. * * @param parent The parent frame. * @param nonterminalSymbolSet The {@link NonterminalSymbolSet}. * @param terminalSymbolSet The {@link TerminalSymbolSet}. * @param model The {@link DefaultGrammarModel}. * @param production The production to configure. * @param redoUndoHandler The {@link RedoUndoHandler}. */ public ProductionDialog ( JFrame parent, NonterminalSymbolSet nonterminalSymbolSet, TerminalSymbolSet terminalSymbolSet, DefaultGrammarModel model, Production production, RedoUndoHandler redoUndoHandler ) { this.parent = parent; this.gui = new ProductionDialogForm ( this, this.parent ); this.model = model; this.oldProduction = production; this.redoUndoHandler = redoUndoHandler; // Nonterminal this.gui.styledNonterminalSymbolSetParserPanel .setStartNonterminalSymbol ( model.getGrammar ().getStartSymbol () ); this.gui.styledNonterminalSymbolSetParserPanel .setText ( nonterminalSymbolSet ); // Terminal this.gui.styledTerminalSymbolSetParserPanel.setText ( terminalSymbolSet ); // ProductionWord this.gui.styledProductionWordParserPanel .setNonterminalSymbolSet ( nonterminalSymbolSet ); this.gui.styledProductionWordParserPanel .setTerminalSymbolSet ( terminalSymbolSet ); this.gui.styledProductionWordParserPanel.setStartNonterminalSymbol ( model .getGrammar ().getStartSymbol () ); // Production this.gui.styledProductionParserPanel .setNonterminalSymbolSet ( nonterminalSymbolSet ); this.gui.styledProductionParserPanel .setTerminalSymbolSet ( terminalSymbolSet ); this.gui.styledProductionParserPanel.setStartNonterminalSymbol ( model .getGrammar ().getStartSymbol () ); for ( NonterminalSymbol current : nonterminalSymbolSet ) { this.listModel.add ( current ); } this.gui.jGTIList.setModel ( this.listModel ); this.gui.jGTIList.setSelectedIndex ( 0 ); this.gui.styledProductionWordParserPanel .addParseableChangedListener ( new ParseableChangedListener < ProductionWord > () { public void parseableChanged ( ProductionWord newProductionWord ) { if ( newProductionWord == null ) { setButtonStatus ( false ); getGui ().styledProductionParserPanel.setText ( null ); } else { setButtonStatus ( true ); getGui ().styledProductionParserPanel .setText ( new DefaultProduction ( ( NonterminalSymbol ) getGui ().jGTIList .getSelectedValue (), newProductionWord ) ); } } } ); if ( this.oldProduction != null ) { this.gui.styledProductionWordParserPanel.setText ( this.oldProduction .getProductionWord () ); for ( NonterminalSymbol current : this.listModel.getList () ) { if ( current.equals ( this.oldProduction.getNonterminalSymbol () ) ) { this.gui.jGTIList.setSelectedIndex ( this.listModel.getList () .indexOf ( current ) ); } } } this.gui.jGTIButtonOk.setEnabled ( this.oldProduction != null ); this.gui.styledProductionWordParserPanel.parse (); ProductionWord productionWord = this.gui.styledProductionWordParserPanel .getParsedObject (); if ( productionWord == null ) { setButtonStatus ( false ); getGui ().styledProductionParserPanel.setText ( null ); } else { setButtonStatus ( true ); getGui ().styledProductionParserPanel.setText ( new DefaultProduction ( ( NonterminalSymbol ) getGui ().jGTIList.getSelectedValue (), productionWord ) ); } this.gui.jGTIList.setCellRenderer ( new PrettyStringListCellRenderer () ); } /** * Returns the {@link ProductionDialogForm}. * * @return the {@link ProductionDialogForm}. */ public final ProductionDialogForm getGui () { return this.gui; } /** * {@inheritDoc} * * @see LogicClass#getGUI() */ public final ProductionDialogForm getGUI () { return this.gui; } /** * Handles dialog canceled. */ public final void handleCancel () { this.gui.dispose (); } /** * Handles list selected value changed. */ public final void handleListSelectionChanged () { this.gui.styledProductionWordParserPanel.parse (); ProductionWord productionWord = this.gui.styledProductionWordParserPanel .getParsedObject (); if ( productionWord == null ) { setButtonStatus ( false ); getGui ().styledProductionParserPanel.setText ( null ); } else { setButtonStatus ( true ); getGui ().styledProductionParserPanel.setText ( new DefaultProduction ( ( NonterminalSymbol ) getGui ().jGTIList.getSelectedValue (), productionWord ) ); } } /** * Handle dialog confirmed. */ public final void handleOk () { Production production = new DefaultProduction ( ( NonterminalSymbol ) this.gui.jGTIList.getSelectedValue (), this.gui.styledProductionWordParserPanel.getParsedObject () ); if ( this.oldProduction != null ) { if ( !production.getNonterminalSymbol ().equals ( this.oldProduction.getNonterminalSymbol () ) || !production.getProductionWord ().equals ( this.oldProduction.getProductionWord () ) ) { RedoUndoItem item = new ProductionChangedItem ( this.oldProduction, production ); this.redoUndoHandler.addItem ( item ); } this.oldProduction.setNonterminalSymbol ( production .getNonterminalSymbol () ); this.oldProduction.setProductionWord ( production.getProductionWord () ); this.model.getGrammar ().updateStartSymbol (); } else { this.model.addProduction ( production, true ); } this.gui.dispose (); this.parent.repaint (); } /** * Set the ok button status. * * @param status the new button status. */ public final void setButtonStatus ( boolean status ) { this.gui.jGTIButtonOk.setEnabled ( status ); } /** * Show this dialog. */ public final void show () { int x = this.parent.getBounds ().x + ( this.parent.getWidth () / 2 ) - ( this.gui.getWidth () / 2 ); int y = this.parent.getBounds ().y + ( this.parent.getHeight () / 2 ) - ( this.gui.getHeight () / 2 ); this.gui.setBounds ( x, y, this.gui.getWidth (), this.gui.getHeight () ); this.gui.setVisible ( true ); } }