Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Query / QueryEditor.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 /*      Copyright (c) 1994,1995,1996 FUJITSU LIMITED    */
24 /*      All Rights Reserved                             */
25
26 /*
27  * $XConsortium: QueryEditor.C /main/14 1996/10/11 17:11:51 cde-hal $
28  *
29  * Copyright (c) 1992 HAL Computer Systems International, Ltd.
30  * All rights reserved.  Unpublished -- rights reserved under
31  * the Copyright Laws of the United States.  USE OF A COPYRIGHT
32  * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
33  * OR DISCLOSURE.
34  * 
35  * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
36  * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.  USE,
37  * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
38  * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
39  * INTERNATIONAL, LTD.
40  * 
41  *                         RESTRICTED RIGHTS LEGEND
42  * Use, duplication, or disclosure by the Government is subject
43  * to the restrictions as set forth in subparagraph (c)(l)(ii)
44  * of the Rights in Technical Data and Computer Software clause
45  * at DFARS 252.227-7013.
46  *
47  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
48  *                  1315 Dell Avenue
49  *                  Campbell, CA  95008
50  * 
51  */
52
53 #define C_TOC_Element
54 #define L_Basic
55
56 #define C_WindowSystem
57 #define L_Other
58
59 #define C_QueryEditor
60 #define C_QueryGroup
61 #define C_QueryTerm
62 #define C_QueryGroupView
63 #define L_Query
64
65 #define C_HelpAgent
66 #define L_Agents
67
68 #define C_SearchMgr
69 #define C_SearchScopeMgr
70 #define C_MessageMgr
71 #define L_Managers
72
73 #include "Other/XmStringLocalized.hh"
74 #include "Managers/CatMgr.hh"
75
76 #include "Prelude.h"
77
78 #include "Registration.hh"
79
80 #include <WWL/WXmMenu.h>
81 #include <WWL/WXmForm.h>
82 #include <WWL/WXmLabel.h>
83 #include <WWL/WXmCascadeButton.h>
84 #include <WWL/WXmSeparator.h>
85 #include <WWL/WXmPanedWindow.h>
86
87 #include <string.h>
88 #include <iostream.h>
89
90 #define CLASS QueryEditor
91 #include "../Agents/create_macros.hh"
92
93 //static bool g_allow_query_text_change;
94   
95 QueryEditor *QueryEditor::f_query_editor;
96
97 // /////////////////////////////////////////////////////////////////
98 // class constructor
99 // /////////////////////////////////////////////////////////////////
100
101 QueryEditor::QueryEditor(UAS_SearchEngine& search_engine)
102 : f_shell (NULL),
103   f_query (NULL),
104   f_query_view (NULL),
105   f_null_terms (0)
106 {
107   f_query_editor = this;
108
109   // NOTE: QueryTerm::f_caps is global. It needs to be term-wise
110   //       to get terms to have varied capabilities.
111   QueryTerm::avail_caps(search_engine.avail_caps());
112
113 #ifdef DEBUG
114   fprintf(stderr, "(DEBUG) search engine capabilities = 0x%x\n",
115                                                 QueryTerm::avail_caps());
116 #endif
117 }
118
119
120 // /////////////////////////////////////////////////////////////////
121 // display - display the query editor
122 // /////////////////////////////////////////////////////////////////
123
124 void
125 QueryEditor::display()
126 {
127   static int count = 0;
128   if (count++ == 0) {
129     if (f_shell == NULL)
130       create_ui();
131
132     if (f_query == NULL)
133       edit_query (NULL);
134
135     f_shell.Popup();
136     f_shell.DeIconify();
137   }
138   count--;
139 }
140
141
142 // /////////////////////////////////////////////////////////////////
143 // new_query - set up interface for a new query
144 // /////////////////////////////////////////////////////////////////
145
146 void
147 QueryEditor::edit_query (QueryGroup *query)
148 {
149   static Boolean first_time = True;
150
151 //#ifdef UseFJMTF
152 #if 1
153   // Fujitsu Motif seems to be buggy for HaL's Restraint widget.
154   // You must not destroy and re-create the Restraint widget.
155   // Instead keep the same Restraint widget forever. - 10/22/94 kamiya
156
157   // Create a group with a single term if none provided.
158   if (query == NULL)
159     {
160       query = new QueryGroup();
161       // This QueryTerm is pointed to by the QueryGroup.
162       new QueryTerm (query, NULL, NULL);
163     }
164
165   f_query = query;
166
167   // re-load the query terms
168   if (f_query_view != NULL)
169         f_query_view->re_load_terms(f_query);
170
171 #else
172   // Clean up old junk.
173   // The query isn't destroyed sometimes??
174   // Need to nuke only if it isn't saved on the history list.  DJB 
175   if (f_query_view != NULL)
176     {
177       QueryGroup *group = f_query_view->query_group();
178       f_query_view->destroy_widgets();
179       delete f_query_view;
180       delete f_query;
181     }
182
183   // NOTE: old query probably leaked!! 15:06 01/29/93 DJB
184   // This is going to need to be fixed up to edit pre-existing querys.
185   // NOTE: Another problem if this is called before the UI is created,
186   // because thar's widgets created below.  17:19 02/03/93 DJB
187   f_query = query;
188
189   // Create a group with a single term if none provided.
190   if (f_query == NULL)
191     {
192       f_null_terms = 0;
193       f_query = new QueryGroup();
194       // This QueryTerm is pointed to by the QueryGroup.
195       new QueryTerm (f_query, NULL, NULL);
196     }
197
198   // QueryGroupView holds the pointer to the QueryGroup. 
199   f_query_view =
200     new QueryGroupView (f_query, WXmForm ((WObject &) f_query_area));
201 #endif
202
203   if (first_time)
204     {
205 //#ifdef UseFJMTF
206 #if 1
207       f_null_terms = 0;
208
209       // QueryGroupView holds the pointer to the QueryGroup. 
210       f_query_view = new QueryGroupView (f_query, f_query_area);
211 #endif
212       // Only let pane get small enough to show two query entries.
213       // Start with the whole scrolled window, then take out the scrolling
214       // area to leave the borders, then add the term height * 2 back in.
215       // NOTE: This really needs to use the height of one row.  If this
216       // dialog comes up with an existing query at this point, the
217       // height will be wrong.  We need to get the height of a single
218       // line somehow.  11:59 02/04/93 DJB 
219       f_query_area.
220         PaneMinimum (f_query_area.Height() -
221                      WCore (XtParent(XtParent(*f_query_view))).Height() +
222                      (2 * f_query_view->Height()));
223
224       // Take the height of each pane - the min size of each pane.
225       // That is the excess height of the dialog.
226       // This needs to equal the current height - min height.
227       // So subtract it from the current height to get the new min height.
228       WXmForm qform (XtParent(f_query_text.Parent()));
229 #ifdef DEBUG
230       printf ("qform height = %d, scrolled height = %d\n",
231               qform.Height(), f_query_area.Height());
232       printf ("qform min = %d, scrolled min = %d\n",
233               qform.PaneMinimum(), f_query_area.PaneMinimum());
234 #endif
235       Dimension excess_height = qform.Height() + f_query_area.Height() -
236         qform.PaneMinimum() - f_query_area.PaneMinimum();
237
238       ON_DEBUG(printf ("Query Editor excess height = %d\n", excess_height));
239
240       f_shell.MinHeight (f_shell.Height() - excess_height);
241       
242       first_time = False;
243     }
244
245   //g_allow_query_text_change = TRUE;
246   f_query_text.Value ("");
247   //g_allow_query_text_change = FALSE;
248
249   // Move the input focus to the term view.
250   f_query_area.InitialFocus (*f_query_view);
251   //  f_query_view->traverse_here();
252
253   display();
254 }
255
256
257 // /////////////////////////////////////////////////////////////////
258 // create_ui - create the query editor user interface
259 // /////////////////////////////////////////////////////////////////
260
261 #define AM WAutoManage
262
263 void
264 QueryEditor::create_ui()
265 {
266   Wait_Cursor bob;
267
268   XmStringLocalized mtfstring;
269   String            string;
270   KeySym            mnemonic;
271
272   f_shell = WTopLevelShell(window_system().toplevel(), WPopup, "query_editor");
273   window_system().register_shell (&f_shell);
274
275   string = CATGETS(Set_QueryEditor, 1, "Dtinfo: Query Editor");
276   XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
277
278   // Main form and menu bar. 
279   WXmForm form                      (f_shell,    "form"                );
280   WXmMenuBar menu_bar               (form,       "menu_bar"            );
281
282   WXmPulldownMenu scope_menu        (form,       "scope_menu");
283   Arg args[1];
284   int n = 0;
285   XtSetArg(args[n], XmNsubMenuId, (Widget) scope_menu); n++;
286   f_scope_option = WXmOptionMenu    (form,       "scope_option", AM, args, n);
287
288   mtfstring = CATGETS(Set_AgentLabel, 212, "Scope Name");
289   XtVaSetValues(f_scope_option, XmNlabelString, (XmString)mtfstring, NULL);
290
291   // Menu definitions.   how about using AddPushButton (name, obj, fun)??
292   WXmCascadeButton edit_cascade     (menu_bar,   "edit",             AM);
293   WXmPulldownMenu edit_menu         (menu_bar,   "edit_menu"           );
294   f_cut_btn = WXmPushButton         (edit_menu,  "cut",              AM);
295   f_copy_btn = WXmPushButton        (edit_menu,  "copy",             AM);
296   f_paste_btn = WXmPushButton       (edit_menu,  "paste",            AM);
297   f_paste_btn = WXmPushButton       (edit_menu,  "new_term",         AM);
298   WXmSeparator group_sep            (edit_menu,  "group_sep",        AM);
299   f_group_btn = WXmPushButton       (edit_menu,  "group",            AM);
300   f_ungroup_btn = WXmPushButton     (edit_menu,  "ungroup",          AM);
301   WXmSeparator undo_sep             (edit_menu,  "undo_sep",         AM);
302   f_undo_btn = WXmPushButton        (edit_menu,  "undo",             AM);
303   f_redo_btn = WXmPushButton        (edit_menu,  "redo",             AM);
304
305   mtfstring =  CATGETS(Set_AgentLabel, 16, "Edit");
306   mnemonic  = *CATGETS(Set_AgentLabel, 17, "E");
307   XtVaSetValues(edit_cascade, XmNlabelString, (XmString)mtfstring,
308                               XmNmnemonic, mnemonic, NULL);
309   mtfstring =  CATGETS(Set_AgentLabel, 224, "Cut");
310   XtVaSetValues(f_cut_btn, XmNlabelString, (XmString)mtfstring, NULL);
311   mtfstring =  CATGETS(Set_AgentLabel, 18, "Copy");
312   XtVaSetValues(f_copy_btn, XmNlabelString, (XmString)mtfstring, NULL);
313   mtfstring =  CATGETS(Set_AgentLabel, 225, "Paste");
314   XtVaSetValues(f_paste_btn, XmNlabelString, (XmString)mtfstring, NULL);
315   mtfstring =  CATGETS(Set_AgentLabel, 226, "Group");
316   XtVaSetValues(f_group_btn, XmNlabelString, (XmString)mtfstring, NULL);
317   mtfstring =  CATGETS(Set_AgentLabel, 227, "Ungroup");
318   XtVaSetValues(f_ungroup_btn, XmNlabelString, (XmString)mtfstring, NULL);
319   mtfstring =  CATGETS(Set_AgentLabel, 228, "Undo");
320   XtVaSetValues(f_undo_btn, XmNlabelString, (XmString)mtfstring, NULL);
321   mtfstring =  CATGETS(Set_AgentLabel, 229, "Redo");
322   XtVaSetValues(f_redo_btn, XmNlabelString, (XmString)mtfstring, NULL);
323
324   // Button area at the bottom 
325   WXmForm hform                     (form,       "hform"               );
326   f_hist_prev = WXmArrowButton      (hform,      "hist_prev",        AM);
327   f_hist_next = WXmArrowButton      (hform,      "hist_next",        AM);
328   WXmLabel history                  (hform,      "history",          AM);
329   f_search_btn = WXmPushButton      (form,       "search",           AM);
330   WXmPushButton cancel              (form,       "cancel",           AM);
331   WXmPushButton clear               (form,       "clear",            AM);
332   WXmPushButton scope               (form,       "scope",            AM);
333   WXmPushButton help                (form,       "help",             AM);
334   WXmSeparator separator            (form,       "separator",        AM);
335
336   mtfstring =  CATGETS(Set_AgentLabel, 92, "History");
337   XtVaSetValues(history, XmNlabelString, (XmString)mtfstring, NULL);
338   mtfstring =  CATGETS(Set_AgentLabel, 102, "Search");
339   XtVaSetValues(f_search_btn, XmNlabelString, (XmString)mtfstring, NULL);
340   mtfstring =  CATGETS(Set_AgentLabel, 231, "Clear All");
341   XtVaSetValues(clear, XmNlabelString, (XmString)mtfstring, NULL);
342   mtfstring =  CATGETS(Set_AgentLabel, 46, "Scope Editor");
343   XtVaSetValues(scope, XmNlabelString, (XmString)mtfstring, NULL);
344   mtfstring =  CATGETS(Set_AgentLabel, 12, "Close");
345   XtVaSetValues(cancel, XmNlabelString, (XmString)mtfstring, NULL);
346   mtfstring =  CATGETS(Set_AgentLabel, 48, "Help");
347   XtVaSetValues(help, XmNlabelString, (XmString)mtfstring, NULL);
348
349   help_agent().add_activate_help (help, "query_editor_help");
350
351   // Main "work" area 
352   WXmPanedWindow pane               (form,       "pane"                );
353   WXmForm qform                     (pane,       "qform"               );
354   WXmLabel qlabel                   (qform,      "qlabel",           AM);
355
356   mtfstring =  CATGETS(Set_AgentLabel, 230, "Query");
357   XtVaSetValues(qlabel, XmNlabelString, (XmString)mtfstring, NULL);
358   
359   f_query_text = WXmScrolledText    (qform,      "qtext",            AM);
360 //  f_query_text.SetEditable(False);
361   f_query_area = WXmScrolledWindow  (pane,       "query_area",       AM);
362   XtUnmanageChild (f_query_area.HorizontalScrollBar());
363
364   edit_cascade.SubMenuId (edit_menu);
365
366   // Callbacks
367   ON_ACTIVATE (f_search_btn, search_activate);
368   ON_ACTIVATE (cancel, cancel);
369   ON_ACTIVATE (clear, clear);
370   ON_ACTIVATE (scope, scope);
371
372 //  f_query_text.SetFocusCallback (this,
373 //                          (WWL_FUN) &QueryEditor::modify_verify);
374 //  f_query_text.SetModifyVerifyCallback (this,
375 //                          (WWL_FUN) &QueryEditor::modify_verify);
376
377   // Set minimum sizes.
378   qform.Manage();
379   pane.Manage();
380   //  hform.Manage();
381   form.DefaultButton (f_search_btn);
382   form.ShadowThickness (0);
383
384   form.InitialFocus (pane);
385   pane.InitialFocus (f_query_area);
386   qform.PaneMinimum (f_query_text.Height());
387   form.Manage();
388
389   f_shell.Realize();
390   f_shell.MinWidth (f_shell.Width());
391   f_shell.MinHeight (f_shell.Height());
392   ON_DEBUG(printf ("Query for height = %d\n", qform.Height()));
393   //cerr << "Query for height = " << qform.Height() << endl;
394
395 //#ifndef UseFJMTF
396 #if 1
397   // Swap the entries in the pane around.  Have to do this now
398   // to get initial sizes right.
399   qform.PositionIndex (1);
400 #endif
401
402   fill_menu();
403
404   UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
405   UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
406   UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
407
408   search_scope_mgr().option_menu(this);
409 }
410
411
412 // /////////////////////////////////////////////////////////////////
413 // search_activate
414 // /////////////////////////////////////////////////////////////////
415
416 void
417 QueryEditor::search_activate()
418 {
419   Wait_Cursor bob;
420
421   // Need to duplicate string returned, because it is in static data space. 
422   char *human_readable =
423     strdup (f_query_view->query_group()->
424             generate_query (QueryGroup::QUERY_TYPE_INFIX));
425
426 #ifdef DEBUG
427   fprintf(stderr, "(DEBUG) human_readable=\"%s\"\n", human_readable);
428 #endif
429
430   UAS_SearchScope *scope =
431     (UAS_SearchScope *) WXmPushButton (f_scope_option.MenuHistory()).UserData();
432
433   try {
434       // Search manager owns query from this point on.  Don't delete it here. 
435       search_mgr().parse_and_search (human_readable, scope);
436    }
437    catch (demoException &, demo) {
438       message_mgr().demo_failure(demo);
439    }
440    end_try;
441
442    free(human_readable);
443
444 }
445
446
447 // /////////////////////////////////////////////////////////////////
448 // cancel - close the window
449 // /////////////////////////////////////////////////////////////////
450
451 void
452 QueryEditor::cancel()
453 {
454   f_shell.Popdown();
455 }
456
457
458 // /////////////////////////////////////////////////////////////////
459 // empty term tracking routines
460 // /////////////////////////////////////////////////////////////////
461
462 void
463 QueryEditor::increment_null_terms()
464 {
465   if (f_null_terms == 0)
466     f_search_btn.SetSensitive (False);
467   f_null_terms++;
468   //  printf ("QueryEditor setting null_terms to %d\n", f_null_terms); 
469 }
470
471 void
472 QueryEditor::decrement_null_terms()
473 {
474   f_null_terms--;
475   //  printf ("QueryEditor setting null_terms to %d\n", f_null_terms); 
476   if (f_null_terms == 0)
477     f_search_btn.SetSensitive (True);
478 }
479
480
481 // /////////////////////////////////////////////////////////////////
482 // clear - clear the current query
483 // /////////////////////////////////////////////////////////////////
484
485 void
486 QueryEditor::clear()
487 {
488   edit_query (NULL);
489 }
490
491
492 // /////////////////////////////////////////////////////////////////////////
493 // scope - activate search scope dialog
494 // /////////////////////////////////////////////////////////////////////////
495 void
496 QueryEditor::scope()
497 {
498   search_scope_mgr().display();
499 }
500
501
502 // /////////////////////////////////////////////////////////////////
503 // query_changed - regenerate the text version
504 // /////////////////////////////////////////////////////////////////
505
506 void
507 QueryEditor::query_changed()
508 {
509   // Need to duplicate string returned, because it is in static data space. 
510 #ifdef UseQSearch
511   const char *human_readable =
512     f_query_view->query_group()->generate_readable();
513 #else
514   const char *human_readable =
515     f_query_view->query_group()->
516       generate_query (QueryGroup::QUERY_TYPE_INFIX);
517 #endif
518
519   //g_allow_query_text_change = TRUE;
520   f_query_text.Value ((char *) human_readable);
521   //g_allow_query_text_change = FALSE;
522 }
523
524
525 // /////////////////////////////////////////////////////////////////
526 // modify_verify
527 // /////////////////////////////////////////////////////////////////
528
529
530 void
531 QueryEditor::modify_verify (WCallback *wcb)
532 {
533 //  if (g_allow_query_text_change)
534 //    return;
535
536 //  XmTextVerifyPtr tvp = (XmTextVerifyPtr) wcb->CallData();
537
538   // Editing never allowed. 
539 //  tvp->doit = False;
540
541 //  message_mgr().warning_dialog (
542 //      (char*)UAS_String(CATGETS(Set_Messages, 47,
543 //                              "This is a display-only field.")));
544 }
545
546
547 // /////////////////////////////////////////////////////////////////
548 // fill_menu - initially file in the scope option menu
549 // /////////////////////////////////////////////////////////////////
550
551 void
552 QueryEditor::fill_menu()
553 {
554   int position = 0;
555   // Create push buttons for each scope.
556   xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
557   List_Iterator<UAS_SearchScope *> s (scope_list);
558   bool old_read_only = TRUE;
559
560   for (; s != NULL; s++)
561     {
562       // Add a separator when they change from read only to changable. 
563       if (old_read_only != s.item()->read_only())
564         {
565           DECLM (WXmSeparator, sep1, f_scope_option.SubMenuId(), "separator");
566           sep1.PositionIndex (position++);
567           old_read_only = FALSE;
568         }
569       DECLM (WXmPushButton, scope,f_scope_option.SubMenuId(),s.item()->name());
570       scope.UserData (s.item());
571       scope.PositionIndex (position++);
572     }
573
574   // Do not want first item (Current Section)
575
576 #ifdef __osf__
577 #if 1
578   Widget w = f_scope_option.SubMenuId();
579   WComposite temp_composite(w);
580   WXmPushButton(temp_composite.Children()[0]).Unmanage();
581 #else
582   int i = 0;
583   Widget w = f_scope_option.SubMenuId();;
584   Arg args[1];
585   WidgetList wl;
586   
587   XtSetArg(args[i], XmNchildren, &wl); i++;
588   XtGetValues(w, args, i);
589   XtUnmanageChild(wl[0]);
590 #endif
591 #else
592   WXmPushButton(WComposite(f_scope_option.SubMenuId()).Children()[0]).Unmanage();
593 #endif
594
595   f_scope_option.
596       MenuHistory (WComposite(f_scope_option.SubMenuId()).Children()[1]);
597   
598   //UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
599   //UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
600   //UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
601 //
602   //search_scope_mgr().option_menu(this);
603 }
604
605
606 // /////////////////////////////////////////////////////////////////
607 // receive* - handle updates to the list of scopes
608 // /////////////////////////////////////////////////////////////////
609
610 void
611 QueryEditor::receive (ScopeCreated &msg, void* /*client_data*/)
612 {
613   int position = 0;
614   const char *scope_name = msg.f_search_scope->name();
615   xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
616   List_Iterator<UAS_SearchScope *> s (scope_list);
617   bool need_sep = TRUE;
618
619   if (msg.f_search_scope->read_only())
620   {
621     // insert read-only scopes at the start; reserve position 0
622     // for "Current Section" scope and position 1 for
623     // the "All Libraries" scope
624     position = 2;
625     need_sep = FALSE;
626   }
627   else
628   {
629     // Scan the current menu to find the correct insertion position. 
630     UAS_SearchScope *scope;
631     for (; s != NULL; s++, position++)
632     {
633       scope = s.item();
634       if (scope->read_only() != need_sep)
635       {
636         position++;  // skip separator
637         need_sep = FALSE;
638       }
639       if (scope->read_only())
640         continue;
641       // Find the first item that the new entry belongs after.
642       ON_DEBUG (printf ("Scope Edit strcmp to <%s>\n", s.item()->name()));
643       if (strcmp (scope_name, scope->name()) < 0)
644         break;
645     }
646   }
647
648   ON_DEBUG (printf ("Final SE position = %d\n", position));
649
650   // Add a separator if this is the first user-defined entry. 
651   if (need_sep == TRUE)
652   {
653     DECLM (WXmSeparator, separator, f_scope_option.SubMenuId(), "separator");
654     separator.PositionIndex (position);
655     position++;
656   }
657
658   // Create the new toggle button. 
659   DECLM (WXmPushButton, scope, f_scope_option.SubMenuId(), scope_name);
660   scope.PositionIndex (position);
661   scope.UserData (msg.f_search_scope);
662 }
663
664
665 void
666 QueryEditor::receive (ScopeDeleted &msg, void* /*client_data*/)
667 {
668   // find the associated button and nuke it
669   ON_DEBUG (puts ("QueryEdit: handling delete message"));
670   // First find renamed button in our list.
671   WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
672   int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
673   int separator_pos = -1;
674   for (int i = 0; i < num_kids; i++)
675     {
676       if (XmIsSeparator (kids[i]))
677         separator_pos = i + 1;
678       if (msg.f_search_scope ==
679           ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
680         break;
681     }
682
683   // It had better be in the list! 
684   Xassert (i != num_kids);
685   ON_DEBUG (printf ("  widget #%d is the button\n", i));
686
687   // if it is selected, select first w/ callback called
688   if (kids[i] == f_scope_option.MenuHistory())
689     f_scope_option.MenuHistory (kids[1]);
690   XtDestroyWidget (kids[i]);
691
692   ON_DEBUG (printf ("QueryEditor: sep pos = %d, kids = %d (%d)\n",
693                     separator_pos, num_kids, num_kids - 1));
694   if (separator_pos == num_kids - 1)
695     {
696       ON_DEBUG (puts ("   destroying separator"));
697       XtDestroyWidget (kids[separator_pos-1]);
698     }
699 }
700
701
702 void
703 QueryEditor::receive (ScopeRenamed &msg, void* /*client_data*/)
704 {
705   ON_DEBUG (puts ("QueryEdit: handling rename message"));
706   // First find renamed button in our list.
707   WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
708   int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
709   for (int i = 0; i < num_kids; i++)
710     {
711       if (msg.f_search_scope ==
712           ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
713         break;
714     }
715
716   // It had better be in the list! 
717   Xassert (i != num_kids);
718   ON_DEBUG (printf ("QueryEdit: widget #%d is the button\n", i));
719
720   // Now find the new insertion position in the list.
721   int position = 0;
722   xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
723   List_Iterator<UAS_SearchScope *> s (scope_list);
724
725   // find the new position in the list
726   for (; s != NULL; s++)
727     {
728       if (s.item() == msg.f_search_scope)
729         continue;
730       position++;
731       if (s.item()->read_only())
732         continue;
733       ON_DEBUG (printf ("QueryEdit: strcmp <%s>\n", s.item()->name()));
734       if (strcmp (msg.f_search_scope->name(), s.item()->name()) < 0)
735         break;
736     }
737
738   ON_DEBUG (printf ("QueryEdit: Rename position = %d\n", position));
739   WXmPushButton scope_btn (kids[i]);
740   scope_btn.LabelString (msg.f_search_scope->name());
741   scope_btn.PositionIndex (position);
742 }
743
744 void
745 QueryEditor::update_option_menu()
746 {
747   WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
748   int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
749
750   // destroy all toggle buttons in menu
751   for (int i = 0; i < num_kids; i++)
752   {
753     XtUnmanageChild (kids[i]);
754     XtDestroyWidget (kids[i]);
755   }
756
757   fill_menu();
758 }