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