source: trunk/gsdl/src/phind/client/ResultCanvas.java@ 1640

Last change on this file since 1640 was 1640, checked in by paynter, 24 years ago

Resolve partial URLs like "phindcgi" and /cgi-bin/library" with respect to
the URL of the document containing the applet. Also lets us pass in extra
parameters to cgi scripts, which will let us keep the Greenstone settings
stored in the "e=...." argument to library.

  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
RevLine 
[1626]1/**********************************************************************
2 *
3 * ResultCanvas.java -- a Canvas onto which a phrase list is drawn
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 *********************************************************************/
[1621]27
[1626]28/*********************************************************************
[1621]29
[1626]30This class is used in the Phind java applet (Phind.java).
31
32The results of a query are displayed on a ResultCanvas object. Each
33line of the result is stored in a ResultItem, and the ResultCanvas
[1621]34contains a Vector of ResultItems.
35
[1626]36Each ResultCanvas is embedded in a ResultBox alongside a Scrollbar.
37When the ResultCanvas is drawn, it looks at the scrollbar, calculates
38which ResultItems are visible, then draws them on the screen.
[1621]39
[1626]40**********************************************************************/
[1621]41
[1626]42
[1621]43import java.awt.Canvas;
44import java.awt.Scrollbar;
45import java.awt.Graphics;
46import java.awt.Font;
47import java.awt.FontMetrics;
48import java.awt.Dimension;
49import java.awt.Color;
50import java.util.Vector;
51import java.awt.Image;
52import java.awt.Event;
53
54import java.net.URL;
55import java.applet.Applet;
56import java.util.Date;
57
58public class ResultCanvas extends Canvas {
59
[1626]60 // Other objects associated with this
61 Phind phind;
62 ResultBox parent;
63 Scrollbar scrollbar;
[1621]64
[1626]65 // fonts and font spacings to use
66 Font areaPlain, areaBold;
67 int lineSpacing;
[1621]68
69 // The phrases to display on this canvas
[1626]70 int numberOfPhrases;
71 int firstPhraseDisplayed;
72 int phraseSelected;
73 Vector phrases;
[1621]74
75 // the background image
[1626]76 public static Image backgroundImage;
[1621]77
78
[1626]79 // Create a ResultCanvas from the ResultBox which is its parent.
80 ResultCanvas(ResultBox p) {
[1621]81
[1626]82 parent = p;
83 phind = p.phind;
84 scrollbar = p.s;
85 parent.disableScrollbar();
[1621]86
[1626]87 areaPlain = phind.plainFont;
88 areaBold = phind.boldFont;
[1621]89
[1626]90 lineSpacing = phind.fontSize + 2;
[1621]91
[1626]92 phrases = new Vector();
93 numberOfPhrases = 0;
94 firstPhraseDisplayed = 0;
95 phraseSelected = -1;
[1621]96
[1626]97 if (backgroundImage == null) {
98 backgroundImage = p.phind.backgroundImage;
99 }
100
[1621]101 }
102
[1626]103 void resetCanvas( ) {
104 phrases.removeAllElements();
105 numberOfPhrases = 0;
106 repaint();
107 }
[1621]108
109
[1626]110 // add a new item of input.
111 // return true if successful, otherwise false.
112 boolean addResultItem( ResultItem item ) {
[1621]113
[1626]114 // Add a new result, in sorted order.
115 // First sort key is item kind (lowest first),
116 // second is frequency (highest first).
117 // This is not efficient, but I don't care right now.
118 int index = 0;
119 while ((index < numberOfPhrases) &&
120 ((item.kind > ((ResultItem) phrases.elementAt(index)).kind) ||
121 ((item.kind == ((ResultItem) phrases.elementAt(index)).kind) &&
122 (item.freq <= ((ResultItem) phrases.elementAt(index)).freq)))) {
123 index++;
124 }
125 phrases.insertElementAt(item,index);
126 numberOfPhrases++;
127 return true;
[1621]128 }
129
130
[1626]131 // Make sure the more Phrases item only appears in the list
132 // if it is meant to.
133 void updateMorePhrasesMarker() {
[1621]134
[1626]135 // System.out.println("updateMorePhrasesMarker() ");
[1621]136
[1626]137 // look for a marker
138 boolean found = false;
139 int index = 0;
140 while (!found && (index < numberOfPhrases)) {
141 if (((ResultItem) phrases.elementAt(index)).isMorePhrases()) {
142 // System.out.println("found marker at: " + index + " of " + numberOfPhrases);
143 found = true;
144 } else {
145 index++;
146 }
147 }
[1621]148
[1626]149 if (parent.expansionsRetrieved == parent.numberOfExpansions) {
150 // there should be no marker
151 // System.out.println("No marker needed");
152 if (found) {
153 // System.out.println("Remove marker");
154 phrases.removeElementAt(index);
155 numberOfPhrases--;
156 }
[1621]157
[1626]158 } else if (parent.expansionsRetrieved < parent.numberOfExpansions) {
159 // there should be a marker
160 // System.out.println("Needs marker");
[1621]161
[1626]162 if (!found) {
163 // System.out.println("Add marker");
164 ResultItem ri = new ResultItem(ResultItem.morePhrases, parent.searchKey);
165 addResultItem(ri);
166 }
167 }
[1621]168 }
169
170
[1626]171 // Make sure the more documents marker appears when required
172 void updateMoreDocumentsMarker() {
[1621]173
[1626]174 // System.out.println("updateMoreDocumentsMarker() ");
[1621]175
[1626]176 // look for a marker
177 boolean found = false;
178 int index = 0;
179 while (!found && (index < numberOfPhrases)) {
180 if (((ResultItem) phrases.elementAt(index)).isMoreDocuments()) {
181 found = true;
182 } else {
183 index++;
184 }
185 }
[1621]186
[1626]187 if (parent.documentsRetrieved == parent.numberOfDocuments) {
188 // there should be no marker
189 if (found) {
190 phrases.removeElementAt(index);
191 numberOfPhrases--;
192 }
[1621]193
[1626]194 } else if (parent.documentsRetrieved < parent.numberOfDocuments) {
195 // there should be a marker
196 if (!found) {
197 ResultItem ri = new ResultItem(ResultItem.moreDocuments, parent.searchKey);
198 addResultItem(ri);
199 }
200 }
[1621]201 }
202
203
204
205
206
207
[1626]208 public void update(Graphics g) {
209 paint(g);
210 }
[1621]211
[1626]212 public void paint(Graphics g) {
[1621]213
[1626]214 // calculate the canvas size, margins, and spacing
215 Dimension canvasSize = getSize();
[1621]216
[1626]217 g.setFont(areaPlain);
218 int space = g.getFontMetrics().stringWidth(" ");
219 int margin = g.getFontMetrics().stringWidth(" 8888 ");
[1621]220
[1626]221 int leftMargin = 0;
222 int secondColumn = canvasSize.width - margin;
223 int firstColumn = secondColumn - margin;
224 int rightMargin = firstColumn;
[1621]225
[1626]226 // calculate the number of values that will fit onscreen
227 int visible = canvasSize.height / lineSpacing;
[1621]228
[1626]229 // get the initial scrollbar setting
230 // and calculate the first result to output
231 int scrollValue = scrollbar.getValue();
232 if (numberOfPhrases <= visible) {
233 scrollValue = 0;
234 } else if (scrollValue > (numberOfPhrases - visible)) {
235 scrollValue = numberOfPhrases - visible;
236 }
237 firstPhraseDisplayed = scrollValue;
[1621]238
[1637]239 // Draw the phrase area
240
[1626]241 // draw the background
242 if (phind.showImage) {
[1627]243 try {
244 g.drawImage(backgroundImage,
245 leftMargin, 0, rightMargin, canvasSize.height,
246 Color.white, null);
247 } catch (Exception e) {
248 phind.showImage = false;
249 System.err.println("ResultCanvas paint error: " + e);
250 g.setColor(Color.white);
251 g.fillRect(0, 0, canvasSize.width, canvasSize.height);
252 }
[1626]253 } else {
254 g.setColor(Color.white);
255 g.fillRect(0, 0, canvasSize.width, canvasSize.height);
256 }
[1621]257
[1637]258 // If there are no phrases, output a brief explanation.
[1626]259 if (numberOfPhrases == 0) {
260 g.drawString("No phrases match this query.", leftMargin + 10, lineSpacing);
261 }
[1621]262
[1626]263 // Output each of the visible ResultItems
[1637]264 ResultItem result;
[1626]265 int tab, i, y = 0;
[1637]266 int center = leftMargin
267 + ((rightMargin - leftMargin
268 - g.getFontMetrics().stringWidth(parent.searchPhrase)) / 2);
269
270 for (i = scrollValue;
271 (i < numberOfPhrases) && (y + lineSpacing < canvasSize.height); i++) {
[1621]272
[1626]273 // Get the resultItem to output
274 result = (ResultItem) phrases.elementAt(i);
[1637]275
[1626]276 // Graphics settings for drawing this line
277 y += lineSpacing;
278 g.setFont(areaPlain);
[1621]279
[1626]280 // Highlight if the selected phrase.
281 if (i == phraseSelected) {
282 g.setColor(new Color(255, 220, 115));
283 g.fillRect(leftMargin, y-lineSpacing+2, rightMargin, lineSpacing);
284 g.setColor(Color.black);
285 }
[1621]286
[1637]287 // Draw the item
[1621]288
[1626]289 if (result.isPhrase()) {
290 // The item is a Phrase
291 tab = center - g.getFontMetrics().stringWidth(result.prefix) - space;
292 g.drawString(result.prefix, tab, y);
293 g.setFont(areaBold);
294 g.drawString(result.body, center, y);
295 tab = center + space + g.getFontMetrics().stringWidth(result.body);
296 g.setFont(areaPlain);
297 g.drawString(result.suffix, tab, y);
[1621]298
[1626]299 } else if (result.isDocument()){
300 // The item is a URL
301 g.setFont(areaPlain);
302 g.setColor(Color.blue);
303 tab = (rightMargin - g.getFontMetrics().stringWidth(result.body)) / 2;
304 g.drawString(result.body, tab, y);
305 g.setColor(Color.black);
[1621]306
[1626]307 } else if (result.isMorePhrases()){
308 // The item is a More documents marker
309 g.setColor(new Color(255, 200, 200));
310 g.fillRect(leftMargin, y-lineSpacing+2, rightMargin, lineSpacing);
311 g.setColor(Color.black);
[1621]312
[1626]313 g.setFont(areaPlain);
314 tab = (rightMargin - g.getFontMetrics().stringWidth("Get more phrases")) / 2;
315 g.drawString("Get more phrases", tab, y);
[1621]316
[1626]317 } else if (result.isMoreDocuments()){
318 // The item is a More documents marker
319 g.setColor(new Color(150, 193, 156));
320 g.fillRect(leftMargin, y-lineSpacing+2, rightMargin, lineSpacing);
321 g.setColor(Color.black);
[1621]322
[1626]323 g.setFont(areaPlain);
324 tab = (rightMargin - g.getFontMetrics().stringWidth("Get more documents")) / 2;
325 g.drawString("Get more documents", tab, y);
[1621]326
[1626]327 }
[1621]328
[1626]329 }
[1621]330
[1637]331 // Draw the frequecy columns
332
333 // column backgrounds
334 g.setColor(new Color(235, 245, 235));
335 g.fillRect(firstColumn, 0, margin, canvasSize.height);
336 g.setColor(new Color(200, 220, 200));
337 g.fillRect(secondColumn, 0, margin, canvasSize.height);
338
339 // fill in the numbers
340 g.setColor(Color.black);
341 g.setFont(areaPlain);
342 y = 0;
343
344 for (i = scrollValue;
345 (i < numberOfPhrases) && (y + lineSpacing < canvasSize.height); i++) {
346
347 // Get the resultItem to output
348 result = (ResultItem) phrases.elementAt(i);
349
350 // Graphics settings for drawing this line
351 y += lineSpacing;
352
353 // Write the document frequency
354 if ((result.documents > 1) || result.isPhrase()) {
355 g.drawString(" " + Integer.toString(result.documents), firstColumn, y);
356 }
357
358 // Write the term frequency
359 if (result.freq > 0) {
360 g.drawString(" " + Integer.toString(result.freq), secondColumn, y);
361 }
362 }
363
364 // Adjust the scrollbar
[1626]365 if (visible >= numberOfPhrases) {
366 parent.disableScrollbar();
367 } else {
368 //System.out.println("s " + scrollValue + ", v " + visible
369 // + ", m " + (numberOfPhrases));
370 scrollbar.setValues(scrollValue, visible, 0, numberOfPhrases);
371 scrollbar.setBlockIncrement(visible - 1);
372 scrollbar.setEnabled(true);
373 }
374
375 g.drawRect(0,0, canvasSize.width - 1, canvasSize.height - 1);
[1621]376 }
377
378
[1627]379 // User interaction
380 //
381 // All interaction with the ResultCanvas is therough mouse clicks, and
382 // is handles in this method. Note we ignore clicks that follow
383 // another too closely to avoid problems with slow connections.
[1626]384 public boolean handleEvent(Event event) {
[1621]385
[1626]386 if (event.id == Event.MOUSE_UP) {
[1621]387
[1626]388 // ignore actions that occur within 1 second of the last
389 Date now = new Date();
390 // System.out.println("Click time: " + now.toString());
391 if (now.getTime() < (phind.lastQueryEndTime.getTime() + 1000)) {
392 System.out.println("Ignoring click - too close to last query.");
393 return true;
394 }
[1621]395
[1626]396 // which Item is selected?
397 int rowSelected = event.y / lineSpacing;
398 int itemSelected = rowSelected + firstPhraseDisplayed;
399 ResultItem item = (ResultItem) phrases.elementAt(itemSelected);
[1621]400
[1626]401 // System.out.println("Select: " + String.valueOf(rowSelected) );
402 if (itemSelected <= numberOfPhrases) {
[1621]403
[1626]404 // What do we do with the event?
405 // If user clicks on a phrase, we expand the phrase
406 // or send the phrase to a search engine (right click)
[1621]407
[1626]408 if (item.isPhrase()) {
409 // Expand the phrase
[1621]410
[1626]411 phraseSelected = itemSelected;
412 update(getGraphics());
[1621]413
[1626]414 parent.lookupPhrase(item.rule, item.toString(), 2);
[1621]415
[1626]416 if (event.metaDown()) {
417 // Also send to search engine
418 if (phind.search_url.equals("none") || phind.search_url.equals("")) {
419 System.out.println("No searching in this collection");
420 } else {
421 URL url;
422 try {
423 url = new URL(phind.search_url + "%22" + item.toString() + "%22&");
424 phind.getAppletContext().showDocument(url, "phindsearch");
425 System.out.println("The query is: " + url.toString());
426 } catch (Exception e) {
427 System.out.println("URL error: " + e.toString());
428 }
429 }
430 }
[1621]431
[1626]432 } else if (item.isDocument()) {
433 // The user clicks on a URL; display it.
434 phraseSelected = itemSelected;
435 update(getGraphics());
[1621]436
[1626]437 URL url;
438 try {
439 String address = phind.library_address
[1640]440 + "a=d&c=" + phind.collection
[1626]441 + "&d=" + item.rule;
442 url = new URL(address);
443 System.out.println("URL selected: " + url.toString());
444 phind.getAppletContext().showDocument(url, "phindselect");
445 } catch (Exception e) {
446 System.out.println("URL error: " + e.toString());
447 }
[1621]448
[1626]449 } else if (item.isMorePhrases()){
450 // The user clicks on a "get more phrases" marker.
451 // We have to send a new query to the host
452 parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 3);
[1621]453
[1626]454 } else if (item.isMoreDocuments()){
455 parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 4);
[1621]456
457
[1626]458 }
459 repaint();
460 }
[1621]461 }
[1626]462 return true;
463 }
[1621]464
465}
466
467
468
Note: See TracBrowser for help on using the repository browser.