package de.unisiegen.gtitool.ui.logic; import java.awt.Rectangle; import java.util.ArrayList; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; import javax.swing.JFrame; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import org.jgraph.graph.DefaultGraphModel; import de.unisiegen.gtitool.core.entities.DefaultState; import de.unisiegen.gtitool.core.entities.DefaultTransition; import de.unisiegen.gtitool.core.entities.State; import de.unisiegen.gtitool.core.entities.Transition; import de.unisiegen.gtitool.core.exceptions.alphabet.AlphabetException; import de.unisiegen.gtitool.core.exceptions.state.StateException; import de.unisiegen.gtitool.core.exceptions.transition.TransitionException; import de.unisiegen.gtitool.core.exceptions.transition.TransitionSymbolNotInAlphabetException; import de.unisiegen.gtitool.core.exceptions.transition.TransitionSymbolOnlyOneTimeException; import de.unisiegen.gtitool.core.machines.Machine; import de.unisiegen.gtitool.core.machines.dfa.DefaultDFA; import de.unisiegen.gtitool.core.parser.style.PrettyString; import de.unisiegen.gtitool.core.storage.exceptions.StoreException; import de.unisiegen.gtitool.logger.Logger; import de.unisiegen.gtitool.ui.jgraph.DefaultStateView; import de.unisiegen.gtitool.ui.jgraph.DefaultTransitionView; import de.unisiegen.gtitool.ui.jgraph.JGTIGraph; import de.unisiegen.gtitool.ui.logic.interfaces.LogicClass; import de.unisiegen.gtitool.ui.model.ConvertMachineTableColumnModel; import de.unisiegen.gtitool.ui.model.DefaultMachineModel; import de.unisiegen.gtitool.ui.model.MinimizeMachineTableModel; import de.unisiegen.gtitool.ui.netbeans.MainWindowForm; import de.unisiegen.gtitool.ui.netbeans.MinimizeMachineDialogForm; import de.unisiegen.gtitool.ui.preferences.PreferenceManager; import de.unisiegen.gtitool.ui.utils.Minimizer; import de.unisiegen.gtitool.ui.utils.TextLoader; /** * The {@link MinimizeMachineDialog}. * * @author Christian Fehler * @version $Id$ */ public final class MinimizeMachineDialog implements LogicClass < MinimizeMachineDialogForm > { /** * Perform auto step. * * @author Benjamin Mies */ protected final class AutoStepTimerTask extends TimerTask { /** * {@inheritDoc} * * @see TimerTask#run() */ @Override public final void run () { SwingUtilities.invokeLater ( new Runnable () { public void run () { handleNextStep (); if ( MinimizeMachineDialog.this.endReached ) { handleStop (); } } } ); } } /** * The {@link Logger} for this class. */ private static final Logger logger = Logger .getLogger ( MinimizeMachineDialog.class ); /** * Flag indicates if autostep is in progress. */ private boolean autoStep = false; /** * Flag that indicates if the begin is reached. */ private boolean beginReached = true; /** * Flag that indicates if the end is reached. */ protected boolean endReached = false; /** * The {@link MinimizeMachineDialogForm}. */ private MinimizeMachineDialogForm gui; /** * The original {@link JGTIGraph} containing the diagramm. */ private JGTIGraph jGTIGraphOriginal; /** * The original {@link Machine}. */ private Machine machine; /** * The {@link MachinePanel}. */ private MachinePanel machinePanel; /** * The parent {@link JFrame}. */ private MainWindowForm mainWindowForm; /** * The {@link MinimizeMachineTableModel}. */ private MinimizeMachineTableModel minimizeMachineTableModel; /** * The {@link Minimizer}. */ private Minimizer minimizer; /** * The new created {@link DefaultMachineModel}. */ private DefaultMachineModel modelMinimized; /** * The original {@link DefaultMachineModel}. */ private DefaultMachineModel modelOriginal; /** * The new created states. */ private HashMap < State, DefaultStateView > states = new HashMap < State, DefaultStateView > (); /** * The {@link ConvertMachineTableColumnModel}. */ private ConvertMachineTableColumnModel tableColumnModel = new ConvertMachineTableColumnModel (); /** * The {@link Timer}. */ private Timer timer = null; /** * The algorithm window */ private TextWindow algorithmWindow; /** * The algorithm */ private String algorithm; /** * Allocates a new {@link MinimizeMachineDialog}. * * @param mainWindowForm The parent {@link MainWindowForm}. * @param machinePanel The {@link MachinePanel}. */ public MinimizeMachineDialog ( MainWindowForm mainWindowForm, MachinePanel machinePanel ) { logger.debug ( "MinimizeMachineDialog", //$NON-NLS-1$ "allocate a new minimize machine dialog" ); //$NON-NLS-1$ this.mainWindowForm = mainWindowForm; this.machinePanel = machinePanel; this.gui = new MinimizeMachineDialogForm ( this, mainWindowForm ); this.gui.jGTISplitPaneGraph.setRightComponent ( null ); this.gui.jGTISplitPaneGraph.setDividerSize ( 0 ); try { this.modelOriginal = new DefaultMachineModel ( this.machinePanel .getModel ().getElement (), null ); this.minimizeMachineTableModel = new MinimizeMachineTableModel (); this.minimizer = new Minimizer ( this.modelOriginal, this ); } catch ( TransitionSymbolOnlyOneTimeException exc ) { exc.printStackTrace (); System.exit ( 1 ); return; } catch ( StateException exc ) { exc.printStackTrace (); System.exit ( 1 ); return; } catch ( AlphabetException exc ) { exc.printStackTrace (); System.exit ( 1 ); return; } catch ( TransitionException exc ) { exc.printStackTrace (); System.exit ( 1 ); return; } catch ( StoreException exc ) { exc.printStackTrace (); System.exit ( 1 ); return; } this.jGTIGraphOriginal = this.modelOriginal.getJGTIGraph (); this.jGTIGraphOriginal.setEnabled ( false ); this.gui.jGTIScrollPaneOriginal.setViewportView ( this.jGTIGraphOriginal ); this.machine = this.modelOriginal.getMachine (); handleStart (); } /** * Adds a outline comment. * * @param prettyString The {@link PrettyString}. * @param transitions List with the {@link Transition}s. */ public final void addOutlineComment ( PrettyString prettyString, ArrayList < Transition > transitions ) { this.minimizeMachineTableModel.addRow ( prettyString, transitions ); this.gui.jGTITableOutline.changeSelection ( this.minimizeMachineTableModel .getRowCount () - 1, MinimizeMachineTableModel.OUTLINE_COLUMN, false, false ); } /** * Build the minimal {@link Machine}. */ private void buildMinimalMachine () { this.states.clear (); this.modelMinimized = new DefaultMachineModel ( new DefaultDFA ( this.machine.getAlphabet (), this.machine.getPushDownAlphabet (), this.machine.isUsePushDownAlphabet () ) ); try { for ( ArrayList < DefaultStateView > current : this.minimizer .getGroups () ) { boolean startState = false; String name = "{"; //$NON-NLS-1$ int count = 0; for ( DefaultStateView defaultStateView : current ) { if ( defaultStateView.getState ().isStartState () ) { startState = true; } if ( count > 0 ) { name += ", "; //$NON-NLS-1$ } name += defaultStateView.toString (); count++ ; } name += "}"; //$NON-NLS-1$ DefaultState state = new DefaultState ( name ); state.setStartState ( startState ); state.setFinalState ( current.get ( 0 ).getState ().isFinalState () ); DefaultStateView stateView = this.modelMinimized.createStateView ( current.get ( 0 ).getPositionX () + 100, current.get ( 0 ) .getPositionY (), state, false ); stateView.setOverwrittenColor ( current.get ( 0 ) .getOverwrittenColor () ); this.states.put ( current.get ( 0 ).getState (), stateView ); } } catch ( StateException exc ) { exc.printStackTrace (); } createTransitions (); } /** * Create the transitions of the {@link Machine}. */ private void createTransitions () { for ( State current : this.states.keySet () ) { HashMap < State, Transition > transitions = new HashMap < State, Transition > (); for ( Transition transition : current.getTransitionBegin () ) { try { DefaultStateView target = getTargetStateView ( transition .getStateEnd () ); Transition newTransition; if ( transitions.containsKey ( target.getState () ) ) { transitions.get ( target.getState () ).add ( transition.getSymbol () ); } else { newTransition = new DefaultTransition ( transition.getAlphabet (), transition.getPushDownAlphabet (), transition .getPushDownWordRead (), transition.getPushDownWordWrite (), this.states.get ( current ) .getState (), target.getState (), transition.getSymbol () ); this.modelMinimized.createTransitionView ( newTransition, this.states.get ( current ), target, false, false, true ); } } catch ( TransitionSymbolNotInAlphabetException exc ) { exc.printStackTrace (); } catch ( TransitionSymbolOnlyOneTimeException exc ) { exc.printStackTrace (); } } } } /** * {@inheritDoc} * * @see de.unisiegen.gtitool.ui.logic.interfaces.LogicClass#getGUI() */ public MinimizeMachineDialogForm getGUI () { return this.gui; } /** * Returns the machinePanel. * * @return The machinePanel. * @see #machinePanel */ public MachinePanel getMachinePanel () { return this.machinePanel; } /** * Returns the minimizeMachineTableModel. * * @return The minimizeMachineTableModel. * @see #minimizeMachineTableModel */ public MinimizeMachineTableModel getMinimizeMachineTableModel () { return this.minimizeMachineTableModel; } /** * Returns the modelMinimized. * * @return The modelMinimized. * @see #modelMinimized */ public DefaultMachineModel getModelMinimized () { return this.modelMinimized; } /** * Returns the modelOriginal. * * @return The modelOriginal. * @see #modelOriginal */ public DefaultMachineModel getModelOriginal () { return this.modelOriginal; } /** * Returns the tableColumnModel. * * @return The tableColumnModel. * @see #tableColumnModel */ public ConvertMachineTableColumnModel getTableColumnModel () { return this.tableColumnModel; } /** * Get the target state view representing the group. * * @param state The {@link State}. * @return The {@link DefaultStateView} representing the group. */ private DefaultStateView getTargetStateView ( State state ) { DefaultStateView target = null; for ( ArrayList < DefaultStateView > current : this.minimizer.getGroups () ) { target = this.states.get ( current.get ( 0 ).getState () ); for ( DefaultStateView defaultStateView : current ) { if ( state.equals ( defaultStateView.getState () ) ) { return target; } } } return target; } /** * Handles the algorithm window changed * * @param show True if window should be shown. */ public void handleAlgorithmWindowChanged ( boolean show ) { if ( ( this.algorithm == null ) || ( this.algorithm.length () == 0 ) ) { TextLoader loader = new TextLoader (); this.algorithm = loader.loadMinimizeAlgorithm (); } if ( this.algorithmWindow == null ) { this.algorithmWindow = new TextWindow ( this.gui, this.algorithm, true, this.gui.jGTIToggleButtonAlgorithm, "MINIMIZE" ); //$NON-NLS-1$ } if ( show ) { this.algorithmWindow.show (); } else { this.algorithmWindow.dispose (); } } /** * Handles the action on the auto step button. */ public final void handleAutoStep () { logger.debug ( "handleAutoStep", "handle auto step" ); //$NON-NLS-1$ //$NON-NLS-2$ this.autoStep = true; setStatus (); this.timer = new Timer (); int time = PreferenceManager.getInstance ().getAutoStepItem () .getAutoStepInterval (); this.timer.schedule ( new AutoStepTimerTask (), time, time ); } /** * Handles the action on the begin step button. */ public void handleBeginStep () { logger.debug ( "handleBeginStep", "handle begin step" ); //$NON-NLS-1$ //$NON-NLS-2$ if ( this.timer != null ) { this.timer.cancel (); this.timer = null; } while ( !this.beginReached ) { handlePreviousStep (); } this.endReached = false; setStatus (); } /** * Handles the action on the cancel button. */ public final void handleCancel () { logger.debug ( "handleCancel", "handle cancel" ); //$NON-NLS-1$ //$NON-NLS-2$ if ( this.timer != null ) { this.timer.cancel (); this.timer = null; } PreferenceManager.getInstance ().setMinimizeMachineDialogPreferences ( this.gui ); this.gui.dispose (); } /** * Handles the action on the end step button. */ public void handleEndStep () { logger.debug ( "handleEndStep", "handle end step" ); //$NON-NLS-1$ //$NON-NLS-2$ if ( this.timer != null ) { this.timer.cancel (); this.timer = null; } while ( !this.endReached ) { handleNextStep (); } this.beginReached = false; this.endReached = true; setStatus (); } /** * Handles the action on the next step button. */ public final void handleNextStep () { logger.debug ( "handleNextStep", "handle next step" ); //$NON-NLS-1$ //$NON-NLS-2$ this.minimizer.nextStep (); this.endReached = this.minimizer.isFinished (); this.beginReached = false; setStatus (); if ( this.endReached ) { buildMinimalMachine (); JGTIGraph graph = this.modelMinimized.getJGTIGraph (); graph.setEnabled ( false ); this.gui.jGTIScrollPaneConverted.setViewportView ( graph ); } highlightTransitions ( this.gui.jGTITableOutline.getSelectedRow () ); if ( this.endReached ) { this.gui.jGTISplitPaneGraph .setRightComponent ( this.gui.jGTIScrollPaneConverted ); this.gui.jGTISplitPaneGraph.setDividerSize ( 3 ); this.gui.jGTISplitPaneGraph .setDividerLocation ( ( this.gui.getHeight () - 100 ) / 2 ); } } /** * Handles the action on the ok button. */ public final void handleOk () { logger.debug ( "handleOk", "handle ok" ); //$NON-NLS-1$ //$NON-NLS-2$ if ( this.timer != null ) { this.timer.cancel (); this.timer = null; } this.gui.setVisible ( false ); while ( !this.endReached ) { handleNextStep (); } buildMinimalMachine (); this.machinePanel.getMainWindow ().handleNew ( this.modelMinimized ); PreferenceManager.getInstance ().setMinimizeMachineDialogPreferences ( this.gui ); this.gui.dispose (); } /** * Handles the action on the previous step button. */ public final void handlePreviousStep () { logger.debug ( "handlePreviousStep", "handle previous step" ); //$NON-NLS-1$ //$NON-NLS-2$ if ( this.endReached ) { this.gui.jGTISplitPaneGraph.setRightComponent ( null ); this.gui.jGTISplitPaneGraph.setDividerSize ( 0 ); } this.minimizer.previousStep (); this.beginReached = this.minimizer.isBegin (); this.endReached = false; setStatus (); this.gui.jGTIScrollPaneConverted.setViewportView ( null ); this.minimizeMachineTableModel.removeLastRow (); int index = this.minimizeMachineTableModel.getRowCount () - 1; this.gui.jGTITableOutline.getSelectionModel ().setSelectionInterval ( index, index ); highlightTransitions ( this.gui.jGTITableOutline.getSelectedRow () ); } /** * Handle print action. */ public void handlePrint () { PrintDialog dialog = new PrintDialog ( this.mainWindowForm, this ); dialog.show (); } /** * Handles the start action. */ private final void handleStart () { this.minimizer.initialize (); setStatus (); } /** * Handles the action on the stop button. */ public final void handleStop () { logger.debug ( "handleStop", "handle stop" ); //$NON-NLS-1$ //$NON-NLS-2$ this.timer.cancel (); this.timer = null; this.gui.jGTIToolBarToggleButtonAutoStep.setSelected ( false ); this.autoStep = false; setStatus (); } /** * Highlight the {@link Transition}s. * * @param selectedRow The actual selected table row. */ public void highlightTransitions ( int selectedRow ) { for ( DefaultTransitionView current : this.modelOriginal .getTransitionViewList () ) { current.getTransition ().setActive ( false ); } if ( selectedRow > -1 ) { ArrayList < Transition > transitionList = this.minimizeMachineTableModel .getTransitionsAt ( selectedRow ); for ( Transition current : transitionList ) { current.setActive ( true ); this.modelOriginal.getGraphModel ().cellsChanged ( DefaultGraphModel.getAll ( this.modelOriginal.getGraphModel () ) ); } } } /** * Returns the endReached. * * @return The endReached. * @see #endReached */ public boolean isEndReached () { return this.endReached; } /** * Minimize the given {@link Machine}. */ public final void minimize () { this.gui.jGTITableOutline.setModel ( this.minimizeMachineTableModel ); this.gui.jGTITableOutline.setColumnModel ( this.tableColumnModel ); this.gui.jGTITableOutline.getTableHeader ().setReorderingAllowed ( false ); this.gui.jGTITableOutline.getSelectionModel ().setSelectionMode ( ListSelectionModel.SINGLE_SELECTION ); Rectangle rect = PreferenceManager.getInstance () .getMinimizeMachineDialogBounds (); this.gui.jGTISplitPaneOutline.setDividerLocation ( rect.width - 250 ); show (); } /** * Sets the button status. */ private final void setStatus () { this.gui.jGTIToolBarButtonPreviousStep.setEnabled ( !this.beginReached && !this.autoStep ); this.gui.jGTIToolBarButtonBeginStep.setEnabled ( !this.beginReached && !this.autoStep ); this.gui.jGTIToolBarButtonNextStep.setEnabled ( !this.endReached && !this.autoStep ); this.gui.jGTIToolBarToggleButtonAutoStep.setEnabled ( !this.endReached && !this.autoStep ); this.gui.jGTIToolBarButtonEndStep.setEnabled ( !this.endReached && !this.autoStep ); this.gui.jGTIToolBarButtonStop.setEnabled ( this.autoStep ); } /** * Shows the {@link MinimizeMachineDialogForm}. */ public final void show () { logger.debug ( "show", "show the minimize machine dialog" ); //$NON-NLS-1$ //$NON-NLS-2$ Rectangle rect = PreferenceManager.getInstance () .getMinimizeMachineDialogBounds (); if ( ( rect.x == PreferenceManager.DEFAULT_MINIMIZE_MACHINE_DIALOG_POSITION_X ) || ( rect.y == PreferenceManager.DEFAULT_MINIMIZE_MACHINE_DIALOG_POSITION_Y ) ) { rect.x = this.mainWindowForm.getBounds ().x + ( this.mainWindowForm.getWidth () / 2 ) - ( this.gui.getWidth () / 2 ); rect.y = this.mainWindowForm.getBounds ().y + ( this.mainWindowForm.getHeight () / 2 ) - ( this.gui.getHeight () / 2 ); } this.gui.setBounds ( rect ); this.gui.setVisible ( true ); } }