source: trunk/gsdl/src/recpt/queryaction.cpp@ 347

Last change on this file since 347 was 347, checked in by sjboddie, 25 years ago

had another crack at the format string code - created a new formattools
module. It can now handle {If} and {Or} statements although there's a
bug preventing nested if's and or's.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * PUT COPYRIGHT NOTICE HERE
7 *
8 * $Id: queryaction.cpp 347 1999-07-07 05:49:35Z sjboddie $
9 *
10 *********************************************************************/
11
12/*
13 $Log$
14 Revision 1.10 1999/07/07 05:49:35 sjboddie
15 had another crack at the format string code - created a new formattools
16 module. It can now handle {If} and {Or} statements although there's a
17 bug preventing nested if's and or's.
18
19 Revision 1.9 1999/07/01 22:48:46 sjboddie
20 had a go at getting a query result format string working
21
22 Revision 1.8 1999/06/27 22:02:11 sjboddie
23 author is added to queryresults if there is one
24
25 Revision 1.7 1999/06/26 01:10:18 rjmcnab
26 Made h, i, and n arguments saved in the compressed arguments.
27
28 Revision 1.6 1999/06/24 05:12:25 sjboddie
29 lots of small changes
30
31 Revision 1.5 1999/06/16 04:03:48 sjboddie
32 Now sets "cl" arg to "search" when going to a document from a search
33 results page. This allows the close book icon (in hierarchy toc) to
34 take you back to the results page if that's where you came from.
35 If you got to the document page somehow other than from a
36 classification or a search (i.e. if "cl" isn't set) then the close
37 book icon is disabled
38
39 Revision 1.4 1999/06/16 02:08:38 sjboddie
40 got queryaction working
41
42 Revision 1.3 1999/03/25 03:06:45 sjboddie
43
44 altered receptionist slightly so it now passes *collectproto to
45 define_internal_macros and define_external_macros - need it
46 for browseaction
47
48 Revision 1.2 1999/03/03 20:26:50 rjmcnab
49
50 Modified stuff.
51
52 Revision 1.1 1999/02/28 22:45:21 rjmcnab
53
54 Initial revision.
55
56 */
57
58
59#include "queryaction.h"
60#include "querytools.h"
61#include "formattools.h"
62
63queryaction::queryaction () {
64 // this action uses cgi variable "a"
65 cgiarginfo arg_ainfo;
66 arg_ainfo.shortname = "a";
67 arg_ainfo.longname = "action";
68 arg_ainfo.multiplechar = true;
69 arg_ainfo.defaultstatus = cgiarginfo::weak;
70 arg_ainfo.argdefault = "q";
71 arg_ainfo.savedarginfo = cgiarginfo::must;
72 argsinfo.addarginfo (NULL, arg_ainfo);
73
74 // "h"
75 arg_ainfo.shortname = "h";
76 arg_ainfo.longname = "main index";
77 arg_ainfo.multiplechar = true;
78 arg_ainfo.defaultstatus = cgiarginfo::weak;
79 arg_ainfo.argdefault = "";
80 arg_ainfo.savedarginfo = cgiarginfo::must;
81 argsinfo.addarginfo (NULL, arg_ainfo);
82
83 // "j"
84 arg_ainfo.shortname = "j";
85 arg_ainfo.longname = "sub collection index";
86 arg_ainfo.multiplechar = true;
87 arg_ainfo.defaultstatus = cgiarginfo::weak;
88 arg_ainfo.argdefault = "";
89 arg_ainfo.savedarginfo = cgiarginfo::must;
90 argsinfo.addarginfo (NULL, arg_ainfo);
91
92 // "n"
93 arg_ainfo.shortname = "n";
94 arg_ainfo.longname = "language index";
95 arg_ainfo.multiplechar = true;
96 arg_ainfo.defaultstatus = cgiarginfo::weak;
97 arg_ainfo.argdefault = "";
98 arg_ainfo.savedarginfo = cgiarginfo::must;
99 argsinfo.addarginfo (NULL, arg_ainfo);
100
101 // "q"
102 arg_ainfo.shortname = "q";
103 arg_ainfo.longname = "query string";
104 arg_ainfo.multiplechar = true;
105 arg_ainfo.defaultstatus = cgiarginfo::weak;
106 arg_ainfo.argdefault = "";
107 arg_ainfo.savedarginfo = cgiarginfo::must;
108 argsinfo.addarginfo (NULL, arg_ainfo);
109
110 // "t" - 1 = ranked 0 = boolean
111 arg_ainfo.shortname = "t";
112 arg_ainfo.longname = "search type";
113 arg_ainfo.multiplechar = false;
114 arg_ainfo.defaultstatus = cgiarginfo::weak;
115 arg_ainfo.argdefault = "1";
116 arg_ainfo.savedarginfo = cgiarginfo::must;
117 argsinfo.addarginfo (NULL, arg_ainfo);
118
119 // "k"
120 arg_ainfo.shortname = "k";
121 arg_ainfo.longname = "casefolding";
122 arg_ainfo.multiplechar = false;
123 arg_ainfo.defaultstatus = cgiarginfo::weak;
124 arg_ainfo.argdefault = "1";
125 arg_ainfo.savedarginfo = cgiarginfo::must;
126 argsinfo.addarginfo (NULL, arg_ainfo);
127
128 // "s"
129 arg_ainfo.shortname = "s";
130 arg_ainfo.longname = "stemming";
131 arg_ainfo.multiplechar = false;
132 arg_ainfo.defaultstatus = cgiarginfo::weak;
133 arg_ainfo.argdefault ="0";
134 arg_ainfo.savedarginfo = cgiarginfo::must;
135 argsinfo.addarginfo (NULL, arg_ainfo);
136
137 // "m"
138 arg_ainfo.shortname = "m";
139 arg_ainfo.longname = "maximum number of documents";
140 arg_ainfo.multiplechar = true;
141 arg_ainfo.defaultstatus = cgiarginfo::weak;
142 arg_ainfo.argdefault = "50";
143 arg_ainfo.savedarginfo = cgiarginfo::must;
144 argsinfo.addarginfo (NULL, arg_ainfo);
145
146 // "o"
147 arg_ainfo.shortname = "o";
148 arg_ainfo.longname = "hits per page";
149 arg_ainfo.multiplechar = true;
150 arg_ainfo.defaultstatus = cgiarginfo::weak;
151 arg_ainfo.argdefault = "20";
152 arg_ainfo.savedarginfo = cgiarginfo::must;
153 argsinfo.addarginfo (NULL, arg_ainfo);
154
155 // "r"
156 arg_ainfo.shortname = "r";
157 arg_ainfo.longname = "start results from";
158 arg_ainfo.multiplechar = true;
159 arg_ainfo.defaultstatus = cgiarginfo::weak;
160 arg_ainfo.argdefault = "1";
161 arg_ainfo.savedarginfo = cgiarginfo::must;
162 argsinfo.addarginfo (NULL, arg_ainfo);
163}
164
165void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
166 action::configure (key, cfgline);
167}
168
169bool queryaction::init (ostream &logout) {
170 return action::init (logout);
171}
172
173bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
174 ostream &logout) {
175
176 // check t argument
177 int arg_t = args.getintarg("t");
178 if (arg_t != 0 && arg_t != 1) {
179 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
180 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
181 if (tinfo != NULL) args["t"] = tinfo->argdefault;
182 }
183
184 // check k argument
185 int arg_k = args.getintarg("k");
186 if (arg_k != 0 && arg_k != 1) {
187 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
188 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
189 if (kinfo != NULL) args["k"] = kinfo->argdefault;
190 }
191
192 // check s argument
193 int arg_s = args.getintarg("s");
194 if (arg_s != 0 && arg_s != 1) {
195 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
196 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
197 if (sinfo != NULL) args["s"] = sinfo->argdefault;
198 }
199
200 // check m argument
201 int arg_m = args.getintarg("m");
202 if (arg_m < 0) {
203 logout << "Warning: \"m\" argument less than 0 (" << arg_m << ")\n";
204 cgiarginfo *minfo = argsinfo.getarginfo ("m");
205 if (minfo != NULL) args["m"] = minfo->argdefault;
206 }
207
208 // check o argument
209 int arg_o = args.getintarg("o");
210 if (arg_o < 0) {
211 logout << "Warning: \"o\" argument less than 0 (" << arg_o << ")\n";
212 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
213 if (oinfo != NULL) args["o"] = oinfo->argdefault;
214 }
215
216 // check r argument
217 int arg_r = args.getintarg("r");
218 if (arg_r < 1) {
219 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
220 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
221 if (rinfo != NULL) args["r"] = rinfo->argdefault;
222 }
223
224 return true;
225}
226
227void queryaction::get_cgihead_info (cgiargsclass &/*args*/, response_t &response,
228 text_t &response_data, ostream &/*logout*/) {
229 response = content;
230 response_data = "text/html";
231}
232
233void queryaction::define_internal_macros (displayclass &/*disp*/, cgiargsclass &/*args*/,
234 recptproto */*collectproto*/, ostream &/*logout*/) {
235
236 // define_internal_macros doesn't set anything for this action. The following
237 // macros are set later though in define_query_macros (they can't be set until
238 // the query has been done).
239
240 // _freqmsg_ the term frequency string
241
242 // _quotedquery_ the part of the query string that was quoted for post-processing
243
244 // _resultline_ the "x documents matched the query" string
245
246 // _prevfirst_ these are used when setting up the links to previous/next
247 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
248 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
249 // _nextlast_
250 // _thisfirst_
251 // _thislast_
252
253}
254
255// sets the selection box macros _hselection_, _jselection_, and _nselection_.
256// each option will need an _optionxoption_ macro (i.e. an _hselection_ macro
257// with options stx and ptx will need _optionhstx_ and _optionhptx_ macros)
258void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
259 const FilterOption_t &option, displayclass &disp) {
260
261 if (option.validValues.size() < 2) return;
262
263 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
264
265 if (current_value.empty()) current_value = option.defaultValue;
266
267 text_tarray::const_iterator thisvalue = option.validValues.begin();
268 text_tarray::const_iterator endvalue = option.validValues.end();
269
270 while (thisvalue != endvalue) {
271 macrovalue += "<option value=\"" + *thisvalue + "\"";
272 if (*thisvalue == current_value)
273 macrovalue += " selected";
274 macrovalue += ">_option" + macroname + *thisvalue + "_\n";
275 thisvalue ++;
276 }
277 macrovalue += "</select>\n";
278 disp.setmacro (macroname + "selection", "Global", macrovalue);
279}
280
281void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
282 recptproto *collectproto, ostream &logout) {
283
284 // define_external_macros sets the following macros:
285
286 // some or all of these may not be required to be set
287 // _hselection_ the selection box for the main part of the index
288 // _jselection_ the selection box for the subcollection part of the index
289 // _nselection_ the selection box for the language part of the index
290
291
292 // can't do anything if collectproto is null (i.e. no collection was specified)
293 if (collectproto == NULL) return;
294
295 comerror_t err;
296 InfoFilterOptionsResponse_t response;
297 InfoFilterOptionsRequest_t request;
298 request.filterName = "QueryFilter";
299
300 collectproto->get_filteroptions (args["c"], request, response, err, logout);
301 if (err == noError) {
302
303 FilterOption_tmap::const_iterator it;
304 FilterOption_tmap::const_iterator end = response.filterOptions.end();
305
306 // _hselection_ (Index)
307 it = response.filterOptions.find ("Index");
308 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
309
310 // _jselection_ (Subcollection)
311 it = response.filterOptions.find ("Subcollection");
312 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
313
314 // _nselection_ (Language)
315 it = response.filterOptions.find ("Language");
316 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
317 }
318}
319
320bool queryaction::do_action (cgiargsclass &args, recptproto *collectproto,
321 displayclass &disp, outconvertclass &outconvert,
322 ostream &textout, ostream &logout) {
323
324 // if we have no format string see if the collection server has one
325 if (formatstring.empty()) {
326 ColInfoResponse_t collectinfo;
327 comerror_t err;
328 collectproto->get_collectinfo (args["c"], collectinfo, err, logout);
329 if (err == noError) {
330 text_tmap::const_iterator result = collectinfo.format.find("result");
331 if (result != collectinfo.format.end())
332 formatstring = (*result).second;
333 }
334 }
335 // if we still don't have a format string use the default
336 if (formatstring.empty())
337 formatstring = "<td valign=top nowrap>[link]_icontext_[/link]</td><td>[Title]</td>";
338
339 if (collectproto == NULL) {
340 logout << "queryaction::do_action called with NULL collectproto\n";
341 textout << outconvert << disp << "_query:header_\n"
342 << "Error: Attempt to do query without setting collection\n"
343 << "_query:footer_\n";
344 } else {
345
346 FilterRequest_t request;
347 FilterResponse_t response;
348 text_t quotedstring;
349 format_t *formatlistptr = new format_t();
350
351 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
352
353 // do the query
354 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
355 if (!do_query (request, args, collectproto, quotedstring, response, logout))
356 return false;
357
358 // set macros
359 define_query_macros (args, disp, response, quotedstring);
360
361 // output the header
362 textout << outconvert << disp << "_query:header_\n"
363 << "_query:content_";
364
365 // output the results
366 textout << "<table cellspacing=4>\n";
367 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
368 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
369
370 while (this_doc != end_doc) {
371 textout << outconvert << disp << "<tr>\n"
372 << get_formatted_string (*this_doc, formatlistptr) << "\n"
373 << "</tr>\n";
374 this_doc ++;
375 }
376 textout << "</table>\n";
377
378 delete (formatlistptr);
379
380 // output the footer
381 textout << outconvert << disp << "_query:footer_";
382 }
383 return true;
384}
385
386// define_query_macros sets the macros that couldn't be set until the
387// query had been done. Those macros are _freqmsg_, _quotedquery_,
388// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
389// _thisfirst_, and _thislast_
390void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
391 const FilterResponse_t &response,
392 const text_t &quotedstring) {
393
394 int numdocs = response.numDocs;
395 int arg_m = args.getintarg("m");
396 if (numdocs > arg_m)
397 numdocs = arg_m;
398
399 // set up _freqmsg_ and _quotedquery_ macros
400 text_t freqmsg = "_textfreqmsg1_";
401 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
402 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
403 while (this_term != end_term) {
404 freqmsg += (*this_term).term + ": " + (*this_term).freq;
405 if ((this_term + 1) != end_term)
406 freqmsg += ", ";
407 this_term ++;
408 }
409
410 disp.setmacro ("quotedquery", "query", quotedstring);
411 disp.setmacro ("freqmsg", "query", freqmsg);
412
413
414 // set up _resultline_ macro
415 text_t resline;
416
417 // can't use isApprox here as it will be false as long
418 // as numDocs < MAXDOCS (currently 500). If arg_m is less
419 // than MAXDOCS numDocs can be greater than arg_m while
420 // isApprox is false.
421 if (response.numDocs > numdocs ||
422 ((response.numDocs == numdocs) && response.isApprox))
423 resline = "_textmorethan_";
424 if (numdocs == 0) resline = "_textnodocs_";
425 else if (numdocs == 1) resline += "_text1doc_";
426 else resline += text_t(numdocs) + " _textlotsdocs_";
427
428 disp.setmacro("resultline", "query", resline);
429
430
431 int firstdoc = args.getintarg("r");
432 int hitsperpage = args.getintarg("o");
433
434 // set up _thisfirst_ and _thislast_ macros
435 disp.setmacro ("thisfirst", "query", firstdoc);
436 int thislast = firstdoc + (hitsperpage - 1);
437 if (thislast > numdocs) thislast = numdocs;
438 disp.setmacro ("thislast", "query", thislast);
439
440 // set up _prevfirst_ and _prevlast_ macros
441 if (firstdoc > 1) {
442 disp.setmacro ("prevlast", "query", firstdoc - 1);
443 int prevfirst = firstdoc - hitsperpage;
444 if (prevfirst < 1) prevfirst = 1;
445 disp.setmacro ("prevfirst", "query", prevfirst);
446 }
447
448 // set up _nextfirst_ and _nextlast_ macros
449 if (thislast < numdocs) {
450 disp.setmacro ("nextfirst", "query", thislast + 1);
451 int nextlast = thislast + hitsperpage;
452 if (nextlast > numdocs) nextlast = numdocs;
453 disp.setmacro ("nextlast", "query", nextlast);
454 }
455}
456
457
458
Note: See TracBrowser for help on using the repository browser.