67d08b3b68b5a80e13405b9971590baade55d0f7
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Agents / SearchScopeAgentMotif.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: SearchScopeAgentMotif.C /main/27 1998/04/17 11:35:37 mgreess $ */
24 /*      Copyright (c) 1994,1995,1996 FUJITSU LIMITED    */
25 /*      All Rights Reserved                             */
26
27 /*
28  * Copyright (c) 1991 HaL Computer Systems, Inc.  All rights reserved.
29  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
30  * States.  Use of a copyright notice is precautionary only and does not
31  * imply publication or disclosure.
32  *  
33  * This software contains confidential information and trade secrets of HaL
34  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
35  * without the prior express written permission of HaL Computer Systems, Inc.
36  * 
37  *                         RESTRICTED RIGHTS LEGEND
38  * Use, duplication, or disclosure by the Government is subject to
39  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
40  * Technical Data and Computer Software clause at DFARS 252.227-7013.
41  *                        HaL Computer Systems, Inc.
42  *                  1315 Dell Avenue, Campbell, CA  95008
43  * 
44  */
45
46 #include "UAS.hh"
47 #include "Support/UtilityFunctions.hh"
48
49 #define C_EnvMgr
50 #define C_LibraryMgr
51 #define C_MessageMgr
52 #define C_SearchMgr
53 #define C_SearchScopeMgr
54 #define L_Managers
55
56 #define C_WindowSystem
57 #define L_Other
58
59 #define C_OutlineList
60 #define C_OutlineString
61 #define C_InfoBase
62 #define C_TOC_Element
63 #define L_Basic
64
65 #define C_xList
66 #define L_Support
67
68 #define C_StringPref
69 #define L_Preferences
70
71 #define C_HelpAgent
72 #define C_OutlineListView
73 #define C_SearchScopeList
74 #define C_SearchScopeAgent
75 #define C_ScopePopup
76 #define L_Agents
77
78 #define C_QueryEditor
79 #define L_Query
80
81 #include "Other/XmStringLocalized.hh"
82 #include "Managers/CatMgr.hh"
83
84 #include "Exceptions.hh"
85 #include "Prelude.h"
86
87 #include "Registration.hh"
88
89 #include <WWL/WXmForm.h>
90 #include <WWL/WXmLabel.h>
91 #include <WWL/WXmPushButton.h>
92 #include <WWL/WXmRowColumn.h>
93 #include <WWL/WXmCascadeButton.h>
94 #include <WWL/WXmSeparator.h>
95 #include <WWL/WXmMenu.h>
96
97 #include <WWL/WXmDialogShell.h>
98 #include <WWL/WXmTextField.h>
99 #include <WWL/WXmMessageBox.h>
100
101 #ifdef SVR4
102 #ifndef USL
103 #include <libintl.h>        // 1/19/94 yuji
104 #endif
105 #endif
106
107 #include <string.h>
108 #include <iostream>
109 using namespace std;
110 #include <stdio.h>
111
112 #define CLASS SearchScopeAgent
113 STATIC_SENDER_CC (UpdateMenu);
114
115
116
117 #if defined(i386) || defined(_IBMR2)
118
119 extern "C" 
120 {
121     extern int strcasecmp(const char *s1, const char *s2);
122 }
123
124 #endif
125
126 #ifdef USL
127
128 strcasecmp(register const char *s1,
129            register const char *s2)
130 {
131     register int c1, c2;
132
133     while (*s1 && *s2) {
134         c1 = isupper(*s1) ? tolower(*s1) : *s1;
135         c2 = isupper(*s2) ? tolower(*s2) : *s2;
136         if (c1 != c2)
137             return (c1 - c2);
138         s1++;
139         s2++;
140     }
141     return (int) (*s1 - *s2);
142 }
143
144 #endif
145
146 #define CLASS SearchScopeAgent
147 #include "create_macros.hh"
148
149 // /////////////////////////////////////////////////////////////////////////
150 // class ScopeOutlineListView
151 //
152 //  This is a subclass of OutlineListView
153 //  The difference between this class and the parent class is that this class
154 //  will deselect all parents and children of a selected item. This
155 //  functionality is to show that a selected item includes its children
156 //    -11:22 07/ 8/93 - jbm  
157 // /////////////////////////////////////////////////////////////////////////
158
159
160 class ScopeOutlineListView : public OutlineListView
161 {
162 public:
163   ScopeOutlineListView(const WComposite &parent,
164                        const char *name,
165                        bool automanage = FALSE,
166                        bool enable_activate = FALSE)
167     : OutlineListView(parent, name, automanage, enable_activate)
168     {}
169   virtual void select(WCallback *wcb);
170   virtual void clear();
171
172
173   OutlineElement *find_parent(int, OutlineElement *);
174
175   void unset_parent(OutlineElement *p);
176   int lid_to_index(const UAS_String &lid);
177   void select_infolib (UAS_String &lid, BitHandle handle);
178   UAS_String name_to_lid(UAS_String& name);
179   UAS_String lid_to_name(UAS_String& lid);
180
181 protected:
182   
183   OutlineElement *find_parent(OutlineElement *possible_parent,
184                               OutlineElement *child);
185  
186 };
187
188 void
189 ScopeOutlineListView::clear()
190 {
191   // empty list like usual
192   OutlineListView::clear();
193
194   // set first element
195   ((OutlineElement *)(*list())[0])->set_selected(data_handle());
196   // NOTE: slow, set directly ???
197   u_int starting_pos = 1;
198   update_highlighting(list(), starting_pos);
199 }
200
201 void
202 ScopeOutlineListView::unset_parent(OutlineElement *parent)
203 {
204   parent->unset_selected(data_handle());
205 }
206
207 void
208 ScopeOutlineListView::select(WCallback *wcb)
209 {
210   bool update = FALSE ;
211
212   // do selection work in base class 
213   OutlineListView::select(wcb);
214
215   // now do some special handling 
216
217   if (f_selected_item_count == 0)
218     {
219       clear();
220     } else {
221
222       // first get item that was selected 
223 #ifdef JBM
224       XmStringTable items = Items();
225 #endif
226       XmListCallbackStruct *lcs = (XmListCallbackStruct *)wcb->CallData();
227       OutlineElement *oe ;
228
229 #ifdef JBM
230       extract_pointer(items[lcs->item_position-1], &oe);
231 #else
232       oe = item_at(lcs->item_position-1);
233 #endif
234
235       // we want to deselect all children 
236       if (oe->has_children() && oe->children_cached())
237         {
238           oe->children()->deselect_all(data_handle());
239           update = TRUE ;
240         }
241
242       // now de-select parent (if have one)
243       OutlineElement *parent;
244       if (strcmp("infobases", XtName(wcb->GetWidget())) == 0)
245         parent = find_parent(1, oe);
246       else
247         parent = find_parent(0, oe);
248
249       if (parent != NULL)
250         {
251           parent->unset_selected(data_handle());
252           update = TRUE ;
253         }
254
255       if (update)
256         {
257           u_int starting_pos = 1;
258           update_highlighting(list(), starting_pos);
259         }
260     }
261 }
262
263 OutlineElement *
264 ScopeOutlineListView::find_parent(int infolib, OutlineElement *element)
265 {
266   OutlineElement *top;
267
268   if (infolib)
269   {
270     UAS_Pointer<UAS_Common> ilib = ((TOC_Element*)element)->toc();
271
272     // need to find out which infolib we're dealing with
273     int infolib_index = lid_to_index(ilib->lid());
274     top = (OutlineElement*)(*list())[infolib_index] ;
275   }
276   else
277     top = (OutlineElement*)(*list())[0] ;
278
279   return find_parent(top, element);
280
281 }
282
283 OutlineElement *
284 ScopeOutlineListView::find_parent(OutlineElement *parent,
285                                   OutlineElement *element)
286 {
287   OutlineElement *current, *value ;
288
289   if (parent->has_children() && parent->children_cached())
290     {
291       OutlineList *olist = parent->children() ;
292       for (unsigned int i = 0 ; i < olist->length(); i++)
293         {
294           current = (OutlineElement*)(*olist)[i] ;
295           if (current == element)
296             return parent ;     // NOTE: procedure EXIT 
297
298           value = find_parent(current, element);
299           if (value != NULL)
300             {
301               // NOTE: this action should not really be here
302                 ((*this).unset_parent)(parent);
303               return value ;    // NOTE: procedure EXIT 
304             }
305         }
306     }
307   return NULL ;
308 }
309
310 void
311 ScopeOutlineListView::select_infolib (UAS_String &lid, BitHandle handle)
312 {
313   int index = lid_to_index(lid);
314   OutlineElement *oe = ((OutlineElement*)(*list())[index]);
315   //((OutlineElement*)(*f_infolib_list->list())[index])->set_selected (handle);
316
317   // select infolib
318   oe->set_selected (handle);
319
320   // deselect all children
321   oe->children()->deselect_all(handle);
322
323   // udpate highlighting
324   u_int starting_pos = 1;
325   update_highlighting(list(), starting_pos);
326 }
327
328
329 // Give a infolib id, return its index into the f_infolib_list
330 // list.
331 int
332 ScopeOutlineListView::lid_to_index(const UAS_String &lid)
333 {
334   OutlineList *ol = list();
335   OutlineElement *oe;
336   for (unsigned int i = 0; i < ol->length(); i++)
337   {
338     oe = ((OutlineElement *) (*ol)[i]);
339     UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
340     if( infolib->lid() == lid)
341       return i;
342   }
343
344   return -1; // lid not found
345 }
346
347 UAS_String
348 ScopeOutlineListView::lid_to_name(UAS_String &lid)
349 {
350   OutlineList *ol = list();
351   OutlineElement *oe;
352   for (unsigned int i = 0; i < ol->length(); i++)
353   {
354     oe = ((OutlineElement *) (*ol)[i]);
355     UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
356     if( infolib->lid() == lid)
357       return infolib->name();
358   }
359   // There has to be an infolib for a given lid--if
360   // not, something has gone wrong.
361   throw (CASTEXCEPT Exception());
362 }
363
364 UAS_String
365 ScopeOutlineListView::name_to_lid(UAS_String &name)
366 {
367   OutlineList *ol = list();
368   OutlineElement *oe;
369   for (unsigned int i = 0; i < ol->length(); i++)
370   {
371     oe = ((OutlineElement *) (*ol)[i]);
372     UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
373     if( infolib->name() == name)
374       return infolib->lid();
375   }
376   // There has to be an infolib for a given lid--if
377   // not, something has gone wrong.
378   throw (CASTEXCEPT Exception());
379 }
380
381 // **********************************************************************
382 // **********************************************************************
383
384 SearchScopeAgent::SearchScopeAgent()
385 : f_shell (NULL),
386   f_scope_list (this),
387   f_first_time (True),
388   f_option_menu (NULL),
389   f_current_scope (NULL)
390 {
391   f_auto_expand = True;
392   create_ui();
393   f_scope_list.restore();
394 }
395
396
397 // /////////////////////////////////////////////////////////////////
398 // class destructor
399 // /////////////////////////////////////////////////////////////////
400
401 SearchScopeAgent::~SearchScopeAgent()
402 {
403 #if 0
404   // dont need to delete these because not called anyway - jbm
405
406   // NOTE: Destroy should destroy & delete! 
407   f_shell->Destroy();
408   delete f_infolib_list;
409   delete f_component_list;
410   // LEAK: need to delete the scope objects 
411   delete f_scope_list;
412
413 #endif
414 }
415   
416
417 // /////////////////////////////////////////////////////////////////
418 // display
419 // /////////////////////////////////////////////////////////////////
420
421 void
422 SearchScopeAgent::display()
423 {
424   Wait_Cursor bob;
425   if (f_shell == 0)
426     {
427       create_ui();
428     }
429   if (f_first_time)
430     {
431       f_first_time = False;
432       fill_option_menu();
433     }
434
435   select_initial();
436
437   f_shell.Popup();
438   f_shell.DeIconify();
439
440   if (search_scope_mgr().show_warning())
441   {
442     // dialog is not real useful in a multi-infolib environment
443     if (env().debug())
444     {
445        message_mgr().warning_dialog (
446         (char*)UAS_String(CATGETS(Set_Messages, 31,
447         "Ignoring invalid scopes in your profile.")));
448     }
449     search_scope_mgr().show_warning(False);
450   }
451
452 }
453
454 // /////////////////////////////////////////////////////////////////
455 // fill_option_menu - fills the option menu with named scopes
456 // /////////////////////////////////////////////////////////////////
457 void
458 SearchScopeAgent::fill_option_menu()
459 {
460   int position = 1; // skip past unnamed scope button
461   List_Iterator<UAS_SearchScope *> i (f_scope_list);
462   WComposite menu (f_scope_option.SubMenuId());
463
464   ON_DEBUG (printf ("There are %d user scopes:\n", f_scope_list.length()));
465   for (; i != 0; i++)
466   {
467     if (i.item()->read_only())
468       continue;
469     //DECLM (WXmPushButton, scope_btn, f_scope_option.SubMenuId(),
470            //i.item()->name());
471     DECLM (WXmPushButton, scope_btn, menu, i.item()->name());
472     ON_ACTIVATE (scope_btn,select_scope);
473     scope_btn.UserData (i.item());
474     scope_btn.PositionIndex (position++);
475   }
476   f_first_time = False;
477 }
478
479 // /////////////////////////////////////////////////////////////////
480 // create_ui
481 // /////////////////////////////////////////////////////////////////
482
483 void
484 SearchScopeAgent::create_ui()
485 {
486   XmStringLocalized mtfstring;
487   String            string;
488
489   f_shell = WTopLevelShell (window_system().toplevel(),WPopup,"scope_editor");
490   window_system().register_shell(&f_shell);
491
492   string = CATGETS(Set_SearchScopeAgent, 1, "Dtinfo: Search Scope Editor");
493   XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
494
495   DECL  (WXmForm,         form,           f_shell,     "form");
496   DECLC (WXmPulldownMenu, scope_menu,     form,        "scope_menu");
497   Arg args[1];
498   int n = 0;
499   XtSetArg(args[n], XmNsubMenuId, (Widget) scope_menu); n++;
500   f_scope_option = WXmOptionMenu (form, (char*)"scope_option", WAutoManage, args, n);
501   ASSN  (WXmPushButton,   f_unnamed,      scope_menu,  "unnamed");
502
503   mtfstring = CATGETS(Set_AgentLabel, 212, "Scope Name");
504   XtVaSetValues(f_scope_option, XmNlabelString, (XmString)mtfstring, NULL);
505   mtfstring = CATGETS(Set_AgentLabel, 213, "Unnamed");
506   XtVaSetValues(f_unnamed, XmNlabelString, (XmString)mtfstring, NULL);
507   
508   ASSNM (WXmPushButton,   f_new,          form,        "new");
509   ASSNM (WXmPushButton,   f_save,         form,        "save");
510   ASSNM (WXmPushButton,   f_rename,       form,        "rename");
511   ASSNM (WXmPushButton,   f_delete,       form,        "delete");
512   ASSNM (WXmPushButton,   f_reset,        form,        "reset");
513   DECLM (WXmPushButton,   close,          form,        "close");
514   DECLM (WXmPushButton,   help,           form,        "help");
515
516   DECLM (WXmSeparator,     separator,     form,        "separator");
517
518   DECLM (WXmLabel,         bookshelf,     form,        "books");
519   DECLM (WXmLabel,         components,    form,        "components");
520
521   mtfstring = CATGETS(Set_AgentLabel, 214, "Books");
522   XtVaSetValues(bookshelf, XmNlabelString, (XmString)mtfstring, NULL);
523   mtfstring = CATGETS(Set_AgentLabel, 215, "Components");
524   XtVaSetValues(components, XmNlabelString, (XmString)mtfstring, NULL);
525   mtfstring = CATGETS(Set_AgentLabel, 216, "New");
526   XtVaSetValues(f_new, XmNlabelString, (XmString)mtfstring, NULL);
527   mtfstring = CATGETS(Set_AgentLabel, 217, "Save");
528   XtVaSetValues(f_save, XmNlabelString, (XmString)mtfstring, NULL);
529   mtfstring = CATGETS(Set_AgentLabel, 218, "Rename");
530   XtVaSetValues(f_rename, XmNlabelString, (XmString)mtfstring, NULL);
531   mtfstring = CATGETS(Set_AgentLabel, 183, "Delete");
532   XtVaSetValues(f_delete, XmNlabelString, (XmString)mtfstring, NULL);
533   mtfstring = CATGETS(Set_AgentLabel, 202, "Reset");
534   XtVaSetValues(f_reset, XmNlabelString, (XmString)mtfstring, NULL);
535   mtfstring = CATGETS(Set_AgentLabel, 12, "Close");
536   XtVaSetValues(close, XmNlabelString, (XmString)mtfstring, NULL);
537   mtfstring = CATGETS(Set_AgentLabel, 48, "Help");
538   XtVaSetValues(help, XmNlabelString, (XmString)mtfstring, NULL);
539
540   // WARNING: the widget name, infobases, is used else where--do not alter.
541   f_infolib_list = new ScopeOutlineListView (form, "infobases", WAutoManage);
542   f_infolib_list->max_level (2);
543
544   f_component_list = new ScopeOutlineListView (form, "components",WAutoManage);
545
546   ON_ACTIVATE (f_new,new_scope);
547   ON_ACTIVATE (f_save,save_scope);
548   ON_ACTIVATE (f_rename,rename_scope);
549   ON_ACTIVATE (f_delete,delete_scope);
550   ON_ACTIVATE (f_reset,reset);
551   ON_ACTIVATE (close,close);
552   help_agent().add_activate_help (help, (char*)"scope_editor_help");
553   
554   form.ShadowThickness (0);
555   form.Manage();
556
557   // set up callback when item selected from list 
558   Observe (f_infolib_list, OutlineListView::ENTRY_SELECTED,
559            &SearchScopeAgent::scope_modified);
560   
561   Observe(f_component_list, OutlineListView::ENTRY_SELECTED,
562           &SearchScopeAgent::scope_modified);
563
564   // NOTE: May want to create dialogs on the fly.
565   // Types: prompt: save & rename, yes/no: delete & close
566
567   /* -------- Fill in lists -------- */
568
569 #if 0
570   OutlineList *ol = new OutlineList (1);
571   // NOTE: hack ahead, direct reference to mmdb for wedged searching: 
572   ol->append (new TOC_Element (new TOC_mmdb_lib (the_mmdb())));
573 #else
574 #if 0
575   UAS_Pointer<UAS_Common> d = UAS_Common::create ("mmdb:/t/");
576   UAS_Pointer<UAS_Collection> cd = (UAS_Collection *) ((UAS_Common *) d);
577   ol->append (new TOC_Element (cd->root()));
578 #else
579   UAS_List<UAS_String> rootList = UAS_Common::rootLocators ();
580   OutlineList *ol = new OutlineList(rootList.length());
581   for (unsigned int i = 0; i < rootList.length(); i ++) {
582       UAS_Pointer<UAS_Common> d = UAS_Common::create(*(UAS_String *)rootList[i]);
583       UAS_Pointer<UAS_Collection> cd = (UAS_Collection *) ((UAS_Common *) d);
584       ol->append (new TOC_Element (cd->root()));
585   }
586
587
588 #endif
589 #endif
590   BitHandle handle = ol->get_data_handle();
591   ((OutlineElement *) (*ol)[0])->set_expanded (handle);
592   f_infolib_list->set_list (ol, handle);
593   f_infolib_list->clear();
594
595   // Generate a components list 
596   OutlineList *component_list = generate_component_list();
597   BitHandle component_handle = component_list->get_data_handle();
598   ((OutlineElement*)(*component_list)[0])->set_expanded (component_handle);
599   f_component_list->set_list (component_list, component_handle);
600   f_component_list->clear();
601
602   ON_DEBUG (printf ("IB handle = %ld, CP handle = %ld\n",
603                     handle, component_handle));
604 }
605
606
607 // /////////////////////////////////////////////////////////////////
608 // new_scppe - create a new scope 
609 // /////////////////////////////////////////////////////////////////
610
611 void
612 SearchScopeAgent::new_scope()
613 {
614   if (f_reset.Sensitive())
615     {
616       bool dosave = message_mgr().question_dialog (
617                 (char*)UAS_String(CATGETS(Set_Messages, 17,
618                         "Do you want to save changes to the current scope?")));
619       if (dosave)
620         save_scope();
621     }
622
623   if (! XtIsManaged((Widget)f_unnamed)) {
624       f_unnamed.Manage();
625       // re-computation needed, weird - 11/2/94 kamiya
626       f_scope_option.Unmanage();
627       f_scope_option.Manage();
628   }
629   f_scope_option.MenuHistory (f_unnamed);
630
631   f_infolib_list->clear();
632   f_component_list->clear();
633
634   ON_DEBUG (printf("new_scope: handle = %ld\n",f_infolib_list->data_handle()));
635
636   f_new.SetSensitive (False);
637   f_save.SetSensitive (True);
638   f_rename.SetSensitive (False);
639   f_delete.SetSensitive (False);
640   f_reset.SetSensitive (False);
641
642   f_current_scope = NULL;
643 }
644
645
646 // /////////////////////////////////////////////////////////////////
647 // scope_name_prompt - prompt for a scope name and validate it
648 // /////////////////////////////////////////////////////////////////
649
650 const char *
651 SearchScopeAgent::scope_name_prompt()
652 {
653   char *default_name = new char [31];
654   int   default_name_len = 20 ;
655   const char *scope_name = "";
656   bool valid = FALSE;
657
658   // Input validation loop. 
659   do
660     {
661       int len = strlen(scope_name);
662       if (len > default_name_len)
663         {
664           delete [] default_name ;
665           default_name = new char[len + 1] ;
666           default_name_len = len ;
667         }
668       *((char *) memcpy(default_name, scope_name, len) + len) = '\0';
669       message_mgr().set_max_length(default_name_len);
670       scope_name = message_mgr().get_string(
671         (char*)UAS_String(CATGETS(Set_SearchScopeAgent, 2,
672                                         "Enter the scope name to save as:")),
673         (char*)UAS_String(CATGETS(Set_SearchScopeAgent, 3,
674                                         "Dtinfo: Save Scope")),
675         default_name);
676
677       // look for canceled operation 
678       if (scope_name == NULL)
679         {
680           delete [] default_name ;
681           message_mgr().set_max_length(40);
682           return (NULL);
683         }
684
685       scope_name = truncate ((char *) scope_name);
686       // look for bogus characters 
687       if (strpbrk (scope_name, ":,;") != NULL)
688         {
689           message_mgr().error_dialog (
690                 (char*)UAS_String(CATGETS(Set_Messages, 18,
691                 "You cannot use a colon, comma or semicolon in a search scope name.")));
692         }
693       // look for empty scope name 
694       else if (*scope_name == '\0')
695         {
696           message_mgr().error_dialog (
697                 (char*)UAS_String(CATGETS(Set_Messages, 19,
698                                 "Please choose a non-empty scope name.")));
699         }
700       // look for name too long
701       else if (strlen (scope_name) > 20)
702         {
703           // this dialog should never popup, since we don't allow
704           // the user to enter more than the max. But, since the
705           // max char length has changed to 20, the message should
706           // be changed to reflect that--or just removed.
707           message_mgr().error_dialog (
708                 (char*)UAS_String(CATGETS(Set_Messages, 20,
709                 "A search scope name may not exceed 30 characters.")));
710         }
711       // look for duplicate scope name 
712       else
713         {
714           // Check for name in use.
715           List_Iterator<UAS_SearchScope *> s (f_scope_list);
716           if (strcasecmp (scope_name, "unnamed") != 0)
717             for (; s != 0; s++)
718               if (strcmp (scope_name, s.item()->name()) == 0)
719                 break;
720           if (s != 0)
721             {
722               message_mgr().error_dialog (
723                 (char*)UAS_String(CATGETS(Set_Messages, 21,
724                 "The name you entered is already in use.")));
725             }
726           else
727             valid = TRUE;
728         }
729     }
730   while (!valid);
731
732   delete [] default_name;
733   message_mgr().set_max_length(40);
734   return (scope_name);
735 }
736
737
738 // /////////////////////////////////////////////////////////////////
739 // save_scope - save the current scope, prompting if necessary
740 // /////////////////////////////////////////////////////////////////
741
742 void
743 SearchScopeAgent::save_scope()
744 {
745   // get a name and create a new scope 
746   const char *name;
747   if (f_current_scope == NULL)  // ie: unnamed 
748     {
749       name = scope_name_prompt();
750       if (name == NULL)
751         return;
752
753       save_unnamed_scope (name);
754       if (XtIsManaged(f_unnamed)) {
755         f_unnamed.Unmanage();
756         // re-computation needed, weird - 11/2/94 kamiya
757         f_scope_option.Unmanage();
758         f_scope_option.Manage();
759       }
760
761       f_new.SetSensitive (True);
762       f_rename.SetSensitive (True);
763       f_delete.SetSensitive (True);
764     }
765   // just save it otherwise 
766   else
767     {
768       BitHandle data_handle = f_scope_list.lookup_handle(f_current_scope);
769       BitHandle visible_handle = f_infolib_list->data_handle();
770   
771       // save the bits from the applied handle
772       ON_DEBUG (printf("Copy handle %ld to %ld\n", visible_handle, data_handle));
773       f_infolib_list->list()->copy_selected (visible_handle, data_handle);
774       if(f_auto_expand)
775         f_infolib_list->list()->copy_expanded (visible_handle, data_handle);
776       f_component_list->list()->copy_selected (visible_handle, data_handle);
777
778       // Update the component mask value in the scope. 
779       f_current_scope->search_zones().zones(component_mask (data_handle));
780
781       UAS_PtrList<UAS_BookcaseEntry>bcases = bookcase_list(data_handle);
782       f_current_scope->bookcases(bcases);
783
784       // Save the scope to disk. 
785       f_scope_list.save();
786     }
787   f_save.SetSensitive (False);
788   f_reset.SetSensitive (False);
789 }
790
791
792 // /////////////////////////////////////////////////////////////////
793 // create_scope - create a new scope given various info
794 // /////////////////////////////////////////////////////////////////
795
796 UAS_SearchScope *
797 SearchScopeAgent::create_scope (const char *name,
798                                 UAS_PtrList<UAS_BookcaseEntry> &base_list,
799                                 unsigned int component_mask, bool ro)
800 {
801   // this flag should be defined elsewhere-this could
802   // become a command-line option
803   if (f_shell == 0)
804     {
805       create_ui();
806     }
807
808   // Get a new bit handle for the new scope. 
809   BitHandle handle = f_infolib_list->list()->get_data_handle();
810
811   // Create the new scope object. 
812   UAS_SearchScope *scope = new UAS_SearchScope (name, base_list, component_mask, ro);
813   // append handle and scope to scope list
814   if(scope->read_only())
815   {
816     List_Iterator<UAS_SearchScope *> s (f_scope_list);
817     s++;
818     // put all read only scopes at beginning, but
819     // after the "Current Section" and "All Libraries" scopes
820     // which should always be the first 2 on the list.
821     f_scope_list.insert_after (s, scope);
822     f_scope_list.add_handle(handle, 1);
823   }
824   else
825   {
826     f_scope_list.append (scope);
827     f_scope_list.add_handle(handle, -1);
828   }
829
830
831   // Select the infobase level if the scope contains no infolibs.
832   if (base_list.numItems() == 0)
833     ((OutlineElement*)(*f_infolib_list->list())[0])->set_selected (handle);
834
835   UAS_BookcaseEntry *bce;
836   for (int i = 0; i < base_list.numItems(); i++)
837     {
838       bce = base_list[i];
839
840       // Select the correct entries in the list.
841       int index = lid_to_index(bce->lid());
842       UAS_String bce_lid(bce->lid());
843       UAS_String bce_bid(bce->bid());
844       int bcindex = bid_to_index(bce_lid, bce_bid);
845       List *iblist = 
846         ((OutlineElement*)(*f_infolib_list->list())[index])->children();
847
848       ON_DEBUG (printf ("Using base %d of %d\n",
849                         bce->base_num(), iblist->length()));
850
851       UAS_ObjList<int> book_list = bce->book_list();
852       if (book_list.numItems() == 0)
853       {
854         ((OutlineElement*)(*iblist)[bcindex])->set_selected (handle);
855 //        ((OutlineElement*)(*iblist)[bce->base_num()])->set_selected (handle);
856
857         // since the bookcase is selected, need to expand parent
858         if(f_auto_expand)
859         {
860           ((OutlineElement*)(*f_infolib_list->list())[index])->set_expanded (handle);
861         }
862       }
863       else
864         {
865           List *books =
866             ((OutlineElement*)(*iblist)[bcindex])->children();
867 //            ((OutlineElement*)(*iblist)[bce->base_num()])->children();
868
869           if (f_auto_expand)
870           {
871             // need to expand bookcase and infolib
872             if(book_list.numItems() > 0)
873             {
874               ((OutlineElement*)(*f_infolib_list->list())[index])->set_expanded (handle);
875               ((OutlineElement*)(*iblist)[bcindex])->set_expanded (handle);
876             }
877           }
878           for (int j = 0; j < book_list.numItems(); j++)
879             ((OutlineElement*)(*books)[book_list[j]-1])->set_selected (handle);
880         }
881       //book_list.clear(); // old code reset this list... but why? -rtp
882     }
883
884   return (scope);
885 }
886
887 void
888 SearchScopeAgent::select_infolib (UAS_String &lid, BitHandle handle)
889 {
890   ((ScopeOutlineListView *)f_infolib_list)->select_infolib(lid, handle);
891 }
892
893 // /////////////////////////////////////////////////////////////////
894 // select_initial - select the first scope and display it
895 // /////////////////////////////////////////////////////////////////
896
897 void
898 SearchScopeAgent::select_initial (Widget exception)
899 {
900   // Select the Unnamed scope if it is the only (non-exception) one left.
901   WComposite menu (f_scope_option.SubMenuId());
902
903   int num_kids = menu.NumChildren();
904   if ((exception != NULL  && num_kids == 2) ||  num_kids == 1)
905     {
906       f_reset.SetSensitive (False);
907       new_scope();
908     }
909   // Select the first (non-exception) scope in the list otherwise. 
910   else
911     {
912       WXmPushButton btn (menu.Children()[1]);
913       if (btn == exception)
914         btn = WXmPushButton (menu.Children()[2]);
915
916       set_current_scope(btn);
917 #if EAM
918       f_scope_option.MenuHistory (btn);
919       f_current_scope = (UAS_SearchScope *) btn.UserData();
920       f_infolib_list->list()->copy_selected(f_scope_list.lookup_handle(f_current_scope),
921                                              f_infolib_list->data_handle());
922       if (f_auto_expand)
923       {
924         f_infolib_list->list()->copy_expanded(f_scope_list.lookup_handle(f_current_scope),
925                                              f_infolib_list->data_handle());
926         f_infolib_list->update_list(f_infolib_list->list(),
927                                     f_infolib_list->data_handle());
928       }
929       set_components (f_current_scope->search_zones().zones());
930       // visually update 
931       f_infolib_list->data_handle (f_infolib_list->data_handle());
932       f_component_list->data_handle (f_component_list->data_handle());
933
934       f_new.SetSensitive (True);
935       f_save.SetSensitive (False);
936       f_delete.SetSensitive (True);
937       f_rename.SetSensitive (True);
938       f_reset.SetSensitive (False);
939 #endif
940     }
941 }
942
943
944 // /////////////////////////////////////////////////////////////////
945 // rename - rename the current scope
946 // /////////////////////////////////////////////////////////////////
947
948 void
949 SearchScopeAgent::rename_scope()
950 {
951   WXmPushButton scope_btn (f_scope_option.MenuHistory());
952   // Rename must be insensitive for Unnamed scope.  Use save instead.
953   Xassert (scope_btn != f_unnamed);
954   Xassert (f_current_scope != NULL);
955   Xassert (f_current_scope == (UAS_SearchScope *) scope_btn.UserData());
956
957   const char *name = scope_name_prompt();
958   if (name == NULL)
959     return;
960
961   scope_btn.LabelString (name);
962
963   f_save.SetSensitive (False);
964   f_reset.SetSensitive (False);
965
966   int position = 1, old_position = -1;
967   List_Iterator<UAS_SearchScope *> s (f_scope_list);
968   for (; s != 0; s++)
969     {
970       if (s.item()->read_only())
971         continue;
972       if (s.item() == f_current_scope)
973         {
974           old_position = position;
975           continue;
976         }
977       ON_DEBUG (printf ("ScopeAgent: strcmp against <%s>\n",
978                         s.item()->name()));
979       if (strcmp (name, s.item()->name()) < 0)
980         break;
981       position++;
982     }
983
984   // Move the item to the correct alphabetical placement in the list.
985   ON_DEBUG (printf ("ScopeAgent: old position = %d, new position = %d\n",
986                     old_position, position));
987   if (position != old_position)
988     {
989       // look up handle for scope and save it
990       BitHandle data_handle = f_scope_list.lookup_handle(f_current_scope);
991       // remove handle and scope from scope list
992       f_scope_list.remove_handle(f_current_scope);
993       f_scope_list.remove (f_current_scope);
994       ON_DEBUG (printf ("ScopeAgent: Inserting before <%s>\n",
995                         s != 0 ? s.item()->name() : "LAST"));
996       // add handle and scope back in appropriate location
997       f_scope_list.add_handle(data_handle, position-1);
998       f_scope_list.insert_before (s, f_current_scope);
999   
1000       scope_btn.PositionIndex (position);
1001     }
1002
1003   // Make sure old scope name preference isn't saved by NULLing out
1004   // it's value.  This should really happen in a ScopeListMgr object.  DJB
1005   char scratch[64];
1006   snprintf (scratch, sizeof(scratch), "Scope.%s", f_current_scope->name());
1007   StringPref (scratch).value ("");
1008   f_current_scope->set_name (name);
1009   f_scope_list.save();
1010 }
1011
1012
1013 // /////////////////////////////////////////////////////////////////////////
1014 // reset - resets window to values at last save
1015 // /////////////////////////////////////////////////////////////////////////
1016
1017 void
1018 SearchScopeAgent::reset()
1019 {
1020   WXmPushButton scope_btn (f_scope_option.MenuHistory());
1021   // Handle Unnamed scope as a special case.
1022   if (scope_btn == f_unnamed)
1023     {
1024       f_infolib_list->clear();
1025       f_component_list->clear();
1026     }
1027   else
1028     {
1029       UAS_SearchScope *scope = (UAS_SearchScope *) scope_btn.UserData();
1030       f_infolib_list->list()->copy_selected(f_scope_list.lookup_handle(scope),
1031                                              f_infolib_list->data_handle());
1032 //      f_infolib_list->list()->copy_expanded(f_scope_list.lookup_handle(scope),
1033 //                                             f_infolib_list->data_handle());
1034       set_components (scope->search_zones().zones());
1035
1036       // update visually by resetting flag (to itself)
1037       f_infolib_list->data_handle(f_infolib_list->data_handle());
1038       f_component_list->data_handle(f_component_list->data_handle());
1039   }
1040
1041   if (scope_btn != f_unnamed)
1042     f_save.SetSensitive (False);
1043   f_reset.SetSensitive (False);
1044 }
1045
1046
1047 // /////////////////////////////////////////////////////////////////////////
1048 // scope_modified - called when selection made in sublist
1049 // /////////////////////////////////////////////////////////////////////////
1050
1051 void
1052 SearchScopeAgent::scope_modified()
1053 {
1054   f_save.SetSensitive (True);
1055   f_reset.SetSensitive (True);
1056 }
1057
1058
1059 // /////////////////////////////////////////////////////////////////
1060 // close
1061 // /////////////////////////////////////////////////////////////////
1062
1063 void
1064 SearchScopeAgent::close()
1065 {
1066   if (f_reset.Sensitive())
1067     {
1068       bool dosave = message_mgr().question_dialog (
1069                 (char*)UAS_String(CATGETS(Set_Messages, 17,
1070                 "Do you want to save changes to the current scope?")));
1071       if (dosave)
1072         save_scope();
1073     }
1074
1075   if (f_current_scope == NULL)
1076     f_unnamed.Unmanage();
1077
1078   f_shell.Popdown();
1079 }
1080
1081
1082 // /////////////////////////////////////////////////////////////////////////
1083 // save_unnamed_scope
1084 // /////////////////////////////////////////////////////////////////////////
1085
1086 void
1087 SearchScopeAgent::save_unnamed_scope (const char *name)
1088 {
1089   Wait_Cursor bob;
1090
1091   // Allocate a bit handle for the new scope 
1092   BitHandle data_handle = f_infolib_list->list()->get_data_handle();
1093   BitHandle visible_handle = f_infolib_list->data_handle();
1094   
1095   // save the bits from the applied handle
1096   ON_DEBUG (printf("Copying handle %ld to %ld\n", visible_handle, data_handle));
1097   f_infolib_list->list()->copy_selected (visible_handle, data_handle);
1098   if(f_auto_expand)
1099     f_infolib_list->list()->copy_expanded (visible_handle, data_handle);
1100   f_component_list->list()->copy_selected (visible_handle, data_handle);
1101
1102   unsigned int mask = component_mask (data_handle);
1103   assert (mask != 0);
1104
1105   UAS_PtrList<UAS_BookcaseEntry>bcases = bookcase_list(data_handle);
1106   f_current_scope = new UAS_SearchScope (name, bcases, mask);
1107
1108   int position = 0;
1109
1110   // Scan the current menu to find the correct insertion position. 
1111   List_Iterator<UAS_SearchScope *> s (f_scope_list);
1112   for (; s != 0; s++, position++)
1113     {
1114       if (s.item()->read_only())
1115         continue;
1116
1117       // Find the first item that the new entry belongs before.
1118       ON_DEBUG (printf ("Editor strcmp to <%s>\n", s.item()->name()));
1119       if (strcmp (name, s.item()->name()) < 0)
1120         break;
1121     }
1122
1123   f_scope_list.add_handle(data_handle, position);
1124   f_scope_list.insert_before (s, f_current_scope);
1125   ON_DEBUG (printf ("Final editor position = %d\n", position));
1126
1127   // Create the new button. 
1128   DECLM (WXmPushButton, scope_btn, f_scope_option.SubMenuId(), name);
1129   ON_ACTIVATE (scope_btn,select_scope);
1130   scope_btn.PositionIndex (position);
1131   scope_btn.UserData (f_current_scope);
1132   f_scope_option.MenuHistory (scope_btn);
1133
1134   // Flush the changes to disk. 
1135   ON_DEBUG (puts (">> About to save scope"));
1136   f_scope_list.save();
1137 }
1138
1139
1140 unsigned int
1141 SearchScopeAgent::component_mask (BitHandle handle)
1142 {
1143   unsigned int return_mask = 0;
1144
1145   OutlineList *scope_list = f_component_list->list();
1146   // BitHandle handle = f_component_list->data_handle();
1147
1148   if (((OutlineElement*)(*scope_list)[0])->is_selected(handle)){
1149     return_mask = f_all;
1150     ON_DEBUG(cerr << "ALL COMPONENTS selected" << endl);
1151   } else { 
1152     List *top = ((OutlineElement*)(*scope_list)[0])->children();
1153     if (((OutlineElement*)(*top)[0])->is_selected(handle)){
1154       return_mask |= f_titles;
1155       ON_DEBUG(cerr << "TITLES selected" << endl);
1156     }
1157     if (((OutlineElement*)(*top)[1])->is_selected(handle)){
1158       return_mask |= f_bodies;
1159       ON_DEBUG(cerr << "BODY selected" << endl);
1160     }
1161     if (((OutlineElement*)(*top)[2])->is_selected(handle)){
1162       return_mask |= f_examples;
1163       ON_DEBUG(cerr << "EXAMPLES selected" << endl);
1164     }
1165     if (((OutlineElement*)(*top)[3])->is_selected(handle)){
1166       return_mask |= f_indexes;
1167       ON_DEBUG(cerr << "INDEX selected" << endl);
1168     }
1169     if (((OutlineElement*)(*top)[4])->is_selected(handle)){
1170       return_mask |= f_tables;
1171       ON_DEBUG(cerr << "TABLES selected" << endl);
1172     }
1173 #ifndef DtinfoClient
1174     if (((OutlineElement*)(*top)[5])->is_selected(handle)){
1175       return_mask |= f_graphics;
1176       ON_DEBUG(cerr << "GRAPHICS selected" << endl);
1177     }
1178 #endif
1179   }
1180   return return_mask ;
1181 }
1182
1183
1184 void
1185 SearchScopeAgent::set_components (u_int mask)
1186 {
1187 #define SELECT(list, item, handle) \
1188   ((OutlineElement*)(*list)[item])->set_selected(handle)
1189 #define DESELECT(list, item, handle) \
1190   ((OutlineElement*)(*list)[item])->unset_selected(handle)
1191
1192   OutlineList *scope_list = f_component_list->list();
1193   BitHandle handle = f_component_list->data_handle();
1194   List *top = ((OutlineElement*)(*scope_list)[0])->children();
1195
1196   if ((mask & f_all) == f_all)
1197     {
1198       SELECT(scope_list, 0, handle);
1199       DESELECT(top,0,handle);
1200       DESELECT(top,1,handle);
1201       DESELECT(top,2,handle);
1202       DESELECT(top,3,handle);
1203       DESELECT(top,4,handle);
1204 #ifndef DtinfoClient
1205       DESELECT(top,5,handle);
1206 #endif
1207     }
1208   else
1209     {
1210       DESELECT(scope_list, 0, handle);
1211
1212       if (mask & f_titles)
1213         SELECT(top,0,handle);
1214       else
1215         DESELECT(top,0,handle);
1216
1217       if (mask & f_bodies)
1218         SELECT(top,1,handle);
1219       else
1220         DESELECT(top,1,handle);
1221
1222       if (mask & f_examples)
1223         SELECT(top,2,handle);
1224       else
1225         DESELECT(top,2,handle);
1226
1227       if (mask & f_indexes)
1228         SELECT(top,3,handle);
1229       else
1230         DESELECT(top,3,handle);
1231
1232       if (mask & f_tables)
1233         SELECT(top,4,handle);
1234       else
1235         DESELECT(top,4,handle);
1236
1237 #ifndef DtinfoClient
1238       if (mask & f_graphics)
1239         SELECT(top,5,handle);
1240       else
1241         DESELECT(top,5,handle);
1242 #endif
1243     }
1244 }
1245 #undef SELECT
1246 #undef DESELECT
1247
1248
1249 // /////////////////////////////////////////////////////////////////
1250 // generate_component_list
1251 // /////////////////////////////////////////////////////////////////
1252
1253 #define ADD(LIST,STRING,CHILD,EXPANDED) \
1254   oe = new OutlineString (STRING); \
1255   if ((bool)CHILD) oe->set_children (CHILD); \
1256   if (EXPANDED) oe->set_expanded (0x1); \
1257   LIST->append (*oe);
1258
1259 OutlineList *
1260 SearchScopeAgent::generate_component_list()
1261 {
1262   OutlineList *components = new OutlineList (10);
1263   OutlineList *parts = new OutlineList (10);
1264   OutlineElement *oe;
1265
1266   ADD (components, CATGETS(Set_Messages, 22, "Everything"), parts, True);
1267   ADD (parts, CATGETS(Set_Messages, 23, "Titles"), 0, False);
1268   ADD (parts, CATGETS(Set_Messages, 24, "Body"), 0, False);
1269   ADD (parts, CATGETS(Set_Messages, 25, "Examples"), 0, False);
1270   ADD (parts, CATGETS(Set_Messages, 26, "Index"), 0, False);
1271   ADD (parts, CATGETS(Set_Messages, 27, "Tables"), 0, False);
1272 #ifndef DtinfoClient
1273   ADD (parts, CATGETS(Set_Messages, 28, "Graphics"), 0, False);
1274 #endif
1275   
1276   return (components);
1277 }
1278 #undef ADD
1279
1280 // check to see if the first infolib is selected in the scope (handle).
1281 bool
1282 SearchScopeAgent::infolib_selected (BitHandle handle)
1283 {
1284   OutlineElement *infolib = (OutlineElement *) (*f_infolib_list->list())[0];
1285   return (infolib->is_selected (handle));
1286 }
1287
1288
1289 // check to see if infolib is selected in the scope (handle).
1290 bool
1291 SearchScopeAgent::infolib_selected (UAS_String &lid, BitHandle handle)
1292 {
1293   int index = lid_to_index(lid);
1294   OutlineElement *infolib = (OutlineElement *) (*f_infolib_list->list())[index];
1295
1296   return (infolib->is_selected (handle));
1297 }
1298
1299 // /////////////////////////////////////////////////////////////////
1300 // bookcase_list - return a list of bookcases for a given handle
1301 // /////////////////////////////////////////////////////////////////
1302
1303 UAS_PtrList<UAS_BookcaseEntry>
1304 SearchScopeAgent::bookcase_list (BitHandle handle)
1305 {
1306   ON_DEBUG (printf ("*** BUILDING SCOPE LIST, handle = %ld ***\n", handle));
1307   // Get the list of all infobases.
1308
1309   // get the list of bookcase names
1310   UAS_List<UAS_Common> bcase_list = bookcaseList();
1311   OutlineList *ol = f_infolib_list->list();
1312
1313   // NOTE: hardcoding - assuming 0 is only library
1314
1315
1316   UAS_PtrList<UAS_BookcaseEntry>  bcases;
1317   UAS_BookcaseEntry              *bce;
1318   OutlineElement                 *oe;
1319   UAS_Pointer<UAS_Common>         common;
1320   int                             infolib, bookcase;
1321
1322   // Iterate over the infolibs looking for selected entries.
1323   assert (handle != 0);
1324   for (infolib = 0; infolib < (int) ol->length(); infolib++)
1325   { 
1326     //
1327     // See if the infolib is selected.
1328     //
1329     oe = ((OutlineElement*)(*ol)[infolib]); 
1330     List *bclist = ((OutlineElement*)(*ol)[infolib])->children();
1331     if (oe->is_selected (handle))
1332     {
1333       // get all bookcases and append them to the selected list
1334       for (bookcase = 0; bookcase < (int) bclist->length(); bookcase++)
1335       {
1336         oe = ((OutlineElement *)(*bclist)[bookcase]);
1337         common = ((TOC_Element*)oe)->toc();
1338         if (common->type() == UAS_BOOKCASE)
1339         {
1340           // note: copied into a scope obj; deleted in scope obj's dtor
1341           bce = new UAS_BookcaseEntry(common);
1342           bcases.append(bce);
1343           ON_DEBUG (printf("Adding base: %s\n",bce->name()));
1344         }
1345       }
1346     }
1347     else
1348     {
1349       // The infolib is not selected--check to see if any of its
1350       // children (bookcases) are selected.
1351       //
1352       // Get children of the infolib.
1353       // If the bookcase is selected, create a BookcaseEntry and 
1354       // append it to the list.
1355       for (bookcase = 0; bookcase < (int) bclist->length(); bookcase++)
1356       {
1357         oe = ((OutlineElement *)(*bclist)[bookcase]);
1358         if (oe->is_selected (handle))
1359         {
1360           common = ((TOC_Element*)oe)->toc();
1361           if (common->type() == UAS_BOOKCASE)
1362           {
1363             // note: copied into a scope obj; deleted in scope obj's dtor
1364             bce = new UAS_BookcaseEntry(common);
1365             bcases.append(bce);
1366             ON_DEBUG (printf("Adding base: %s\n",bce->name()));
1367           }
1368         }
1369         else
1370         {
1371           // The bookcase is not selected, so check to see if any kids are.
1372           //
1373           // Check for any children book selections.  If found, add an
1374           // entry for the enclosing bookcase and add the books to it.
1375           UAS_ObjList<int> booklist;
1376           if (oe->children_cached())
1377           {
1378             //
1379             // build a list of books for a give bookcase
1380             //
1381             List *books = oe->children();
1382             // (1-based book, since that's how they're indexed in Fulcrum.)
1383             for (int book_num = 1; book_num <= (int)books->length(); book_num++)
1384             {
1385                 ON_DEBUG (printf ("Checking Book #%d: ", book_num));
1386               if (((OutlineElement*)(*books)[book_num-1])->is_selected (handle))
1387               {
1388                 ON_DEBUG (puts ("selected"));
1389                 booklist.append (book_num);
1390               }
1391               else
1392               {
1393                 ON_DEBUG (puts ("NOT selected"));
1394               }
1395             }
1396             if (booklist.numItems() == 0)
1397               continue; // nothing was selected--go to next infolib
1398   
1399             common = ((TOC_Element*)oe)->toc();
1400             // note: copied into a scope obj; deleted in scope obj's dtor
1401             bce = new UAS_BookcaseEntry(common);
1402             bcases.append(bce);
1403             ON_DEBUG (printf("Adding base: %s\n",bce->name()));
1404
1405             // Now add the booklist to that parent, which owns it now.
1406             bce->set_book_list (booklist);
1407             booklist.clear();
1408           }
1409         }
1410       }
1411     }
1412   }
1413   return (bcases);
1414 }
1415
1416 // ////////////////////////////////////////////////////////////////
1417 // return a list of bookcases from all infolibs currently installed
1418 // ////////////////////////////////////////////////////////////////
1419 UAS_PtrList<UAS_BookcaseEntry>
1420 SearchScopeAgent::bookcase_list()
1421 {
1422   UAS_PtrList<UAS_BookcaseEntry> bcases;
1423   UAS_BookcaseEntry *bce;
1424   OutlineList *ol = f_infolib_list->list();
1425   OutlineElement *oe;
1426
1427   for (unsigned int i = 0; i < ol->length(); i++)
1428   {
1429     oe = ((OutlineElement *) (*ol)[i]);
1430     UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
1431     UAS_List<UAS_Common> kids = infolib->children();
1432     for (unsigned int j = 0; j < kids.length(); j++)
1433     {
1434       if (kids[j]->type() == UAS_BOOKCASE)
1435       {
1436         // the uas scope object dups this list and will delete it
1437         bce = new UAS_BookcaseEntry(kids[j]);
1438         bce->set_base_num(j);
1439         bce->set_infolib_num(i);
1440         bcases.append(bce);
1441       }
1442     }
1443   }
1444
1445   return (bcases);
1446 }
1447
1448 // Return the list of bookcases for a given infolib.
1449 //
1450 UAS_PtrList<UAS_BookcaseEntry>
1451 SearchScopeAgent::bookcase_list(UAS_String &lid)
1452 {
1453   int index = lid_to_index(lid);
1454   OutlineList *ol = f_infolib_list->list();
1455   OutlineElement *oe = ((OutlineElement *) (*ol)[index]);
1456   UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
1457
1458   UAS_PtrList<UAS_BookcaseEntry> bcases;
1459   UAS_BookcaseEntry *bce;
1460   UAS_List<UAS_Common> kids = infolib->children();
1461
1462   for (unsigned int j = 0; j < kids.length(); j++)
1463   {
1464     if (kids[j]->type() == UAS_BOOKCASE)
1465     {
1466       // the uas scope object dups this list and will delete it
1467       bce = new UAS_BookcaseEntry(kids[j]);
1468       bce->set_base_num(j);
1469       bcases.append(bce);
1470     }
1471   }
1472   return (bcases);
1473 }
1474
1475 // /////////////////////////////////////////////////////////////////////////
1476 // truncate - destructively removes leading and trailing blanks
1477 // /////////////////////////////////////////////////////////////////////////
1478
1479 char *
1480 SearchScopeAgent::truncate (char *string)
1481 {
1482   // remove leading blanks 
1483   char *newstr = string;
1484   while (*newstr == ' ')
1485     newstr++;
1486
1487   // remove trailing blanks
1488   u_int len = strlen (newstr);
1489   char *eptr = newstr + len - 1 ;
1490   while (*eptr == ' ')
1491     --eptr ;
1492
1493   // terminate string
1494   *(eptr + 1) = '\0';
1495
1496   // change newlines to spaces 
1497   for (char *s = newstr; *s != '\0'; s++)
1498     if (*s == '\n')
1499       *s = ' ';
1500
1501   return (newstr);
1502 }
1503
1504
1505 // /////////////////////////////////////////////////////////////////////////
1506 // select_scope
1507 // /////////////////////////////////////////////////////////////////////////
1508
1509 void
1510 SearchScopeAgent::select_scope (WCallback *wcb)
1511 {
1512   WXmPushButton scope_btn (wcb->GetWidget());
1513   ON_DEBUG (fprintf (stderr,"ScopeEdit: selecting scope\n"));
1514
1515   if (f_reset.Sensitive())
1516     {
1517       bool dosave = message_mgr().question_dialog (
1518                 (char*)UAS_String(CATGETS(Set_Messages, 17,
1519                 "Do you want to save changes to the current scope?")));
1520       if (dosave)
1521         save_scope();
1522       // Reset the menu history in case a new scope was created. 
1523       f_scope_option.MenuHistory (scope_btn);
1524     }
1525   set_current_scope(scope_btn);
1526 }
1527
1528 void
1529 SearchScopeAgent::set_current_scope (WXmPushButton& btn)
1530 {
1531   // update current selection in option menu
1532   f_scope_option.MenuHistory (btn);
1533   f_unnamed.Unmanage();
1534
1535   // re-computation needed. - 12/20/94 haya(addition 11/2/94 kamiya)
1536   f_scope_option.Unmanage();
1537   f_scope_option.Manage();
1538
1539   f_current_scope = (UAS_SearchScope *) btn.UserData();
1540
1541   // Copy the specified scope's selections in the list.
1542   f_infolib_list->list()->copy_selected(f_scope_list.lookup_handle(f_current_scope),
1543                                          f_infolib_list->data_handle());
1544   if (f_auto_expand)
1545   {
1546     f_infolib_list->list()->copy_expanded(f_scope_list.lookup_handle(f_current_scope),
1547                                          f_infolib_list->data_handle());
1548     f_infolib_list->update_list(f_infolib_list->list(), f_infolib_list->data_handle());
1549   }
1550   set_components (f_current_scope->search_zones().zones());
1551
1552   // visually update 
1553   f_infolib_list->data_handle (f_infolib_list->data_handle());
1554   f_component_list->data_handle (f_component_list->data_handle());
1555
1556   f_new.SetSensitive (True);
1557   f_save.SetSensitive (False);
1558   f_rename.SetSensitive (True);
1559   f_delete.SetSensitive (True);
1560   f_reset.SetSensitive (False);
1561 }
1562
1563
1564 void
1565 SearchScopeAgent::delete_scope()
1566 {
1567   Xassert (f_current_scope != NULL);
1568
1569   bool doit = message_mgr().question_dialog (
1570                 (char*)UAS_String(CATGETS(Set_Messages, 29,
1571                 "Are you sure you want to delete the scope?")));
1572   if (!doit)
1573     return;
1574
1575   UAS_SearchScope *scope = f_current_scope;
1576
1577   // remove the associated button
1578   Widget dead_meat = f_scope_option.MenuHistory();
1579   XtUnmanageChild (dead_meat);
1580   XtDestroyWidget (dead_meat);
1581   select_initial (dead_meat);
1582
1583   // remove the scope from the scope list
1584   f_scope_list.remove_handle(scope);
1585   f_scope_list.remove (scope);
1586
1587   // Make sure old scope name preference isn't saved by NULLing out
1588   // it's value.  This should really happen in a ScopeListMgr object.  DJB
1589   char scratch[64];
1590   snprintf (scratch, sizeof(scratch), "Scope.%s", scope->name());
1591   StringPref (scratch).value ("");
1592   delete scope;
1593
1594   // flush to disk. 
1595   f_scope_list.save();
1596 }
1597
1598 // Add new infolib to list
1599 void
1600 SearchScopeAgent::add_infolib(UAS_Pointer<UAS_Common> &lib)
1601 {
1602   // get infolib list and append new infolib to the list
1603   OutlineList *ol = f_infolib_list->list();
1604   OutlineElement *oe;
1605
1606   UAS_String temp_lid;
1607
1608   // See if infolib is already in list--if it's there, 
1609   // don't add it again.
1610   unsigned int i;
1611   for (i = 0; i < ol->length(); i++)
1612   {
1613     oe = ((OutlineElement *) (*ol)[i]);
1614     if (((TOC_Element *)oe)->toc() == lib)
1615       return;
1616   }
1617
1618   // need to make our own copy of this infolib
1619   UAS_Pointer<UAS_Common> newLib = UAS_Common::create(lib->locator());
1620   UAS_Pointer<UAS_Collection> cd = (UAS_Collection *) ((UAS_Common *) newLib);
1621   newLib = cd->root();
1622   ol->append (new TOC_Element (cd->root()));
1623
1624   // update list
1625   BitHandle handle = f_infolib_list->data_handle();
1626   ((OutlineElement *) (*ol)[0])->set_expanded (handle);
1627   f_infolib_list->set_list (ol, handle);
1628   f_infolib_list->clear();
1629
1630   // find infolib insertion point in list; need the index number
1631   for (i = 0; i < ol->length(); i++)
1632   {
1633       oe = ((OutlineElement *) (*ol)[i]);
1634       if (((TOC_Element *)oe)->toc()->lid() == newLib->lid())  
1635           break;
1636   }
1637
1638   // Create search scope for new infolib
1639   UAS_String newLib_lid(newLib->lid());
1640   UAS_SearchScope *scope = create_infolib_scope(newLib_lid);
1641   
1642   //
1643   // update the "All Libraries" search scope
1644   //
1645
1646   // find the scope
1647   scope = get_search_scope((char*)UAS_String(
1648                 CATGETS(Set_SearchScopeAgent, 4, "All Libraries")));
1649   
1650   // get a list of all bookcases
1651   UAS_PtrList<UAS_BookcaseEntry>bcases = bookcase_list();
1652   
1653   // update list of bookcases in the scope
1654   scope->bookcases(bcases);
1655
1656   if (f_first_time)
1657   {
1658     f_first_time = False;
1659     fill_option_menu();
1660     select_initial();
1661   }
1662
1663   rebuild_scope_list();
1664 }
1665
1666 // Remove infolib from infobase list
1667 void
1668 SearchScopeAgent::remove_infolib(UAS_Pointer<UAS_Common> &lib)
1669 {
1670   // get infolib list and remove infolib from the list
1671   OutlineList *ol = f_infolib_list->list();
1672   int infolib_num;
1673
1674   // Get index of infolib in infobase list
1675   infolib_num = lid_to_index(lib->lid());
1676
1677   if (infolib_num < 0)
1678     return;  // infolib not in list
1679
1680   // Remove infolib from list
1681   ol->remove (infolib_num);
1682
1683   // update list
1684   BitHandle handle = f_infolib_list->data_handle();
1685
1686   f_infolib_list->clear();
1687   unsigned int i;
1688   for (i = 0; i < ol->length(); i ++)
1689     ((OutlineElement *) (*ol)[i])->set_expanded (handle);
1690
1691   f_infolib_list->set_list (ol, handle);
1692   for (i = 0; i < ol->length(); i ++)
1693     ((OutlineElement *) (*ol)[i])->set_expanded (handle);
1694
1695   f_infolib_list->set_list (ol, handle);
1696
1697
1698 #ifdef EAM
1699
1700   // find the scope for deleted library.
1701   // TEMPORARY: The scope name is the id of the first
1702   // bookcase;
1703   UAS_List<UAS_Common> kids = lib->children();
1704   for (i = 0; i < kids.length(); i++)
1705   {
1706       if (kids[i]->type() == UAS_BOOKCASE)
1707         break;
1708   }
1709   char scratch[128];
1710   snprintf(scratch, sizeof(scratch), "Infolib %s", (char *)kids[i]->id());
1711 #endif
1712
1713   // remove search scope associated with infolib
1714   UAS_SearchScope *scope = get_search_scope(lib);
1715
1716   // remove the scope from the scope list
1717   f_scope_list.remove_handle(scope);
1718   f_scope_list.remove (scope);
1719
1720 #ifdef EAM
1721   // Make sure old scope name preference isn't saved by NULLing out
1722   // it's value.  This should really happen in a ScopeListMgr
1723   // object.  DJB
1724   char scratch[128];
1725   snprintf (scratch, sizeof(scratch), "Scope.%s", scope->name());
1726   StringPref (scratch).value ("");
1727 #endif
1728
1729   delete scope;
1730
1731   //
1732   // update the "All Libraries" search scope
1733   //
1734
1735   // find the scope
1736   scope = get_search_scope((char*)UAS_String(
1737                 CATGETS(Set_SearchScopeAgent, 4, "All Libraries")));
1738   
1739   // get a list of all bookcases
1740   UAS_PtrList<UAS_BookcaseEntry>bcases = bookcase_list();
1741   
1742   // update list of bookcases in the scope
1743   scope->bookcases(bcases);
1744
1745   rebuild_scope_list();
1746 }
1747
1748 /* work procedure */
1749 // Set current scope after callback has finished
1750 bool
1751 current_scope(XtPointer client_data)
1752 {
1753   SearchScopeAgent* agent = (SearchScopeAgent*)client_data;
1754   agent->update_current_scope();
1755   return True;
1756 }
1757
1758 void
1759 SearchScopeAgent::update_current_scope()
1760 {
1761   int n;
1762   Arg args[2];
1763   WidgetList kids;
1764   Cardinal num_kids;
1765   UAS_SearchScope* scope;
1766
1767   n = 0;
1768   XtSetArg(args[n], XmNnumChildren, &num_kids); n++;
1769   XtSetArg(args[n], XmNchildren, &kids); n++;
1770   XtGetValues(f_scope_option.SubMenuId(), args, n);
1771
1772   if(f_current_scope != NULL)
1773   {
1774     for (unsigned int i = 1; i < num_kids; i++)
1775     {
1776       WXmPushButton btn (kids[i]);
1777       scope = (UAS_SearchScope*)btn.UserData();
1778       if(scope->name() == f_current_scope->name())
1779       {
1780         set_current_scope(btn);
1781         return;
1782       }
1783     }
1784   }
1785
1786   if (num_kids > 1)
1787   {
1788     WXmPushButton btn (kids[1]);
1789     set_current_scope(btn);
1790     return;
1791   }
1792
1793   // There are no user scopes in list. Manage the unnamed button
1794   // and set current scope to NULL
1795   f_reset.SetSensitive (False);
1796   new_scope();
1797 }
1798
1799 // Rebuild the scope list after an infolib is added or removed.
1800 // Then update the option menu to reflect changes that may
1801 // have occurred in the scope list.
1802 // 
1803 void
1804 SearchScopeAgent::rebuild_scope_list()
1805 {
1806   UAS_SearchScope *scope;
1807   // Save the name of the current scope.
1808   UAS_String name;
1809   if (f_current_scope != NULL)
1810   {
1811     name = UAS_String(f_current_scope->name());
1812   }
1813
1814   // Delete all named scopes so list can be rebuilt.
1815   List_Iterator<UAS_SearchScope *> si (f_scope_list);
1816
1817   for (; si != 0; si++)
1818   {
1819     scope = si.item();
1820
1821     // delete all named scopes
1822     if (!scope->read_only())
1823     {
1824       // remove the scope from the scope list
1825       f_scope_list.remove_handle(scope);
1826       f_scope_list.remove (scope);
1827
1828       delete scope;
1829       si.reset(); // this really is necessary.
1830                   // see comment in List_base::remove()
1831     }
1832   }
1833
1834   // Rebuild the named scope list.
1835   f_scope_list.create_named_scopes();
1836
1837   // update query editor menu
1838   if (f_option_menu != NULL)
1839     f_option_menu->update_option_menu();
1840
1841   update_option_menu(name);
1842
1843   static UpdateMenu update_menu;
1844   update_menu.update = True;
1845   send_message(update_menu);
1846 }
1847
1848 // Update the option menu to reflect any changes
1849 // that may have occurred in the list of named scopes due
1850 // to addition or removal of infolibs.
1851 // Update current scope.
1852 void
1853 SearchScopeAgent::update_option_menu(UAS_String &scope_name)
1854 {
1855
1856   int n;
1857   Arg args[2];
1858   WidgetList kids;
1859   Cardinal num_kids;
1860
1861   n = 0;
1862   XtSetArg(args[n], XmNnumChildren, &num_kids); n++;
1863   XtSetArg(args[n], XmNchildren, &kids); n++;
1864   XtGetValues(f_scope_option.SubMenuId(), args, n);
1865
1866   // destroy all toggle buttons in menu except
1867   // the unnamed button.
1868   for (unsigned int i = 1; i < num_kids; i++)
1869   {
1870     XtUnmanageChild (kids[i]);
1871     XtDestroyWidget (kids[i]);
1872   }
1873
1874   fill_option_menu();
1875
1876   XtAppAddWorkProc(window_system().app_context(), (XtWorkProc)current_scope, this);
1877 #if EAM
1878   // need to set current scope to a valid scope.
1879   // see if the former "current scope" is still around.
1880   // if not, set current scope to first scope in list.
1881   // if there are no scopes in the list, set current scope
1882   // to NULL and manage the UnNamed scope button.
1883
1884   // iterate through search scope list to see if current
1885   // scope is still there
1886   List_Iterator<UAS_SearchScope *> si (f_scope_list);
1887   UAS_String name;
1888   UAS_SearchScope *scope;
1889   UAS_SearchScope *user_scope = NULL;
1890
1891   f_current_scope = NULL;
1892   for (; si != NULL; si++)
1893   {
1894     scope = si.item();
1895
1896     if (!scope->read_only())
1897     {
1898       if (user_scope == NULL)
1899         user_scope = scope; // keep track of first user scope
1900       if(scope_name == scope->name())
1901       {
1902         set_current_scope(scope);
1903         return;
1904       }
1905     }
1906   }
1907
1908   // see if former current scope has been deleted
1909   // due to infolib removal.
1910   if (user_scope == NULL)
1911   {
1912     // There are no user scopes in list. Manage the unnamed button
1913     // and set current scope to NULL
1914     f_reset.SetSensitive (False);
1915     new_scope();
1916     return;
1917   }
1918
1919   // set current scope to first user scope-need to get
1920   // associated menu button.
1921
1922   n = 0;
1923   XtSetArg(args[n], XmNnumChildren, &num_kids); n++;
1924   XtSetArg(args[n], XmNchildren, &kids); n++;
1925   XtGetValues(f_scope_option.SubMenuId(), args, n);
1926
1927   set_current_scope(kids[1]);
1928 #endif
1929
1930 }
1931
1932 UAS_List<UAS_Common>
1933 SearchScopeAgent::list()
1934 {
1935   if (f_shell == 0)
1936   {
1937     create_ui();
1938   }
1939
1940   UAS_List<UAS_Common> rval;
1941   OutlineList *ol = f_infolib_list->list();
1942   OutlineElement *oe;
1943
1944   for (unsigned int i = 0; i < ol->length(); i++)
1945   {
1946     oe = ((OutlineElement *) (*ol)[i]);
1947     UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
1948     rval.insert_item((UAS_Common *)(infolib));
1949   }
1950   return rval;
1951 }
1952
1953 // return a list of bookcase objects for a given infolib
1954 //
1955 UAS_List<UAS_Common>
1956 SearchScopeAgent::list(UAS_String &lid)
1957 {
1958   // convert lid into index
1959   int index = lid_to_index(lid);
1960   OutlineList *ol = f_infolib_list->list();
1961   OutlineElement *oe = ((OutlineElement *) (*ol)[index]);
1962
1963   // extract the infolib
1964   UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
1965
1966   UAS_List<UAS_Common> rval;
1967
1968   // get infolibs children--only save bookcases
1969   UAS_List<UAS_Common> kids = infolib->children();
1970   for (unsigned int i = 0; i < kids.length(); i++)
1971     if (kids[i]->type() == UAS_BOOKCASE)
1972       rval.insert_item(kids[i]);
1973   return rval;
1974 }
1975
1976 // Create a scope for an infolib based on the infolib id
1977 //
1978 UAS_SearchScope *
1979 SearchScopeAgent::create_infolib_scope(UAS_String &lid)
1980 {
1981   int index          = lid_to_index(lid);
1982   OutlineList *ol    = f_infolib_list->list();
1983   OutlineElement *oe = ((OutlineElement *) (*ol)[index]);
1984   UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
1985
1986   UAS_PtrList<UAS_BookcaseEntry> bcases;
1987   UAS_BookcaseEntry *bce;
1988
1989 #ifdef EAM
1990   int base_num = 0;
1991   int first_base_num = -1;
1992 #endif
1993
1994   if(env().debug())
1995   {
1996     cerr << endl;
1997     cerr << "locator: " << (char *)infolib->locator() << endl;
1998     cerr << "     id: " << (char *)infolib->id() << endl;
1999     cerr << "    lid: " << (char *)infolib->lid() << endl;
2000     cerr << "   name: " << (char *)infolib->name() << endl;
2001     cerr << " locale: " << (char *)infolib->locale() << endl;
2002   }
2003
2004   // get list of all bookcases for infolib and create bookcase
2005   // entry for each one.
2006   //
2007   UAS_List<UAS_Common> kids = list(lid);
2008   for (unsigned int i = 0; i < kids.length(); i++)
2009   {
2010     bce = new UAS_BookcaseEntry(kids[i]);
2011     bcases.append(bce);
2012   }
2013
2014 #ifdef EAM
2015   char scratch[128];
2016   snprintf(scratch, sizeof(scratch), "Infolib %s",
2017                         (char *)kids[first_base_num]->id());
2018 #endif
2019
2020   // create search scope for infolib using the infolib name as
2021   // search scope name.
2022   //
2023   UAS_SearchScope *s;
2024   s = create_scope((char*)infolib->name(), bcases, f_all, TRUE);
2025   s->set_infolib(infolib);
2026   return s;
2027 }
2028
2029 // Find the index into the f_infolib_list given a lid
2030 //
2031 int
2032 SearchScopeAgent::lid_to_index(const UAS_String &lid)
2033 {
2034   return ((ScopeOutlineListView *)f_infolib_list)->lid_to_index(lid);
2035 }
2036
2037 UAS_String
2038 SearchScopeAgent::lid_to_name(UAS_String &lid)
2039 {
2040   return ((ScopeOutlineListView *)f_infolib_list)->lid_to_name(lid);
2041 }
2042
2043 UAS_String
2044 SearchScopeAgent::name_to_lid(UAS_String &name)
2045 {
2046   return ((ScopeOutlineListView *)f_infolib_list)->name_to_lid(name);
2047 }
2048
2049 // Given a bookcase id, return its index into the f_infolib_list
2050 // list.
2051 int
2052 SearchScopeAgent::bid_to_index(UAS_String &lid, UAS_String &bid)
2053 {
2054   int index =  ((ScopeOutlineListView *)f_infolib_list)->lid_to_index(lid);
2055   OutlineList *ol = f_infolib_list->list();
2056   OutlineElement *oe = ((OutlineElement *) (*ol)[index]);
2057   UAS_Pointer<UAS_Common> infolib = ((TOC_Element *)oe)->toc();
2058   UAS_List<UAS_Common> kids = infolib->children();
2059   for (unsigned int i = 0; i < kids.length(); i++)
2060   {
2061     if (kids[i]->bid() == bid)
2062       return i;
2063   }
2064   // There has to be an bookcase for a given bid--if
2065   // not, something has gone wrong.
2066   throw (CASTEXCEPT Exception());
2067 }
2068
2069 // given a search scope name, return the search scope
2070 UAS_SearchScope *
2071 SearchScopeAgent::get_search_scope(const char* name)
2072 {
2073   xList<UAS_SearchScope *> &scopes = f_scope_list;
2074   List_Iterator<UAS_SearchScope *> iter (scopes);
2075   UAS_SearchScope *scope;
2076
2077   for(;iter;iter++)
2078   {
2079     scope = iter.item();
2080     if (strcmp(name, scope->name()) == 0)
2081       return scope;
2082   }
2083   throw (CASTEXCEPT Exception());
2084 }
2085
2086 // Given an infolib, return the search scope.
2087 //
2088 UAS_SearchScope *
2089 SearchScopeAgent::get_search_scope(UAS_Pointer<UAS_Common> &infolib)
2090 {
2091   xList<UAS_SearchScope *> &scopes = f_scope_list;
2092   List_Iterator<UAS_SearchScope *> iter (scopes);
2093   UAS_SearchScope *scope;
2094
2095   iter++; // skip "Current Section" scope
2096   iter++; // skip "All Libraries" scope
2097
2098   // find scope for associated infolib
2099   for(;iter;iter++)
2100   {
2101     scope = iter.item();
2102     if(scope->get_infolib() == infolib)
2103       return scope;
2104   }
2105   throw (CASTEXCEPT Exception());
2106 }
2107
2108 // Search scope agent needs access to query editor
2109 void
2110 SearchScopeAgent::option_menu(QueryEditor *menu)
2111 {
2112   f_option_menu = menu;
2113 }