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

Last change on this file since 11144 was 11144, checked in by jrm21, 18 years ago

put the output document text in its own div, and give it some CSS to make
sure it is shown underneath any floating divs instead of next to them.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 44.6 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 *********************************************************************/
25
26#include <string.h>
27
28#include "documentaction.h"
29#include "browsetools.h"
30#include "OIDtools.h"
31#include "querytools.h"
32#include "unitool.h"
33#include "gsdltools.h"
34#include "highlighttext.h"
35
36documentaction::documentaction () {
37 recpt = NULL;
38
39
40 // this action uses cgi variables "a", "d", "cl",
41 // "x", "gc", "gt", "gp", and "hl"
42 cgiarginfo arg_ainfo;
43 arg_ainfo.shortname = "a";
44 arg_ainfo.longname = "action";
45 arg_ainfo.multiplechar = true;
46 arg_ainfo.defaultstatus = cgiarginfo::weak;
47 arg_ainfo.argdefault = "p";
48 arg_ainfo.savedarginfo = cgiarginfo::must;
49 argsinfo.addarginfo (NULL, arg_ainfo);
50
51 arg_ainfo.shortname = "d";
52 arg_ainfo.longname = "document OID";
53 arg_ainfo.multiplechar = true;
54 arg_ainfo.defaultstatus = cgiarginfo::none;
55 arg_ainfo.argdefault = g_EmptyText;
56 arg_ainfo.savedarginfo = cgiarginfo::can;
57 argsinfo.addarginfo (NULL, arg_ainfo);
58
59 // whether or not a document should be retrieved from the
60 // library or the Web.
61 arg_ainfo.shortname = "il";
62 arg_ainfo.longname = "internal link preference";
63 arg_ainfo.multiplechar = false;
64 arg_ainfo.defaultstatus = cgiarginfo::weak;
65 arg_ainfo.argdefault = "l";
66 arg_ainfo.savedarginfo = cgiarginfo::must;
67 argsinfo.addarginfo (NULL, arg_ainfo);
68
69 arg_ainfo.shortname = "cl";
70 arg_ainfo.longname = "classification OID";
71 arg_ainfo.multiplechar = true;
72 arg_ainfo.defaultstatus = cgiarginfo::none;
73 arg_ainfo.argdefault = g_EmptyText;
74 arg_ainfo.savedarginfo = cgiarginfo::can;
75 argsinfo.addarginfo (NULL, arg_ainfo);
76
77 // in this action "gc" controls the expand/contract
78 // contents function
79 arg_ainfo.shortname = "gc";
80 arg_ainfo.longname = "expand contents";
81 arg_ainfo.multiplechar = false;
82 arg_ainfo.defaultstatus = cgiarginfo::weak;
83 arg_ainfo.argdefault = "0";
84 arg_ainfo.savedarginfo = cgiarginfo::can;
85 argsinfo.addarginfo (NULL, arg_ainfo);
86
87 // in this action "gt" controls the expand/contract
88 // text function 0 = not expanded, 1 = expand unless
89 // there are more than 10 sections containing text,
90 // 2 = expand all
91 arg_ainfo.shortname = "gt";
92 arg_ainfo.longname = "expand text";
93 arg_ainfo.multiplechar = false;
94 arg_ainfo.defaultstatus = cgiarginfo::weak;
95 arg_ainfo.argdefault = "0";
96 arg_ainfo.savedarginfo = cgiarginfo::can;
97 argsinfo.addarginfo (NULL, arg_ainfo);
98
99 // in this action "gp" is the "go to page" control
100 // used by the Book type of toc
101 arg_ainfo.shortname = "gp";
102 arg_ainfo.longname = "go to page";
103 arg_ainfo.multiplechar = true;
104 arg_ainfo.defaultstatus = cgiarginfo::none;
105 arg_ainfo.argdefault = g_EmptyText;
106 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
107 argsinfo.addarginfo (NULL, arg_ainfo);
108
109 // in this action "hl" is the "highlighting on/
110 // highlighting off control ("hl" == "2" is a
111 // special case that forces phrase highlighting
112 // to be used even if the query string doesn't
113 // appear to be a phrase)
114 arg_ainfo.shortname = "hl";
115 arg_ainfo.longname = "highlighting on/off";
116 arg_ainfo.multiplechar = false;
117 arg_ainfo.defaultstatus = cgiarginfo::weak;
118 arg_ainfo.argdefault = "1";
119 arg_ainfo.savedarginfo = cgiarginfo::must;
120 argsinfo.addarginfo (NULL, arg_ainfo);
121
122 // "x" is 0 normally or 1 if page
123 // has been "detached"
124 arg_ainfo.shortname = "x";
125 arg_ainfo.longname = "detached page";
126 arg_ainfo.multiplechar = false;
127 arg_ainfo.defaultstatus = cgiarginfo::weak;
128 arg_ainfo.argdefault = "0";
129 arg_ainfo.savedarginfo = cgiarginfo::must;
130 argsinfo.addarginfo (NULL, arg_ainfo);
131
132 // "xx" is 0 normally or 1 if documents should be detached by default
133 arg_ainfo.shortname = "xx";
134 arg_ainfo.longname = "detach all doc pages";
135 arg_ainfo.multiplechar = false;
136 arg_ainfo.defaultstatus = cgiarginfo::weak;
137 arg_ainfo.argdefault = "0";
138 arg_ainfo.savedarginfo = cgiarginfo::must;
139 argsinfo.addarginfo (NULL, arg_ainfo);
140
141
142 // f arg is set to 1 if document is to
143 // be displayed in a frame
144 arg_ainfo.shortname = "f";
145 arg_ainfo.longname = "frame";
146 arg_ainfo.multiplechar = false;
147 arg_ainfo.defaultstatus = cgiarginfo::weak;
148 arg_ainfo.argdefault = "0";
149 arg_ainfo.savedarginfo = cgiarginfo::mustnot;
150 argsinfo.addarginfo (NULL, arg_ainfo);
151
152 // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
153 // the httpdocument macro will include "&f=1"
154 arg_ainfo.shortname = "fc";
155 arg_ainfo.longname = "include search bar";
156 arg_ainfo.multiplechar = false;
157 arg_ainfo.defaultstatus = cgiarginfo::weak;
158 arg_ainfo.argdefault = "1";
159 arg_ainfo.savedarginfo = cgiarginfo::must;
160 argsinfo.addarginfo (NULL, arg_ainfo);
161
162 //rd is whether a document will be displayed
163 //with a relevant document list
164 arg_ainfo.shortname = "rd";
165 arg_ainfo.longname = "include relevant documents";
166 arg_ainfo.multiplechar = false;
167 arg_ainfo.defaultstatus = cgiarginfo::weak;
168 arg_ainfo.argdefault = "0";
169 arg_ainfo.savedarginfo = cgiarginfo::must;
170 argsinfo.addarginfo (NULL, arg_ainfo);
171
172 //dm is the metadata that has been used for the datelist
173 arg_ainfo.shortname = "dm";
174 arg_ainfo.longname = "date metadata";
175 arg_ainfo.multiplechar = true;
176 arg_ainfo.defaultstatus = cgiarginfo::weak;
177 arg_ainfo.argdefault = g_EmptyText;
178 arg_ainfo.savedarginfo = cgiarginfo::must;
179 argsinfo.addarginfo (NULL, arg_ainfo);
180
181}
182
183documentaction::~documentaction () {
184}
185
186bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
187 recptprotolistclass *protos, ostream &logout) {
188
189 if(!args["d"].empty())
190 {
191 text_t docTop;
192 get_top(args["d"],docTop);
193
194 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
195 if (collectproto != NULL)
196 {
197 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
198
199 if(cinfo->authenticate == "document")
200 {
201 // both are either commented out or uncomment and are empty
202 if (cinfo->public_documents.empty() && cinfo->private_documents.empty())
203 {
204 //deny everything
205 args["uan"] = "1";
206 args["ug"] = cinfo->auth_group;
207 }
208
209 // both public_documents and private_documents are turned on !
210 else if (!cinfo->public_documents.empty() && !cinfo->private_documents.empty())
211 {
212 //deny everything
213 args["uan"] = "1";
214 args["ug"] = cinfo->auth_group;
215 }
216
217 // if public_documents is set but this document isn't
218 // listed in it we need to authenticate
219 else if ((!cinfo->public_documents.empty()) &&
220 (cinfo->public_documents.find(docTop) == cinfo->public_documents.end()))
221 {
222 args["uan"] = "1";
223 args["ug"] = cinfo->auth_group;
224 }
225
226 // if private_documents is set and this document is
227 // listed in it we need to authenticate
228 else if ((!cinfo->private_documents.empty()) &&
229 (cinfo->private_documents.find(docTop) != cinfo->private_documents.end()))
230 {
231 args["uan"] = "1";
232 args["ug"] = cinfo->auth_group;
233 }
234
235 }
236 }
237 }
238 // check gc argument
239 int arg_gc = args.getintarg("gc");
240 if (arg_gc < 0 || arg_gc > 2) {
241 logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
242 cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
243 if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
244 }
245
246 // check gt argument (may be either 0, 1 or 2)
247 int arg_gt = args.getintarg("gt");
248 if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
249 logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
250 cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
251 if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
252 }
253
254 // check hl argument
255 int arg_hl = args.getintarg("hl");
256 if (arg_hl < 0 || arg_hl > 2) {
257 logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
258 cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
259 if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
260 }
261
262 // check x argument
263 int arg_x = args.getintarg("x");
264 if (arg_x != 0 && arg_x != 1) {
265 logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
266 cgiarginfo *xinfo = argsinfo.getarginfo ("x");
267 if (xinfo != NULL) args["x"] = xinfo->argdefault;
268 }
269
270 //checks whether rd arg is valid
271 int arg_rd = args.getintarg("rd");
272 if (arg_rd != 0 && arg_rd != 1) {
273 logout << "Warning: \"rd\" argument out of range (" << arg_rd << ")\n";
274 cgiarginfo *rdinfo = argsinfo.getarginfo ("rd");
275 if (rdinfo != NULL) args["rd"] = rdinfo->argdefault;
276 }
277
278
279 return true;
280}
281
282void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
283 response_t &response,text_t &response_data,
284 ostream &logout) {
285
286 if ((args["il"] == "w") && (!args["d"].empty())) {
287
288 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
289 if (collectproto != NULL) {
290
291 text_tset metadata;
292 FilterResponse_t filt_response;
293 text_t top;
294
295 metadata.insert ("URL");
296
297 // get metadata for parent document
298 get_top (args["d"], top);
299 if (get_info (top, args["c"], args["l"], metadata, false, collectproto, filt_response, logout)) {
300 text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
301
302 response = location;
303 response_data = url;
304 return;
305 } else {
306 // error, no URL
307 logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
308 }
309 }
310 }
311 response = content;
312 response_data = "text/html";
313}
314
315// set_widthtspace calculates how wide the spaces in the nav bar should
316// be and sets the appropriate macro
317void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response,
318 bool has_search_button) {
319
320 text_t width;
321 int twidth, swidth, iwidth = 0;
322
323 int numc = response.docInfo.size();
324 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
325 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
326
327 disp.expandstring (displayclass::defaultpackage, "_pagewidth_", width);
328 twidth = width.getint();
329
330 if (has_search_button) {
331 disp.expandstring ("query", "_searchwidth_", width);
332 iwidth += width.getint();
333 } else {
334 numc -= 1;
335 }
336
337 while (dochere != docend) {
338 const text_t &title = (*dochere).metadata["Title"].values[0];
339
340 disp.expandstring ("document", "_" + title + "width_", width);
341 if (width == ("_" + title + "width_")) {
342 disp.expandstring ("document", "_defaultwidth_", width);
343 }
344 iwidth += width.getint();
345 ++dochere;
346 }
347
348 if ((twidth - iwidth) < numc) swidth = 2;
349 else {
350 swidth = twidth - iwidth;
351 if (numc > 0) swidth = swidth / numc;
352 }
353 disp.setmacro ("widthtspace", displayclass::defaultpackage, swidth);
354}
355
356// set_navbarmacros sets _navigationbar_ and _httpbrowseXXX_ macros
357// reponse contains 1 metadata field (Title)
358void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response,
359 bool has_search_button, cgiargsclass &args,
360 ColInfoResponse_t &cinfo) {
361
362
363 bool use_pulldown = false;
364 text_tmap::iterator it = cinfo.format.find("NavigationBar");
365 if (it != cinfo.format.end()) {
366 if (it->second == "pulldown") {
367 use_pulldown = true;
368 }
369 }
370
371 text_t topparent;
372 text_t &arg_d = args["d"];
373 text_t navigationbar = "<!-- Navigation Bar -->\n";
374
375 text_t date_extra = g_EmptyText;
376 get_top (args["cl"], topparent);
377 int numc = response.docInfo.size();
378 ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
379 ResultDocInfo_tarray::iterator docend = response.docInfo.end();
380
381 if (!use_pulldown) {
382 navigationbar += "_navtabsearch_";
383 if (has_search_button) {
384 if (args["a"] == "q") {
385 navigationbar += "(selected)";
386 }
387 }
388
389 if (has_search_button || numc == 0) navigationbar += "_navbarspacer_";
390
391 bool first = true;
392 while (dochere != docend) {
393 date_extra = g_EmptyText;
394 if (!first) navigationbar += "_navbarspacer_";
395
396 text_t title = (*dochere).metadata["Title"].values[0];
397 if (title == "Date") { // a date list
398 text_t date_meta = (*dochere).metadata["mdtype"].values[0];
399 if (date_meta == g_EmptyText) {
400 date_meta = "Date";
401 }
402 date_extra = "&amp;dm="+date_meta;
403 }
404 bool unknown = false;
405
406 // test if the _tabtext$FIELD_ macro is defined, which means
407 // this is a "known" metadata type and we have a translation for it
408 text_t tmpwidth;
409 text_t macroname="_tabtext" + title + "_";
410 disp.expandstring ("document", macroname, tmpwidth);
411 if (tmpwidth == macroname) // it wasn't expanded
412 unknown = true;
413
414 // if we're inside a document all the classification buttons should be enabled
415 text_t this_tab;
416 bool is_top;
417
418 is_top = ((*dochere).OID == topparent);
419 // set default text fragment
420 this_tab = "_navtab_(";
421
422 if (unknown) { // just give the field name
423 if (!arg_d.empty() || !is_top) {
424 // work out the link for this classifier, as it isn't the
425 // current page
426 this_tab += "_httpdocument_&amp;cl=" + (*dochere).OID
427 + date_extra;
428 }
429 this_tab += "," + title + "," + title;
430 } else { // use the macro for this field so we get translations
431 this_tab += "_httpbrowse" + title;
432 this_tab += "_,_tabtext" + title;
433 this_tab += "_,_textdescr" + title + "_";
434 }
435
436 if (arg_d.empty() && is_top) {
437 // don't link to this classifier as it is the current one
438 this_tab += ",selected";
439 }
440
441 // set the _httpbrowseXXX_ macro for this classification
442 // set the correct url for this link
443 disp.setmacro ("httpbrowse" + title, displayclass::defaultpackage, "_httpdocument_&amp;cl=" + (*dochere).OID+date_extra);
444
445
446 this_tab += ")";
447
448 navigationbar += this_tab;
449
450 ++dochere;
451 first = false;
452 }
453
454 if (!has_search_button && numc == 1) navigationbar += "_navbarspacer_";
455
456 navigationbar += "\n<!-- End of Navigation Bar -->\n";
457
458 } else {
459
460 navigationbar = "<form method=\"get\" name=\"navform\">\n";
461 navigationbar += "<select name=\"navbar\" onChange=\"location.href=";
462 navigationbar += "document.navform.navbar.options[document.navform.navbar.selectedIndex].value\">\n";
463
464 if (args["a"] != "q" && args["cl"].empty()) {
465 navigationbar += "<option value=\"\" selected>_textselectpage_</option>\n";
466 }
467
468 if (has_search_button) {
469 navigationbar += "<option value=\"_httpquery_\"";
470 if (args["a"] == "q") {
471 navigationbar += " selected";
472 }
473 navigationbar += ">_tabtextsearch_</option>\n";
474 }
475
476 while (dochere != docend) {
477 text_t title = dochere->metadata["Title"].values[0];
478 if (title == "Date") { // a date list
479 text_t date_meta = (*dochere).metadata["mdtype"].values[0];
480 if (date_meta == "") {
481 date_meta = "Date";
482 }
483 date_extra = "&amp;dm="+date_meta;
484 }
485
486 navigationbar += "<option value=\"_httpdocument_&amp;cl=" + dochere->OID +date_extra+ "\"";
487 if (topparent == dochere->OID) {
488 navigationbar += " selected";
489 }
490 navigationbar += ">" + title + "</option>\n";
491 ++dochere;
492 }
493
494 navigationbar += "</select>\n";
495 navigationbar += "</form>\n";
496 }
497
498 disp.setmacro ("navigationbar", displayclass::defaultpackage, navigationbar);
499}
500
501// define all the macros which might be used by other actions
502// to produce pages.
503void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args,
504 recptprotolistclass *protos, ostream &logout) {
505
506 // define_external_macros sets the following macros:
507
508 // _navigationbar_ this is the navigation bar containing the search button
509 // and any classification buttons - it goes at the top of
510 // most pages. for now we're assuming that there'll always
511 // be a search button - we should probably check that there
512 // is a query action before making this assumption
513
514 // _httpbrowseXXX_ the http macros for each classification (i.e. if there
515 // are Title and Creator classifications _httpbrowseTitle_
516 // and _httpbrowseCreator_ will be set
517
518 // _widthtspace_ the width of the spacers between buttons in navigation
519 // bar
520
521 // _httpdocument_ has '&f=1' added if displaying document inside a frame
522
523 // _gsdltop_ macro to replace _top targets with
524
525 // _httppagehome_ overridden home url if html collections have own homepage
526
527
528 // must have a valid collection server to continue
529
530 text_t &collection = args["c"];
531 if (collection.empty()) return;
532 recptproto *collectproto = protos->getrecptproto (collection, logout);
533 if (collectproto == NULL) return;
534
535 if (recpt == NULL) {
536 logout << "ERROR (documentaction::define_external_macros): This action does not contain\n"
537 << " information about any receptionists. The method set_receptionist was\n"
538 << " probably not called from the module which instantiated this action.\n";
539 return;
540 }
541
542 outconvertclass text_t2ascii;
543 comerror_t err;
544 InfoFiltersResponse_t filterinfo;
545 FilterResponse_t response;
546 text_tset metadata;
547
548 // get info on current collection and load up formatinfo
549 // I'd prefer not to do this here as we're getting
550 // collection info every time (and probably also getting
551 // it in other places some of the time) - One day I'll
552 // fix it ... maybe - Stefan.
553 ColInfoResponse_t cinfo;
554
555 collectproto->get_collectinfo (collection, cinfo, err, logout);
556 load_formatinfo (cinfo.format, args.getintarg("gt"));
557 // ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
558 // if (cinfo == NULL) {
559 // logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
560 // return;
561 // }
562 //load_formatinfo (cinfo->format, args.getintarg("gt"));
563
564 if (formatinfo.DocumentUseHTML) {
565
566 // frame stuff
567 if (args["fc"] == "1") {
568 text_t httpdocument;
569 disp.expandstring (displayclass::defaultpackage, "_httpdocument_", httpdocument);
570 httpdocument += "&amp;f=1";
571 disp.setmacro ("httpdocument", displayclass::defaultpackage, httpdocument);
572 disp.setmacro ("gsdltop", displayclass::defaultpackage, "documenttop");
573 formatinfo.DocumentText = "[Text]";
574 }
575 text_tmap::iterator it = cinfo.format.find ("homepage");
576 if (it != cinfo.format.end()) {
577 text_t httppagehome;
578 if (get_link (args, protos, (*it).second, httppagehome, logout))
579 disp.setmacro ("httppagehome", displayclass::defaultpackage, httppagehome);
580 }
581 }
582
583 // don't want navigation bar if page is 'detached'
584 if (!args.getintarg("x")) {
585
586 collectproto->get_filterinfo (collection, filterinfo, err, logout);
587 if (err == noError) {
588 // check that there's a browse filter
589 if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
590
591 metadata.insert ("Title");
592 metadata.insert ("mdtype"); // in case there is a datelist
593 bool getParents = false;
594 get_children ("", collection, args["l"], metadata, getParents, collectproto, response, logout);
595
596 bool has_search_button = true;
597 collectproto->is_searchable(collection, has_search_button, err, logout);
598 if (err != noError) has_search_button = true;
599
600 // calculate width of spacers and set _widthtspace_ macro
601 if (args.getintarg("v") == 0) set_spacemacro (disp, response, has_search_button);
602
603 // set _navigationbar_ macro
604 set_navbarmacros (disp, response, has_search_button, args, cinfo);
605
606 }
607 } else {
608 logout << text_t2ascii
609 << "Error (documentaction::define_external_macros()) in call to get_filterinfo() "
610 << get_comerror_string (err);
611 }
612 }
613}
614
615bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
616 const text_t &inlink, text_t &outlink, ostream &logout) {
617
618 FilterResponse_t response;
619 text_tset metadata;
620 metadata.insert ("section");
621
622 // check current collection first
623 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
624
625 if (get_info (inlink, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
626 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
627 outlink = "_httpdocument_&amp;d=" + response.docInfo[0].metadata["section"].values[0];
628 return true;
629 }
630 }
631
632 // check all the other enabled collections
633
634 if (args["ccs"] == "1" && !args["cc"].empty()) {
635 text_tarray collections;
636 splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
637
638 text_tarray::const_iterator col_here = collections.begin();
639 text_tarray::const_iterator col_end = collections.end();
640
641 while (col_here != col_end) {
642
643 // don't need to check current collection again
644 if (*col_here == args["c"]) {++col_here; continue;}
645
646 collectproto = protos->getrecptproto (*col_here, logout);
647
648 if (get_info (inlink, *col_here, args["l"], metadata, false, collectproto, response, logout)) {
649 if (!response.docInfo[0].metadata["section"].values[0].empty()) {
650 outlink = "_httpdocument_&amp;c=" + *col_here + "&amp;d=" +
651 response.docInfo[0].metadata["section"].values[0];
652 return true;
653 }
654 }
655 ++col_here;
656 }
657 }
658 return false;
659}
660
661void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
662
663 formatinfo.clear();
664 text_tmap::const_iterator format_here = colformat.begin();
665 text_tmap::const_iterator format_end = colformat.end();
666
667 while (format_here != format_end) {
668 if (((*format_here).first == "DocumentImages") &&
669 ((*format_here).second == "true"))
670 formatinfo.DocumentImages = true;
671 else if (((*format_here).first == "DocumentTitles") &&
672 ((*format_here).second == "false"))
673 formatinfo.DocumentTitles = false;
674 else if ((*format_here).first == "DocumentHeading")
675 formatinfo.DocumentHeading = (*format_here).second;
676 else if (((*format_here).first == "DocumentContents") &&
677 ((*format_here).second == "false"))
678 formatinfo.DocumentContents = false;
679 else if (((*format_here).first == "DocumentArrowsBottom") &&
680 ((*format_here).second == "false"))
681 formatinfo.DocumentArrowsBottom = false;
682 else if (((*format_here).first == "DocumentArrowsTop") &&
683 ((*format_here).second == "true"))
684 formatinfo.DocumentArrowsTop = true;
685 else if ((*format_here).first == "DocumentButtons")
686 splitchar ((*format_here).second.begin(), (*format_here).second.end(),
687 '|', formatinfo.DocumentButtons);
688 else if ((*format_here).first == "DocumentText")
689 formatinfo.DocumentText = (*format_here).second;
690 else if ((*format_here).first == "RelatedDocuments")
691 formatinfo.RelatedDocuments = (*format_here).second;
692 else if (((*format_here).first == "DocumentUseHTML") &&
693 ((*format_here).second == "true"))
694 formatinfo.DocumentUseHTML = true;
695 else if (((*format_here).first == "AllowExtendedOptions") &&
696 ((*format_here).second == "true"))
697 formatinfo.AllowExtendedOptions = true;
698 else
699 formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
700
701 ++format_here;
702 }
703
704 // never want arrows when text is expanded
705 if (gt) {
706 formatinfo.DocumentArrowsBottom = false;
707 formatinfo.DocumentArrowsTop = false;
708 }
709}
710
711
712// define all the macros which are related to pages generated
713// by this action. we also load up the formatinfo structure
714// here (it's used in do_action as well as here)
715void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
716 recptprotolistclass *protos, ostream &logout) {
717
718 // define_internal_macros sets the following macros:
719
720 // _pagetitle_ the title to be displayed at the top of the browser window
721
722 // _imagethispage_ the title image to be displayed at top right of page
723
724 // _navarrowsbottom_ this may be overridden to "" when format option
725 // DocumentArrowsBottom is false
726
727 // _navarrowstop_ likewise for DocumentArrowsTop
728
729 // _httpprevarrow_ links to next and previous sections of document - used
730 // _httpnextarrow_ by DocumentArrowsBottom
731
732 // _header_ the header macro is overridden if we're not at a top level
733 // classification to remove the title block
734
735 // _thisOID_ the OID (directory) of the current document - this corresponds
736 // to the archivedir metadata element
737
738 // must have a valid collection server to continue
739
740 text_t &collection = args["c"];
741 if (collection.empty()) return;
742 recptproto *collectproto = protos->getrecptproto (collection, logout);
743 if (collectproto == NULL) return;
744
745 text_tset metadata;
746 FilterResponse_t response;
747 text_t &arg_d = args["d"];
748 text_t &arg_cl = args["cl"];
749
750 if (!formatinfo.DocumentArrowsBottom) {
751 disp.setmacro("navarrowsbottom", "document", "");
752 } else if (!formatinfo.DocumentArrowsBottom) {
753 disp.setmacro("navarrowstop", "document", "");
754 }
755
756 if (!arg_d.empty() && (formatinfo.DocumentArrowsBottom || formatinfo.DocumentArrowsTop)) {
757 // set _httpprevarrow_ and _httpnextarrow_
758 set_arrow_macros (args, collectproto, disp, logout);
759 }
760
761 metadata.insert ("Title");
762
763 bool fulltoc = false;
764
765 if (args["cl"] != "search") {
766 // see if there's a FullTOC string
767 text_t cl_top, full_toc;
768 get_top (arg_cl, cl_top);
769 if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
770 if (full_toc == "true") fulltoc = true;
771 }
772
773 if (!arg_d.empty() && !fulltoc) {
774 // we're at document level
775
776 metadata.insert ("archivedir");
777
778 comerror_t err;
779 OptionValue_tarray options;
780 // we need to do the query again for the z3950proto
781 if (collectproto->get_protocol_name(err)=="z3950proto") {
782 OptionValue_t opt;
783 opt.name="Term";opt.value=args["q"];options.push_back(opt);
784 opt.name="QueryType";
785 opt.value=(args.getintarg("t")) ? "ranked" : "boolean";
786 options.push_back(opt);
787 opt.name="Index";opt.value=args["h"];options.push_back(opt);
788 }
789
790 //do not display relation metadata
791 disp.setmacro ("relateddoc", "document", "");
792
793 //if preferences indicate relevant docs should be collected
794 //and there is no particular format specified then display
795 //this default format.
796 if(args["rd"] == "1" && formatinfo.RelatedDocuments.empty()){
797
798 text_t relation = g_EmptyText; //string for displaying relation metadata
799
800 //call function in formattools.cpp which will return the text of the
801 //related documents in a vertical list. This is the default format.
802
803 if (get_info (arg_d, collection, args["l"], metadata, options, false, collectproto, response, logout))
804 relation += get_related_docs(collection, collectproto, response.docInfo[0], logout);
805
806 //set macro to be the related document string
807
808 disp.setmacro ("relateddoc", "document", relation);
809 }
810
811
812 // get metadata for this document and it's parents
813 if (get_info (arg_d, collection, args["l"], metadata, options,
814 true, collectproto, response, logout)) {
815
816 disp.setmacro ("header", "document", "_textheader_");
817
818 text_tarray pagetitlearray;
819 if (!response.docInfo[0].metadata["Title"].values[0].empty())
820 pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
821
822 if (args["gt"] != "1") {
823 MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
824 while (parenttitle != NULL) {
825 if (!parenttitle->values[0].empty())
826 pagetitlearray.push_back (parenttitle->values[0]);
827 parenttitle = parenttitle->parent;
828 }
829 }
830 reverse (pagetitlearray.begin(), pagetitlearray.end());
831 text_t pagetitle;
832 joinchar (pagetitlearray, ": ", pagetitle);
833 // remove html tags from the title
834 text_t::iterator open_tag=pagetitle.begin();
835 while (open_tag < pagetitle.end()) {
836 if (*open_tag == '<') {
837 text_t::iterator close_tag=open_tag+1;
838 text_t::iterator donechar=pagetitle.end();
839 while (close_tag < donechar) {
840 if (*close_tag == '>')
841 break;
842 ++close_tag;
843 }
844 if (close_tag < donechar) // remove this html tag, replace with space
845 *close_tag=' ';
846 pagetitle.erase(open_tag, close_tag);
847 }
848 ++open_tag;
849 }
850 disp.setmacro ("pagetitle", "document", pagetitle);
851
852 if (is_top (arg_d))
853 disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
854 else {
855 MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
856 text_t thisOID;
857 while (parentad != NULL) {
858 thisOID = parentad->values[0];
859 parentad = parentad->parent;
860 }
861 disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(thisOID));
862 }
863 }
864 } else {
865 if (!arg_cl.empty()) {
866
867 // create the currentnodevalue macro - this is the value of the node
868 // in the hierarchy that is currently open.
869 if (get_info (arg_cl, collection, args["l"], metadata, false, collectproto, response, logout)) {
870 text_t &title = response.docInfo[0].metadata["Title"].values[0];
871 disp.setmacro ("currentnodevalue", "document", title);
872 }
873 // get metadata for top level classification
874 text_t classtop;
875 get_top (arg_cl, classtop);
876 metadata.insert ("childtype");
877 metadata.insert ("parameters");
878
879 if (get_info (classtop, collection, args["l"], metadata, false, collectproto, response, logout)) {
880
881 text_t &title = response.docInfo[0].metadata["Title"].values[0];
882 bool unknown = false;
883
884 // test the _iconXXXpage_ macro to see if image macros are
885 // defined for this type of classification - if not we'll
886 // just display the text
887 text_t tmp;
888 text_t macroname="_icon" + title + "page_";
889 disp.expandstring ("document", macroname, tmp);
890 if (tmp == macroname) unknown = true; // it wasn't expanded
891
892 if (unknown) {
893 disp.setmacro ("pagetitle", "document", title);
894 disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
895 } else {
896 disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
897 disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
898 }
899
900 //if the document is not a document from a collection
901 //we must set the macro to be an empty string
902 disp.setmacro ("relateddoc", "document", "");
903
904 // Add macros specific to the Collage/Phind classifiers
905 text_t &childtype = response.docInfo[0].metadata["childtype"].values[0];
906 if (childtype == "Collage") {
907
908 text_t::iterator a = arg_cl.begin();
909 text_t::iterator b = arg_cl.end();
910
911 bool collage = true;
912 while (a != b) {
913 if (*a == 46) collage = false;
914 ++a;
915 }
916
917 if (collage) {
918 disp.setmacro ("collageclassifier", "document", "_collageapplet_");
919
920 // Next, macros that control the way the classifier is displayed
921 text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
922
923 // extract key=value pairs and set as macros
924 text_t::iterator here = parameters.begin();
925 text_t::iterator end = parameters.end();
926 text_t key, value;
927
928 while (here != end) {
929 // get the next key and value pair
930 here = getdelimitstr (here, end, '=', key);
931 here = getdelimitstr (here, end, ';', value);
932
933 // store this key=value pair
934 if (!key.empty() && !value.empty()) {
935 disp.setmacro ("collage"+key, "document", value);
936 }
937 }
938
939
940 }
941 }
942
943 if (childtype == "Phind") {
944
945 // First, a macro to display the phind classifier
946 disp.setmacro ("phindclassifier", "document", "_phindapplet_");
947
948 // Next, macros that control the way the classifier is displayed
949 text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
950
951 // extract key=value pairs and set as macros
952 text_t::iterator here = parameters.begin();
953 text_t::iterator end = parameters.end();
954 text_t key, value;
955
956 while (here != end) {
957 // get the next key and value pair
958 here = getdelimitstr (here, end, '=', key);
959 here = getdelimitstr (here, end, ';', value);
960
961 // store this key=value pair
962 if (!key.empty() && !value.empty()) {
963 disp.setmacro (key, "document", value);
964 }
965 }
966 } // end if (childtype == "Phind")
967 }
968 } // end if (!arg_cl.empty()) {
969 }
970}
971
972
973bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
974 browsermapclass *browsers, displayclass &disp,
975 outconvertclass &outconvert, ostream &textout,
976 ostream &logout) {
977
978 // must have a valid collection server
979 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
980 if (collectproto == NULL) {
981 logout << "documentaction::do_action called with NULL collectproto\n";
982 textout << outconvert << disp << "_document:header_\n"
983 << "Error: Attempt to get document without setting collection\n"
984 << "_document:footer_\n";
985 } else {
986
987 text_t OID = args["d"];
988 if (OID.empty()) OID = args["cl"];
989 if (OID.empty()) {
990 textout << outconvert << disp << "Document contains no data_document:footer_\n";
991 return true;
992 }
993
994
995 if (formatinfo.DocumentUseHTML && !args["d"].empty()) {
996
997 if (args["f"] == "1") {
998 textout << outconvert << disp
999 << "<html><head></head>\n"
1000 << "<frameset rows=\"68,*\" noresize border=0>\n"
1001 << "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
1002 << "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d="
1003 << args["d"] << "\">"
1004 << "<noframes>\n"
1005 << "<p>You must have a frame enabled browser to view this.</p>\n"
1006 << "</noframes>\n"
1007 << "</frameset>\n"
1008 << "</html>\n";
1009 } else {
1010 output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1011 }
1012 return true;
1013 }
1014
1015
1016 textout << outconvert << disp << "_document:header_\n"
1017 << "_document:content_\n";
1018
1019 // output the table of contents
1020 output_toc (args, browsers, formatinfo, collectproto,
1021 disp, outconvert, textout, logout);
1022
1023 if (formatinfo.DocumentArrowsTop && !args["d"].empty()) {
1024 textout << outconvert << disp << "_document:navarrowstop_\n";
1025 }
1026
1027 //output the related documents (may be the empty string)
1028 //will not output the docs if a format string is specified
1029 textout << outconvert << disp << "_document:relateddoc_\n";
1030
1031 // output the document text
1032 if (!args["d"].empty()) {
1033 textout << outconvert << "<p>\n";
1034 output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
1035 }
1036
1037 textout << outconvert << disp << "_document:footer_\n";
1038 }
1039 return true;
1040}
1041
1042void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
1043 const TermInfo_tarray &terminfo, const text_t &OID,
1044 bool highlight, int hastxt, int wanttext,
1045 text_t &collection, recptproto *collectproto,
1046 browsermapclass *browsers, displayclass &disp,
1047 outconvertclass &outconvert, ostream &textout,
1048 ostream &logout, cgiargsclass &args) {
1049
1050 DocumentRequest_t docrequest;
1051 DocumentResponse_t docresponse;
1052 comerror_t err;
1053 if (hastxt == 1) {
1054
1055 if (wanttext) {
1056 // get the text
1057 docrequest.OID = OID;
1058 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1059
1060 // cut down on overhead by not using formattools if we only want the text
1061 // (wanttext will equal 2 if we want text and other stuff too)
1062 if (wanttext == 1)
1063 if (highlight) {
1064 highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
1065 } else {
1066 textout << outconvert << disp << docresponse.doc;
1067 }
1068 }
1069
1070 if (wanttext != 1) {
1071 text_tmap options;
1072 options["text"] = docresponse.doc;
1073
1074 if (formatinfo.AllowExtendedOptions) {
1075 load_extended_options(options, args, browsers, formatinfo,
1076 collectproto, disp, outconvert, logout);
1077 }
1078
1079 text_t doctext
1080 = get_formatted_string (collection, collectproto, docinfo, disp,
1081 formatlistptr, options, logout);
1082
1083 if (highlight) {
1084 highlighttext(doctext, args, terminfo, disp, outconvert, textout);
1085 } else {
1086 textout << outconvert << disp << doctext;
1087 }
1088 }
1089 }
1090}
1091
1092
1093void documentaction::output_document (const text_t &OID, cgiargsclass &args,
1094 recptproto *collectproto, browsermapclass *browsers,
1095 displayclass &disp, outconvertclass &outconvert,
1096 ostream &textout, ostream &logout) {
1097 FilterResponse_t inforesponse;
1098 FilterResponse_t queryresponse;
1099 text_tset metadata;
1100 bool getParents = false;
1101 bool highlight = false;
1102 int wanttext = 0;
1103 int arg_gt = args.getintarg("gt");
1104 text_t &collection = args["c"];
1105
1106 // if we have a query string and highlighting is turned on we need
1107 // to redo the query to get the terms for highlighting
1108
1109 if (!args["q"].empty() && args.getintarg("hl")) {
1110
1111 ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
1112 bool segment = false;
1113 if (cinfo != NULL) {
1114 segment = cinfo->isSegmented;
1115 }
1116 FilterRequest_t request;
1117 comerror_t err;
1118 request.filterResultOptions = FRmatchTerms;
1119 text_t formattedstring = args["q"];
1120 format_querystring (formattedstring, args.getintarg("b"), segment);
1121 set_queryfilter_options (request, formattedstring, args);
1122 args["q"] = formattedstring; // need to set this here for phrase
1123 // highlighting, where we look at the querystring
1124 collectproto->filter (args["c"], request, queryresponse, err, logout);
1125 if (err != noError) {
1126 outconvertclass text_t2ascii;
1127 logout << text_t2ascii
1128 << "documentaction::output_document: call to QueryFilter failed "
1129 << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
1130 highlight = false;
1131 } else {
1132 highlight = true;
1133 }
1134 }
1135
1136 format_t *formatlistptr = new format_t();
1137 parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
1138
1139 metadata.insert ("hastxt");
1140 metadata.insert ("haschildren");
1141
1142 if (formatinfo.DocumentText == "[Text]")
1143 wanttext = 1;
1144 else {
1145 char *docformat = formatinfo.DocumentText.getcstr();
1146 if (strstr (docformat, "[Text]") != NULL)
1147 wanttext = 2;
1148 delete []docformat;
1149 }
1150
1151 textout << outconvert << "<div class=\"documenttext\">\n";
1152
1153 if (get_info (OID, collection, args["l"], metadata, getParents, collectproto, inforesponse, logout)) {
1154 int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
1155 int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
1156
1157 if (arg_gt == 0) {
1158 output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo,
1159 OID, highlight, hastxt, wanttext, collection, collectproto,
1160 browsers, disp, outconvert, textout, logout, args);
1161
1162 } else {
1163
1164 ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
1165
1166 // text is to be expanded
1167 text_t exOID = OID;
1168 if (haschildren != 1) exOID = get_parent (OID);
1169 if (exOID.empty()) exOID = OID;
1170
1171 // if we're not in a document (i.e. we're in a top level classification)
1172 // we need to pass "is_classify = true" to get_contents so that it
1173 // doesn't recurse all the way through each document in the classification
1174 bool is_classify = false;
1175 if (args["d"].empty()) is_classify = true;
1176
1177 get_contents (exOID, is_classify, metadata, collection, args["l"],
1178 collectproto, inforesponse, logout);
1179
1180 ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
1181 ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
1182
1183 if (arg_gt == 1) {
1184 // check if there are more than 10 sections containing text to be expanded -
1185 // if there are output warning message - this isn't a great way to do this
1186 // since the sections may be very large or very small - one day I'll fix it
1187 // -- Stefan.
1188 int seccount = 0;
1189 while (sechere != secend) {
1190 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1191 if (shastxt == 1) ++seccount;
1192 if (seccount > 10) break;
1193 ++sechere;
1194 }
1195 if (seccount > 10) {
1196 // more than 10 sections so output warning message and text
1197 // for current section only
1198 textout << outconvert << disp << "_document:textltwarning_";
1199
1200 output_text (thisdocinfo, formatlistptr, queryresponse.termInfo,
1201 OID, highlight, hastxt, wanttext, collection,
1202 collectproto, browsers, disp, outconvert, textout, logout, args);
1203
1204 }
1205 else arg_gt = 2;
1206 }
1207
1208 if (arg_gt == 2) {
1209 // get the text for each section
1210 sechere = inforesponse.docInfo.begin();
1211 int count = 0;
1212 while (sechere != secend) {
1213 textout << outconvert << disp << "\n<p><a name=" << (*sechere).OID << "></a>\n";
1214
1215 int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
1216
1217 output_text (*sechere, formatlistptr, queryresponse.termInfo,
1218 (*sechere).OID, highlight, shastxt, wanttext, collection,
1219 collectproto, browsers, disp, outconvert, textout, logout, args);
1220 ++count;
1221 ++sechere;
1222 }
1223 }
1224 }
1225 }
1226 textout << outconvert << "</div>\n";
1227 delete formatlistptr;
1228}
1229
1230void documentaction::set_arrow_macros (cgiargsclass &args, recptproto *collectproto,
1231 displayclass &disp, ostream &logout) {
1232
1233 text_tset metadata;
1234 FilterResponse_t response;
1235 FilterResponse_t presponse;
1236
1237 int haschildren = 0;
1238 text_tarray next_siblings;
1239 text_t previous_sibling;
1240 text_t &arg_d = args["d"];
1241
1242 // get info on current section
1243 metadata.insert("haschildren");
1244 if (!get_info(arg_d, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
1245 logout << "error 1 in documentaction::set_arrow_macros\n";
1246 return;
1247 }
1248 haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
1249
1250 // get OIDs of next and previous siblings of current section and
1251 // all it's parents
1252 int parentcount = countchar(arg_d.begin(), arg_d.end(), '.');
1253 text_t thisoid = arg_d;
1254 while (parentcount > 0) {
1255 get_children (get_parent(thisoid), args["c"], args["l"], metadata, false,
1256 collectproto, response, logout);
1257 ResultDocInfo_tarray::iterator this_sibling = response.docInfo.begin();
1258 ResultDocInfo_tarray::iterator last_sibling = response.docInfo.end();
1259 bool first = true;
1260 while (this_sibling != last_sibling) {
1261 if ((*this_sibling).OID == thisoid) {
1262 if (!first && next_siblings.empty()) {
1263 previous_sibling = (*(this_sibling-1)).OID;
1264 int section_has_children = (*(this_sibling-1)).metadata["haschildren"].values[0].getint();
1265 // if previous sibling has children we need to recurse
1266 // down to the last descendant
1267 while (section_has_children) {
1268 get_children (previous_sibling, args["c"], args["l"], metadata, false,
1269 collectproto, presponse, logout);
1270 if (!presponse.docInfo.empty()) {
1271 ResultDocInfo_tarray::iterator it = presponse.docInfo.end() - 1;
1272 previous_sibling = (*it).OID;
1273 section_has_children = (*it).metadata["haschildren"].values[0].getint();
1274 } else {
1275 section_has_children = 0; // this should never happen
1276 }
1277 }
1278 }
1279
1280 if ((this_sibling+1) != last_sibling) {
1281 next_siblings.push_back((*(this_sibling+1)).OID);
1282 } else {
1283 next_siblings.push_back("");
1284 }
1285 break;
1286 }
1287 ++this_sibling;
1288 first = false;
1289 }
1290 thisoid = get_parent(thisoid);
1291 --parentcount;
1292 }
1293
1294 // work out values for next link
1295 if (haschildren) {
1296 disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1297 "&amp;d=" + arg_d + ".fc");
1298 } else {
1299 text_tarray::const_iterator h = next_siblings.begin();
1300 text_tarray::const_iterator e = next_siblings.end();
1301 while (h != e) {
1302 if (!(*h).empty()) {
1303 disp.setmacro ("httpnextarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1304 "&amp;d=" + *h);
1305 break;
1306 }
1307 ++h;
1308 }
1309 }
1310
1311 // work out value for previous link
1312 if (!previous_sibling.empty()) {
1313 disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1314 "&amp;d=" + previous_sibling);
1315 } else {
1316 if (countchar(arg_d.begin(), arg_d.end(), '.')) {
1317 disp.setmacro ("httpprevarrow", "document", "_httpdocument_&amp;cl=" + args["cl"] +
1318 "&amp;d=" + get_parent(arg_d));
1319 }
1320 }
1321}
Note: See TracBrowser for help on using the repository browser.