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

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

Rearranged paint function so that frequencys do not get written over by
long titles and phrases.

  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
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 *********************************************************************/
27
28/*********************************************************************
29
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
34contains a Vector of ResultItems.
35
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.
39
40**********************************************************************/
41
42
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
60 // Other objects associated with this
61 Phind phind;
62 ResultBox parent;
63 Scrollbar scrollbar;
64
65 // fonts and font spacings to use
66 Font areaPlain, areaBold;
67 int lineSpacing;
68
69 // The phrases to display on this canvas
70 int numberOfPhrases;
71 int firstPhraseDisplayed;
72 int phraseSelected;
73 Vector phrases;
74
75 // the background image
76 public static Image backgroundImage;
77
78
79 // Create a ResultCanvas from the ResultBox which is its parent.
80 ResultCanvas(ResultBox p) {
81
82 parent = p;
83 phind = p.phind;
84 scrollbar = p.s;
85 parent.disableScrollbar();
86
87 areaPlain = phind.plainFont;
88 areaBold = phind.boldFont;
89
90 lineSpacing = phind.fontSize + 2;
91
92 phrases = new Vector();
93 numberOfPhrases = 0;
94 firstPhraseDisplayed = 0;
95 phraseSelected = -1;
96
97 if (backgroundImage == null) {
98 backgroundImage = p.phind.backgroundImage;
99 }
100
101 }
102
103 void resetCanvas( ) {
104 phrases.removeAllElements();
105 numberOfPhrases = 0;
106 repaint();
107 }
108
109
110 // add a new item of input.
111 // return true if successful, otherwise false.
112 boolean addResultItem( ResultItem item ) {
113
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;
128 }
129
130
131 // Make sure the more Phrases item only appears in the list
132 // if it is meant to.
133 void updateMorePhrasesMarker() {
134
135 // System.out.println("updateMorePhrasesMarker() ");
136
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 }
148
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 }
157
158 } else if (parent.expansionsRetrieved < parent.numberOfExpansions) {
159 // there should be a marker
160 // System.out.println("Needs marker");
161
162 if (!found) {
163 // System.out.println("Add marker");
164 ResultItem ri = new ResultItem(ResultItem.morePhrases, parent.searchKey);
165 addResultItem(ri);
166 }
167 }
168 }
169
170
171 // Make sure the more documents marker appears when required
172 void updateMoreDocumentsMarker() {
173
174 // System.out.println("updateMoreDocumentsMarker() ");
175
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 }
186
187 if (parent.documentsRetrieved == parent.numberOfDocuments) {
188 // there should be no marker
189 if (found) {
190 phrases.removeElementAt(index);
191 numberOfPhrases--;
192 }
193
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 }
201 }
202
203
204
205
206
207
208 public void update(Graphics g) {
209 paint(g);
210 }
211
212 public void paint(Graphics g) {
213
214 // calculate the canvas size, margins, and spacing
215 Dimension canvasSize = getSize();
216
217 g.setFont(areaPlain);
218 int space = g.getFontMetrics().stringWidth(" ");
219 int margin = g.getFontMetrics().stringWidth(" 8888 ");
220
221 int leftMargin = 0;
222 int secondColumn = canvasSize.width - margin;
223 int firstColumn = secondColumn - margin;
224 int rightMargin = firstColumn;
225
226 // calculate the number of values that will fit onscreen
227 int visible = canvasSize.height / lineSpacing;
228
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;
238
239 // Draw the phrase area
240
241 // draw the background
242 if (phind.showImage) {
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 }
253 } else {
254 g.setColor(Color.white);
255 g.fillRect(0, 0, canvasSize.width, canvasSize.height);
256 }
257
258 // If there are no phrases, output a brief explanation.
259 if (numberOfPhrases == 0) {
260 g.drawString("No phrases match this query.", leftMargin + 10, lineSpacing);
261 }
262
263 // Output each of the visible ResultItems
264 ResultItem result;
265 int tab, i, y = 0;
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++) {
272
273 // Get the resultItem to output
274 result = (ResultItem) phrases.elementAt(i);
275
276 // Graphics settings for drawing this line
277 y += lineSpacing;
278 g.setFont(areaPlain);
279
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 }
286
287 // Draw the item
288
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);
298
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);
306
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);
312
313 g.setFont(areaPlain);
314 tab = (rightMargin - g.getFontMetrics().stringWidth("Get more phrases")) / 2;
315 g.drawString("Get more phrases", tab, y);
316
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);
322
323 g.setFont(areaPlain);
324 tab = (rightMargin - g.getFontMetrics().stringWidth("Get more documents")) / 2;
325 g.drawString("Get more documents", tab, y);
326
327 }
328
329 }
330
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
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);
376 }
377
378
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.
384 public boolean handleEvent(Event event) {
385
386 if (event.id == Event.MOUSE_UP) {
387
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 }
395
396 // which Item is selected?
397 int rowSelected = event.y / lineSpacing;
398 int itemSelected = rowSelected + firstPhraseDisplayed;
399 ResultItem item = (ResultItem) phrases.elementAt(itemSelected);
400
401 // System.out.println("Select: " + String.valueOf(rowSelected) );
402 if (itemSelected <= numberOfPhrases) {
403
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)
407
408 if (item.isPhrase()) {
409 // Expand the phrase
410
411 phraseSelected = itemSelected;
412 update(getGraphics());
413
414 parent.lookupPhrase(item.rule, item.toString(), 2);
415
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 }
431
432 } else if (item.isDocument()) {
433 // The user clicks on a URL; display it.
434 phraseSelected = itemSelected;
435 update(getGraphics());
436
437 URL url;
438 try {
439 String address = phind.library_address
440 + "?a=d&c=" + phind.collection
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 }
448
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);
453
454 } else if (item.isMoreDocuments()){
455 parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 4);
456
457
458 }
459 repaint();
460 }
461 }
462 return true;
463 }
464
465}
466
467
468
Note: See TracBrowser for help on using the repository browser.