1 /* Copyright (c) 1994,1995,1996 FUJITSU LIMITED */
2 /* All Rights Reserved */
5 * $XConsortium: QueryEditor.C /main/14 1996/10/11 17:11:51 cde-hal $
7 * Copyright (c) 1992 HAL Computer Systems International, Ltd.
8 * All rights reserved. Unpublished -- rights reserved under
9 * the Copyright Laws of the United States. USE OF A COPYRIGHT
10 * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
13 * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
14 * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE,
15 * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
16 * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
19 * RESTRICTED RIGHTS LEGEND
20 * Use, duplication, or disclosure by the Government is subject
21 * to the restrictions as set forth in subparagraph (c)(l)(ii)
22 * of the Rights in Technical Data and Computer Software clause
23 * at DFARS 252.227-7013.
25 * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
34 #define C_WindowSystem
40 #define C_QueryGroupView
47 #define C_SearchScopeMgr
51 #include "Other/XmStringLocalized.hh"
52 #include "Managers/CatMgr.hh"
56 #include "Registration.hh"
58 #include <WWL/WXmMenu.h>
59 #include <WWL/WXmForm.h>
60 #include <WWL/WXmLabel.h>
61 #include <WWL/WXmCascadeButton.h>
62 #include <WWL/WXmSeparator.h>
63 #include <WWL/WXmPanedWindow.h>
68 #define CLASS QueryEditor
69 #include "../Agents/create_macros.hh"
71 //static bool g_allow_query_text_change;
73 QueryEditor *QueryEditor::f_query_editor;
75 // /////////////////////////////////////////////////////////////////
77 // /////////////////////////////////////////////////////////////////
79 QueryEditor::QueryEditor(UAS_SearchEngine& search_engine)
85 f_query_editor = this;
87 // NOTE: QueryTerm::f_caps is global. It needs to be term-wise
88 // to get terms to have varied capabilities.
89 QueryTerm::avail_caps(search_engine.avail_caps());
92 fprintf(stderr, "(DEBUG) search engine capabilities = 0x%x\n",
93 QueryTerm::avail_caps());
98 // /////////////////////////////////////////////////////////////////
99 // display - display the query editor
100 // /////////////////////////////////////////////////////////////////
103 QueryEditor::display()
105 static int count = 0;
120 // /////////////////////////////////////////////////////////////////
121 // new_query - set up interface for a new query
122 // /////////////////////////////////////////////////////////////////
125 QueryEditor::edit_query (QueryGroup *query)
127 static Boolean first_time = True;
131 // Fujitsu Motif seems to be buggy for HaL's Restraint widget.
132 // You must not destroy and re-create the Restraint widget.
133 // Instead keep the same Restraint widget forever. - 10/22/94 kamiya
135 // Create a group with a single term if none provided.
138 query = new QueryGroup();
139 // This QueryTerm is pointed to by the QueryGroup.
140 new QueryTerm (query, NULL, NULL);
145 // re-load the query terms
146 if (f_query_view != NULL)
147 f_query_view->re_load_terms(f_query);
150 // Clean up old junk.
151 // The query isn't destroyed sometimes??
152 // Need to nuke only if it isn't saved on the history list. DJB
153 if (f_query_view != NULL)
155 QueryGroup *group = f_query_view->query_group();
156 f_query_view->destroy_widgets();
161 // NOTE: old query probably leaked!! 15:06 01/29/93 DJB
162 // This is going to need to be fixed up to edit pre-existing querys.
163 // NOTE: Another problem if this is called before the UI is created,
164 // because thar's widgets created below. 17:19 02/03/93 DJB
167 // Create a group with a single term if none provided.
171 f_query = new QueryGroup();
172 // This QueryTerm is pointed to by the QueryGroup.
173 new QueryTerm (f_query, NULL, NULL);
176 // QueryGroupView holds the pointer to the QueryGroup.
178 new QueryGroupView (f_query, WXmForm ((WObject &) f_query_area));
187 // QueryGroupView holds the pointer to the QueryGroup.
188 f_query_view = new QueryGroupView (f_query, f_query_area);
190 // Only let pane get small enough to show two query entries.
191 // Start with the whole scrolled window, then take out the scrolling
192 // area to leave the borders, then add the term height * 2 back in.
193 // NOTE: This really needs to use the height of one row. If this
194 // dialog comes up with an existing query at this point, the
195 // height will be wrong. We need to get the height of a single
196 // line somehow. 11:59 02/04/93 DJB
198 PaneMinimum (f_query_area.Height() -
199 WCore (XtParent(XtParent(*f_query_view))).Height() +
200 (2 * f_query_view->Height()));
202 // Take the height of each pane - the min size of each pane.
203 // That is the excess height of the dialog.
204 // This needs to equal the current height - min height.
205 // So subtract it from the current height to get the new min height.
206 WXmForm qform (XtParent(f_query_text.Parent()));
208 printf ("qform height = %d, scrolled height = %d\n",
209 qform.Height(), f_query_area.Height());
210 printf ("qform min = %d, scrolled min = %d\n",
211 qform.PaneMinimum(), f_query_area.PaneMinimum());
213 Dimension excess_height = qform.Height() + f_query_area.Height() -
214 qform.PaneMinimum() - f_query_area.PaneMinimum();
216 ON_DEBUG(printf ("Query Editor excess height = %d\n", excess_height));
218 f_shell.MinHeight (f_shell.Height() - excess_height);
223 //g_allow_query_text_change = TRUE;
224 f_query_text.Value ("");
225 //g_allow_query_text_change = FALSE;
227 // Move the input focus to the term view.
228 f_query_area.InitialFocus (*f_query_view);
229 // f_query_view->traverse_here();
235 // /////////////////////////////////////////////////////////////////
236 // create_ui - create the query editor user interface
237 // /////////////////////////////////////////////////////////////////
239 #define AM WAutoManage
242 QueryEditor::create_ui()
246 XmStringLocalized mtfstring;
250 f_shell = WTopLevelShell(window_system().toplevel(), WPopup, "query_editor");
251 window_system().register_shell (&f_shell);
253 string = CATGETS(Set_QueryEditor, 1, "Dtinfo: Query Editor");
254 XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
256 // Main form and menu bar.
257 WXmForm form (f_shell, "form" );
258 WXmMenuBar menu_bar (form, "menu_bar" );
260 WXmPulldownMenu scope_menu (form, "scope_menu");
263 XtSetArg(args[n], XmNsubMenuId, (Widget) scope_menu); n++;
264 f_scope_option = WXmOptionMenu (form, "scope_option", AM, args, n);
266 mtfstring = CATGETS(Set_AgentLabel, 212, "Scope Name");
267 XtVaSetValues(f_scope_option, XmNlabelString, (XmString)mtfstring, NULL);
269 // Menu definitions. how about using AddPushButton (name, obj, fun)??
270 WXmCascadeButton edit_cascade (menu_bar, "edit", AM);
271 WXmPulldownMenu edit_menu (menu_bar, "edit_menu" );
272 f_cut_btn = WXmPushButton (edit_menu, "cut", AM);
273 f_copy_btn = WXmPushButton (edit_menu, "copy", AM);
274 f_paste_btn = WXmPushButton (edit_menu, "paste", AM);
275 f_paste_btn = WXmPushButton (edit_menu, "new_term", AM);
276 WXmSeparator group_sep (edit_menu, "group_sep", AM);
277 f_group_btn = WXmPushButton (edit_menu, "group", AM);
278 f_ungroup_btn = WXmPushButton (edit_menu, "ungroup", AM);
279 WXmSeparator undo_sep (edit_menu, "undo_sep", AM);
280 f_undo_btn = WXmPushButton (edit_menu, "undo", AM);
281 f_redo_btn = WXmPushButton (edit_menu, "redo", AM);
283 mtfstring = CATGETS(Set_AgentLabel, 16, "Edit");
284 mnemonic = *CATGETS(Set_AgentLabel, 17, "E");
285 XtVaSetValues(edit_cascade, XmNlabelString, (XmString)mtfstring,
286 XmNmnemonic, mnemonic, NULL);
287 mtfstring = CATGETS(Set_AgentLabel, 224, "Cut");
288 XtVaSetValues(f_cut_btn, XmNlabelString, (XmString)mtfstring, NULL);
289 mtfstring = CATGETS(Set_AgentLabel, 18, "Copy");
290 XtVaSetValues(f_copy_btn, XmNlabelString, (XmString)mtfstring, NULL);
291 mtfstring = CATGETS(Set_AgentLabel, 225, "Paste");
292 XtVaSetValues(f_paste_btn, XmNlabelString, (XmString)mtfstring, NULL);
293 mtfstring = CATGETS(Set_AgentLabel, 226, "Group");
294 XtVaSetValues(f_group_btn, XmNlabelString, (XmString)mtfstring, NULL);
295 mtfstring = CATGETS(Set_AgentLabel, 227, "Ungroup");
296 XtVaSetValues(f_ungroup_btn, XmNlabelString, (XmString)mtfstring, NULL);
297 mtfstring = CATGETS(Set_AgentLabel, 228, "Undo");
298 XtVaSetValues(f_undo_btn, XmNlabelString, (XmString)mtfstring, NULL);
299 mtfstring = CATGETS(Set_AgentLabel, 229, "Redo");
300 XtVaSetValues(f_redo_btn, XmNlabelString, (XmString)mtfstring, NULL);
302 // Button area at the bottom
303 WXmForm hform (form, "hform" );
304 f_hist_prev = WXmArrowButton (hform, "hist_prev", AM);
305 f_hist_next = WXmArrowButton (hform, "hist_next", AM);
306 WXmLabel history (hform, "history", AM);
307 f_search_btn = WXmPushButton (form, "search", AM);
308 WXmPushButton cancel (form, "cancel", AM);
309 WXmPushButton clear (form, "clear", AM);
310 WXmPushButton scope (form, "scope", AM);
311 WXmPushButton help (form, "help", AM);
312 WXmSeparator separator (form, "separator", AM);
314 mtfstring = CATGETS(Set_AgentLabel, 92, "History");
315 XtVaSetValues(history, XmNlabelString, (XmString)mtfstring, NULL);
316 mtfstring = CATGETS(Set_AgentLabel, 102, "Search");
317 XtVaSetValues(f_search_btn, XmNlabelString, (XmString)mtfstring, NULL);
318 mtfstring = CATGETS(Set_AgentLabel, 231, "Clear All");
319 XtVaSetValues(clear, XmNlabelString, (XmString)mtfstring, NULL);
320 mtfstring = CATGETS(Set_AgentLabel, 46, "Scope Editor");
321 XtVaSetValues(scope, XmNlabelString, (XmString)mtfstring, NULL);
322 mtfstring = CATGETS(Set_AgentLabel, 12, "Close");
323 XtVaSetValues(cancel, XmNlabelString, (XmString)mtfstring, NULL);
324 mtfstring = CATGETS(Set_AgentLabel, 48, "Help");
325 XtVaSetValues(help, XmNlabelString, (XmString)mtfstring, NULL);
327 help_agent().add_activate_help (help, "query_editor_help");
330 WXmPanedWindow pane (form, "pane" );
331 WXmForm qform (pane, "qform" );
332 WXmLabel qlabel (qform, "qlabel", AM);
334 mtfstring = CATGETS(Set_AgentLabel, 230, "Query");
335 XtVaSetValues(qlabel, XmNlabelString, (XmString)mtfstring, NULL);
337 f_query_text = WXmScrolledText (qform, "qtext", AM);
338 // f_query_text.SetEditable(False);
339 f_query_area = WXmScrolledWindow (pane, "query_area", AM);
340 XtUnmanageChild (f_query_area.HorizontalScrollBar());
342 edit_cascade.SubMenuId (edit_menu);
345 ON_ACTIVATE (f_search_btn, search_activate);
346 ON_ACTIVATE (cancel, cancel);
347 ON_ACTIVATE (clear, clear);
348 ON_ACTIVATE (scope, scope);
350 // f_query_text.SetFocusCallback (this,
351 // (WWL_FUN) &QueryEditor::modify_verify);
352 // f_query_text.SetModifyVerifyCallback (this,
353 // (WWL_FUN) &QueryEditor::modify_verify);
355 // Set minimum sizes.
359 form.DefaultButton (f_search_btn);
360 form.ShadowThickness (0);
362 form.InitialFocus (pane);
363 pane.InitialFocus (f_query_area);
364 qform.PaneMinimum (f_query_text.Height());
368 f_shell.MinWidth (f_shell.Width());
369 f_shell.MinHeight (f_shell.Height());
370 ON_DEBUG(printf ("Query for height = %d\n", qform.Height()));
371 //cerr << "Query for height = " << qform.Height() << endl;
375 // Swap the entries in the pane around. Have to do this now
376 // to get initial sizes right.
377 qform.PositionIndex (1);
382 UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
383 UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
384 UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
386 search_scope_mgr().option_menu(this);
390 // /////////////////////////////////////////////////////////////////
392 // /////////////////////////////////////////////////////////////////
395 QueryEditor::search_activate()
399 // Need to duplicate string returned, because it is in static data space.
400 char *human_readable =
401 strdup (f_query_view->query_group()->
402 generate_query (QueryGroup::QUERY_TYPE_INFIX));
405 fprintf(stderr, "(DEBUG) human_readable=\"%s\"\n", human_readable);
408 UAS_SearchScope *scope =
409 (UAS_SearchScope *) WXmPushButton (f_scope_option.MenuHistory()).UserData();
412 // Search manager owns query from this point on. Don't delete it here.
413 search_mgr().parse_and_search (human_readable, scope);
415 catch (demoException &, demo) {
416 message_mgr().demo_failure(demo);
420 free(human_readable);
425 // /////////////////////////////////////////////////////////////////
426 // cancel - close the window
427 // /////////////////////////////////////////////////////////////////
430 QueryEditor::cancel()
436 // /////////////////////////////////////////////////////////////////
437 // empty term tracking routines
438 // /////////////////////////////////////////////////////////////////
441 QueryEditor::increment_null_terms()
443 if (f_null_terms == 0)
444 f_search_btn.SetSensitive (False);
446 // printf ("QueryEditor setting null_terms to %d\n", f_null_terms);
450 QueryEditor::decrement_null_terms()
453 // printf ("QueryEditor setting null_terms to %d\n", f_null_terms);
454 if (f_null_terms == 0)
455 f_search_btn.SetSensitive (True);
459 // /////////////////////////////////////////////////////////////////
460 // clear - clear the current query
461 // /////////////////////////////////////////////////////////////////
470 // /////////////////////////////////////////////////////////////////////////
471 // scope - activate search scope dialog
472 // /////////////////////////////////////////////////////////////////////////
476 search_scope_mgr().display();
480 // /////////////////////////////////////////////////////////////////
481 // query_changed - regenerate the text version
482 // /////////////////////////////////////////////////////////////////
485 QueryEditor::query_changed()
487 // Need to duplicate string returned, because it is in static data space.
489 const char *human_readable =
490 f_query_view->query_group()->generate_readable();
492 const char *human_readable =
493 f_query_view->query_group()->
494 generate_query (QueryGroup::QUERY_TYPE_INFIX);
497 //g_allow_query_text_change = TRUE;
498 f_query_text.Value ((char *) human_readable);
499 //g_allow_query_text_change = FALSE;
503 // /////////////////////////////////////////////////////////////////
505 // /////////////////////////////////////////////////////////////////
509 QueryEditor::modify_verify (WCallback *wcb)
511 // if (g_allow_query_text_change)
514 // XmTextVerifyPtr tvp = (XmTextVerifyPtr) wcb->CallData();
516 // Editing never allowed.
517 // tvp->doit = False;
519 // message_mgr().warning_dialog (
520 // (char*)UAS_String(CATGETS(Set_Messages, 47,
521 // "This is a display-only field.")));
525 // /////////////////////////////////////////////////////////////////
526 // fill_menu - initially file in the scope option menu
527 // /////////////////////////////////////////////////////////////////
530 QueryEditor::fill_menu()
533 // Create push buttons for each scope.
534 xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
535 List_Iterator<UAS_SearchScope *> s (scope_list);
536 bool old_read_only = TRUE;
538 for (; s != NULL; s++)
540 // Add a separator when they change from read only to changable.
541 if (old_read_only != s.item()->read_only())
543 DECLM (WXmSeparator, sep1, f_scope_option.SubMenuId(), "separator");
544 sep1.PositionIndex (position++);
545 old_read_only = FALSE;
547 DECLM (WXmPushButton, scope,f_scope_option.SubMenuId(),s.item()->name());
548 scope.UserData (s.item());
549 scope.PositionIndex (position++);
552 // Do not want first item (Current Section)
556 Widget w = f_scope_option.SubMenuId();
557 WComposite temp_composite(w);
558 WXmPushButton(temp_composite.Children()[0]).Unmanage();
561 Widget w = f_scope_option.SubMenuId();;
565 XtSetArg(args[i], XmNchildren, &wl); i++;
566 XtGetValues(w, args, i);
567 XtUnmanageChild(wl[0]);
570 WXmPushButton(WComposite(f_scope_option.SubMenuId()).Children()[0]).Unmanage();
574 MenuHistory (WComposite(f_scope_option.SubMenuId()).Children()[1]);
576 //UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
577 //UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
578 //UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
580 //search_scope_mgr().option_menu(this);
584 // /////////////////////////////////////////////////////////////////
585 // receive* - handle updates to the list of scopes
586 // /////////////////////////////////////////////////////////////////
589 QueryEditor::receive (ScopeCreated &msg, void* /*client_data*/)
592 const char *scope_name = msg.f_search_scope->name();
593 xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
594 List_Iterator<UAS_SearchScope *> s (scope_list);
595 bool need_sep = TRUE;
597 if (msg.f_search_scope->read_only())
599 // insert read-only scopes at the start; reserve position 0
600 // for "Current Section" scope and position 1 for
601 // the "All Libraries" scope
607 // Scan the current menu to find the correct insertion position.
608 UAS_SearchScope *scope;
609 for (; s != NULL; s++, position++)
612 if (scope->read_only() != need_sep)
614 position++; // skip separator
617 if (scope->read_only())
619 // Find the first item that the new entry belongs after.
620 ON_DEBUG (printf ("Scope Edit strcmp to <%s>\n", s.item()->name()));
621 if (strcmp (scope_name, scope->name()) < 0)
626 ON_DEBUG (printf ("Final SE position = %d\n", position));
628 // Add a separator if this is the first user-defined entry.
629 if (need_sep == TRUE)
631 DECLM (WXmSeparator, separator, f_scope_option.SubMenuId(), "separator");
632 separator.PositionIndex (position);
636 // Create the new toggle button.
637 DECLM (WXmPushButton, scope, f_scope_option.SubMenuId(), scope_name);
638 scope.PositionIndex (position);
639 scope.UserData (msg.f_search_scope);
644 QueryEditor::receive (ScopeDeleted &msg, void* /*client_data*/)
646 // find the associated button and nuke it
647 ON_DEBUG (puts ("QueryEdit: handling delete message"));
648 // First find renamed button in our list.
649 WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
650 int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
651 int separator_pos = -1;
652 for (int i = 0; i < num_kids; i++)
654 if (XmIsSeparator (kids[i]))
655 separator_pos = i + 1;
656 if (msg.f_search_scope ==
657 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
661 // It had better be in the list!
662 Xassert (i != num_kids);
663 ON_DEBUG (printf (" widget #%d is the button\n", i));
665 // if it is selected, select first w/ callback called
666 if (kids[i] == f_scope_option.MenuHistory())
667 f_scope_option.MenuHistory (kids[1]);
668 XtDestroyWidget (kids[i]);
670 ON_DEBUG (printf ("QueryEditor: sep pos = %d, kids = %d (%d)\n",
671 separator_pos, num_kids, num_kids - 1));
672 if (separator_pos == num_kids - 1)
674 ON_DEBUG (puts (" destroying separator"));
675 XtDestroyWidget (kids[separator_pos-1]);
681 QueryEditor::receive (ScopeRenamed &msg, void* /*client_data*/)
683 ON_DEBUG (puts ("QueryEdit: handling rename message"));
684 // First find renamed button in our list.
685 WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
686 int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
687 for (int i = 0; i < num_kids; i++)
689 if (msg.f_search_scope ==
690 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
694 // It had better be in the list!
695 Xassert (i != num_kids);
696 ON_DEBUG (printf ("QueryEdit: widget #%d is the button\n", i));
698 // Now find the new insertion position in the list.
700 xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
701 List_Iterator<UAS_SearchScope *> s (scope_list);
703 // find the new position in the list
704 for (; s != NULL; s++)
706 if (s.item() == msg.f_search_scope)
709 if (s.item()->read_only())
711 ON_DEBUG (printf ("QueryEdit: strcmp <%s>\n", s.item()->name()));
712 if (strcmp (msg.f_search_scope->name(), s.item()->name()) < 0)
716 ON_DEBUG (printf ("QueryEdit: Rename position = %d\n", position));
717 WXmPushButton scope_btn (kids[i]);
718 scope_btn.LabelString (msg.f_search_scope->name());
719 scope_btn.PositionIndex (position);
723 QueryEditor::update_option_menu()
725 WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
726 int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
728 // destroy all toggle buttons in menu
729 for (int i = 0; i < num_kids; i++)
731 XtUnmanageChild (kids[i]);
732 XtDestroyWidget (kids[i]);