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