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