import java.applet.*; import java.awt.*; import java.util.Vector; import MultiImageDisplay; import Location; /** * This Applet provides a tutorial service on points * on an image. It uses the MultiImageDisplay class * to present 1 or more images each with 0 or more * Locations to be learned. It has two modes: * * - Study mode: user can click on a point and * the name and description of that point * will be displayed. * * - Quiz mode: user is prompted to find a * point, and is congratulated if they succeed, * or insulted if they fail (no, not really). * * At all times, the user has access to a Choice * object that allows them to switch between the * images that make up the MultiImageDisplay. */ public class PointQuiz extends Applet { protected Label banner = null; protected Choice imageChooser; protected Label message; protected List pointList; protected TextArea textdisplay; protected Checkbox mode; protected MultiImageDisplay images; protected Vector allLocations; protected Location quizLocation; protected int quizTries; /** * this routine simply does some housekeeping * when the applet is started. */ public void start() { images.currentImage = 0; images.repaint(); imageChooser.select(0); quizLocation = null; quizTries = 0; mode.setState(false); message.setText("Study mode: please click on a point"); textdisplay.setText(""); return; } /** * The processParameters method picks up and * uses the dozens of parameters that this * Applet expects. It feeds much of this data * to the MultiImageDisplay, which must already * exist prior to this routine being called. * The following parameters are processed here. * (N and M represent decimal numbers in names) * * Name Value * -------------------------------------- * imageN URL for image no. N * nameN Name of image no. N * locN_M Location M on image N * in format name:x,y * descN_M Description of point M * on image N, string * * Values for N and M must be consecutive, or * this routine will not notice them. Values * of N and M start at 1. */ protected int processParameters() { int N = 1; int M; Image im_n; Location loc_m; String urlstr, pval; allLocations = new Vector(20); do { im_n = null; urlstr = getParameter("image" + N); if (urlstr != null) { im_n = images.addImage(this,urlstr); if (im_n != null) { images.currentImage = (N - 1); pval = getParameter("name" + N); if (pval == null) pval = urlstr; imageChooser.addItem(pval); M = 1; do { loc_m = null; pval = getParameter("loc"+N+"_"+M); if (pval != null) { try { loc_m = images.addLocation(pval); } catch (NumberFormatException e) { System.err.println("Bad location coord format" + " on location loc"+N+"_"+M); loc_m = null; } if (loc_m != null) { loc_m.tag = N - 1; allLocations.addElement(loc_m); pval = getParameter("desc"+N+"_"+M); if (pval != null) loc_m.setDesc(pval.replace('%', '\n')); } } M = M + 1; } while (loc_m != null); } } N = N + 1; } while (im_n != null); // sort allLocations int len = allLocations.size(); Object oi, oj, tmp; for(int i = 0; i < len - 1; i += 1) { oi = allLocations.elementAt(i); for(int j = i + 1; j < len; j += 1) { oj = allLocations.elementAt(j); if (oi.toString().compareTo(oj.toString()) > 0) { tmp = oi; oi = oj; allLocations.setElementAt(tmp,j); allLocations.setElementAt(oi,i); } } } // return number of locations found return allLocations.size(); } /** * This initialization function is called when * the applet starts. It creates the parts of * our interface, and then returns. */ public void init() { if (banner != null) return; /* first create all our GUI objects */ banner = new Label(" PointQuiz 0.3"); banner.setFont(new Font("TimesRoman", Font.BOLD, 18)); banner.setAlignment(Label.RIGHT); imageChooser = new Choice(); message = new Label("Starting PointQuiz, please wait..."); textdisplay = new TextArea(6, 34); textdisplay.setEditable(false); mode = new Checkbox("Quiz mode "); mode.setState(false); images = new MultiImageDisplay(6); images.setBackground(new Color(170,170,255)); // now process our parameters processParameters(); images.currentImage = 1; /* now lay out the objects */ setLayout(new FlowLayout(FlowLayout.LEFT,2,3)); int awid = size().width; int ahgt = size().height; add(imageChooser); add(banner); images.resize(awid - 8, (ahgt*61)/100); add(images); Panel botpanel = new Panel(); botpanel.setLayout(new BorderLayout(2,2)); // panel.setBackground(Color.pink); pointList = new List(6, false); for(int ix = 0; ix < allLocations.size(); ix += 1) pointList.addItem(allLocations.elementAt(ix).toString()); Panel subpanel = new Panel(); subpanel.setLayout(new BorderLayout(3,1)); subpanel.add("West",mode); subpanel.add("Center",message); botpanel.add("North", subpanel); botpanel.add("East", pointList); botpanel.add("Center", textdisplay); add(botpanel); show(); } /** * this picks a random Location object from our * allLocations vector. */ protected Location getRandomLocation() { int siz = allLocations.size(); return (Location)allLocations.elementAt( (int)(Math.floor(siz * Math.random()))); } /** * supplement just for the list... */ public boolean handleEvent(Event evt) { if (evt.id == Event.LIST_SELECT && evt.target == pointList) { Location sel; sel = (Location)(allLocations.elementAt(pointList.getSelectedIndex())); evt = new Event(evt.target, Event.ACTION_EVENT, sel); return action(evt, sel); } else return super.handleEvent(evt); } /** * this method is called when one of the components * in the applet gets activated. We get the event * and a supplementary object handle. * * The MultiImageDisplay component sends us an * action with a supplementary handle of a Location * if the user clicks on one. */ public boolean action(Event evt, Object obj) { boolean ret = false; String wrongpick = "nothing"; if (evt.target == imageChooser) { images.currentImage = imageChooser.getSelectedIndex(); images.repaint(); return true; } else if (evt.target == pointList) { if (obj instanceof Location) { Location loc = (Location)obj; textdisplay.setText("Selected: " + loc.name() + "\n" + loc.desc()); quizLocation = null; mode.setState(false); quizTries = 0; images.specialLocation = loc; images.currentImage = loc.tag; imageChooser.select(loc.tag); images.repaint(); return true; } } else if (evt.target == mode) { if (((Boolean)obj).booleanValue()) { quizLocation = getRandomLocation(); pointList.deselect(pointList.getSelectedIndex()); images.specialLocation = null; images.drawLocationPoints(null); } else { quizLocation = null; quizTries = 0; } ret = true; } else if (evt.target == images) { if (obj == null) { textdisplay.setText("No point there?\n" + "Please click on a point."); return true; } if (quizLocation == null) { // we are in study mode if (obj instanceof Location) { Location loc = (Location)obj; textdisplay.setText("Selected: " + loc.name() + "\n" + loc.desc()); images.specialLocation = loc; images.drawLocationPoints(null); pointList.deselect(pointList.getSelectedIndex()); int len = allLocations.size(); for(int fx = 0; fx < len; fx += 1) { if (allLocations.elementAt(fx).toString().equals(loc.toString())) { pointList.select(fx); break; } } } } else { // we are in quiz mode if (obj instanceof Location) { Location loc = (Location)obj; if (loc.name().equals(quizLocation.name())) { textdisplay.setText("Correct on " + (quizTries+1) + ((quizTries>0)?(" tries"):(" try")) + "!\n" + loc.name() + "\n" + loc.desc()); quizLocation = null; mode.setState(false); quizTries = 0; } else { wrongpick = loc.name(); quizTries += 1; } } } ret = true; } if (quizLocation != null) { if (quizTries > 0) { textdisplay.setText("Try no. " + quizTries + " incorrect.\n"); textdisplay.appendText("(you picked " + wrongpick + ")\n"); } else { textdisplay.setText("Quiz Mode!\n"); } textdisplay.appendText("Please find " + quizLocation.name()); message.setText("Quiz mode: find "+quizLocation.name()); } else { message.setText("Study mode: click on a point"); } return ret; } }