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

Last change on this file since 800 was 800, checked in by sjboddie, 24 years ago

tidied up cross-collection searching a bit

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 34.8 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: queryaction.cpp 800 1999-12-05 21:22:33Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.31 1999/12/05 21:22:33 sjboddie
31 tidied up cross-collection searching a bit
32
33 Revision 1.30 1999/11/08 20:26:37 sjboddie
34 added multiplevalue option to cgiarginfo
35
36 Revision 1.29 1999/11/04 20:29:53 sjboddie
37 small change to cross-collection searching
38
39 Revision 1.28 1999/11/03 22:49:50 sjboddie
40 A few changes to cross-collection searching for fao
41
42 Revision 1.27 1999/11/01 21:53:27 sjboddie
43 added cross-collection searching capability - still needs lots of
44 work but the basic functionality is there
45
46 Revision 1.26 1999/10/10 08:14:10 sjboddie
47 - metadata now returns mp rather than array
48 - redesigned browsing support (although it's not finished so
49 won't currently work ;-)
50
51 Revision 1.25 1999/09/24 04:49:39 sjboddie
52 fixed up the query selection boxes to display properly if there's only
53 a single index/sub-collection
54
55 Revision 1.24 1999/09/22 03:44:31 sjboddie
56 EndResults query filter option may now take '-1' for 'all'
57
58 Revision 1.23 1999/09/21 11:34:42 sjboddie
59 added Maxdocs queryfilter option which may be -1 for 'all'
60
61 Revision 1.22 1999/09/07 23:08:51 rjmcnab
62 removed some compiler warnings
63
64 Revision 1.21 1999/09/07 04:56:57 sjboddie
65 added GPL notice
66
67 Revision 1.20 1999/08/25 04:47:55 sjboddie
68 added advanced search option - other minor changes
69
70 Revision 1.19 1999/08/13 04:17:24 sjboddie
71 small change to do with new collection-level metadata
72
73 Revision 1.18 1999/08/10 22:46:33 sjboddie
74 changed format option result to QueryResults and added QueryLinks option
75
76 Revision 1.17 1999/07/30 02:24:42 sjboddie
77 added collectinfo argument to some functions
78
79 Revision 1.16 1999/07/19 00:16:58 sjboddie
80 no longer display documents that don't match all phrases in query string
81
82 Revision 1.15 1999/07/16 08:33:36 rjmcnab
83 Changed the logic for getting the results string slightly
84
85 Revision 1.14 1999/07/16 03:41:29 sjboddie
86 changed isApprox
87
88 Revision 1.13 1999/07/16 00:19:01 sjboddie
89 some changes to the way quoted queries are handled
90
91 Revision 1.12 1999/07/09 02:17:55 rjmcnab
92 Setting macros needed for a second query.
93
94 Revision 1.11 1999/07/07 06:13:10 rjmcnab
95 Added ability to combine two independant queries.
96
97 Revision 1.10 1999/07/07 05:49:35 sjboddie
98 had another crack at the format string code - created a new formattools
99 module. It can now handle {If} and {Or} statements although there's a
100 bug preventing nested if's and or's.
101
102 Revision 1.9 1999/07/01 22:48:46 sjboddie
103 had a go at getting a query result format string working
104
105 Revision 1.8 1999/06/27 22:02:11 sjboddie
106 author is added to queryresults if there is one
107
108 Revision 1.7 1999/06/26 01:10:18 rjmcnab
109 Made h, i, and n arguments saved in the compressed arguments.
110
111 Revision 1.6 1999/06/24 05:12:25 sjboddie
112 lots of small changes
113
114 Revision 1.5 1999/06/16 04:03:48 sjboddie
115 Now sets "cl" arg to "search" when going to a document from a search
116 results page. This allows the close book icon (in hierarchy toc) to
117 take you back to the results page if that's where you came from.
118 If you got to the document page somehow other than from a
119 classification or a search (i.e. if "cl" isn't set) then the close
120 book icon is disabled
121
122 Revision 1.4 1999/06/16 02:08:38 sjboddie
123 got queryaction working
124
125 Revision 1.3 1999/03/25 03:06:45 sjboddie
126
127 altered receptionist slightly so it now passes *collectproto to
128 define_internal_macros and define_external_macros - need it
129 for browseaction
130
131 Revision 1.2 1999/03/03 20:26:50 rjmcnab
132
133 Modified stuff.
134
135 Revision 1.1 1999/02/28 22:45:21 rjmcnab
136
137 Initial revision.
138
139 */
140
141
142#include "queryaction.h"
143#include "querytools.h"
144#include "formattools.h"
145#include "cgiutils.h"
146#include "OIDtools.h"
147
148void colinfo_t::clear () {
149 formatlistptr = NULL;
150 browserptr = NULL;
151}
152
153void QueryResult_t::clear() {
154 doc.clear();
155 collection.clear();
156}
157
158queryaction::queryaction () {
159
160 num_phrases = 0;
161
162 // this action uses cgi variable "a"
163 cgiarginfo arg_ainfo;
164 arg_ainfo.shortname = "a";
165 arg_ainfo.longname = "action";
166 arg_ainfo.multiplechar = true;
167 arg_ainfo.defaultstatus = cgiarginfo::weak;
168 arg_ainfo.argdefault = "q";
169 arg_ainfo.savedarginfo = cgiarginfo::must;
170 argsinfo.addarginfo (NULL, arg_ainfo);
171
172 // "b" - 0 = simple, 1 = advanced
173 arg_ainfo.shortname = "b";
174 arg_ainfo.longname = "query mode";
175 arg_ainfo.multiplechar = false;
176 arg_ainfo.defaultstatus = cgiarginfo::weak;
177 arg_ainfo.argdefault = "0";
178 arg_ainfo.savedarginfo = cgiarginfo::must;
179 argsinfo.addarginfo (NULL, arg_ainfo);
180
181 // "h"
182 arg_ainfo.shortname = "h";
183 arg_ainfo.longname = "main index";
184 arg_ainfo.multiplechar = true;
185 arg_ainfo.defaultstatus = cgiarginfo::weak;
186 arg_ainfo.argdefault = "";
187 arg_ainfo.savedarginfo = cgiarginfo::must;
188 argsinfo.addarginfo (NULL, arg_ainfo);
189
190 // "h2"
191 arg_ainfo.shortname = "h2";
192 arg_ainfo.longname = "main index for second query";
193 arg_ainfo.multiplechar = true;
194 arg_ainfo.defaultstatus = cgiarginfo::weak;
195 arg_ainfo.argdefault = "";
196 arg_ainfo.savedarginfo = cgiarginfo::must;
197 argsinfo.addarginfo (NULL, arg_ainfo);
198
199 // "j"
200 arg_ainfo.shortname = "j";
201 arg_ainfo.longname = "sub collection index";
202 arg_ainfo.multiplechar = true;
203 arg_ainfo.defaultstatus = cgiarginfo::weak;
204 arg_ainfo.argdefault = "";
205 arg_ainfo.savedarginfo = cgiarginfo::must;
206 argsinfo.addarginfo (NULL, arg_ainfo);
207
208 // "j2"
209 arg_ainfo.shortname = "j2";
210 arg_ainfo.longname = "sub collection index for second query";
211 arg_ainfo.multiplechar = true;
212 arg_ainfo.defaultstatus = cgiarginfo::weak;
213 arg_ainfo.argdefault = "";
214 arg_ainfo.savedarginfo = cgiarginfo::must;
215 argsinfo.addarginfo (NULL, arg_ainfo);
216
217 // "n"
218 arg_ainfo.shortname = "n";
219 arg_ainfo.longname = "language index";
220 arg_ainfo.multiplechar = true;
221 arg_ainfo.defaultstatus = cgiarginfo::weak;
222 arg_ainfo.argdefault = "";
223 arg_ainfo.savedarginfo = cgiarginfo::must;
224 argsinfo.addarginfo (NULL, arg_ainfo);
225
226 // "n2"
227 arg_ainfo.shortname = "n2";
228 arg_ainfo.longname = "language index for second query";
229 arg_ainfo.multiplechar = true;
230 arg_ainfo.defaultstatus = cgiarginfo::weak;
231 arg_ainfo.argdefault = "";
232 arg_ainfo.savedarginfo = cgiarginfo::must;
233 argsinfo.addarginfo (NULL, arg_ainfo);
234
235 // "q"
236 arg_ainfo.shortname = "q";
237 arg_ainfo.longname = "query string";
238 arg_ainfo.multiplechar = true;
239 arg_ainfo.defaultstatus = cgiarginfo::weak;
240 arg_ainfo.argdefault = "";
241 arg_ainfo.savedarginfo = cgiarginfo::must;
242 argsinfo.addarginfo (NULL, arg_ainfo);
243
244 // "q2"
245 arg_ainfo.shortname = "q2";
246 arg_ainfo.longname = "query string for second query";
247 arg_ainfo.multiplechar = true;
248 arg_ainfo.defaultstatus = cgiarginfo::weak;
249 arg_ainfo.argdefault = "";
250 arg_ainfo.savedarginfo = cgiarginfo::must;
251 argsinfo.addarginfo (NULL, arg_ainfo);
252
253 // "cq2" ""=don't combine, "and", "or", "not"
254 arg_ainfo.shortname = "cq2";
255 arg_ainfo.longname = "combine queries";
256 arg_ainfo.multiplechar = true;
257 arg_ainfo.defaultstatus = cgiarginfo::weak;
258 arg_ainfo.argdefault = "";
259 arg_ainfo.savedarginfo = cgiarginfo::must;
260 argsinfo.addarginfo (NULL, arg_ainfo);
261
262 // "t" - 1 = ranked 0 = boolean
263 arg_ainfo.shortname = "t";
264 arg_ainfo.longname = "search type";
265 arg_ainfo.multiplechar = false;
266 arg_ainfo.defaultstatus = cgiarginfo::weak;
267 arg_ainfo.argdefault = "1";
268 arg_ainfo.savedarginfo = cgiarginfo::must;
269 argsinfo.addarginfo (NULL, arg_ainfo);
270
271 // "k"
272 arg_ainfo.shortname = "k";
273 arg_ainfo.longname = "casefolding";
274 arg_ainfo.multiplechar = false;
275 arg_ainfo.defaultstatus = cgiarginfo::weak;
276 arg_ainfo.argdefault = "1";
277 arg_ainfo.savedarginfo = cgiarginfo::must;
278 argsinfo.addarginfo (NULL, arg_ainfo);
279
280 // "s"
281 arg_ainfo.shortname = "s";
282 arg_ainfo.longname = "stemming";
283 arg_ainfo.multiplechar = false;
284 arg_ainfo.defaultstatus = cgiarginfo::weak;
285 arg_ainfo.argdefault ="0";
286 arg_ainfo.savedarginfo = cgiarginfo::must;
287 argsinfo.addarginfo (NULL, arg_ainfo);
288
289 // "m"
290 arg_ainfo.shortname = "m";
291 arg_ainfo.longname = "maximum number of documents";
292 arg_ainfo.multiplechar = true;
293 arg_ainfo.defaultstatus = cgiarginfo::weak;
294 arg_ainfo.argdefault = "50";
295 arg_ainfo.savedarginfo = cgiarginfo::must;
296 argsinfo.addarginfo (NULL, arg_ainfo);
297
298 // "o"
299 arg_ainfo.shortname = "o";
300 arg_ainfo.longname = "hits per page";
301 arg_ainfo.multiplechar = true;
302 arg_ainfo.defaultstatus = cgiarginfo::weak;
303 arg_ainfo.argdefault = "20";
304 arg_ainfo.savedarginfo = cgiarginfo::must;
305 argsinfo.addarginfo (NULL, arg_ainfo);
306
307 // "r"
308 arg_ainfo.shortname = "r";
309 arg_ainfo.longname = "start results from";
310 arg_ainfo.multiplechar = true;
311 arg_ainfo.defaultstatus = cgiarginfo::weak;
312 arg_ainfo.argdefault = "1";
313 arg_ainfo.savedarginfo = cgiarginfo::must;
314 argsinfo.addarginfo (NULL, arg_ainfo);
315
316 // "ccs"
317 arg_ainfo.shortname = "ccs";
318 arg_ainfo.longname = "cross collection searching";
319 arg_ainfo.multiplechar = false;
320 arg_ainfo.defaultstatus = cgiarginfo::weak;
321 arg_ainfo.argdefault = "0";
322 arg_ainfo.savedarginfo = cgiarginfo::must;
323 argsinfo.addarginfo (NULL, arg_ainfo);
324
325 // "ccp"
326 arg_ainfo.shortname = "ccp";
327 arg_ainfo.longname = "cross collection page";
328 arg_ainfo.multiplechar = false;
329 arg_ainfo.defaultstatus = cgiarginfo::weak;
330 arg_ainfo.argdefault = "0";
331 arg_ainfo.savedarginfo = cgiarginfo::must;
332 argsinfo.addarginfo (NULL, arg_ainfo);
333
334 // "cc"
335 arg_ainfo.shortname = "cc";
336 arg_ainfo.longname = "collections to search";
337 arg_ainfo.multiplechar = true;
338 arg_ainfo.multiplevalue = true;
339 arg_ainfo.defaultstatus = cgiarginfo::weak;
340 arg_ainfo.argdefault = "";
341 arg_ainfo.savedarginfo = cgiarginfo::must;
342 argsinfo.addarginfo (NULL, arg_ainfo);
343
344}
345
346void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
347 action::configure (key, cfgline);
348}
349
350bool queryaction::init (ostream &logout) {
351 return action::init (logout);
352}
353
354bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
355 ostream &logout) {
356
357 // check t argument
358 int arg_t = args.getintarg("t");
359 if (arg_t != 0 && arg_t != 1) {
360 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
361 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
362 if (tinfo != NULL) args["t"] = tinfo->argdefault;
363 }
364
365 // check k argument
366 int arg_k = args.getintarg("k");
367 if (arg_k != 0 && arg_k != 1) {
368 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
369 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
370 if (kinfo != NULL) args["k"] = kinfo->argdefault;
371 }
372
373 // check s argument
374 int arg_s = args.getintarg("s");
375 if (arg_s != 0 && arg_s != 1) {
376 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
377 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
378 if (sinfo != NULL) args["s"] = sinfo->argdefault;
379 }
380
381 // check m argument
382 int arg_m = args.getintarg("m");
383 if (arg_m < -1) {
384 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
385 cgiarginfo *minfo = argsinfo.getarginfo ("m");
386 if (minfo != NULL) args["m"] = minfo->argdefault;
387 }
388
389 // check o argument
390 int arg_o = args.getintarg("o");
391 if (arg_o < -1) {
392 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
393 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
394 if (oinfo != NULL) args["o"] = oinfo->argdefault;
395 }
396
397 // check r argument
398 int arg_r = args.getintarg("r");
399 if (arg_r < 1) {
400 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
401 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
402 if (rinfo != NULL) args["r"] = rinfo->argdefault;
403 }
404
405 return true;
406}
407
408void queryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
409 response_t &response, text_t &response_data,
410 ostream &/*logout*/) {
411 response = content;
412 response_data = "text/html";
413}
414
415void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
416 recptprotolistclass * /*protos*/,
417 ostream &/*logout*/) {
418
419 // define_internal_macros sets the following macros:
420
421 // _quotedquery_ the part of the query string that was quoted for post-processing
422
423
424
425 // The following macros are set later (in define_query_macros) as they can't be set until
426 // the query has been done.
427
428 // _freqmsg_ the term frequency string
429
430 // _resultline_ the "x documents matched the query" string
431
432 // _prevfirst_ these are used when setting up the links to previous/next
433 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
434 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
435 // _nextlast_
436 // _thisfirst_
437 // _thislast_
438
439
440 // get the quoted bits of the query string and set _quotedquery_
441 text_tarray phrases;
442 get_phrases (args["q"], phrases);
443 num_phrases = phrases.size();
444 text_tarray::const_iterator phere = phrases.begin();
445 text_tarray::const_iterator pend = phrases.end();
446 bool first = true;
447 text_t quotedquery;
448 while (phere != pend) {
449 if (!first)
450 if ((phere +1) == pend) quotedquery += " and ";
451 else quotedquery += ", ";
452
453 quotedquery += "\"" + *phere + "\"";
454 first = false;
455 phere ++;
456 }
457 if (args.getintarg("s")) quotedquery += "_textstemon_";
458 disp.setmacro ("quotedquery", "query", quotedquery);
459}
460
461// sets the selection box macros _hselection_, _jselection_, and _nselection_.
462void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
463 const FilterOption_t &option, displayclass &disp) {
464
465 if (option.validValues.empty()) return;
466 else if (option.validValues.size() == 1) {
467 disp.setmacro (macroname + "selection", "Global", "_" + option.defaultValue + "_");
468 return;
469 }
470 if (option.validValues.size() < 2) return;
471
472 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
473
474 if (current_value.empty()) current_value = option.defaultValue;
475
476 text_tarray::const_iterator thisvalue = option.validValues.begin();
477 text_tarray::const_iterator endvalue = option.validValues.end();
478
479 while (thisvalue != endvalue) {
480 macrovalue += "<option value=\"" + *thisvalue + "\"";
481 if (*thisvalue == current_value)
482 macrovalue += " selected";
483 macrovalue += ">_" + *thisvalue + "_\n";
484 thisvalue ++;
485 }
486 macrovalue += "</select>\n";
487 disp.setmacro (macroname + "selection", "Global", macrovalue);
488}
489
490void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
491 recptprotolistclass *protos, ostream &logout) {
492
493 // define_external_macros sets the following macros:
494
495 // some or all of these may not be required to be set
496 // _hselection_, _h2selection_ the selection box for the main part of the index
497 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
498 // _nselection_, _n2selection_ the selection box for the language part of the index
499 // _cq2selection the selection box for combining two queries
500
501
502 // can't do anything if collectproto is null (i.e. no collection was specified)
503 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
504 if (collectproto == NULL) return;
505
506 comerror_t err;
507 InfoFilterOptionsResponse_t response;
508 InfoFilterOptionsRequest_t request;
509 request.filterName = "QueryFilter";
510
511 collectproto->get_filteroptions (args["c"], request, response, err, logout);
512 if (err == noError) {
513
514 FilterOption_tmap::const_iterator it;
515 FilterOption_tmap::const_iterator end = response.filterOptions.end();
516
517 // _hselection_ and _h2selection_ (Index)
518 it = response.filterOptions.find ("Index");
519 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
520 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
521
522 // _jselection_ and _j2selection_ (Subcollection)
523 it = response.filterOptions.find ("Subcollection");
524 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
525 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
526
527 // _nselection_ and _n2selection_ (Language)
528 it = response.filterOptions.find ("Language");
529 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
530 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
531
532 // _cq2selection_ (CombineQuery)
533 it = response.filterOptions.find ("CombineQuery");
534 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
535 }
536}
537
538void queryaction::output_ccp (cgiargsclass &args, recptprotolistclass *protos,
539 displayclass &disp, outconvertclass &outconvert,
540 ostream &textout, ostream &logout) {
541
542 ColInfoResponse_t cinfo;
543 comerror_t err;
544 InfoFilterOptionsResponse_t fresponse;
545 InfoFilterOptionsRequest_t frequest;
546 frequest.filterName = "QueryFilter";
547
548 text_t &index = args["h"];
549 text_t &subcollection = args["j"];
550 text_t &language = args["n"];
551
552 text_tset collections;
553 text_t arg_cc = args["cc"];
554 decode_cgi_arg (arg_cc);
555 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
556
557 textout << outconvert << disp << "_query:header_\n"
558 << "<center>_navigationbar_</center><br>\n"
559 << "<form name=QueryForm method=get action=\"_gwcgi_\">\n"
560 << "<input type=hidden name=a value=\"q\">\n"
561 << "<input type=hidden name=e value=\"_compressedoptions_\">\n"
562 << "<input type=hidden name=ccp value=\"1\">\n"
563 << "<center><table width=_pagewidth_><tr valign=top>\n"
564 << "<td>Select collections to search for \"" << args["q"]
565 << "\" <i>(index=" << index << " subcollection=" << subcollection
566 << " language=" << language << ")</i></td>\n"
567 << "<td><input type=\"submit\" value=\"_query:textbeginsearch_\"></td>\n"
568 << "</tr></table></center>\n"
569 << "<center><table width=_pagewidth_>\n"
570 << "<tr><td>\n";
571
572 recptprotolistclass::iterator rprotolist_here = protos->begin();
573 recptprotolistclass::iterator rprotolist_end = protos->end();
574 while (rprotolist_here != rprotolist_end) {
575 if ((*rprotolist_here).p != NULL) {
576
577 text_tarray collist;
578 (*rprotolist_here).p->get_collection_list (collist, err, logout);
579 if (err == noError) {
580 text_tarray::iterator collist_here = collist.begin();
581 text_tarray::iterator collist_end = collist.end();
582 while (collist_here != collist_end) {
583
584 (*rprotolist_here).p->get_collectinfo (*collist_here, cinfo, err, logout);
585 // if (err == noError && cinfo.isPublic && (cinfo.buildDate > 0)) {
586 if (err == noError && (cinfo.buildDate > 0)) {
587
588 (*rprotolist_here).p->get_filteroptions (*collist_here, frequest, fresponse, err, logout);
589 if (err == noError) {
590
591 FilterOption_tmap::const_iterator it;
592 FilterOption_tmap::const_iterator end = fresponse.filterOptions.end();
593 if (!index.empty()) {
594 it = fresponse.filterOptions.find ("Index");
595 if (it == end) {collist_here ++; continue;}
596 text_tarray::const_iterator there = (*it).second.validValues.begin();
597 text_tarray::const_iterator tend = (*it).second.validValues.end();
598 while (there != tend) {
599 if (*there == index) break;
600 there ++;
601 }
602 if (there == tend) {collist_here++; continue;}
603 }
604 if (!subcollection.empty()) {
605 it = fresponse.filterOptions.find ("Subcollection");
606 if (it == end) {collist_here++; continue;}
607 text_tarray::const_iterator there = (*it).second.validValues.begin();
608 text_tarray::const_iterator tend = (*it).second.validValues.end();
609 while (there != tend) {
610 if (*there == subcollection) break;
611 there ++;
612 }
613 if (there == tend) {collist_here++; continue;}
614 }
615 if (!language.empty()) {
616 it = fresponse.filterOptions.find ("Language");
617 if (it == end) {collist_here++; continue;}
618 text_tarray::const_iterator there = (*it).second.validValues.begin();
619 text_tarray::const_iterator tend = (*it).second.validValues.end();
620 while (there != tend) {
621 if (*there == language) break;
622 there ++;
623 }
624 if (there == tend) {collist_here++; continue;}
625 }
626
627 // we've got a matching collection
628 textout << "<input type=checkbox";
629
630 text_tset::const_iterator t = collections.find (*collist_here);
631 if (t != collections.end()) textout << " checked";
632
633 textout << outconvert
634 << " name=cc value=\"" << *collist_here << "\">";
635
636 if (!cinfo.collectionmeta["collectionname"].empty())
637 textout << outconvert << disp << cinfo.collectionmeta["collectionname"];
638 else
639 textout << outconvert << *collist_here;
640
641 textout << "<br>\n";
642
643 }
644 }
645 collist_here ++;
646 }
647 }
648 }
649 rprotolist_here ++;
650 }
651 textout << outconvert << disp
652 << "</td></tr></table></center>\n"
653 << "</form>\n"
654 << "_query:footer_\n";
655
656}
657
658bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
659 browsermapclass *browsers, displayclass &disp,
660 outconvertclass &outconvert, ostream &textout,
661 ostream &logout) {
662
663 if (args["ccs"] == 1) {
664 // cross collection searching (we'll just borrow the el argument
665 // from extlinkaction for now - this will probably want to use
666 // a separate argument eventually)
667 // if (args["ccp"] != 1 && args["el"] != "direct") {
668 // display the cross collection search page
669 // output_ccp (args, protos, disp, outconvert, textout, logout);
670 // } else {
671 // query the selected collections
672
673 text_t::const_iterator b = args["cc"].begin();
674 text_t::const_iterator e = args["cc"].end();
675 if (!args["cc"].empty() && (findchar (b, e, ',') != e))
676 if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
677 textout, logout)) return false;
678 else return true;
679 }
680
681 // simply query the current collection
682 if (!search_single_collection (args, protos, browsers, disp, outconvert,
683 textout, logout)) return false;
684
685 return true;
686}
687
688bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
689 browsermapclass *browsers, displayclass &disp,
690 outconvertclass &outconvert, ostream &textout,
691 ostream &logout) {
692
693 text_tarray collections;
694
695 text_t arg_cc = args["cc"];
696 decode_cgi_arg (arg_cc);
697 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
698
699 if (collections.empty()) {
700 logout << "queryaction::search_multiple_collections: No collections "
701 << "set for doing multiple query - will search current collection\n";
702 textout << outconvert << disp << "_query:textwarningnocollections_\n";
703 return search_single_collection (args, protos, browsers, disp,
704 outconvert, textout, logout);
705 }
706
707 // queryaction uses "VList" browser to display results,
708 // a queries clasification is "Search"
709 text_t browsertype = "VList";
710 text_t classification = "Search";
711
712 QueryResult_tset results;
713 map<text_t, colinfo_t, lttext_t> colinfomap;
714
715 ColInfoResponse_t cinfo;
716 comerror_t err;
717 FilterRequest_t request;
718 FilterResponse_t response;
719 request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
720 text_t formattedstring = args["q"];
721 text_t freqmsg = "_textfreqmsg1_";
722 int numdocs = 0;
723 isapprox isApprox = Exact;
724 text_tset colnamedata;
725 colnamedata.insert ("collectionname");
726
727 format_querystring (formattedstring, args.getintarg("b"));
728 set_queryfilter_options (request, formattedstring, args);
729
730 // need to retrieve maxdocs matches for each collection
731 // (will eventually want to tidy this up, do so caching etc.)
732 OptionValue_t option;
733 option.name = "StartResults";
734 option.value = "1";
735 request.filterOptions.push_back (option);
736
737 option.name = "EndResults";
738 option.value = args["m"];
739 request.filterOptions.push_back (option);
740
741 text_tarray::iterator col_here = collections.begin();
742 text_tarray::iterator col_end = collections.end();
743
744 while (col_here != col_end) {
745
746 request.fields.erase (request.fields.begin(), request.fields.end());
747 request.getParents = false;
748
749 recptproto *collectproto = protos->getrecptproto (*col_here, logout);
750 if (collectproto == NULL) {
751 logout << outconvert << "queryaction::search_multiple_collections: " << *col_here
752 << " collection has a NULL collectproto, ignoring\n";
753 col_here ++;
754 continue;
755 }
756 collectproto->get_collectinfo (*col_here, cinfo, err, logout);
757
758 browserclass *bptr = browsers->getbrowser (browsertype);
759
760 // get the formatstring if there is one
761 text_t formatstring;
762 if (!get_formatstring (classification, browsertype,
763 cinfo.format, formatstring))
764 formatstring = bptr->get_default_formatstring();
765
766 bptr->load_metadata_defaults (request.fields);
767
768 format_t *formatlistptr = new format_t();
769 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
770
771 colinfo_t thiscolinfo;
772 thiscolinfo.formatlistptr = formatlistptr;
773 thiscolinfo.browserptr = bptr;
774 colinfomap[*col_here] = thiscolinfo;
775
776 // do the query
777 collectproto->filter (*col_here, request, response, err, logout);
778 if (err != noError) {
779 outconvertclass text_t2ascii;
780 logout << text_t2ascii
781 << "queryaction::search_multiple_collections: call to QueryFilter failed "
782 << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
783 return false;
784 }
785
786 if (isApprox == Exact)
787 isApprox = response.isApprox;
788 else if (isApprox == MoreThan)
789 if (response.isApprox == Approximate)
790 isApprox = response.isApprox;
791
792 text_t collectionname = *col_here;
793 FilterResponse_t nresponse;
794 if (get_info ("collection", *col_here, colnamedata, false, collectproto, nresponse, logout)) {
795 if (!nresponse.docInfo[0].metadata["collectionname"].values[0].empty())
796 collectionname = nresponse.docInfo[0].metadata["collectionname"].values[0];
797 }
798
799 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
800 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
801 freqmsg += "<br><b>" + collectionname + "</b>: ";
802 while (this_term != end_term) {
803 freqmsg += (*this_term).term + ": " + (*this_term).freq;
804 if ((this_term + 1) != end_term)
805 freqmsg += ", ";
806 this_term ++;
807 }
808
809 if (response.numDocs > 0) {
810 numdocs += response.numDocs;
811
812 QueryResult_t thisresult;
813 thisresult.collection = *col_here;
814 ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
815 ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
816 while (doc_here != doc_end) {
817 thisresult.doc = *doc_here;
818 results.insert (thisresult);
819 doc_here ++;
820 }
821 }
822 col_here ++;
823 }
824
825 disp.setmacro ("freqmsg", "query", freqmsg);
826
827 text_t resline;
828 if (num_phrases > 0) isApprox = Exact;
829 if (isApprox == Approximate) resline = "_textapprox_";
830 else if (isApprox == MoreThan) resline = "_textmorethan_";
831
832 if (numdocs == 0) resline = "_textnodocs_";
833 else if (numdocs == 1) resline += "_text1doc_";
834 else resline += text_t(numdocs) + " _textlotsdocs_";
835 disp.setmacro("resultline", "query", resline);
836
837 QueryResult_tset::iterator res_here = results.begin();
838 QueryResult_tset::iterator res_end = results.end();
839 text_tset metadata; // empty !!
840 bool getParents = false; // don't care !!
841 recptproto *collectproto = NULL;
842 bool use_table;
843 ResultDocInfo_t thisdoc;
844 format_t *formatlistptr = NULL;
845 browserclass *browserptr = NULL;
846
847 int maxdocs = args.getintarg("m");
848 int firstdoc = args.getintarg("r");
849 int hitsperpage = args.getintarg("o");
850 if (numdocs > maxdocs) numdocs = maxdocs;
851 if (hitsperpage == -1) hitsperpage = numdocs;
852
853 // set up _thisfirst_ and _thislast_ macros
854 disp.setmacro ("thisfirst", "query", firstdoc);
855 int thislast = firstdoc + (hitsperpage - 1);
856 if (thislast > numdocs) thislast = numdocs;
857 disp.setmacro ("thislast", "query", thislast);
858
859 // set up _prevfirst_ and _prevlast_ macros
860 if (firstdoc > 1) {
861 disp.setmacro ("prevlast", "query", firstdoc - 1);
862 int prevfirst = firstdoc - hitsperpage;
863 if (prevfirst < 1) prevfirst = 1;
864 disp.setmacro ("prevfirst", "query", prevfirst);
865 }
866
867 // set up _nextfirst_ and _nextlast_ macros
868 if (thislast < numdocs) {
869 disp.setmacro ("nextfirst", "query", thislast + 1);
870 int nextlast = thislast + hitsperpage;
871 if (nextlast > numdocs) nextlast = numdocs;
872 disp.setmacro ("nextlast", "query", nextlast);
873 }
874
875 textout << outconvert << disp << "_query:header_\n"
876 << "_query:content_";
877
878 int count = 1;
879
880 // output results
881 while (res_here != res_end) {
882 if (count < firstdoc) {count ++; res_here ++; continue;}
883 if (count > thislast) break;
884 formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
885 browserptr = colinfomap[(*res_here).collection].browserptr;
886 thisdoc = (*res_here).doc;
887 use_table = is_table_content (formatlistptr);
888 browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0,
889 formatlistptr, use_table, metadata, getParents,
890 collectproto, disp, outconvert, textout, logout);
891 // textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
892 res_here ++;
893 count ++;
894 }
895
896 textout << outconvert << disp << "_query:footer_";
897
898 // clean up the format_t pointers
899 map<text_t, colinfo_t, lttext_t>::iterator here = colinfomap.begin();
900 map<text_t, colinfo_t, lttext_t>::iterator end = colinfomap.end();
901 while (here != end) {
902 delete ((*here).second.formatlistptr);
903 here ++;
904 }
905 return true;
906}
907
908bool queryaction::search_single_collection (cgiargsclass &args, recptprotolistclass *protos,
909 browsermapclass *browsers, displayclass &disp,
910 outconvertclass &outconvert, ostream &textout,
911 ostream &logout) {
912
913 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
914 if (collectproto == NULL) {
915 logout << outconvert << "queryaction::search_single_collection: " << args["c"]
916 << " collection has a NULL collectproto\n";
917 return false;
918 }
919
920 // queryaction uses "VList" browser to display results,
921 // a queries clasification is "Search"
922 text_t browsertype = "VList";
923 text_t classification = "Search";
924
925 ColInfoResponse_t cinfo;
926 comerror_t err;
927 collectproto->get_collectinfo (args["c"], cinfo, err, logout);
928
929 browserclass *bptr = browsers->getbrowser (browsertype);
930
931 // get the formatstring if there is one
932 text_t formatstring;
933 if (!get_formatstring (classification, browsertype,
934 cinfo.format, formatstring))
935 formatstring = bptr->get_default_formatstring();
936
937 FilterRequest_t request;
938 FilterResponse_t response;
939 bptr->set_filter_options (request, args);
940 bptr->load_metadata_defaults (request.fields);
941
942 format_t *formatlistptr = new format_t();
943 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
944
945 // do the query
946 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
947 text_t formattedstring = args["q"];
948 format_querystring (formattedstring, args.getintarg("b"));
949 set_queryfilter_options (request, formattedstring, args);
950 collectproto->filter (args["c"], request, response, err, logout);
951 if (err != noError) {
952 outconvertclass text_t2ascii;
953 logout << text_t2ascii
954 << "queryaction::search_single_collections: call to QueryFilter failed "
955 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
956 return false;
957 }
958
959 define_query_macros (args, disp, response);
960
961 textout << outconvert << disp << "_query:header_\n"
962 << "_query:content_";
963
964 // output the results
965 bool use_table = is_table_content (formatlistptr);
966 bptr->output_section_group (response, args, "", 0, formatlistptr,
967 use_table, request.fields, request.getParents,
968 collectproto, disp, outconvert, textout, logout);
969
970
971 textout << outconvert << disp << "_query:footer_";
972
973 delete (formatlistptr);
974
975 return true;
976}
977
978// define_query_macros sets the macros that couldn't be set until the
979// query had been done. Those macros are _freqmsg_, _quotedquery_,
980// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
981// _thisfirst_, and _thislast_
982void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
983 const FilterResponse_t &response) {
984 // set up _freqmsg_ and _quotedquery_ macros
985 text_t freqmsg = "_textfreqmsg1_";
986 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
987 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
988 while (this_term != end_term) {
989 freqmsg += (*this_term).term + ": " + (*this_term).freq;
990 if ((this_term + 1) != end_term)
991 freqmsg += ", ";
992 this_term ++;
993 }
994
995 disp.setmacro ("freqmsg", "query", freqmsg);
996
997
998 // set up _resultline_ macro
999 text_t resline;
1000 int maxdocs = args.getintarg("m");
1001 int numdocs = response.numDocs;
1002 if (maxdocs == -1) maxdocs = response.numDocs;
1003 isapprox isApprox = response.isApprox;
1004
1005 // if there were phrases (post-processing) we're not going to include
1006 // those documents that didn't match
1007 if (num_phrases > 0) isApprox = Exact;
1008
1009 if (isApprox == Approximate) resline = "_textapprox_";
1010 else if (isApprox == MoreThan) resline = "_textmorethan_";
1011
1012 if (numdocs == 0) resline = "_textnodocs_";
1013 else if (numdocs == 1) resline += "_text1doc_";
1014 else resline += text_t(numdocs) + " _textlotsdocs_";
1015
1016 disp.setmacro("resultline", "query", resline);
1017
1018 int firstdoc = args.getintarg("r");
1019 int hitsperpage = args.getintarg("o");
1020 if (hitsperpage == -1) hitsperpage = numdocs;
1021
1022 // set up _thisfirst_ and _thislast_ macros
1023 disp.setmacro ("thisfirst", "query", firstdoc);
1024 int thislast = firstdoc + (hitsperpage - 1);
1025 if (thislast > numdocs) thislast = numdocs;
1026 disp.setmacro ("thislast", "query", thislast);
1027
1028 // set up _prevfirst_ and _prevlast_ macros
1029 if (firstdoc > 1) {
1030 disp.setmacro ("prevlast", "query", firstdoc - 1);
1031 int prevfirst = firstdoc - hitsperpage;
1032 if (prevfirst < 1) prevfirst = 1;
1033 disp.setmacro ("prevfirst", "query", prevfirst);
1034 }
1035
1036 // set up _nextfirst_ and _nextlast_ macros
1037 if (thislast < numdocs) {
1038 disp.setmacro ("nextfirst", "query", thislast + 1);
1039 int nextlast = thislast + hitsperpage;
1040 if (nextlast > numdocs) nextlast = numdocs;
1041 disp.setmacro ("nextlast", "query", nextlast);
1042 }
1043}
1044
1045
1046
Note: See TracBrowser for help on using the repository browser.