source: trunk/gsdl/src/phind/client/Phind.java@ 2054

Last change on this file since 2054 was 2054, checked in by paynter, 23 years ago

Convert UTF8 query terms into URL-safe "x-www-form-urlencoded" form before
sending them to phindcgi.

  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/**********************************************************************
2 *
3 * Phind.java -- the Phind java applet
4 *
5 * Copyright 1997-2000 Gordon W. Paynter
6 * Copyright 2000 The New Zealand Digital Library Project
7 *
8 * A component of the Greenstone digital library software
9 * from the New Zealand Digital Library Project at the
10 * University of Waikato, New Zealand.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 *********************************************************************/
27
28
29/*********************************************************************
30
31To use the applet, you'll need to embed it in a web page like this:
32
33<APPLET CODE="Phind.class" WIDTH=500 HEIGHT=500>
34
35 <PARAM NAME=collection VALUE="fao.org">
36 <PARAM NAME=classifier VALUE="1">
37 <PARAM NAME=phindcgi VALUE="http://kowhai/cgi-bin/phindcgi">
38 <PARAM NAME=library VALUE="http://kowhai/cgi-bin/library">
39 <PARAM NAME=backdrop VALUE="http://kowhai/~paynter/transfer/phindtest/green1.jpg">
40 The Phind java applet.
41</APPLET>
42
43There are a bunch of other parameters; these are described in the
44getParameters method below. It is all done for you in Greenstone
45in the document.dm macro file (the _phindapplet_ macro).
46
47You may have problems with Java applet security. Java applet's can only
48open socket connections (including the HTTP connections the applet uses
49to get data) to the same server the applet was loaded from. This means
50that your phindcgi, library, and (optional) backdrop URLs must be on the
51same machine that your web page was loaded from.
52
53**********************************************************************
54
55The applet comprises several classes:
56
571. Phind (this file) is the applet class, loaded by the browser.
58 It also handles network connections.
592. ResultDisplay is a Panel that sits in the applet and displays
60 things; displays are connected in a doubly-linked list.
613. ResultBox holds the results of a query. Result boxes are shown
62 to the user through ResultDisplays. Another doubly-linked list.
634. ResultTitle acts as a caption to a ResultBox describing its contents.
645. ResultCanvas is what the ResultBox data is drawn on. It draws the
65 words on the screen, and handles user input from the mouse.
666. ResultItem represents a single result object (a phrase or document).
677. PhindTitle is for drawing backdrops in ResultDisplays.
68
69**********************************************************************/
70
71
72import java.awt.BorderLayout;
73import java.awt.Button;
74import java.awt.Choice;
75import java.awt.Color;
76import java.awt.Component;
77import java.awt.Dimension;
78import java.awt.Event;
79import java.awt.FlowLayout;
80import java.awt.Font;
81import java.awt.GridLayout;
82import java.awt.Image;
83import java.awt.Label;
84import java.awt.Panel;
85import java.awt.TextField;
86
87import java.net.URL;
88import java.io.DataInputStream;
89
90import java.net.Socket;
91import java.net.InetAddress;
92import java.net.UnknownHostException;
93import java.io.IOException;
94
95import java.util.Vector;
96import java.util.Date;
97
98public class Phind extends java.applet.Applet {
99
100 // What is the collection called?
101 public String collection;
102
103 // Which phind classifier are we using? (There may be more than one.)
104 public String classifier;
105
106 // Internet address of phind resources
107 public String library_address, phindcgi_address;
108
109 // Initial serach term
110 public String initialSearch;
111
112 // Number of phrases to retrieve at any one time
113 public int phraseBlockSize;
114
115 // Appearance parameters
116 public boolean vertical;
117 public int depth;
118
119 // Font
120 public int fontSize;
121 public String fontName;
122 public Font plainFont, boldFont;
123
124 // Do we want a background image in the applet?
125 public boolean showImage;
126 public String backdrop_address;
127 public Image backgroundImage;
128 public boolean showBorder;
129
130 // Colours
131 public Color panel_fg, panel_bg,
132 column_1_fg, column_1_bg,
133 column_2_fg, column_2_bg,
134 highlight_fg, highlight_bg,
135 thesaurus_fg, thesaurus_bg, thesaurus_bar_fg, thesaurus_bar_bg,
136 expansion_fg, expansion_bg, expansion_bar_fg, expansion_bar_bg,
137 document_fg, document_bg, document_bar_fg, document_bar_bg,
138 message_fg, message_bg;
139
140 // Column dimensions
141 int column_1_width, column_2_width;
142
143 // Where do we open new windows
144 String searchWindowName, documentWindowName;
145
146 // the mode of operation
147 int mode;
148 final int initMode = 0;
149 final int idleMode = 1;
150 final int searchMode = 2;
151
152 // Elements of the control panel
153 boolean showControlPanel;
154 Label titleLabel;
155 TextField wordField;
156 Button searchButton, prevButton, nextButton;
157
158 // Holders for the downloaded data
159 Panel resultPanel;
160 ResultDisplay firstDisplay, lastDisplay;
161
162 // The time at which the last query finished
163 Date lastQueryEndTime;
164
165 // lastQueryEndTime is stored to ensure a 1 second gap between a query
166 // returning and a new one beginning. It is needed because the FAO
167 // folks in Rome have a huge lag, and frquently click several times
168 // while they wait; these clicks are turned into new queries, which
169 // they await again. It is no elegant solution, but it seems like the
170 // easiest, given that I don't know threads.
171 // 1. The search button is easy to disable, and is disabled when a
172 // socket connection is in progress.
173 // 2. ResutCanvas widgets can'r be similarly disabled because the
174 // browser hides or wipes them, which looks very bad.
175 // 3. I cannot just ignore clicks on canvasses because the browser
176 // caches the clicks while the socket connection is going on, and then
177 // sends them through afterwards, when the canvas is accepting clicks
178 // again.
179 // 4. Current sequence of events is to record the time the last query
180 // ends, then whenever a click happens make sure a second has past. if
181 // you double-click the the first query is sent, returns, end-tie is
182 // set, and the second (and any others made during query time) is
183 // *immediately* processed, but since 1 second hasn't past it is
184 // ignored.
185
186
187 public String getAppletInfo() {
188 return "Phind by Gordon Paynter ([email protected]). Copyright 1997-2000.";
189 }
190
191
192 public void init() {
193
194 mode = initMode;
195
196 // Read applet parameters
197 getParameters();
198
199 // Initialise the user interface
200 setBackground(panel_bg);
201 lastQueryEndTime = new Date();
202
203 // fonts used to output text
204 plainFont = new Font(fontName, Font.PLAIN, fontSize);
205 boldFont = new Font(fontName, Font.BOLD, fontSize);
206
207 // The phind applet layout manager
208 setLayout(new BorderLayout());
209
210 // Panel containing the displays is in the center of the display
211 resultPanel = new Panel();
212 if (vertical) {
213 resultPanel.setLayout(new GridLayout(depth,1,0,2));
214 } else {
215 System.out.println("horizontal");
216 resultPanel.setLayout(new GridLayout(1,depth,2,0));
217 }
218 add("Center", resultPanel);
219
220 // Create ResultDisplays and place into the interface
221 ResultDisplay d1, d2 = null;
222 firstDisplay = new ResultDisplay(this, null);
223 resultPanel.add(firstDisplay);
224
225 if (depth == 1) {
226 lastDisplay = firstDisplay;
227 } else {
228 d1 = firstDisplay;
229 for (int i = 2; i <= depth; i++) {
230 d2 = new ResultDisplay(this, d1);
231 resultPanel.add(d2);
232 d1 = d2;
233 }
234 lastDisplay = d2;
235 }
236
237 // The control panel
238 initialiseControlPanel();
239
240 // lets get started then
241 setStatus("Welcome to Phind.");
242 mode = idleMode;
243
244 // Perform initial search, if requested
245 if (initialSearch.length() > 0) {
246 searchForWord(initialSearch);
247 }
248 }
249
250
251 // Display a message in the status bar
252 void setStatus(String status) {
253 showStatus(status);
254 }
255
256 // The user performs an action in the interface
257 public boolean action(Event evt, Object arg) {
258
259 if (evt.target == searchButton) {
260 searchForWord(getSearchTerm());
261 } else if (evt.target == wordField) {
262 searchForWord(getSearchTerm());
263 } else if (evt.target == prevButton) {
264 shiftPrevious();
265 } else if (evt.target == nextButton) {
266 shiftNext();
267 } else {
268 System.out.println("unknown action: " + evt.toString()
269 + ", object: " + arg.toString());
270 }
271 return true;
272 }
273
274
275 // Search for a word
276 //
277 // Called on two occasions:
278 // when the "Search" Button is pressed, or
279 // to perform an "initial search"
280 void searchForWord(String searchWord) {
281
282 if (mode == idleMode) {
283
284 setSearchTerm(searchWord);
285
286 // Convert the String from UTF8 charaters into
287 // an encoding that is okay for a URL.
288 searchWord = URLUTF8Encoder.encode(searchWord);
289
290 // Look up the word
291 if (searchWord.length() > 1) {
292 setStatus("searching for \"" + searchWord + "\"");
293 firstDisplay.emptyContents();
294 ResultBox result = lookupPhraseOnServer(null, false, searchWord, searchWord, 2);
295
296 // if there is an error, return
297 if (result == null) {
298 setStatus("No results for \"" + searchWord + "\"");
299 return;
300 }
301
302 // display the result
303 result.display = firstDisplay.display(result);
304 result.resize(result.display.size());
305 result.paintAll(result.getGraphics());
306 }
307
308 enablePreviousAndNext();
309 }
310 }
311
312
313 // Search for a phrase
314 //
315 // If querymode is 2, the user has clicked on a phrase.
316 // If querymode is 3, the user has requested more phrases.
317 // If querymode is 4, the user has requested more documents.
318 void searchForPhrase(ResultBox source, String key, String phrase, int queryMode) {
319
320 // System.out.println("searchForPhrase: " + key + " " + phrase + " " + queryMode);
321
322 if (mode == idleMode) {
323
324 // If we are going to replace the first ResultDisplay, then empty it
325 if (queryMode <= 2) {
326 if (source.display.next != null) source.display.next.emptyContents();
327 }
328
329 // look up the word
330 setStatus("Searching for \"" + phrase + "\"");
331 ResultBox result = lookupPhraseOnServer(source, true, key, phrase, queryMode);
332 if (result == null) {
333 setStatus("No result for \"" + phrase + "\"");
334 return;
335 }
336
337 // If this is not already displayed, display it in the last free spot
338 if (queryMode <= 2) {
339 result.display = lastDisplay.display(result);
340 result.resize(result.display.size());
341 result.paintAll(result.getGraphics());
342 }
343
344 enablePreviousAndNext();
345 }
346 }
347
348
349 // Look up a phrase (or symbol) on the server
350 //
351 // Arguments are the source of the query (a ResultBox, or null if the
352 // query comes from hitting the search button), the key to search for
353 // (the text of a phrase or a symbol number), the phrase as a string,
354 // and the query mode.
355 // Query modes are:
356 // 0 = obsolete
357 // 1 = obsolete
358 // 2 = get first N phrases and URLs,
359 // 3 = get another N phrases into same window
360 // 4 = get another N documents into same window
361 // 5 = get another N thesaurus links into same window
362
363 ResultBox lookupPhraseOnServer(ResultBox source,
364 boolean keyKnown, String key, String phrase,
365 int queryMode) {
366 disableSearchButton();
367 mode = searchMode;
368 ResultBox r = null;
369
370 if (queryMode <= 2) {
371 r = new ResultBox(this, collection, key, phrase, source);
372 } else if ((queryMode == 3) || (queryMode == 4) || (queryMode == 5)) {
373 r = source;
374 }
375
376 try {
377 queryServer(keyKnown, key, queryMode, r);
378 } catch (Exception e) {
379 System.out.println("Phind query error: " + e.toString());
380 setStatus("Query error: " + e.toString());
381 mode = idleMode;
382 enableSearchButton();
383 return null;
384 }
385
386 // The query is finished
387 setStatus(r.c.numberOfItems + " results for \"" + phrase + "\"");
388 mode = idleMode;
389 enableSearchButton();
390 lastQueryEndTime = new Date();
391
392 return r;
393 }
394
395
396 // Query the phindcgi program
397 //
398 // Send a query (a word or symbol number) to the server
399 // and pass the response to a ResultBox.
400
401 void queryServer(boolean keyKnown, String word, int queryMode, ResultBox area)
402 throws IOException {
403
404 // Build the query
405 String query = phindcgi_address + "x=1&c=" + collection + "&d=" + classifier;
406
407 if (keyKnown) {
408 query = query + "&n=" + word;
409 } else {
410 query = query + "&p=" + word;
411 }
412
413
414 // Specify the set of results to return
415 int first_e = 0;
416 int last_e = 0;
417 int first_d = 0;
418 int last_d = 0;
419 int first_l = 0;
420 int last_l = 0;
421
422 // the initial query
423 if (queryMode <= 2) {
424 last_e = phraseBlockSize;
425 last_d = phraseBlockSize;
426 last_l = phraseBlockSize;
427 }
428
429 // add phrases to an existing result set
430 else if (queryMode == 3) {
431 first_e = area.nextPhraseBlock * phraseBlockSize;
432 area.nextPhraseBlock++;
433 last_e = area.nextPhraseBlock * phraseBlockSize;
434 }
435
436 // add documents to existing result set
437 else if (queryMode == 4) {
438 first_d = area.nextDocumentBlock * phraseBlockSize;
439 area.nextDocumentBlock++;
440 last_d = area.nextDocumentBlock * phraseBlockSize;
441 }
442
443 // add thesaurus links to existing result set
444 else if (queryMode == 5) {
445 first_l = area.nextThesaurusLinkBlock * phraseBlockSize;
446 area.nextThesaurusLinkBlock++;
447 last_l = area.nextThesaurusLinkBlock * phraseBlockSize;
448 }
449
450 query = query + "&e=" + first_e + "&f=" + last_e
451 + "&h=" + first_d + "&i=" + last_d
452 + "&k=" + first_l + "&l=" + last_l;
453
454 // Send the query to the phindcgi program
455 System.out.println("sending query: " + query);
456 try {
457 URL phindcgi = new URL(query);
458 DataInputStream in = new DataInputStream(phindcgi.openStream());
459 byte[] buffer;
460 int availableBytes = 0;
461
462 while (!area.finished) {
463 availableBytes = in.available();
464 if (availableBytes == 0) {
465 // if i had threads i'd do a wait here for 1 second
466 } else {
467 buffer = new byte[availableBytes];
468 in.read(buffer);
469 area.parseBytes(buffer);
470 }
471 }
472
473 in.close();
474 } catch (Exception e) {
475 System.err.println( "Error sending query to phindcgi: " + e);
476 }
477 area.repaint();
478 }
479
480
481 // Tidy up URLs
482 //
483 // Ensure a URL address (as string) has a protocol, host, and file.
484 //
485 // If the URL is a CGI script URL, it should be tidied up so that it is
486 // appropriate to tage attrib=value pairs on the end. This means it
487 // must either end with a "?" or (if it contains a question-mark
488 // internally) end with a "&".
489 String tidy_URL(String address, boolean isCGI) {
490
491 // System.out.println("tidy URL: " + address);
492
493 // make sure the URL has protocol, host, and file
494 if (address.startsWith("http")) {
495 // the address has all the necessary components
496 } else if (address.startsWith("/")) {
497 // there is not protocol and host
498 URL document = getDocumentBase();
499 address = "http://" + document.getHost() + address;
500 } else {
501 // this URL is relative to the dirwectory the document is in
502 URL document = getDocumentBase();
503 String directory = document.getFile();
504 int end = directory.lastIndexOf('/');
505 directory = directory.substring(0,end + 1);
506 address = "http://" + document.getHost() + directory + address;
507
508 }
509
510 // if the URL is a cgi script, make sure it has a "?" in ti,
511 // and that it ends with a "?" or "&"
512 if (isCGI) {
513 if (address.indexOf((int) '?') == -1) {
514 address = address + "?";
515 } else if (!address.endsWith("?")) {
516 address = address + "&";
517 }
518 }
519
520 return address;
521 }
522
523
524
525 // Open an arbitrary web page
526 void displayWebPage(String address, String window) {
527 try {
528 URL url= new URL(address);
529 if (window.length() > 0) {
530 getAppletContext().showDocument(url, window);
531 } else {
532 getAppletContext().showDocument(url);
533 }
534 } catch (Exception e) {
535 System.out.println("Cannot open web page: " + e.toString());
536 }
537 }
538
539
540 // Get the applet parameters
541 void getParameters() {
542
543 // What is this collection called?
544 collection = parameterValue("collection");
545 System.out.println("Phind collection: " + collection);
546
547 // Which of the collection's classifiers are we using?
548 classifier = parameterValue("classifier", "1");
549 System.out.println("Phind classifier: " + classifier);
550
551 // Where is the phind CGI script
552 phindcgi_address = parameterValue("phindcgi");
553 phindcgi_address = tidy_URL(phindcgi_address, true);
554 System.out.println("Phind phindcgi: " + phindcgi_address);
555
556 // Where is the Greenstone library
557 library_address = parameterValue("library");
558 library_address = tidy_URL(library_address, true);
559 System.out.println("Phind library: " + library_address);
560
561 // Is there a default search term?
562 initialSearch = parameterValue("initial_search", "");
563
564 // Should we display the control panel
565 showControlPanel = true;
566 if (parameterValue("control_panel", "show").toLowerCase().equals("hide")) {
567 showControlPanel = false;
568 }
569
570 // Should we show a background image?
571 backdrop_address = parameterValue("backdrop", "");
572 if (backdrop_address.length() > 0) {
573 backdrop_address = tidy_URL(backdrop_address, false);
574 System.out.println("Phind backdrop URL: " + backdrop_address);
575
576 try {
577 URL backdrop_url = new URL(backdrop_address);
578 backgroundImage = getImage(backdrop_url);
579 showImage = true;
580 } catch (Exception e) {
581 System.out.println("Phind could not load " + backdrop_address);
582 showImage = false;
583 }
584 }
585
586 // Should we draw a border?
587 showBorder = parameterValue("border", "on").equals("off");
588
589 // Are the windows arranged vertically or horizontally
590 if (parameterValue("orientation", "vertical").toLowerCase().startsWith("hori")) {
591 vertical = false;
592 } else {
593 vertical = true;
594 }
595
596 // How many phind windows are there?
597 depth = parameterValue("depth", 3);
598
599 // Result sort order
600 // Standard is "LlEeDd", expansion-first is "EeLlDd"
601 String order = parameterValue("resultorder", "standard");
602 if (!order.equals("standard")) {
603 int next = 20;
604 ResultItem.sortMessage = next;
605 for (int x = 0; x < order.length(); x++) {
606 if (order.charAt(x) == ',') {
607 next--;
608 } else if (order.charAt(x) == 'L') {
609 ResultItem.sortLinkItem = next;
610 } else if (order.charAt(x) == 'l') {
611 ResultItem.sortMoreLinks = next;
612 } else if (order.charAt(x) == 'E') {
613 ResultItem.sortPhraseItem = next;
614 } else if (order.charAt(x) == 'e') {
615 ResultItem.sortMorePhrases = next;
616 } else if (order.charAt(x) == 'D') {
617 ResultItem.sortDocumentItem = next;
618 } else if (order.charAt(x) == 'd') {
619 ResultItem.sortMoreDocuments = next;
620 }
621 }
622 System.out.println("link: " + ResultItem.sortLinkItem);
623 System.out.println("exps: " + ResultItem.sortPhraseItem);
624 System.out.println("docs: " + ResultItem.sortDocumentItem);
625
626 }
627
628 // How many phrases should we fetch at any given time?
629 phraseBlockSize = parameterValue("blocksize", 10);
630
631 // What font should we use?
632 fontSize = parameterValue("fontsize", 10);
633 fontName = parameterValue("fontname", "Helvetica");
634
635 // Column dimensions
636 column_1_width = parameterValue("first_column_width", 6);
637 column_2_width = parameterValue("second_column_width", column_1_width);
638
639 // Where do we open new windows
640 searchWindowName = parameterValue("search_window", "phindsearch");
641 documentWindowName = parameterValue("document_window", "phinddoc");
642
643 // Colours
644 panel_fg = parameterValue("panel_fg", Color.black);
645 panel_bg = parameterValue("panel_bg", Color.white);
646
647 highlight_bg = parameterValue("highlight_bg", Color.yellow);
648
649 expansion_fg = parameterValue("expansion_fg", Color.black);
650 thesaurus_fg = parameterValue("thesaurus_fg", new Color(0, 100, 0));
651 document_fg = parameterValue("document_fg", Color.blue);
652
653 thesaurus_bar_fg = parameterValue("thesaurus_bar_fg", Color.black);
654 expansion_bar_fg = parameterValue("expansion_bar_fg", Color.black);
655 document_bar_fg = parameterValue("document_bar_fg", Color.black);
656
657 thesaurus_bar_bg = parameterValue("thesaurus_bar_bg", new Color(160, 160, 190));
658 expansion_bar_bg = parameterValue("expansion_bar_bg", new Color(255, 200, 200));
659 document_bar_bg = parameterValue("document_bar_bg", new Color(150, 193, 156));
660
661 column_1_fg = parameterValue("first_column_fg", Color.black);
662 column_1_bg = parameterValue("first_column_bg", new Color(235, 245, 235));
663 column_2_fg = parameterValue("second_column_fg", Color.black);
664 column_2_bg = parameterValue("second_column_bg", new Color(200, 220, 200));
665
666 message_fg = parameterValue("message_fg", Color.black);
667 message_bg = parameterValue("message_bg", Color.white);
668
669 // Colours I don't use, yet
670 // thesaurus_bg = parameterValue("thesaurus_bg", Color.white);
671 // expansion_bg = parameterValue("expansion_bg", Color.white);
672 // document_bg = parameterValue("document_bg", Color.white);
673 }
674
675 // Get the value of a parameter given its name.
676 // There are many types of parameters, hence the variety of functions.
677
678 // Get a REQUIRED string. Stop the applet if we cannot.
679 String parameterValue(String name) {
680 try {
681 return getParameter(name);
682 } catch (Exception e) {
683 System.err.println("Phind: you must give a parameter for \""
684 + name + "\". Stopping.");
685 stop();
686 }
687 return "";
688 }
689
690 // Get an optional parameter. Return a default if we cannot.
691 String parameterValue(String name, String defaultValue) {
692 String text = getParameter(name);
693 if (text == null) {
694 return defaultValue;
695 }
696 System.out.println("Phind " + name + ": " + text);
697 return text;
698 }
699
700 int parameterValue(String name, int defaultValue) {
701 int value;
702 try {
703 value = Integer.parseInt(getParameter(name));
704 } catch (Exception e) {
705 return defaultValue;
706 }
707 System.out.println("Phind " + name + ": " + value);
708 return value;
709 }
710
711 Color parameterValue(String name, Color defaultValue) {
712
713 String text = getParameter(name);
714 if (text == null) {
715 return defaultValue;
716 }
717 text = text.toLowerCase();
718
719 // a number of the form "#ddffee"
720 if (text.startsWith("#") && (text.length() == 7)) {
721 text = text.substring(1);
722 int r, g, b;
723 try {
724 r = Integer.parseInt(text.substring(0,2), 16);
725 g = Integer.parseInt(text.substring(2,4), 16);
726 b = Integer.parseInt(text.substring(4), 16);
727 return new Color(r, g, b);
728 } catch (Exception e) {
729 return defaultValue;
730 }
731 }
732
733 // a known Java colour string
734 else if (text.equals("black")) { return Color.black; }
735 else if (text.equals("blue")) { return Color.blue; }
736 else if (text.equals("cyan")) { return Color.cyan; }
737 else if (text.equals("darkgray")) { return Color.darkGray; }
738 else if (text.equals("gray")) { return Color.gray; }
739 else if (text.equals("green")) { return Color.green; }
740 else if (text.equals("lightgray")) { return Color.lightGray; }
741 else if (text.equals("magenta")) { return Color.magenta; }
742 else if (text.equals("orange")) { return Color.orange; }
743 else if (text.equals("pink")) { return Color.pink; }
744 else if (text.equals("red")) { return Color.red; }
745 else if (text.equals("white")) { return Color.white; }
746 else if (text.equals("yellow")) { return Color.yellow; }
747
748 return defaultValue;
749 }
750
751
752 // Control panel operations
753
754 // Initialise the control panel
755 void initialiseControlPanel() {
756
757 if (showControlPanel) {
758 Panel p1 = new Panel();
759 add("North", p1);
760 p1.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
761
762 searchButton = new Button("Search");
763 searchButton.setFont(boldFont);
764 p1.add(searchButton);
765
766 Label tempLabel = new Label(" for");
767 tempLabel.setFont(boldFont);
768 p1.add(tempLabel);
769
770 wordField = new TextField(12);
771 wordField.setFont(boldFont);
772 p1.add(wordField);
773
774 Label temp2 = new Label(" ");
775 p1.add(temp2);
776
777 prevButton = new Button("Previous");
778 prevButton.setFont(boldFont);
779 prevButton.disable();
780
781 p1.add(prevButton);
782
783 nextButton = new Button(" Next ");
784 nextButton.setFont(boldFont);
785 nextButton.disable();
786 p1.add(nextButton);
787
788 }
789 }
790
791 // Button and field functionality
792
793 // Enable and disable the word field
794 void enableSearchButton() {
795 if (showControlPanel) {
796 searchButton.enable();
797 }
798 }
799 void disableSearchButton() {
800 if (showControlPanel) {
801 searchButton.disable();
802 }
803 }
804
805 // Get and set the search text in the wordField
806 String getSearchTerm() {
807 if (showControlPanel) {
808 return wordField.getText();
809 } else {
810 return initialSearch;
811 }
812 }
813 void setSearchTerm(String word) {
814 if (showControlPanel) {
815 wordField.setText(word);
816 }
817 }
818
819 // Enable or disable the "Previous" and "Next" buttons
820 void enablePreviousAndNext() {
821
822 if (showControlPanel) {
823 Component c = firstDisplay.current;
824 if (c.getClass().getName().equals("ResultBox")) {
825 if (((ResultBox) c).prevBoxExists()) {
826 prevButton.enable();
827 } else {
828 prevButton.disable();
829 }
830 }
831
832 c = lastDisplay.current;
833 if (c.getClass().getName().equals("ResultBox")) {
834 if (((ResultBox) c).nextBoxExists()) {
835 nextButton.enable();
836 } else {
837 nextButton.disable();
838 }
839 }
840 }
841 }
842
843 // Shift to previous box
844 //
845 // If the user clicks "Previous" then scroll up.
846 void shiftPrevious() {
847
848 Component c = firstDisplay.current;
849 if (c.getClass().getName().equals("ResultBox")) {
850
851 ResultBox b = (ResultBox) c;
852 if (b.prevBoxExists()) {
853 b = b.prev;
854
855 // empty all the displays
856 firstDisplay.emptyContents();
857
858 // add as many result boxes as there are displays
859 for (int i = 1 ; ((i <= depth) && (b != null)); i++) {
860 lastDisplay.display(b);
861 b.resize(b.display.size());
862 b.paintAll(b.getGraphics());
863 b = b.next;
864 }
865 }
866 }
867 enablePreviousAndNext();
868 }
869
870 // Shift to next box
871 //
872 // If the user clicks "Next" then scroll down if possible
873 void shiftNext() {
874
875 Component c = lastDisplay.current;
876 if (c.getClass().getName().equals("ResultBox")) {
877
878 ResultBox b = (ResultBox) c;
879 if (b.nextBoxExists()) {
880
881 // find the new "first" displayed box
882 c = firstDisplay.current;
883 b = (ResultBox) c;
884 b = b.next;
885
886 // empty all the displays
887 firstDisplay.emptyContents();
888
889 // add as many result boxes as there are displays
890 for (int i = 1 ; ((i <= depth) && (b != null)); i++) {
891 lastDisplay.display(b);
892 b.resize(b.display.size());
893 b.paintAll(b.getGraphics());
894 b = b.next;
895 }
896 }
897 }
898 enablePreviousAndNext();
899 }
900
901
902
903
904
905}
Note: See TracBrowser for help on using the repository browser.