source: trunk/gsdl/src/recpt/documentaction.cpp@ 1048

Last change on this file since 1048 was 1048, checked in by nzdl, 24 years ago

tidied up some of the browsing code - replaced DocumentImages,
DocumentTitles and DocumentHeading with DocumentIcon

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/**********************************************************************
2 *
3 * documentaction.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: documentaction.cpp 1048 2000-03-31 03:04:32Z nzdl $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.35 2000/03/31 03:04:31 nzdl
31 tidied up some of the browsing code - replaced DocumentImages,
32 DocumentTitles and DocumentHeading with DocumentIcon
33
34 Revision 1.34 2000/02/15 22:53:49 kjm18
35 search history stuff added.
36
37 Revision 1.33 2000/02/13 20:40:05 sjboddie
38 now dm_safe _thisOID_ macro
39
40 Revision 1.32 2000/01/25 22:39:15 sjboddie
41 added DocumentUseHTML - tidied some things up (and messed up some others)
42
43 Revision 1.31 1999/11/13 08:57:00 sjboddie
44 fixed bug in last changes
45
46 Revision 1.30 1999/11/01 21:54:27 sjboddie
47 changes for cross-collection searching - changes to arguments
48 of many functions
49
50 Revision 1.29 1999/10/24 07:23:40 sjboddie
51 added FullTOC option
52
53 Revision 1.28 1999/10/19 03:23:42 davidb
54 Collection building support through web pages
55 and internal and external link handling for collection documents
56
57 Revision 1.27 1999/10/14 23:00:53 sjboddie
58 finished changes to browsing support
59
60 Revision 1.26 1999/10/10 08:14:06 sjboddie
61 - metadata now returns mp rather than array
62 - redesigned browsing support (although it's not finished so
63 won't currently work ;-)
64
65 Revision 1.25 1999/09/17 04:46:05 sjboddie
66 fixed a couple of problems with 'unknown' classifier
67
68 Revision 1.24 1999/09/17 04:00:26 sjboddie
69 tidied up navigation bar to produce a default "unknown" button if
70 it comes across metadata it can't display
71
72 Revision 1.23 1999/09/07 04:56:54 sjboddie
73 added GPL notice
74
75 Revision 1.22 1999/08/20 01:00:22 sjboddie
76 split some of the larger functions up to simplify the creation of
77 collection specific receptionists
78
79 Revision 1.21 1999/08/11 23:28:03 sjboddie
80 -added support for html classifier
81 - removed _random_ macro - now use _blank for detach page
82
83 Revision 1.20 1999/08/10 23:16:39 sjboddie
84 a couple of small changes to get format options DocumentArrowsBottom
85 and DocumentArrowsTop working correctly
86
87 Revision 1.19 1999/08/10 22:40:01 sjboddie
88 added some more format options including the ability to format the
89 document text
90
91 Revision 1.18 1999/08/09 04:25:18 sjboddie
92 moved OID translation stuff from documentaction::define_external_macros
93 to receptionist
94
95 Revision 1.17 1999/08/09 02:13:53 sjboddie
96 fixed small bug in ShowSectionTitles
97
98 Revision 1.16 1999/08/03 03:30:47 sjboddie
99 a few small changes related to new format options
100
101 Revision 1.15 1999/07/30 02:18:49 sjboddie
102 -added collectinfo argument to some functions
103 -caught up with changes to browsetools (allowing nested classifications)
104 -added showtoppage format option
105
106 Revision 1.14 1999/07/21 05:01:09 sjboddie
107 fixed up wrapping of classificationlinks
108
109 Revision 1.13 1999/07/20 02:59:54 sjboddie
110 List and AZList classifications now use format strings
111
112 Revision 1.12 1999/07/16 00:19:01 sjboddie
113 some changes to the way quoted queries are handled
114
115 Revision 1.11 1999/07/07 05:47:41 sjboddie
116 changed around the way browsetools works
117
118 Revision 1.10 1999/06/29 01:46:44 sjboddie
119 now sets a _navigationbar_ macro even if there aren't any
120 classifications (it will just have the 'search' button
121
122 Revision 1.9 1999/06/27 22:05:58 sjboddie
123 now set a _thisOID_ macro for use in displaying images
124
125 Revision 1.8 1999/06/24 05:12:20 sjboddie
126 lots of small changes
127
128 Revision 1.7 1999/06/17 03:06:58 sjboddie
129 got detach button working properly - the close book icon is now disabled
130 when page is detached as the javascript close() function I was using is
131 too unreliable over different browsers
132 note that in my last comment I meant the "cl" arg (not the "c" arg).
133
134 Revision 1.6 1999/06/16 23:53:15 sjboddie
135 tidied a few things up. documentaction::define_external_macros now
136 resets the "c" arg if it's set to something stupid by the .xx suffixes
137
138 Revision 1.5 1999/06/16 03:10:49 sjboddie
139 define_internal_macros() now sets _pagetitle_ macro to document's title
140 (including parents of current document)
141
142 Revision 1.4 1999/06/15 01:55:29 sjboddie
143 - got text highlighting working
144 - got multiple collections working (now outputs error message if an
145 attempt is made to get a document when the "c" arg isn't set.
146
147 Revision 1.3 1999/06/08 04:29:37 sjboddie
148 added argsinfo to the call to check_cgiargs to make it easy to set
149 args to their default if they're found to be screwed up
150
151 Revision 1.2 1999/05/10 03:40:35 sjboddie
152 lots of changes - slowly getting document action sorted out
153
154 Revision 1.1 1999/04/30 01:59:40 sjboddie
155 lots of stuff - getting documentaction working (documentaction replaces
156 old browseaction)
157
158 Revision 1.2 1999/03/29 02:14:27 sjboddie
159
160 More changes to browseaction
161
162 Revision 1.1 1999/03/25 03:09:40 sjboddie
163
164 subjectbrowseaction became browseaction
165
166
167 */
168
169
170#include <string.h>
171#include "documentaction.h"
172#include "browsetools.h"
173#include "OIDtools.h"
174#include "querytools.h"
175#include "unitool.h"
176#include "htmlutils.h"
177
178documentaction::documentaction () {
179
180 // this action uses cgi variables "a", "d", "cl",
181 // "x", "gc", "gt", "gp", and "hl"
182 cgiarginfo arg_ainfo;
183 arg_ainfo.shortname = "a";
184 arg_ainfo.longname = "action";
185 arg_ainfo.multiplechar = true;
186 arg_ainfo.defaultstatus = cgiarginfo::weak;
187 arg_ainfo.argdefault = "p";
188 arg_ainfo.savedarginfo = cgiarginfo::must;
189 argsinfo.addarginfo (NULL, arg_ainfo);
190
191 arg_ainfo.shortname = "d";
192 arg_ainfo.longname = "document OID";
193 arg_ainfo.multiplechar = true;
194 arg_ainfo.defaultstatus = cgiarginfo::none;
195 arg_ainfo.argdefault = "";
196 arg_ainfo.savedarginfo = cgiarginfo::can;
197 argsinfo.addarginfo (NULL, arg_ainfo);
198
199 // whether or not a document should be retrieved from the
200 // library or the Web.
201 arg_ainfo.shortname = "il";
202 arg_ainfo.longname = "internal link preference";
203 arg_ainfo.multiplechar = false;
204 arg_ainfo.defaultstatus = cgiarginfo::weak;
205 arg_ainfo.argdefault = "l";
206 arg_ainfo.savedarginfo = cgiarginfo::must;
207 argsinfo.addarginfo (NULL, arg_ainfo);
208
209 arg_ainfo.shortname = "cl";
210 arg_ainfo.longname = "classification OID";
211 arg_ainfo.multiplechar = true;
212 arg_ainfo.defaultstatus = cgiarginfo::none;
213 arg_ainfo.argdefault = "";
214 arg_ainfo.savedarginfo = cgiarginfo::can;
215 argsinfo.addarginfo (NULL, arg_ainfo);
216
217 // in this action "gc" controls the expand/contract
218 // contents function
219 arg_ainfo.shortname = "gc";
220 arg_ainfo.longname = "expand contents";
221 arg_ainfo.multiplechar = false;
222 arg_ainfo.defaultstatus = cgiarginfo::weak;
223 arg_ainfo.argdefault = "0";
224 arg_ainfo.savedarginfo = cgiarginfo::can;
225 argsinfo.addarginfo (NULL, arg_ainfo);
226
227 // in this action "gt" controls the expand/contract
228 // text function 0 = not expanded, 1 = expand unless
229 // there are more than 10 sections containing text,
230 // 2 = expand all
231 arg_ainfo.shortname = "gt";
232 arg_ainfo.longname = "expand text";
233 arg_ainfo.multiplechar = false;
234 arg_ainfo.defaultstatus = cgiarginfo::weak;
235 arg_ainfo.argdefault = "0";
236 arg_ainfo.savedarginfo = cgiarginfo::can;
237 argsinfo.addarginfo (NULL, arg_ainfo);
238
239 // in this action "gp" is the "go to page" control
240 // used by the Book type of toc
241 arg_ainfo.shortname = "gp";
242 arg_ainfo.longname = "go to page";
243 arg_ainfo.multiplechar = true;
244 arg_ainfo.defaultstatus = cgiarginfo::none;
245 arg_ainfo.argdefault = "";
246 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
247 argsinfo.addarginfo (NULL, arg_ainfo);
248
249 // in this action "hl" is the "highlighting on/
250 // highlighting off control
251 arg_ainfo.shortname = "hl";
252 arg_ainfo.longname = "highlighting on/off";
253 arg_ainfo.multiplechar = false;
254 arg_ainfo.defaultstatus = cgiarginfo::weak;
255 arg_ainfo.argdefault = "1";
256 arg_ainfo.savedarginfo = cgiarginfo::must;
257 argsinfo.addarginfo (NULL, arg_ainfo);
258
259 // "x" is 0 normally or 1 if page
260 // has been "detached"
261 arg_ainfo.shortname = "x";
262 arg_ainfo.longname = "detached page";
263 arg_ainfo.multiplechar = false;
264 arg_ainfo.defaultstatus = cgiarginfo::weak;
265 arg_ainfo.argdefault = "0";
266 arg_ainfo.savedarginfo = cgiarginfo::must;
267 argsinfo.addarginfo (NULL, arg_ainfo);
268
269 // f arg is set to 1 if document is to
270 // be displayed in a frame
271 arg_ainfo.shortname = "f";
272 arg_ainfo.longname = "frame";
273 arg_ainfo.multiplechar = false;
274 arg_ainfo.defaultstatus = cgiarginfo::weak;
275 arg_ainfo.argdefault = "0";
276 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
277 argsinfo.addarginfo (NULL, arg_ainfo);
278
279 // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
280 // the httpdocument macro will include "&f=1"
281 arg_ainfo.shortname = "fc";
282 arg_ainfo.longname = "include search bar";
283 arg_ainfo.multiplechar = false;
284 arg_ainfo.defaultstatus = cgiarginfo::weak;
285 arg_ainfo.argdefault = "1";
286 arg_ainfo.savedarginfo = cgiarginfo::must;
287 argsinfo.addarginfo (NULL, arg_ainfo);
288}
289
290documentaction::~documentaction () {
291}
292
293bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
294 ostream &logout) {
295
296 // check gc argument
297 int arg_gc = args.getintarg("gc");
298 if (arg_gc != 0 && arg_gc != 1) {
299 logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
300 cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
301 if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
302 }
303
304 // check gt argument (may be either 0, 1 or 2)
305 int arg_gt = args.getintarg("gt");
306 if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
307 logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
308 cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
309 if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
310 }
311
312 // check hl argument
313 int arg_hl = args.getintarg("hl");
314 if (arg_hl != 0 && arg_hl != 1) {
315 logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
316 cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
317 if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
318 }
319
320 // check x argument
321 int arg_x = args.getintarg("x");
322 if (arg_x != 0 && arg_x != 1) {
323 logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
324 cgiarginfo *xinfo = argsinfo.getarginfo ("x");
325 if (xinfo != NULL) args["x"] = xinfo->argdefault;
326 }
327
328 return true;
329}
330
331void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
332 response_t &response,text_t &response_data,
333 ostream &logout) {
334
335 if ((args["il"] == "w") && (!args["d"].empty())) {
336
337 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
338 if (collectproto != NULL) {
339
340 text_tset metadata;
341 FilterResponse_t filt_response;
342 text_t top;
343
344 metadata.insert ("URL");
345
346 // get metadata for parent document
347 get_top (args["d"], top);
348 if (get_info (top, args["c"], metadata, false, collectproto, filt_response, logout)) {
349 text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
350
351 response = location;
352 response_data = url;
353 return;
354 } else {
355 // error, no URL
356 logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
357 }
358 }
359 }
360 response = content;
361 response_data = "text/html";
362}
363
364// set_widthtspace calculates how wide the spaces in the nav bar should
365// be and sets the appropriate macro
366void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response) {
367
368 text_t width;
369 int twidth, swidth, iwidth = 0;
370
371 int numc = response.docInfo.size();
372 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
373 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
374
375 disp.expandstring ("Global", "_pagewidth_", width);
376 twidth = width.getint();
377
378 disp.expandstring ("query", "_searchwidth_", width);
379 iwidth += width.getint();
380
381
382
383 while (dochere != docend) {
384 const text_t &title = (*dochere).metadata["Title"].values[0];
385
386 disp.expandstring ("document", "_" + title + "width_", width);
387 if (width == ("_" + title + "width_"))
388 disp.expandstring ("document", "_defaultwidth_", width);
389 iwidth += width.getint();
390 dochere ++;
391 }
392 if ((twidth - iwidth) < numc) swidth = 2;
393 else {
394 swidth = twidth - iwidth;
395 if (numc > 0) swidth = swidth / numc;
396 }
397 disp.setmacro ("widthtspace", "Global", swidth);
398}
399
400// set_navbarmacros sets _navigationbar_, _javaimagesnavbar_ and _httpbrowseXXX_ macros
401// reponse contains 1 metadata field (Title)
402void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response,
403 cgiargsclass &args) {
404
405 text_t javaimagesnavbar, topparent;
406 text_t &arg_d = args["d"];
407 text_t navigationbar = "<!-- Navigation Bar -->\n";
408
409 get_top (args["cl"], topparent);
410 int numc = response.docInfo.size();
411 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
412 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
413
414 navigationbar += "<nobr>\n";
415 if (args["a"] == "q") {
416 navigationbar += "_icontabsearchgreen_";
417 } else {
418 navigationbar += "_imagesearch_";
419 javaimagesnavbar = "_javasearch_";
420 }
421
422
423 if (numc == 0) navigationbar += "_imagespacer_";
424
425 while (dochere != docend) {
426 text_t title = (*dochere).metadata["Title"].values[0];
427
428 bool unknown = false;
429
430 // test the _XXXwidth_ macro to see if image macros are
431 // defined for this type of classification - if not we'll
432 // just display the text
433 text_t tmpwidth;
434 disp.expandstring ("document", "_" + title + "width_", tmpwidth);
435 if (tmpwidth == ("_" + title + "width_")) unknown = true;
436
437 // if we're inside a document all the classification buttons should be enabled
438 if (arg_d.empty() && ((*dochere).OID == topparent)) {
439 if (unknown) navigationbar += "_imagespacer_&nbsp;" + title + "&nbsp;";
440 else navigationbar += "_imagespacer__icontab" + title + "green_";
441 } else {
442
443 // set the _httpbrowseXXX_ macro for this classification
444 if (unknown) navigationbar += "_imagespacer_&nbsp;<a href=\"_httpdocument_&cl=" +
445 (*dochere).OID + "\">" + title + "</a>&nbsp;";
446 else {
447 navigationbar += "_imagespacer__image" + title + "_";
448 disp.setmacro ("httpbrowse" + title, "Global", "_httpdocument_&cl=" + (*dochere).OID);
449 }
450 }
451 if (!unknown) javaimagesnavbar += "_java" + title + "_";
452 dochere ++;
453 }
454 navigationbar += "\n</nobr>\n";
455 navigationbar += "<!-- End of Navigation Bar -->\n";
456 disp.setmacro ("navigationbar", "Global", navigationbar);
457 if (args.getintarg("v") == 0)
458 disp.setmacro ("javaimagesnavbar", "Global", javaimagesnavbar);
459}
460
461// define all the macros which might be used by other actions
462// to produce pages.
463void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args,
464 recptprotolistclass *protos, ostream &logout) {
465
466 // define_external_macros sets the following macros:
467
468 // _navigationbar_ this is the navigation bar containing the search button
469 // and any classification buttons - it goes at the top of
470 // most pages. for now we're assuming that there'll always
471 // be a search button - we should probably check that there
472 // is a query action before making this assumption
473
474 // _httpbrowseXXX_ the http macros for each classification (i.e. if there
475 // are Title and Creator classifications _httpbrowseTitle_
476 // and _httpbrowseCreator_ will be set
477
478 // _javaimagesnavbar_ this is the javascript code to shove in to make the
479 // flashy images used by _navigationbar_ work
480
481 // _widthtspace_ the width of the spacers between buttons in navigation
482 // bar
483
484 // _httpdocument_ has '&f=1' added if displaying document inside a frame
485
486 // _gsdltop_ macro to replace _top targets with
487
488 // _httppagehome_ overridden home url if html collections have own homepage
489
490 // must have a valid collection server to continue
491 text_t &collection = args["c"];
492 if (collection.empty()) return;
493 recptproto *collectproto = protos->getrecptproto (collection, logout);
494 if (collectproto == NULL) return;
495
496 outconvertclass text_t2ascii;
497 comerror_t err;
498 InfoFiltersResponse_t filterinfo;
499 FilterResponse_t response;
500 text_tset metadata;
501
502
503 // get info on current collection and load up formatinfo
504 // I'd prefer not to do this here as we're getting
505 // collection info every time (and probably also getting
506 // it in other places some of the time) - One day I'll
507 // fix it ... maybe - Stefan.
508 ColInfoResponse_t cinfo;
509 collectproto->get_collectinfo (collection, cinfo, err, logout);
510 load_formatinfo (cinfo.format, args.getintarg("gt"));
511
512 if (formatinfo.DocumentUseHTML) {
513
514 // frame stuff
515 if (args["fc"] == "1") {
516 text_t httpdocument;
517 disp.expandstring ("Global", "_httpdocument_", httpdocument);
518 httpdocument += "&f=1";
519 disp.setmacro ("httpdocument", "Global", httpdocument);
520 disp.setmacro ("gsdltop", "Global", "documenttop");
521 }
522 text_tmap::iterator it = cinfo.format.find ("homepage");
523 if (it != cinfo.format.end()) {
524 text_t httppagehome;
525 if (get_link (args, protos, (*it).second, httppagehome, logout))
526 disp.setmacro ("httppagehome", "Global", httppagehome);
527 }
528 }
529
530 // don't want navigation bar if page is 'detached'
531 if (!args.getintarg("x")) {
532
533 collectproto->get_filterinfo (collection, filterinfo, err, logout);
534 if (err == noError) {
535 // check that there's a browse filter
536 if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
537
538 metadata.insert ("Title");
539 bool getParents = false;
540 get_children ("", collection, metadata, getParents, collectproto, response, logout);
541
542 // calculate width of spacers and set _widthtspace_ macro
543 if (args.getintarg("v") == 0) set_spacemacro (disp, response);
544
545 // set _navigationbar_ and _javaimagesnavbar_ macros
546 set_navbarmacros (disp, response, args);
547
548 }
549 } else {
550 logout << text_t2ascii
551 << "Error (documentaction::define_external_macros()) in call to get_filterinfo() "
552 << get_comerror_string (err);
553 }
554 }
555}
556
557bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
558 const text_t &inlink, text_t &outlink, ostream &logout) {
559
560 FilterResponse_t response;
561 text_tset metadata;
562 metadata.insert ("section");
563
564 // check current collection first
565 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
566
567 if (get_info (inlink, args["c"], metadata, false, collectproto, response, logout)) {
568 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
569 outlink = "_httpdocument_&d=" + response.docInfo[0].metadata["section"].values[0];
570 return true;
571 }
572 }
573
574 // check all the other enabled collections
575
576 if (args["ccs"] == "1" && !args["cc"].empty()) {
577 text_tarray collections;
578 splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
579
580 text_tarray::const_iterator col_here = collections.begin();
581 text_tarray::const_iterator col_end = collections.end();
582
583 while (col_here != col_end) {
584
585 // don't need to check current collection again
586 if (*col_here == args["c"]) {col_here ++; continue;}
587
588 collectproto = protos->getrecptproto (*col_here, logout);
589
590 if (get_info (inlink, *col_here, metadata, false, collectproto, response, logout)) {
591 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
592 outlink = "_httpdocument_&c=" + *col_here + "&d=" +
593 response.docInfo[0].metadata["section"].values[0];
594 return true;
595 }
596 }
597 col_here ++;
598 }
599 }
600 return false;
601}
602
603void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
604
605 formatinfo.clear();
606 text_tmap::const_iterator format_here = colformat.begin();
607 text_tmap::const_iterator format_end = colformat.end();
608
609 while (format_here != format_end) {
610 if ((*format_here).first == "DocumentIcon")
611 formatinfo.DocumentIcon = (*format_here).second;
612 else if (((*format_here).first == "DocumentContents") &&
613 ((*format_here).second == "false"))
614 formatinfo.DocumentContents = false;
615 else if (((*format_here).first == "DocumentArrowsBottom") &&
616 ((*format_here).second == "false"))
617 formatinfo.DocumentArrowsBottom = false;
618 else if ((*format_here).first == "DocumentButtons")
619 splitchar ((*format_here).second.begin(), (*format_here).second.end(),
620 '|', formatinfo.DocumentButtons);
621 else if ((*format_here).first == "DocumentText")
622 formatinfo.DocumentText = (*format_here).second;
623 else if (((*format_here).first == "DocumentUseHTML") &&
624 ((*format_here).second == "true"))
625 formatinfo.DocumentUseHTML = true;
626 else
627 formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
628
629 format_here ++;
630 }
631
632 // never want arrows when text is expanded
633 if (gt) formatinfo.DocumentArrowsBottom = false;
634}
635
636void documentaction::set_java_macros (cgiargsclass &args, displayclass &disp) {
637
638 text_t javaimagescontent = "_javaextras_";
639
640 int arg_gt = args.getintarg("gt");
641 int arg_gc = args.getintarg("gc");
642 int arg_hl = args.getintarg("hl");
643
644 text_tarray::const_iterator button_here = formatinfo.DocumentButtons.begin();
645 text_tarray::const_iterator button_end = formatinfo.DocumentButtons.end();
646
647 while (button_here != button_end) {
648 if (*button_here == "Detach")
649 javaimagescontent += "_javadetach_";
650 else if (*button_here == "Expand Text") {
651 if (arg_gt == 1)
652 javaimagescontent += "_javacontracttext__javacontinue_";
653 else if (arg_gt == 2)
654 javaimagescontent += "_javacontracttext_";
655 else
656 javaimagescontent += "_javaexpandtext_";
657 } else if (*button_here == "Expand Contents") {
658 if (arg_gc == 1)
659 javaimagescontent += "_javacontractcontents_";
660 else
661 javaimagescontent += "_javaexpandcontents_";
662 } else if (*button_here == "Highlight") {
663 if (arg_hl == 1)
664 javaimagescontent += "_javanohighlighting_";
665 else
666 javaimagescontent += "_javahighlighting_";
667 }
668 button_here ++;
669 }
670 disp.setmacro ("javaimagescontent", "document", javaimagescontent);
671}
672
673
674// define all the macros which are related to pages generated
675// by this action. we also load up the formatinfo structure
676// here (it's used in do_action as well as here)
677void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
678 recptprotolistclass *protos, ostream &logout) {
679
680 // define_internal_macros sets the following macros:
681
682 // _pagetitle_ the title to be displayed at the top of the browser window
683
684 // _imagethispage_ the title image to be displayed at top right of page
685
686 // _navarrows_ this may be overridden to "" when format option
687 // DocumentArrowsBottom is false
688
689 // _header_ the header macro is overridden if we're not at a top level
690 // classification to remove the title block
691
692 // _javaimagescontent_ this is the javascript code to shove in to make the
693 // flashy buttons work
694
695 // _thisOID_ the OID (directory) of the current document - this corresponds
696 // to the archivedir metadata element
697
698 // must have a valid collection server to continue
699 text_t &collection = args["c"];
700 if (collection.empty()) return;
701 recptproto *collectproto = protos->getrecptproto (collection, logout);
702 if (collectproto == NULL) return;
703
704 text_tset metadata;
705 FilterResponse_t response;
706 text_t &arg_d = args["d"];
707 text_t &arg_cl = args["cl"];
708
709 if (!formatinfo.DocumentArrowsBottom)
710 disp.setmacro("navarrows", "document", "");
711
712 metadata.insert ("Title");
713
714 bool fulltoc = false;
715
716 if (args["cl"] != "search") {
717 // see if there's a FullTOC string
718 text_t cl_top, full_toc;
719 get_top (arg_cl, cl_top);
720 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
721 if (full_toc == "true") fulltoc = true;
722 }
723
724 if (!arg_d.empty() && !fulltoc) {
725 // we're at document level
726
727 metadata.insert ("archivedir");
728
729 // get metadata for this document and it's parents
730 if (get_info (arg_d, collection, metadata, true, collectproto, response, logout)) {
731 disp.setmacro ("header", "document", "_textheader_");
732
733 text_tarray pagetitlearray;
734 if (!response.docInfo[0].metadata["Title"].values[0].empty())
735 pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
736 if (args["gt"] != "1") {
737 MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
738 while (parenttitle != NULL) {
739 if (!parenttitle->values[0].empty())
740 pagetitlearray.push_back (parenttitle->values[0]);
741 parenttitle = parenttitle->parent;
742 }
743 }
744 reverse (pagetitlearray.begin(), pagetitlearray.end());
745 text_t pagetitle;
746 joinchar (pagetitlearray, ": ", pagetitle);
747 disp.setmacro ("pagetitle", "document", pagetitle);
748
749 if (is_top (arg_d))
750 disp.setmacro ("thisOID", "Global", dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
751 else {
752 MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
753 text_t thisOID;
754 while (parentad != NULL) {
755 thisOID = parentad->values[0];
756 parentad = parentad->parent;
757 }
758 disp.setmacro ("thisOID", "Global", dm_safe(thisOID));
759 }
760
761 if (args["u"] != "1")
762 set_java_macros (args, disp);
763
764 }
765 } else {
766 if (!arg_cl.empty()) {
767
768 // get metadata for top level classification
769 text_t classtop;
770 get_top (arg_cl, classtop);
771 if (get_info (classtop, collection, metadata, false, collectproto, response, logout)) {
772
773 text_t &title = response.docInfo[0].metadata["Title"].values[0];
774 bool unknown = false;
775
776 // test the _XXXwidth_ macro to see if image macros are
777 // defined for this type of classification - if not we'll
778 // just display the text
779 text_t tmp;
780 disp.expandstring ("document", "_" + title + "width_", tmp);
781 if (tmp == ("_" + title + "width_")) unknown = true;
782
783 if (unknown) {
784 disp.setmacro ("pagetitle", "document", title);
785 disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
786 } else {
787 disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
788 disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
789 }
790 }
791 }
792 }
793}
794
795
796bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
797 browsermapclass *browsers, displayclass &disp,
798 outconvertclass &outconvert, ostream &textout,
799 ostream &logout) {
800
801
802 // must have a valid collection server
803 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
804 if (collectproto == NULL) {
805 logout << "documentaction::do_action called with NULL collectproto\n";
806 textout << outconvert << disp << "_document:header_\n"
807 << "Error: Attempt to get document without setting collection\n"
808 << "_document:footer_\n";
809 } else {
810
811 text_t OID = args["d"];
812 if (OID.empty()) OID = args["cl"];
813 if (OID.empty()) {
814 textout << outconvert << disp << "Document contains no data_document:footer_\n";
815 return true;
816 }
817
818 if (formatinfo.DocumentUseHTML) {
819
820 if (!args["d"].empty()) {
821 if (args["f"] == "1") {
822 textout << outconvert << disp
823 << "<html><head></head>\n"
824 << "<frameset rows=\"68,*\" noresize border=0>\n"
825 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=p&p=nav\">\n"
826 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?e=_compressedoptions_&a=d&d="
827 << args["d"] << "\">"
828 << "<noframes>\n"
829 << "<p>You must have a frame enabled browser to view this.</p>\n"
830 << "</noframes>\n"
831 << "</frameset>\n"
832 << "</html>\n";
833 } else {
834 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
835 }
836 return true;
837 }
838 }
839
840 textout << outconvert << disp << "_document:header_\n"
841 << "_document:content_\n";
842
843 // output the table of contents
844 output_toc (args, browsers, formatinfo, collectproto,
845 disp, outconvert, textout, logout);
846
847 // output the document text
848 textout << "<p>\n";
849 output_document (OID, args, collectproto, disp, outconvert, textout, logout);
850
851 textout << outconvert << disp << "_document:footer_\n";
852 }
853 return true;
854}
855
856void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
857 const TermInfo_tarray &terminfo, const text_t &OID,
858 bool highlight, int hastxt, int wanttext,
859 text_t &collection, recptproto *collectproto,
860 displayclass &disp, outconvertclass &outconvert,
861 ostream &textout, ostream &logout) {
862
863 DocumentRequest_t docrequest;
864 DocumentResponse_t docresponse;
865 comerror_t err;
866
867 if (hastxt == 1) {
868
869 if (wanttext) {
870 // get the text
871 docrequest.OID = OID;
872 collectproto->get_document (collection, docrequest, docresponse, err, logout);
873
874 // cut down on overhead by not using formattools if we only want the text
875 // (wanttext will equal 2 if we want text and other stuff too)
876 if (wanttext == 1)
877 if (highlight)
878 highlighttext(docresponse.doc, terminfo, disp, outconvert, textout, logout);
879 else
880 textout << outconvert << disp << docresponse.doc;
881 }
882
883 if (wanttext != 1) {
884 text_t doctext = get_formatted_string (docinfo, formatlistptr, docresponse.doc);
885
886 if (highlight)
887 highlighttext(doctext, terminfo, disp, outconvert, textout, logout);
888 else
889 textout << outconvert << disp << doctext;
890 }
891 }
892}
893
894
895void documentaction::output_document (const text_t &OID, cgiargsclass &args,
896 recptproto *collectproto, displayclass &disp,
897 outconvertclass &outconvert, ostream &textout,
898 ostream &logout) {
899 FilterResponse_t inforesponse;
900 FilterResponse_t queryresponse;
901 text_tset metadata;
902 bool getParents = false;
903 bool highlight = false;
904 int wanttext = 0;
905 int arg_gt = args.getintarg("gt");
906 text_t &collection = args["c"];
907
908 // if we have a query string and highlighting is turned on we need
909 // to redo the query to get the terms for highlighting
910 if (!args["q"].empty() && args.getintarg("hl")) {
911 FilterRequest_t request;
912 comerror_t err;
913 request.filterResultOptions = FRmatchTerms;
914 text_t formattedstring = args["q"];
915 format_querystring (formattedstring, args.getintarg("b"));
916 set_queryfilter_options (request, formattedstring, args);
917 collectproto->filter (args["c"], request, queryresponse, err, logout);
918 if (err != noError) {
919 outconvertclass text_t2ascii;
920 logout << text_t2ascii
921 << "documentaction::output_document: call to QueryFilter failed "
922 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
923 highlight = false;
924 } else {
925 highlight = true;
926 }
927 }
928
929 format_t *formatlistptr = new format_t();
930 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
931
932 metadata.insert ("hastxt");
933 metadata.insert ("haschildren");
934
935 if (formatinfo.DocumentText == "[Text]")
936 wanttext = 1;
937 else {
938 char *docformat = formatinfo.DocumentText.getcstr();
939 if (strstr (docformat, "[Text]") != NULL)
940 wanttext = 2;
941 delete docformat;
942 }
943
944 if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
945 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
946 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
947
948 if (arg_gt == 0) {
949 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
950 OID, highlight, hastxt, wanttext, collection, collectproto,
951 disp, outconvert, textout, logout);
952
953
954 } else {
955
956 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
957
958 // text is to be expanded
959 text_t exOID = OID;
960 if (haschildren != 1) exOID = get_parent (OID);
961 if (exOID.empty()) exOID = OID;
962
963 // if we're not in a document (i.e. we're in a top level classification)
964 // we need to pass "is_classify = true" to get_contents so that it
965 // doesn't recurse all the way through each document in the classification
966 bool is_classify = false;
967 if (args["d"].empty()) is_classify = true;
968
969 get_contents (exOID, is_classify, metadata, collection,
970 collectproto, inforesponse, logout);
971
972 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
973 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
974
975 if (arg_gt == 1) {
976 // check if there are more than 10 sections containing text to be expanded -
977 // if there are output warning message - this isn't a great way to do this
978 // since the sections may be very large or very small - one day I'll fix it
979 // -- Stefan.
980 int seccount = 0;
981 while (sechere != secend) {
982 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
983 if (shastxt == 1) seccount ++;
984 if (seccount > 10) break;
985 sechere ++;
986 }
987 if (seccount > 10) {
988 // more than 10 sections so output warning message and text
989 // for current section only
990 textout << outconvert << disp << "_document:textltwarning_";
991
992 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
993 OID, highlight, hastxt, wanttext, collection,
994 collectproto, disp, outconvert, textout, logout);
995
996 }
997 else arg_gt = 2;
998 }
999
1000 if (arg_gt == 2) {
1001 // get the text for each section
1002 sechere = inforesponse.docInfo.begin();
1003 int count = 0;
1004 while (sechere != secend) {
1005 textout << outconvert << disp << "\n<p><a name=" << count << "></a>\n";
1006
1007 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1008
1009 output_text (*sechere, formatlistptr, queryresponse.termInfo,
1010 (*sechere).OID, highlight, shastxt, wanttext, collection,
1011 collectproto, disp, outconvert, textout, logout);
1012 count ++;
1013 sechere ++;
1014 }
1015 }
1016 }
1017 }
1018 delete formatlistptr;
1019}
1020
1021// highlighttext highlights query terms in text string and outputs the resulting text string
1022void documentaction::highlighttext(text_t &text, const TermInfo_tarray &terms,
1023 displayclass &disp, outconvertclass &outconvert,
1024 ostream &textout, ostream &/*logout*/) {
1025
1026 text_tmap allterms;
1027 text_tmap::const_iterator it;
1028
1029 // first load all the term variations into a map
1030 TermInfo_tarray::const_iterator this_term = terms.begin();
1031 TermInfo_tarray::const_iterator last_term = terms.end();
1032 while (this_term != last_term) {
1033 text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
1034 text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
1035 while (this_var != last_var) {
1036 allterms[*this_var] = 1;
1037 this_var ++;
1038 }
1039 this_term ++;
1040 }
1041
1042 // get the text to start and end a hightlight
1043 text_t starthighlight = "<b><u>";
1044 text_t endhighlight = "</u></b>";
1045 if (disp.isdefaultmacro("Global", "starthighlight"))
1046 disp.expandstring("Global", "_starthighlight_", starthighlight);
1047 if (disp.isdefaultmacro("Global", "endhighlight"))
1048 disp.expandstring("Global", "_endhighlight_", endhighlight);
1049
1050
1051 text_t::iterator here = text.begin();
1052 text_t::iterator end = text.end();
1053 text_t word, buffer;
1054 while (here != end) {
1055 if (is_unicode_letdig(*here)) {
1056 // not word boundary
1057 word.push_back(*here);
1058 here++;
1059
1060 } else {
1061 // found word boundary
1062 // add last word if there was one
1063 if (!word.empty()) {
1064 it = allterms.find(word);
1065 if (it != allterms.end()) {
1066 word = starthighlight + word + endhighlight;
1067 }
1068 buffer += word;
1069 word.clear();
1070 }
1071
1072 if (*here == '<') {
1073 // skip over rest of html tag
1074 while ((here != end) && (*here != '>')) {
1075 buffer.push_back(*here);
1076 here++;
1077 }
1078 }
1079
1080 buffer.push_back(*here);
1081 here++;
1082
1083 if (buffer.size() > 1024) {
1084 textout << outconvert << disp << buffer;
1085 buffer.clear();
1086 }
1087 }
1088 }
1089 textout << outconvert << disp << buffer;
1090}
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
Note: See TracBrowser for help on using the repository browser.