package de.unisiegen.gtitool.ui.logic; import java.util.ArrayList; import java.util.Collections; import javax.swing.JFrame; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; import de.unisiegen.gtitool.core.entities.State; import de.unisiegen.gtitool.core.entities.Symbol; import de.unisiegen.gtitool.core.entities.Transition; import de.unisiegen.gtitool.core.entities.Transition.TransitionType; import de.unisiegen.gtitool.core.machines.Machine; import de.unisiegen.gtitool.logger.Logger; import de.unisiegen.gtitool.ui.history.HistoryPath; import de.unisiegen.gtitool.ui.history.HistoryPathPart; import de.unisiegen.gtitool.ui.history.HistoryPathTableCellRenderer; import de.unisiegen.gtitool.ui.history.TransitionSymbolPair; import de.unisiegen.gtitool.ui.i18n.Messages; import de.unisiegen.gtitool.ui.logic.interfaces.LogicClass; import de.unisiegen.gtitool.ui.netbeans.HistoryDialogForm; /** * The {@link HistoryDialog}. * * @author Christian Fehler * @version $Id$ */ public final class HistoryDialog implements LogicClass < HistoryDialogForm > { /** * The {@link Logger} for this class. */ private static final Logger logger = Logger.getLogger ( HistoryDialog.class ); /** * The max calculating step. */ private static final int MAX_CALCULATING_STEP = 10000; /** * The current calculating step. */ private int calculatingStep = -1; /** * The {@link TableColumnModel}. */ private DefaultTableColumnModel columnModel; /** * The {@link HistoryDialogForm}. */ private HistoryDialogForm gui; /** * The {@link TableModel}. */ private DefaultTableModel historyModel; /** * The {@link HistoryPath} list. */ private ArrayList < HistoryPath > historyPathList; /** * The {@link Machine}. */ private Machine machine; /** * The parent {@link JFrame}. */ private JFrame parent; /** * The remaining {@link HistoryPathPart} list. */ private ArrayList < HistoryPathPart > remainingHistoryPathList = new ArrayList < HistoryPathPart > (); /** * The {@link MachinePanel}. */ private MachinePanel machinePanel; /** * The complete readed {@link Symbol} list. */ private ArrayList < Symbol > completeReadedSymbolList; /** * Allocates a new {@link HistoryDialog}. * * @param parent The parent {@link JFrame}. * @param machine The {@link Machine}. * @param machinePanel The {@link MachinePanel}. */ public HistoryDialog ( JFrame parent, Machine machine, MachinePanel machinePanel ) { logger.debug ( "HistoryDialog", "allocate a new history dialog" ); //$NON-NLS-1$ //$NON-NLS-2$ this.parent = parent; this.machine = machine; this.machinePanel = machinePanel; this.historyPathList = new ArrayList < HistoryPath > (); this.gui = new HistoryDialogForm ( this, parent ); // Model this.historyModel = new DefaultTableModel () { /** * The serial version uid. */ private static final long serialVersionUID = -5238984692740682487L; @Override public boolean isCellEditable ( @SuppressWarnings ( "unused" ) int row, @SuppressWarnings ( "unused" ) int column ) { return false; } }; this.historyModel.addColumn ( "history" ); //$NON-NLS-1$ this.completeReadedSymbolList = new ArrayList < Symbol > (); ArrayList < Symbol > inputList = new ArrayList < Symbol > (); try { this.completeReadedSymbolList.addAll ( this.machine.getReadedSymbols () ); } catch ( Exception exc ) { // Do nothing } inputList.addAll ( this.completeReadedSymbolList ); for ( State current : this.machine.getState () ) { if ( current.isActive () ) { HistoryPathPart pathPart = new HistoryPathPart ( new ArrayList < TransitionSymbolPair > (), inputList, current, this.completeReadedSymbolList ); this.remainingHistoryPathList.add ( pathPart ); } } calculate (); Collections.sort ( this.historyPathList ); for ( HistoryPath current : this.historyPathList ) { this.historyModel.addRow ( new Object [] { current } ); } // ColumnModel this.columnModel = new DefaultTableColumnModel (); TableColumn historyColumn = new TableColumn ( 0 ); historyColumn.setHeaderValue ( Messages .getString ( "HistoryDialog.HistoryColumn" ) ); //$NON-NLS-1$ historyColumn.setCellRenderer ( new HistoryPathTableCellRenderer () ); this.columnModel.addColumn ( historyColumn ); this.gui.jGTITableHistory.setModel ( this.historyModel ); this.gui.jGTITableHistory.setColumnModel ( this.columnModel ); this.gui.jGTITableHistory.getTableHeader ().setReorderingAllowed ( false ); this.gui.jGTITableHistory.getTableHeader ().setResizingAllowed ( false ); } /** * Calculates the list of history paths. */ private final void calculate () { this.calculatingStep++ ; if ( this.remainingHistoryPathList.size () == 0 ) { return; } HistoryPathPart path = this.remainingHistoryPathList.remove ( 0 ); if ( this.calculatingStep >= MAX_CALCULATING_STEP ) { logger.error ( "calculate", "max calculating step reached" ); //$NON-NLS-1$ //$NON-NLS-2$ return; } ArrayList < TransitionSymbolPair > transitionList = path .getTransitionList (); ArrayList < Symbol > readedSymbolList = path.getReadedSymbolList (); State state; if ( path.getState () == null ) { state = transitionList.get ( transitionList.size () - 1 ).getFirst () .getStateBegin (); } else { state = path.getState (); } if ( state.isStartState () && readedSymbolList.isEmpty () ) { this.historyPathList.add ( getHistoryPath ( transitionList ) ); calculate (); return; } for ( Transition currentTransition : state.getTransitionEnd () ) { if ( currentTransition.getTransitionType ().equals ( TransitionType.EPSILON_ONLY ) ) { ArrayList < TransitionSymbolPair > newTransitionList = new ArrayList < TransitionSymbolPair > (); newTransitionList.addAll ( transitionList ); Symbol epsilonSymbol = null; for ( Symbol current : currentTransition ) { if ( current.isEpsilon () ) { epsilonSymbol = current; break; } } newTransitionList.add ( new TransitionSymbolPair ( currentTransition, epsilonSymbol ) ); ArrayList < Symbol > newReadedSymbolList = new ArrayList < Symbol > (); newReadedSymbolList.addAll ( readedSymbolList ); HistoryPathPart newPathPart = new HistoryPathPart ( newTransitionList, newReadedSymbolList, null, this.completeReadedSymbolList ); cycleDetection ( newPathPart ); } else if ( currentTransition.getTransitionType ().equals ( TransitionType.EPSILON_SYMBOL ) ) { // epsilon transition handling ArrayList < TransitionSymbolPair > newTransitionList = new ArrayList < TransitionSymbolPair > (); newTransitionList.addAll ( transitionList ); Symbol epsilonSymbol = null; for ( Symbol current : currentTransition ) { if ( current.isEpsilon () ) { epsilonSymbol = current; break; } } newTransitionList.add ( new TransitionSymbolPair ( currentTransition, epsilonSymbol ) ); ArrayList < Symbol > newReadedSymbolList = new ArrayList < Symbol > (); newReadedSymbolList.addAll ( readedSymbolList ); HistoryPathPart newPathPart = new HistoryPathPart ( newTransitionList, newReadedSymbolList, null, this.completeReadedSymbolList ); cycleDetection ( newPathPart ); // symbol transition handling if ( ( readedSymbolList.size () > 0 ) && currentTransition.contains ( readedSymbolList .get ( readedSymbolList.size () - 1 ) ) ) { Symbol currentSymbol = readedSymbolList.get ( readedSymbolList .size () - 1 ); newTransitionList = new ArrayList < TransitionSymbolPair > (); newTransitionList.addAll ( transitionList ); newTransitionList.add ( new TransitionSymbolPair ( currentTransition, currentSymbol ) ); newReadedSymbolList = new ArrayList < Symbol > (); newReadedSymbolList.addAll ( readedSymbolList ); newReadedSymbolList.remove ( newReadedSymbolList.size () - 1 ); newPathPart = new HistoryPathPart ( newTransitionList, newReadedSymbolList, null, this.completeReadedSymbolList ); cycleDetection ( newPathPart ); } } else if ( ( readedSymbolList.size () > 0 ) && currentTransition.contains ( readedSymbolList .get ( readedSymbolList.size () - 1 ) ) ) { Symbol currentSymbol = readedSymbolList .get ( readedSymbolList.size () - 1 ); ArrayList < TransitionSymbolPair > newTransitionList = new ArrayList < TransitionSymbolPair > (); newTransitionList.addAll ( transitionList ); newTransitionList.add ( new TransitionSymbolPair ( currentTransition, currentSymbol ) ); ArrayList < Symbol > newReadedSymbolList = new ArrayList < Symbol > (); newReadedSymbolList.addAll ( readedSymbolList ); newReadedSymbolList.remove ( newReadedSymbolList.size () - 1 ); HistoryPathPart newPathPart = new HistoryPathPart ( newTransitionList, newReadedSymbolList, null, this.completeReadedSymbolList ); cycleDetection ( newPathPart ); } } calculate (); } /** * Detects cycles in the given {@link HistoryPathPart}. * * @param historyPathPart The {@link HistoryPathPart}. */ private final void cycleDetection ( HistoryPathPart historyPathPart ) { if ( historyPathPart.isCycleDetected () ) { logger.debug ( "cycleDetection", "cycle detected: " + historyPathPart ); //$NON-NLS-1$//$NON-NLS-2$ } else { this.remainingHistoryPathList.add ( historyPathPart ); } } /** * Returns the columnModel. * * @return The columnModel. * @see #columnModel */ public DefaultTableColumnModel getColumnModel () { return this.columnModel; } /** * {@inheritDoc} * * @see LogicClass#getGUI() */ public final HistoryDialogForm getGUI () { return this.gui; } /** * Returns the historyModel. * * @return The historyModel. * @see #historyModel */ public DefaultTableModel getHistoryModel () { return this.historyModel; } /** * Returns the {@link HistoryPath} of the given {@link Transition} list. * * @param transitionList The {@link Transition} list. * @return The {@link HistoryPath} of the given {@link Transition} list. */ private final HistoryPath getHistoryPath ( ArrayList < TransitionSymbolPair > transitionList ) { HistoryPath historyPath = new HistoryPath (); if ( transitionList.size () == 0 ) { State startState = null; for ( State currentState : this.machine.getState () ) { if ( currentState.isStartState () ) { startState = currentState; break; } } historyPath.setStartState ( startState ); } else { for ( int i = transitionList.size () - 1 ; i >= 0 ; i-- ) { Transition currentTransition = transitionList.get ( i ).getFirst (); historyPath.add ( currentTransition, transitionList.get ( i ) .getSecond () ); } } return historyPath; } /** * Returns the machinePanel. * * @return The machinePanel. * @see #machinePanel */ public MachinePanel getMachinePanel () { return this.machinePanel; } /** * Closes the {@link HistoryDialogForm}. */ public final void handleClose () { logger.debug ( "handleClose", "handle close" ); //$NON-NLS-1$ //$NON-NLS-2$ this.gui.dispose (); } /** * Handle print action. */ public void handlePrint () { PrintDialog dialog = new PrintDialog ( this.parent, this ); dialog.show (); } /** * Shows the {@link HistoryDialogForm}. */ public final void show () { logger.debug ( "show", "show the history dialog" ); //$NON-NLS-1$ //$NON-NLS-2$ 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 ); } }