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