/* Stem-and-Leaf Plot -- User enters data points. The applet draws the corresponding stem-and-leaf plot (either in vertical or horizontal orientation). Then the user is supposed to calculate the data set's mean, median, and mode(s). The applet can check these values and show the user the correct ones. Developed for Project Interactivate. Applet tag: Last modified November 2006 by Deborah Hussey Last modified March 11, 2002 by Alton Patrick. Written 1999 by Adam Simpkins. */ package stemleaf; import java.applet.Applet; import java.awt.Button; import java.awt.Checkbox; import java.awt.CheckboxGroup; import java.awt.Choice; import java.awt.Color; import java.awt.Font; import java.awt.Label; import java.awt.Panel; import java.awt.Scrollbar; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.LinkedList; import java.util.StringTokenizer; import org.shodor.gui11.MenuCreator; import org.shodor.gui11.MsgWindow; import org.shodor.gui11.NumInput; //porting encrypted progress reporter import org.shodor.encryption.EncryptedProgressReporter; import org.shodor.encryption.PrivateKeys; import org.shodor.gui11.ScoreBoard; import org.shodor.gui11.ScoreboardButtonPanel; import org.shodor.gui11.ShodorApplicationFrame; import org.shodor.gui11.ShodorCopyright; import org.shodor.gui11.TextCanvas; import org.shodor.io.ProgressReporter; import org.shodor.layout.ShodorGridLayout; import org.shodor.layout.ShodorHorizontalLayout; import org.shodor.layout.ShodorVerticalLayout; import org.shodor.util11.StrLib; public class StemLeaf extends Applet implements ItemListener, ActionListener { private static final long serialVersionUID = 4254971077741544462L; public static final double LINEAR_TOLERANCE = 0.01; /* * The absolute amount the median and mode may be off by and still be * considered correct. */ public static final int PLOTWIDTH = 300;// Canvas is required to be square. private static boolean isApplication = false; public Plot plot; private TextArea data_area; private NumInput mean_field, median_field, mode_field; private Choice cOrientation, difficulty; private Button bUpdate, bCheckAnswers, bShowAnswers, bClear, bNext; private MsgWindow msg; private EncryptedProgressReporter reporter; // Used for checking answers private double mean, median; private String modes; private TextCanvas plotTitle; private TextField tfTitle; private Button bSetTitle; private ScoreBoard scoreBoard; private ScoreboardButtonPanel pScore; // Strings for View/Guess mode public static final String VIEW = "View"; public static final String GUESS = "Guess"; private CheckboxGroup cbgViewOrGuess; // choice of modes private Checkbox cbView, cbGuess; private Panel pViewGuess, pButton, pBelowLeft; // Levels of difficulty public static final int LEVEL1 = 0; public static final int LEVEL2 = 1; public static final int LEVEL3 = 2; public static final int VERTICAL = 0, HORIZONTAL = 1; private static final String UPDATE = "Update Plot", CHECK_ANSWERS = "Check Answers", SHOW = "Show Answers", HIDE = "Hide Answers", CORRECT = "Correct!", INCORRECT = "Incorrect", MEAN = "Mean:", MEDIAN = "Median:", MODE = "Mode(s):"; private static final int NUM_INPUT_COLS = 9; private static final String DEFAULT_TITLE = "Stem and Leaf Plot"; boolean answered = false; public void init() { setBackground(Color.white); bUpdate = new Button(UPDATE); bUpdate.addActionListener(this); bClear = new Button("Clear Plot"); bClear.addActionListener(this); bCheckAnswers = new Button(CHECK_ANSWERS); bCheckAnswers.addActionListener(this); bShowAnswers = new Button(SHOW); bShowAnswers.addActionListener(this); bSetTitle = new Button("Set"); bSetTitle.addActionListener(this); bNext = new Button("Next"); bNext.addActionListener(this); cbView = new Checkbox(VIEW, cbgViewOrGuess, true); cbGuess = new Checkbox(GUESS, cbgViewOrGuess, false); cbView.addItemListener(this); cbGuess.addItemListener(this); String[] description = new String[3]; description[0] = "Mean"; description[1] = "Median"; description[2] = "Mode"; scoreBoard = new ScoreBoard("Current Question", "Overall", description, "Score", true, this, this); plotTitle = new TextCanvas(DEFAULT_TITLE, PLOTWIDTH, 50, TextCanvas.CENTER); plotTitle.setHardFont(new Font("Dialog", Font.BOLD, 14)); plotTitle.setTextColor(Color.red); tfTitle = new TextField(DEFAULT_TITLE, 20); TextCanvas tcTitle = new TextCanvas("Title: ", 50, TextCanvas.LHEIGHT, TextCanvas.RIGHT, 20); tcTitle.setHardFont(new Font("Title", Font.BOLD, 12)); tcTitle.setTextColor(Color.red); Panel pTitle = new Panel(); pTitle.setLayout(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pTitle.add(ShodorHorizontalLayout.EAST, tcTitle); pTitle.add(ShodorHorizontalLayout.WEST, tfTitle); pTitle.add(ShodorHorizontalLayout.WEST, bSetTitle); // Choice of vertical or horizontal plot cOrientation = new Choice(); cOrientation.addItem("Vertical Plot"); cOrientation.addItem("Horizontal Plot"); cOrientation.addItemListener(this); pViewGuess = new Panel(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pViewGuess.add(ShodorHorizontalLayout.CENTER, cbView); pViewGuess.add(ShodorHorizontalLayout.CENTER, cbGuess); // Choice of Difficulty Levels difficulty = new Choice(); difficulty.addItem("Level 1"); difficulty.addItem("Level 2"); difficulty.addItem("Level 3"); difficulty.addItemListener(this); pViewGuess.add(new Label("Difficulty:")); pViewGuess.add(ShodorHorizontalLayout.CENTER, difficulty); Panel pPlotButtons = new Panel(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pPlotButtons.add(ShodorHorizontalLayout.CENTER, bUpdate); pPlotButtons.add(ShodorHorizontalLayout.CENTER, bClear); TextCanvas tcData = new TextCanvas("Enter data:", 100, TextCanvas.LHEIGHT, TextCanvas.CENTER, TextCanvas.MIDDLE); tcData.setHardFont(new Font("Data", Font.BOLD, 12)); tcData.setTextColor(Color.red); Panel pData = new Panel(new ShodorVerticalLayout( ShodorVerticalLayout.NORTH)); pData.add(ShodorVerticalLayout.CENTER, tcData); data_area = new TextArea(5, 10); pData.add(ShodorVerticalLayout.CENTER, data_area); pData.add(ShodorVerticalLayout.CENTER, pPlotButtons); Scrollbar horiz_bar = new Scrollbar(Scrollbar.HORIZONTAL); Scrollbar vert_bar = new Scrollbar(Scrollbar.VERTICAL); plot = new Plot(horiz_bar, vert_bar, PLOTWIDTH, PLOTWIDTH); Panel pPlot = new Panel(new ShodorGridLayout(2, 2)); pPlot.add(ShodorGridLayout.CENTER, plot); pPlot.add(ShodorGridLayout.FILL, vert_bar); pPlot.add(ShodorGridLayout.FILL, horiz_bar); pPlot.add(ShodorGridLayout.FILL, new TextCanvas("", 10, 10, TextCanvas.LEFT)); TextCanvas tcCalculate = new TextCanvas("Calculate these values:", 175, TextCanvas.LHEIGHT, TextCanvas.CENTER, TextCanvas.MIDDLE); tcCalculate.setHardFont(new Font("Calculate", Font.BOLD, 12)); tcCalculate.setTextColor(Color.red); Panel pCalculate = new Panel(new ShodorVerticalLayout( ShodorVerticalLayout.NORTH)); pCalculate.add(ShodorVerticalLayout.CENTER, tcCalculate); Panel math_panel = new Panel(new ShodorGridLayout(4, 2)); math_panel.add(ShodorGridLayout.WEST, new TextCanvas(MEAN, 50, TextCanvas.LHEIGHT, TextCanvas.CENTER)); mean_field = new NumInput("", NUM_INPUT_COLS); math_panel.add(ShodorGridLayout.EAST, mean_field); math_panel.add(ShodorGridLayout.WEST, new TextCanvas(MEDIAN, 50, TextCanvas.LHEIGHT, TextCanvas.CENTER)); median_field = new NumInput("", NUM_INPUT_COLS); math_panel.add(ShodorGridLayout.EAST, median_field); math_panel.add(ShodorGridLayout.WEST, new TextCanvas(MODE, 50, TextCanvas.LHEIGHT, TextCanvas.CENTER)); mode_field = new NumInput("", NUM_INPUT_COLS); math_panel.add(ShodorGridLayout.EAST, mode_field); pCalculate.add(ShodorVerticalLayout.CENTER, math_panel); // created as space to position pButton correctly. TextCanvas space = new TextCanvas(" ", 35, TextCanvas.LHEIGHT, TextCanvas.LEFT); pButton = new Panel(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pButton.add(ShodorHorizontalLayout.WEST, space); pButton.add(ShodorHorizontalLayout.WEST, bCheckAnswers); pButton.add(ShodorHorizontalLayout.EAST, bShowAnswers); pButton.add(ShodorHorizontalLayout.EAST, bNext); pCalculate.add(ShodorVerticalLayout.CENTER, pButton); pBelowLeft = new Panel(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pBelowLeft.add(ShodorHorizontalLayout.WEST, pScore = new ScoreboardButtonPanel(scoreBoard)); pBelowLeft.add(ShodorHorizontalLayout.EAST, new ShodorCopyright(this)); // created as space to position pBelowLeft correctly. TextCanvas blankSpace = new TextCanvas(" ", 15, TextCanvas.LHEIGHT, TextCanvas.LEFT); pBelowLeft.add(ShodorHorizontalLayout.WEST, blankSpace); Panel pLeft = new Panel(new ShodorVerticalLayout( ShodorVerticalLayout.NORTH)); pLeft.add(ShodorVerticalLayout.CENTER, plotTitle); pLeft.add(ShodorVerticalLayout.CENTER, pPlot); pLeft.add(ShodorVerticalLayout.CENTER, pBelowLeft); Panel pRight = new Panel(new ShodorVerticalLayout( ShodorVerticalLayout.RIGHT)); pRight.add(ShodorVerticalLayout.CENTER, pTitle); pRight.add(ShodorVerticalLayout.CENTER, cOrientation); pRight.add(ShodorVerticalLayout.CENTER, pViewGuess);// adds check boxes // for mode choices pRight.add(ShodorVerticalLayout.CENTER, pData); pRight.add(ShodorVerticalLayout.CENTER, pCalculate); Panel pMiddle = new Panel(new ShodorHorizontalLayout( ShodorHorizontalLayout.NORTH)); pMiddle.add(ShodorHorizontalLayout.CENTER, pLeft); pMiddle.add(ShodorHorizontalLayout.CENTER, pRight); setLayout(new ShodorHorizontalLayout(ShodorHorizontalLayout.NORTH)); add(ShodorHorizontalLayout.CENTER, pMiddle); if (getParameter("debug") != null && (new Boolean(getParameter("debug").trim()).booleanValue())) { for (int i = 0; i < ProgressReporter.DATABASE_PARAMETERS.length; i++) { System.out .println(ProgressReporter.DATABASE_PARAMETERS[i] + ": " + getParameter(ProgressReporter.DATABASE_PARAMETERS[i])); } } if (getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.INTERACTIVATE_PLUS]) != null && (new Boolean( getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.INTERACTIVATE_PLUS]))) .booleanValue()) { reporter = new EncryptedProgressReporter( getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.SERVER]), Integer .parseInt(getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.PORT])), getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.URI]), Integer .parseInt(getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.ACTIVITYID])), Integer .parseInt(getParameter(ProgressReporter.DATABASE_PARAMETERS[ProgressReporter.USERID]))); // setSecurity method on reporter w/ parameters referencing applet & // applet's private key. reporter.setSecurity(this, PrivateKeys.STEMLEAF); } } public void itemStateChanged(ItemEvent evt) { if (evt.getSource() == cOrientation) { plot.setOrientation(cOrientation.getSelectedIndex()); plot.plotData(data_area.getText()); plot.drawAll(); } /* TODO:Test code */ if (evt.getSource() == cbView) { pButton.setVisible(false);// in view mode not visible pScore.setVisible(false);// only visible in guess mode } if (evt.getSource() == cbGuess) { pScore.setVisible(true); pButton.setVisible(true); } /* TODO: If difficulty level is chosen there should changes to plot */ if (evt.getSource() == difficulty) { if (difficulty.getSelectedIndex() == LEVEL1) { } if (difficulty.getSelectedIndex() == LEVEL2) { } if (difficulty.getSelectedIndex() == LEVEL3) { } } } public void actionPerformed(ActionEvent evt) { if (isApplication && MenuCreator.processExitEvent(evt)) { return; } if (evt.getSource() == bUpdate && inputValidation(data_area.getText())) { plot.plotData(data_area.getText()); plot.drawAll(); if (bShowAnswers.getLabel().equalsIgnoreCase(HIDE)) { showAnswers(); } else { mean_field.setText(""); median_field.setText(""); mode_field.setText(""); } } else if (evt.getSource() == bClear) { data_area.setText(""); plot.plotData(data_area.getText()); plot.drawAll(); mean_field.setText(""); median_field.setText(""); mode_field.setText(""); bShowAnswers.setLabel(SHOW); } else if (evt.getSource() == bCheckAnswers && inputValidation(data_area.getText())) { plot.plotData(data_area.getText()); try { mean = mean_field.getDouble(); } catch (NumberFormatException e) { doError("I cannot understand your value for the mean. Please try again."); return; } try { median = median_field.getDouble(); } catch (NumberFormatException e) { doError("I cannot understand your value for the median. Please try again."); return; } modes = mode_field.getText().trim(); boolean modesCorrect = false; try { modesCorrect = checkModes(plot.getModes(), modes); } catch (NumberFormatException nfe) { doError(nfe.getMessage()); return; } if (Math.abs(mean - plot.getMean()) < LINEAR_TOLERANCE) mean_field.setText(CORRECT); else mean_field.setText(INCORRECT); if (Math.abs(median - plot.getMedian()) < LINEAR_TOLERANCE) median_field.setText(CORRECT); else median_field.setText(INCORRECT); if (modesCorrect) mode_field.setText(CORRECT); else mode_field.setText(INCORRECT); plot.drawAll(); } else if (evt.getSource() == bShowAnswers) { if (bShowAnswers.getLabel().equalsIgnoreCase(SHOW)) { if (inputValidation(data_area.getText())) { plot.plotData(data_area.getText()); showAnswers(); plot.drawAll(); bShowAnswers.setLabel(HIDE); } } else { mean_field.setText(""); median_field.setText(""); mode_field.setText(""); bShowAnswers.setLabel(SHOW); } } else if (evt.getSource() == bSetTitle) { plotTitle.setText(tfTitle.getText().trim()); }/* TODO:Test code */ if (evt.getSource() == cbView) { cbGuess.setEnabled(false);// disables guess checkbox pButton.setVisible(false); pScore.setVisible(false);// only visible in guess mode } if (evt.getSource() == cbGuess) { cbView.setEnabled(false);// disables view checkbox pButton.setVisible(true); } if (evt.getSource() == bShowAnswers && evt.getSource() == cbGuess) { bCheckAnswers.setEnabled(false); } else if (evt.getSource() == bNext) ; } // Account for the question types. public String getQuestionType() { if (cbView.getState()) { return ProgressReporter.MEAN; } else if (cbView.getState()) { return ProgressReporter.MEDIAN; } else { return ProgressReporter.MODE; } } private void showAnswers() { boolean needZero = true; String temp = ""; temp = StrLib.chopZeros(StrLib.round(plot.getMean(), 5)); for (int i = 0; i < temp.length(); i++) { if (temp.charAt(i) == '.') { needZero = false; } } if (needZero == true) { temp = temp + ".0"; } mean_field.setText(temp); median_field.setText(String.valueOf(plot.getMedian())); if ((plot.getModeString()).length() != 0) { mode_field.setText(plot.getModeString()); } else { mode_field.setText("No mode"); } } private boolean inputValidation(String data) { StringTokenizer c; double temp; c = new StringTokenizer(data); try { while (c.hasMoreTokens()) { temp = Double.parseDouble(c.nextToken()); if ((temp > 999) || (temp < 0)) { doError("All entries must be whole " + " numbers between " + " 0" + " and " + "999."); return false; } } } catch (NumberFormatException e) { doError("At least one of the values you entered is unreadable as a number. Please check your input and try again."); return false; } return true; } private boolean checkModes(double[] modes, String s) throws NumberFormatException { StringTokenizer mode = new StringTokenizer(s, " ,;&", false); int[] user_modes = new int[mode.countTokens()]; int count = 0; int[] final_user_modes; LinkedList p1 = new LinkedList(); if (s.equalsIgnoreCase("no mode")) { if (modes.length == 0) { return true; } else { return false; } } while (mode.hasMoreTokens()) { String nextToken = mode.nextToken(); if (nextToken.indexOf('.') != -1) { throw new NumberFormatException(NumInput.NUMDECIMAL); } try { user_modes[count] = (Integer.valueOf(nextToken)).intValue(); count = count + 1; } catch (NumberFormatException e) { throw new NumberFormatException( "I cannot understand a number you typed. Please try again."); } } // sorts arrays for easier testing and removes repeated numbers from // users guess of mode if (user_modes.length > 0) { org.shodor.util11.QuickSort.sort(user_modes); // removes repeated numbers from the users guess of mode int num = user_modes[0]; for (int i = 1; i < user_modes.length; i++) { if (user_modes[i] != num) { p1.add(new Integer(num)); } num = user_modes[i]; } p1.add(new Integer(user_modes[user_modes.length - 1])); final_user_modes = new int[p1.size()]; int listSize = p1.size(); // convert list back into array for (int i = 0; i < listSize; i++) { final_user_modes[i] = ((Integer) p1.removeFirst()).intValue(); } } else { final_user_modes = new int[user_modes.length]; for (int i = 0; i < user_modes.length; i++) { final_user_modes[i] = user_modes[i]; } } if (modes.length > 0) { org.shodor.util11.QuickSort.sort(modes); } // this catches if they leave the mode field blank if (final_user_modes.length == 0 && modes.length == 0) { return true; } else if (final_user_modes.length != modes.length) { return false; } else { for (int i = 0; i < modes.length; i++) { if ((int) modes[i] != final_user_modes[i]) { return false; } } } return true; } private void doError(String errorMsg) { if (msg == null || !msg.isShowing()) { msg = new MsgWindow(MsgWindow.getFrame(getParent()), "Error", errorMsg); msg.setVisible(true); } } /** * Allow applet to be run as an application * * @param args * Must have three parameters, Width, height, and the application * title e.g. 800 600 "Bargraph Applet" */ public static void main(String args[]) { isApplication = true; // Create an instance of the applet StemLeaf myApplet = new StemLeaf(); // Create the frame this applet will run in ShodorApplicationFrame appletFrame = new ShodorApplicationFrame( myApplet, MenuCreator.createOnlyExitMenu(myApplet)); appletFrame.validate(); } }