/** @author Scott Marshall @author University of Glasgow, MSc IT Project 2001 @author Building an OnLine Course in Computing Fundamentals Multiple Choice Questions */ package ukacgla_HTMLMulti; import ukacgla_HTMLMulti.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.JApplet; import javax.swing.border.*; import java.io.*; import java.util.*; import java.net.*; /** Generates user interface for the applet. This will display a single question at a time. */ public class TestUI { /** TestEngine is a complete series of questions. Each TestEngine contains a number of of TestItem objects.*/ private TestEngine testEngine; /** TestItem is a complete individual question. It contains the URL of the Question, and a collection of TestLine objects. */ private TestItem item; /** TestLine is a complete answer option to be displayed to the user, including Icons, answerLine is used to record the line the student has selected. */ private TestLine answerLine; /** Primitive int used to keep track of current index through the TestEngine, and retrieve each TestItem at that index within the TestEngine. */ private int questionCount = 0; /** Editor pane used to display the question. */ private Viewer questionViewer; /** Editor pane used to display further information related to the question. */ private Viewer outputViewer; private JCheckBox[] checkBox; private JApplet test; //applet being processed private Container contentPane; private JButton clear, reveal,refresh, nextQuestion, reset; private JPanel northPanel; //displays question private JPanel southPanel; //holds buttons and further information private JPanel centerPanel; //displays option private JPanel master; //JPanel holds the complete GUI. private Container c; public TestUI(TestEngine testEngine, JApplet test) { this.test = test; this.testEngine = testEngine; contentPane = test.getContentPane(); questionCount = 0; c = mkUI(getNextTextItem()); contentPane.add(c); contentPane.validate(); contentPane.repaint(); } //----------------------- TEST MANIPULATION METHODS ------------------------- /** Removes current container holding GUI Generates a new container to display next test item, then adds it to the content pane */ private void nextTest() { contentPane.removeAll(); c = mkUI(getNextTextItem()); contentPane.add(c); contentPane.validate(); contentPane.repaint(); } /** Retrieves next TestItem from the TestEngine. Returns either TestItem or a null object. Customer code must be prepared to deal with either */ private TestItem getNextTextItem(){ try { if ((item = testEngine.getNextTest(questionCount))!=null) questionCount++; } catch(IndexOutOfBoundsException e){ item = null; } return item; } /** Resets test back to first question in the current series. */ private void reset(){ questionCount = 0; nextTest(); } //----------------------- GUI METHODS ------------------------- /** Generates and returns a Container holding the complete GUI. TestItem objects are retrieved by the getNextTextItem() method. The TestItem object supplied by the method will be either an object or null. Null will be fed in when the student reaches the end of the testItems held in the TestEngine object. If not null, the TestItem will be displayed. If null, a defualt blank screen will be displayed. */ private JScrollPane mkUI(TestItem item){ //set to Windows look and feel try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { } master = new JPanel(new BorderLayout()); if (item!=null) { //----------------------- QUESTION VIEWER ------------------------- //1 row for JLabel, 1 row for HTML viewer northPanel = new JPanel(new BorderLayout()); northPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); JLabel question = new JLabel("Question View"); northPanel.add("North", question); int questionViewerSize = Integer.parseInt(test.getParameter("questionViewerSize")); questionViewer = new Viewer(item.getQuestionURL(),questionViewerSize); northPanel.add("Center",questionViewer); northPanel.validate(); master.add("North", northPanel); //----------------------- OPTION PANEL ------------------------- /** Aim is a n by 2 grid layout for question options. Set to number of lines divided by 2 (always round up) */ centerPanel = new JPanel(new BorderLayout()); centerPanel.add("North",new JLabel("Answer Options")); JPanel optionsPanel = new JPanel(new GridLayout((int) Math.round(item.getNumLines()/2.0),2)); centerPanel.add("Center",optionsPanel); centerPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); /** Set up array of checkboxes, one box for each test line. For each line make a JPanel, flowing left to right add a RigidArea for cosmetic appearance create and add a label to indicate the number of the option get the TestLine to be displayed make a label based on the text and icon (if any) of the test line, add it to the panel make a JCheckBox, and add it to the JPanel add the JPanel to the centerPanel Add the centerPanel to the master container. */ checkBox = new JCheckBox[item.getNumLines()]; for (int i=0; i End of this section's tests reached

"); questionViewer.displayPage(endText1); northPanel.add("Center",questionViewer); northPanel.validate(); master.add("North", northPanel); //----------------------- FURTHER INFORMATION VIEWER ------------------------- //make in intermediate panel (southPanel) to hold : 1. Further information viewer and 2.ButtonPanel southPanel = new JPanel(new BorderLayout()); southPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); //add label JLabel output = new JLabel("Program Output"); southPanel.add("North", output); //add viewer, set to default size of 1 outputViewer = new Viewer(1); String endText2 = mkHTMLString( "Press Reset on the applet to attempt the same series again.

" + "

Press Refresh (IE5) or Reload (Netscape) on your browser to generate" + "< another series of questions on this topic.

"); outputViewer.displayPage(endText2); southPanel.add("Center", outputViewer); //Make the buttons, add to panel and add to southPanel JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); reset = mkButton("Reset", buttonPanel); reset.setToolTipText("Back to start"); southPanel.add("South", buttonPanel); master.add("Center",southPanel); } JScrollPane masterPane = new JScrollPane(master); masterPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); return masterPane; } /** Returns JButton at defined size (150,40) with actionListener included */ private JButton mkButton(String nm,Container c) { JButton b = new JButton(nm); b.setForeground(Color.blue); b.setPreferredSize(new Dimension(150,40)); b.addActionListener(new ButtonListener()); c.add(b); return b; } /** Returns JCheckBox at defined size (20,20) with checkBoxListener included */ private JCheckBox mkChkButton(Container b,String name,boolean checked, String actionCommand) { JCheckBox temp = new JCheckBox(name,checked); temp.setPreferredSize(new Dimension(20,20)); temp.setActionCommand(actionCommand); temp.addItemListener(new checkBoxListener() ); b.add(temp); return temp; } /** Makes a JOptionPane with user specified message. */ private void makeDialog(String title,String message,int messageType,int optionType){ JOptionPane optionPane = new JOptionPane(message,messageType,optionType); JDialog dialog = optionPane.createDialog(contentPane,title); dialog.show(); } /** Strings must be formatted as HTML to avoid CSS exceptions being thrown when displayed in a viewer. Use with the Viewer displayPage(String s) method to display. */ private String mkHTMLString(String nm){ String temp = "" + "" + "" + nm + " "; return temp; } /** Sets all JCheckBoxes in GUI to de-selected. Used for each new table.*/ private void clear(){ for (int i = 0; i