/* UserInputFrame.java User Input Frame - allows users to provide data */ package ciips.animation; import java.awt.*; import java.applet.*; import java.io.*; import java.net.*; import java.lang.reflect.*; /** * User input frame which pops up when user input is allowed * @see AlgAnimFrame */ public class UserInputFrame extends Frame implements ActionListener { private AlgAnimFrame parent; private static final boolean DEBUG = true; private static boolean user_input_allowed = false; private static int DEF_ROWS = 10, DEF_COLUMNS = 30; private Panel text_input; private TextArea ta = null; private Button text_ok = null; public UserInputFrame( AlgAnimFrame parent_frame, String algname ) { if ( !user_input_allowed ) return; // Don't create a user input frame setTitle("User Input for " + algname); if( DEBUG ) System.out.println("UserInputFrame - User input allowed "); setLayout( new BorderLayout() ); setFont(helv14); // Make the text input panel text_input = new Panel(); text_input.setLayout( new FlowLayout() ); TextField prompt = new TextField( "Type desired input, click OK" ); prompt.setEditable( false ); text_input.add( prompt ); ta = new TextArea( DEF_ROWS, DEF_COLUMNS ); text_input.add( ta ); text_ok = new Button( "OK" ); add("North", text_input); setVisible( false ); } public void setVisible( boolean visible ) { if ( visible ) { if( DEBUG ) System.out.println("User Input Window Visible"); validate(); } super.setVisible( visible ); } public String getTextInput() { return ta.getText(); } public void actionPerformed( ActionEvent e ) { } /* Source panel */ tf = new TextFrame( sourceURL ); /* Commentary panel */ cpanel = new ComPanel( algname, COMPANEL_LINES ); add( "South", cpanel ); setMenuBar(createMenuBar()); // setMenuBar(createMenuBar()); // generate initial data set alg.generateData(); pack(); validate(); show(); //if (tf.getTextPanel().getNumLines() > 0) //tf.toFront(); cp.refreshButtons(); } // init() private AlgThread makeAlgThread() { Constructor c; AlgThread alg = null; String thread_name = algname + thread_suffix; if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - " + thread_name ); try { Class alg_thread = Class.forName( thread_name ); if ( alg_thread == null ) { System.out.println("forName( " + thread_name + " ) returns null!"); } if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - class " + thread_name + " loaded" ); Class arg_classes[] = new Class[ 1 ]; // arg_classes[0] = Class.forName( "ciips.animation.AlgAnimFrame" ); arg_classes[0] = this.getClass(); if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - cons args formed" ); if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - arg_classes " + arg_classes ); if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - arg_classes[0] " + arg_classes[0] ); // try { // SecurityManager sm = System.getSecurityManager(); // sm.checkMemberAccess( alg_thread, Member.DECLARED ); // } catch( Exception e ) { // System.out.println("SecManager - member declared exception"); // } try { c = alg_thread.getConstructor( arg_classes ); if( DEBUG ) System.out.println("AlgAnimFrame:makeAlgThread - cons found" ); Object args[] = new Object[ 1 ]; args[ 0 ] = this; try { alg = (AlgThread)(c.newInstance( args )); // alg = (AlgThread)(alg_thread.newInstance()); if( DEBUG ) System.out.println( "AlgAnimFrame:makeAlgThread - AlgThread constructed" ); } catch( InvocationTargetException ite ) { Throwable ee = ite.getTargetException(); System.out.println("newIns: " + ite.getClass() + ":" + ite.getMessage() ); System.out.println("newIns: threw " + ee.getClass() + ":" + ee.getMessage() ); } catch( Exception e ) { System.out.println("newIns: " + e.getClass() + ":" + e.getMessage() ); } } catch( Exception e ) { System.out.println("getDecCons: " + e.getClass() + ":" + e.getMessage() ); } } catch( Exception e ) { if( DEBUG ) System.out.println("AlgAnimFrame:cons " + e.getClass().toString() + " " + e.getMessage() ); } return alg; } private MenuBar createMenuBar() { MenuBar mb = new MenuBar(); mb.setFont(helv14); dataMenu = new Menu("Select"); mb.add(dataMenu); String dataSets[] = alg.getDataSets(); dataChoice = new CheckboxMenuItem[dataSets.length]; for (int i = 0; i < dataSets.length; i++) { dataChoice[i] = new CheckboxMenuItem(dataSets[i]); dataMenu.add(dataChoice[i]); } if (dataSets.length > 0) dataChoice[0].setState(true); dataMenu.addSeparator(); quitItem = new MenuItem("Quit"); dataMenu.add(quitItem); Menu animMenu = new Menu("Animation"); mb.add(animMenu); enableAnim = new CheckboxMenuItem("Enable"); enableAnim.setState(true); disableAnim = new CheckboxMenuItem("Disable"); animMenu.add(enableAnim); animMenu.add(disableAnim); animMenu.addSeparator(); delayMenu = new Menu("Delay"); animMenu.add(delayMenu); delayChoice = new CheckboxMenuItem[5]; for (int i = 0; i < 5; i++) { delayChoice[i] = new CheckboxMenuItem(""+((i+1)*200)+"msec"); delayMenu.add(delayChoice[i]); } delayChoice[0].setState(true); Menu viewMenu = new Menu("View"); mb.add(viewMenu); MenuItem srcCode = new MenuItem("Source Code"); if (tf.getTextPanel().getNumLines() < 1) srcCode.disable(); viewMenu.add(new MenuItem("Source Code")); viewMenu.add(new MenuItem("Legend Panel")); Menu helpMenu = new Menu("About"); mb.setHelpMenu(helpMenu); helpMenu.add(new MenuItem("Credits")); helpMenu.add(new MenuItem("Copyrights")); return mb; } // createMenuBar() /** * Returns the preferred size of the frame. By default, it is set * to 850x700. It can be modified based on the specific application. * @return the dimension of the frame */ public Dimension preferredSize() { return frameSize; } /** * Sets the size of the frame. * @param size The desired sized of the frame. */ public void setDimension(Dimension size) { this.frameSize = size; } /** * Event handler of the frame. The main purpose of this method is to * cleanup upon receival of the WINDOW_DESTROY event message. */ public boolean handleEvent(Event event) { if (cp != null) cp.refreshButtons(); if (event.id == Event.WINDOW_DESTROY) { if (alg != null) { // alg.dpAfter = null; if (alg.isAlive()) alg.stop(); } parentApp.start_button.enable(); tf.dispose(); dispose(); } return super.handleEvent(event); } /** * Action handler for the buttons and choice buttons in the control * panel. * @param e Event invoked * @param arg Object that invokes the event */ public boolean action(Event e, Object arg) { Object target = e.target; if (target == quitItem) { getApplet().start_button.enable(); if (getAlg() != null && getAlg().isAlive()) getAlg().stop(); getTextFrame().dispose(); dispose(); } else if (target instanceof CheckboxMenuItem) { Menu parent = (Menu)((MenuItem)target).getParent(); if (parent == dataMenu) { for (int i = 0; i < dataChoice.length; i++) { if (target == dataChoice[i]) { dataSelected = i; alg.generateData(); dataChoice[i].setState(true); } else dataChoice[i].setState(false); } } else if (parent == delayMenu) { for (int i = 0; i < delayChoice.length; i++) { if (target == delayChoice[i]) { setDelay((i+1)*200); getAlg().setDelay(getDelay()); setText(0, "Animation delay now set to " + getDelay() + " msec..."); delayChoice[i].setState(true); } else delayChoice[i].setState(false); } } else { // parent is Animation.. -> enable/disable anim if (target == enableAnim) { disableAnim.setState(!enableAnim.getState()); noAnim = false; dpAfter.setNoAnim(noAnim); } else if (target == disableAnim) { enableAnim.setState(!disableAnim.getState()); noAnim = true; dpAfter.setNoAnim(noAnim); } } } else { if (target instanceof MenuItem) { String text = ((MenuItem)target).getLabel(); if (text.trim().equals("Source Code")) { tf.show(); tf.toFront(); } else if(text.trim().equals("Legend Panel")) { lf = new LegendFrame (); lf.show(); lf.toFront(); } else if (text.trim().equals("Credits")) { setText(0, "Author: Woi L Ang Supervised by: John Morris"); } else if (text.trim().equals("Copyrights")) { setText(0, "Copyright (c) 1998 The Department of Electrical and Electronic Engineering. University of Western Australia"); } } } return false; } // action() /** * Sets the text string to be displayed on a specific text field on the * commentary panel return from getComPanel. * @see AlgAnimFrame#getComPanel * @param n The text field to display the string. First is 0. * @param s The string to be displayed. */ public void setText( int n, String s ) { cpanel.setText( n, s ); } /** * Highlights the specified line of the source code on the text panel. * If the line is beyond the scroll pane, it will be scrolled to the * center of the window. * @param n The line to be highlighted. */ public void Highlight( int n ) { if( DEBUG ) System.out.println("AlgAnimFrame:Highlight " + n ); if (tf.getTextPanel().getNumLines() < 1) return; if (!((Component)tf).isShowing()) return; tf.getTextPanel().Highlight(n); int numLineVisible = tf.getTextPanel().size().height/tf.getTextPanel().getLineSpace(); if ( (n < (tf.getTextPanel().getStart() + 2)) || (n > (tf.getTextPanel().getStart() + numLineVisible - 2))) { int max = tf.getVertScrollbar().getMaximum(); int min = tf.getVertScrollbar().getMinimum(); int startLine = n - numLineVisible/2; if (startLine > 0) { tf.getTextPanel().setStart(startLine); tf.getVertScrollbar().setValue(startLine * (max - min) / tf.getTextPanel().getNumLines()); } else { tf.getTextPanel().setStart(0); tf.getVertScrollbar().setValue(0); } } try { Thread.sleep(delay/4); } catch (InterruptedException e) {} } /** * Restore the drawing panel at the end of the animation or during * initialization. */ public void restoreDrawingPanel() { alg.restoreDrawingPanel(); } /** * Start the animation algorithm if the run or step * button is pressed. */ public void startAlg() { if (!stepWait) { ((ImageButton)runItem).setDisable(); dataMenu.disable(); } ((ImageButton)stopItem).setEnable(); ((ImageButton)stepItem).setEnable(); if (alg.isAlive() && !stepWait) { alg.stop(); alg = makeAlgThread(); alg.start(); } else if (alg.isAlive() && stepWait) { //alg.resume(); step = !step; stepWait = false; } else { // alg.isAlive() == false alg = makeAlgThread(); alg.start(); } } /** * This method is invoked at the end of the animation or when * the stop button is pressed. It restores the buttons * status on the control panel. */ public void finishAlg() { ((ImageButton)stopItem).setDisable(); ((ImageButton)runItem).setEnable(); ((ImageButton)skipItem).setEnable(); dataMenu.enable(); ((ImageButton)stepItem).setEnable(); step = false; alg.restoreDrawingPanel(); } /** * This method is called when the step execution mode is used. * It is normally added to the line where the execution will wait * for the step button to be pressed. */ public void waitStep() { if( DEBUG ) System.out.println("AlgAnimFrame:waitStep - step " + step ); if (step) { ((ImageButton)stepItem).setEnable(); repaint(); step = false; stepWait = true; // Sleep to prevent CPU busy waiting for user while ( !step ) { setText(0, "Click NEXT STEP..."); try { Thread.sleep(100); } catch (InterruptedException e) {} } if (!stepWait) step = false; setText(0, ""); if( DEBUG ) System.out.println("AlgAnimFrame:waitStep exit - step " + step ); } } /** * This method is called when the skip execution mode is used. * It is normally added to the line where the execution will wait * after the skip button to be pressed. */ public void waitSkip() { alg.waitSkip(); } /** * Sets the attribute which indicate if the skip execution * mode is current. */ public void setSkip(boolean skip) { dpAfter.setSkip(skip); } /** * Sets the attribute which indicate if the step execution * mode is current. */ public void setStep(boolean step) { System.out.println("AlgAnimFrame:setStep " + step ); this.step = step; ((ImageButton)stepItem).setDisable(); ((ImageButton)runItem).setEnable(); dataMenu.enable(); if (step) { ((ImageButton)stepItem).setDisable(); stepWait = true; } else stepWait = false; } /** * Returns the reference to the AlgThread which contains the details and * execution sequences of the algorithm. * @see AlgThread */ public AlgThread getAlg() { return alg; } /** * Set the delay for highlighting text. */ public void setDelay(int delay) { this.delay = delay; } /** * Get the delay for highlighting text. */ public int getDelay() { return delay; } /** * Get the applet which contains a button to start up this window. * @return Returns the applet which contains the button to start up * this window. */ public AlgAnimApp getApplet() { return parentApp; } /** * Returns an instance of the drawing panel which is cast to its super class * Panel. */ public BasicDrawingPanel[] getDrawingPanel() { return dp; } public BasicDrawingPanel getBeforeDp() { if ( dp.length > 1 ) return dp[dp.length-2]; return null; } /** * Shuffles the images down and draws a label on the "before" image * (the one immediately preceding the current one */ public void drawBeforeLabel( ShadowLabel label ) { panel.drawBeforeLabel( label ); } /** * Sets the drawing panel which is cast to its super class * Panel. This instance is used to set the GridBagConstraint * of the layout manager ??????. * @see DrawingPanel */ public void setDrawingPanel(DrawingPanel panel) { this.dpAfter = panel; } /** * Returns an instance of the TextFrame used to set the layout * constraints and highlight certain lines of the source code. * @see TextFrame */ public TextFrame getTextFrame() { return tf; } /** * Get the commentary panel that displays messages of any type. * @return Commentary panel, in which each text field within can be set to * display text string from this class. * @see ComPanel */ public ComPanel getComPanel() { return cpanel; } /** * Get the index of selected choice from the 'Select' pull menu. * @return The choice of the data selected. */ public int getDataChoice() { return dataSelected; } /** * Get the skip button from the control panel. * @return The skip button. */ public Button getSkipItem() { return skipItem; } /** * Get the run button from the control panel. * @return The run button. */ public Button getRunItem() { return runItem; } /** * Get the stop button from the control panel. * @return The stop button. */ public Button getStopItem() { return stopItem; } /** * Obtain the status of the preferred animation style. * @return True is the animation is kept to a minimum for the animated * algorithm; false otherwise. */ public boolean isNoAnim() { return noAnim; } /** * Get the menu item which specify if the animation is enabled. * @return The checkbox menu item to enable the Animation of the alg. */ public CheckboxMenuItem getEnableAnim() { return enableAnim; } /** * Get the menu item which specify if the animation is disabled. * @return The checkbox menu item to disable the Animation of the alg. */ public CheckboxMenuItem getDisableAnim() { return disableAnim; } public DrawingPanel getCurrentPanel() { return (DrawingPanel)dp[ dp.length-1 ]; } public BasicDrawingPanel getPreviousPanel() { if ( dp.length > 1 ) return dp[ dp.length-2 ]; return null; } /* ------ static methods allow the animation to run without having a reference to the animation frame ----- */ public static AlgAnimFrame makeAlgAnimFrame(AlgAnimApp parentApp, URL sourceURL) { frame = new AlgAnimFrame ( parentApp, sourceURL); return frame; } public static void pause() { try { Thread.sleep(100); } catch (InterruptedException e) {} } public static void pauseStep() { frame.waitStep(); } public static void pauseSkip(){ frame.waitSkip(); } public static void highlightText( int n ){ frame.Highlight ( n ); } public static void showText( int n, String s ) { System.out.println("AlgAnimFrame:showText [" + s + "]" ); frame.cpanel.setTopText( n, s ); } public static DrawingPanel getPanel(){ DrawingPanel dp = frame.getCurrentPanel(); return dp; } } // class AlgAnimApp