/** * @Lookup.java * @version 1.1, 10 Apr 1998 * @author: John Donohue * * This applet allows the user to search, by keyword, through a flat file of records. * The user can specify one or more fields in each record to search on. * If only one is given the applet treats each record as one field and searches and * displays it as a whole. If more than one field is given it assumes that the file has * one record per line, and the fields in each line are delimited with a field separator * character (like comma or "|") * The fields are specified as parameters in the APPLET HTML code. For each field * the applet displays a text box for searching inside of that field. * When the serach button, or RETURN, is hit the applet does a AND search * through the data file. Only records that have fields that contain all or part of * the string entered in its corresponding text box will be shown. * * Example of APPLET code: * * * * * * * * * Parameters: * * UrlOfDataFile * Is the flat file with the records to search. * This must be a URL of a file that the browser running the Apllet is allowed * to retreive (i.e. on the same web server as the applet). * You can make this the same html file that calls the applet. This will * give you a web page with a search applet at the top of the page, and a list of * all the data below. When reading the flat file the applet only uses lines * that do not contain the "<". You can therefore put html code in this file * above and below the actual lines of data. * * fieldNames * This is a list of the fields in each line of the data file. * Each field is given a name to label it with. Following each field name is a * number that specifies the number of characters to display in the results box * for this field before truncation. * In this example the fiels are "First Name", "Last Name", and "Phone #", * and when displaying the results we will truncate after 12, 20, and 15 * characters respectively. This applet will not work if the data does not * match the layout given in the fieldnaemes parameter. * * fieldSeparatorCharacter * This the character that delimites each field in the data file. Pick something * that isn't likely to be in inside a field in your data file. * * foregroundColor/backgroundColor * This is the colors to use for the foreground(text) and background in the applet * The colors are specifed using the same notation as the HTML BODY tag. * If you want the applet to blend in with the page its on, give it the * same colors as the in your html page. */ import java.awt.*; import java.applet.*; import java.util.*; import java.io.*; import java.net.*; /** * The Applet. */ public class Lookup extends Applet { private TextArea resultsTA; private TextField searchKeysTF; private Button searchBT; private Panel fieldsPanel; private Panel resultsPanel; private Panel columnHeadingsPanel; private String fieldSeparatorCharacter; private String fieldNames; private String urlOfDataFile; private Vector dataLinesVector; private Vector fieldNamesVector; private Vector fieldsVector; private String eightyBlanks; private int currentFocus; private Vector tabOrderVector; public void start() { Enumeration enum; String backgroundColor; String foregroundColor; String currentToken; eightyBlanks = " "; dataLinesVector = new Vector(100); fieldNamesVector = new Vector(5); fieldsVector = new Vector(5); tabOrderVector = new Vector(6); searchBT = new Button("Search"); super.init(); //fieldsPanel will hold the N number of TextFields specified in the HTML code fieldsPanel = new Panel(); fieldsPanel.setLayout( new FlowLayout(FlowLayout.LEFT) ); //resultsPanel has a TextArea at bottom and a label at top that serves as a //column heading resultsPanel = new Panel(); resultsPanel.setLayout( new BorderLayout() ); //Put the column heading label in a FlowLayout.LEFT panel to left justify it. columnHeadingsPanel = new Panel(); columnHeadingsPanel.setLayout( new FlowLayout(FlowLayout.LEFT) ); resultsTA = new TextArea(); resultsTA.setEditable(false); //Need to use a Font with all the letters the same size, so that our //resutls will line up into columns //setFont(new Font("Courier", Font.PLAIN, 12) ); setFont(new Font("Helvetica", Font.PLAIN, 11) ); //Get the parameters specified in the APPLET tag of the HTML fieldSeparatorCharacter = getParameter("fieldSeparatorCharacter"); fieldNames = getParameter("fieldNames"); urlOfDataFile = getParameter("UrlOfDataFile"); backgroundColor = getParameter("backgroundColor"); foregroundColor = getParameter("foregroundColor"); //Change our foreground, and background color to the ones specified int backRed = (Integer.valueOf(backgroundColor.substring(0,2),16) ).intValue(); int backGreen = (Integer.valueOf(backgroundColor.substring(2,4),16) ).intValue(); int backBlue = (Integer.valueOf(backgroundColor.substring(4,6),16) ).intValue(); int foreRed = (Integer.valueOf(foregroundColor.substring(0,2),16) ).intValue(); int foreGreen = (Integer.valueOf(foregroundColor.substring(2,4),16) ).intValue(); int foreBlue = (Integer.valueOf(foregroundColor.substring(4,6),16) ).intValue(); setForeground(new Color(foreRed, foreGreen, foreBlue) ); setBackground(new Color(backRed, backGreen, backBlue) ); loadFieldParameters(); //Load in field names/length from Applet param, //and create "Field" objects and add it to screen. readDataUrl(); //Read in the data from URL supplied in Applet //parameter and save in string Vector. labelColumns(); //Create heading line of column labels fieldsPanel.add( new Label(" ")); //ensure some whitespace fieldsPanel.add(searchBT); tabOrderVector.addElement(searchBT); //Search button is last in tab order resultsPanel.add("Center", resultsTA); if ( fieldsVector.size() > 1) { //Set GridLayout so that our FlowLayout Panel with the N number of TextFields will //wrap instead of being its "preffered" size, which is all components on one line. setLayout( new GridLayout(2,1) ); add(fieldsPanel); resultsPanel.add("North", columnHeadingsPanel); add(resultsPanel); } else { //Set BorderLayout so that our FlowLayout Panel with the 1 TextFields will //be at "North" allowing the rest of the space for the results TextArea. setLayout( new BorderLayout() ); add("North", fieldsPanel); add("Center",resultsPanel); } //Put cursor in first TextField, and init our tab tracker ((Field)fieldsVector.elementAt(0)).fieldTextField.requestFocus(); currentFocus = 0; } public void stop() { removeAll(); } /** * Put Column heading labels above results TextArea. */ public void labelColumns() { String workStr = ""; String headingLine = ""; int numPadBlanks =0; if ( fieldsVector.size() > 1) { for ( int i=0; i < fieldsVector.size(); i++ ) { //Use field name supplied by HTML APPLET code workStr = ((Field)fieldsVector.elementAt(i)).fieldName; //If needed, pad blanks to fill up to start of next column(skip for last column) if ( workStr.length() < ((Field)fieldsVector.elementAt(i)).fieldLength && i < (fieldsVector.size() -1) ) { numPadBlanks = ( ((Field)fieldsVector.elementAt(i)).fieldLength - workStr.length() ); workStr = workStr + eightyBlanks.substring(0,numPadBlanks); } headingLine = headingLine + workStr; } } columnHeadingsPanel.add(new Label(headingLine)); } /** * Create A "Field" object for each field name supplied in the applet parms. */ public void loadFieldParameters() { String fieldName; Integer fieldLength; Field tmpField; //Load field names from Applet parameter into a Vector StringTokenizer t; t = new StringTokenizer(fieldNames, ","); while(t.hasMoreTokens() ) { fieldName = t.nextToken(); fieldLength = Integer.valueOf(t.nextToken()); tmpField = new Field( fieldName, fieldLength.intValue()); fieldsVector.addElement(tmpField); fieldsPanel.add(tmpField.fieldPanel); tabOrderVector.addElement(tmpField.fieldTextField); } } /** * Read in data from URL provided * Load each line into a Vector os strings for later searching. */ public void readDataUrl() { Enumeration enum; URL fileURL = null; InputStream input = null; DataInputStream dataInput = null; String inputLine = null; boolean moreRecords = true; try { fileURL = new URL(urlOfDataFile); } catch (MalformedURLException e) { resultsTA.appendText("Data file URL given is bad: Error MalformedURLException");} try { input = fileURL.openStream(); dataInput = new DataInputStream(input); } catch ( IOException e) { resultsTA.appendText("Data file URL not opened correctly");} while (moreRecords) { try { inputLine = dataInput.readLine(); if ( inputLine == null) { moreRecords= false; break; } if ( inputLine.indexOf("<") < 0 && !inputLine.equals("") ) { dataLinesVector.addElement(inputLine); } } catch ( IOException e) { resultsTA.appendText("Data file URL not read correctly"); } } try { dataInput.close(); } catch ( IOException e) { resultsTA.appendText("Error closing data file URL "); } } /** * Search through Vector of Strings holding raw input lines. * breaking each line into fields and comparing each field against its * the contents of its corresponding TextField input. */ private void doSearch() { StringTokenizer t; Enumeration linesEnum; Enumeration fieldsEnum; Vector fieldsInDataLineVector; String currentDataLine; String currentText; String currentToken; String workStr = ""; String resultLine =""; boolean gotHit; boolean noneFound; String currentElement; searchBT.disable(); noneFound = true; resultsTA.setText(""); linesEnum = dataLinesVector.elements(); // Get each line of data and break it up into fields. Save the fields // in a vector- then compare whats in field 1 to what was entered in // TextField 1 on the screen, and so on for all fields. while (linesEnum.hasMoreElements()) { resultLine = ""; gotHit = true; currentDataLine = (String)linesEnum.nextElement(); fieldsInDataLineVector = new Vector(10); //Break string into tokens including separator char back as tokens t = new StringTokenizer(currentDataLine, fieldSeparatorCharacter,true); // We get back "item" "sep-char" "item" "sep-char" .... for ( int i=0; i < fieldsVector.size(); i++ ) { currentElement = ""; //Default to no if (t.hasMoreTokens()) // If not at end of line { currentElement = (String)t.nextElement(); // If two separator characters in a row this item is blank if ( currentElement.startsWith(fieldSeparatorCharacter) ) currentElement = ""; else { if (t.hasMoreTokens()) // If not at end of line t.nextElement(); // Eat the separator character } } fieldsInDataLineVector.addElement(currentElement); } for ( int i=0; i < fieldsVector.size(); i++ ) { currentText = ((Field)fieldsVector.elementAt(i)).fieldTextField.getText(); currentToken = (String)fieldsInDataLineVector.elementAt(i); currentText = currentText.toLowerCase(); currentToken = currentToken.toLowerCase(); if ( !(currentText.equals("")) && currentToken.indexOf(currentText) < 0 ) gotHit = false; } if (gotHit) { noneFound = false; for ( int i=0; i < fieldsVector.size(); i++ ) { workStr = (String)fieldsInDataLineVector.elementAt(i); //If data field is less than display length pad it with blanks if ( workStr.length() < ((Field)fieldsVector.elementAt(i)).fieldLength ) { workStr = workStr + eightyBlanks.substring(0, ((Field)fieldsVector.elementAt(i)).fieldLength - workStr.length() ); } //If data field is >=less than display length truncate it. else { if ( fieldsVector.size() > 1) //Don't truncate if only 1 field { workStr = workStr.substring(0,((Field)fieldsVector.elementAt(i)).fieldLength -2); workStr = workStr + "* "; } } resultLine = resultLine + workStr; } resultsTA.appendText(resultLine + "\n"); } } if (noneFound) resultsTA.appendText("*** No matches Found ***\n"); else { resultsTA.insertText("!",0); //Insert at beginning to put scroll bar resultsTA.replaceText("",0,1); //back at top of TextArea-then blank it out } searchBT.enable(); } /** * */ public boolean action (Event e, Object o) { if ( e.target instanceof Button ) { if (e.target == searchBT) { doSearch(); } } return false; } /** * */ public boolean keyDown(Event e, int key) { // If tab key hit move the cursor amongst the TextFields if ( key == '\t') // Tab key hit { if ( e.shiftDown()) //Shift was down { currentFocus--; if (currentFocus < 0 ) currentFocus = tabOrderVector.size() -1; } else { currentFocus++; if (currentFocus > (tabOrderVector.size() -1) ) currentFocus =0; } ((Component)tabOrderVector.elementAt(currentFocus)).requestFocus(); } if ( key == Event.ENTER) { doSearch(); currentFocus =0; ((Component)tabOrderVector.elementAt(currentFocus)).requestFocus(); } return false; } /** */ public boolean handleEvent(Event evt) { return super.handleEvent(evt); } }