2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* Copyright (c) 1994,1995,1996 FUJITSU LIMITED */
24 /* All Rights Reserved */
27 * $XConsortium: QueryEditor.C /main/14 1996/10/11 17:11:51 cde-hal $
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
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
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.
47 * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
56 #define C_WindowSystem
62 #define C_QueryGroupView
69 #define C_SearchScopeMgr
73 #include "Other/XmStringLocalized.hh"
74 #include "Managers/CatMgr.hh"
78 #include "Registration.hh"
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>
90 #define CLASS QueryEditor
91 #include "../Agents/create_macros.hh"
93 //static bool g_allow_query_text_change;
95 QueryEditor *QueryEditor::f_query_editor;
97 // /////////////////////////////////////////////////////////////////
99 // /////////////////////////////////////////////////////////////////
101 QueryEditor::QueryEditor(UAS_SearchEngine& search_engine)
107 f_query_editor = this;
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());
114 fprintf(stderr, "(DEBUG) search engine capabilities = 0x%x\n",
115 QueryTerm::avail_caps());
120 // /////////////////////////////////////////////////////////////////
121 // display - display the query editor
122 // /////////////////////////////////////////////////////////////////
125 QueryEditor::display()
127 static int count = 0;
142 // /////////////////////////////////////////////////////////////////
143 // new_query - set up interface for a new query
144 // /////////////////////////////////////////////////////////////////
147 QueryEditor::edit_query (QueryGroup *query)
149 static Boolean first_time = True;
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
157 // Create a group with a single term if none provided.
160 query = new QueryGroup();
161 // This QueryTerm is pointed to by the QueryGroup.
162 new QueryTerm (query, NULL, NULL);
167 // re-load the query terms
168 if (f_query_view != NULL)
169 f_query_view->re_load_terms(f_query);
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)
177 QueryGroup *group = f_query_view->query_group();
178 f_query_view->destroy_widgets();
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
189 // Create a group with a single term if none provided.
193 f_query = new QueryGroup();
194 // This QueryTerm is pointed to by the QueryGroup.
195 new QueryTerm (f_query, NULL, NULL);
198 // QueryGroupView holds the pointer to the QueryGroup.
200 new QueryGroupView (f_query, WXmForm ((WObject &) f_query_area));
209 // QueryGroupView holds the pointer to the QueryGroup.
210 f_query_view = new QueryGroupView (f_query, f_query_area);
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
220 PaneMinimum (f_query_area.Height() -
221 WCore (XtParent(XtParent(*f_query_view))).Height() +
222 (2 * f_query_view->Height()));
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()));
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());
235 Dimension excess_height = qform.Height() + f_query_area.Height() -
236 qform.PaneMinimum() - f_query_area.PaneMinimum();
238 ON_DEBUG(printf ("Query Editor excess height = %d\n", excess_height));
240 f_shell.MinHeight (f_shell.Height() - excess_height);
245 //g_allow_query_text_change = TRUE;
246 f_query_text.Value ("");
247 //g_allow_query_text_change = FALSE;
249 // Move the input focus to the term view.
250 f_query_area.InitialFocus (*f_query_view);
251 // f_query_view->traverse_here();
257 // /////////////////////////////////////////////////////////////////
258 // create_ui - create the query editor user interface
259 // /////////////////////////////////////////////////////////////////
261 #define AM WAutoManage
264 QueryEditor::create_ui()
268 XmStringLocalized mtfstring;
272 f_shell = WTopLevelShell(window_system().toplevel(), WPopup, "query_editor");
273 window_system().register_shell (&f_shell);
275 string = CATGETS(Set_QueryEditor, 1, "Dtinfo: Query Editor");
276 XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
278 // Main form and menu bar.
279 WXmForm form (f_shell, "form" );
280 WXmMenuBar menu_bar (form, "menu_bar" );
282 WXmPulldownMenu scope_menu (form, "scope_menu");
285 XtSetArg(args[n], XmNsubMenuId, (Widget) scope_menu); n++;
286 f_scope_option = WXmOptionMenu (form, "scope_option", AM, args, n);
288 mtfstring = CATGETS(Set_AgentLabel, 212, "Scope Name");
289 XtVaSetValues(f_scope_option, XmNlabelString, (XmString)mtfstring, NULL);
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);
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);
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);
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);
349 help_agent().add_activate_help (help, "query_editor_help");
352 WXmPanedWindow pane (form, "pane" );
353 WXmForm qform (pane, "qform" );
354 WXmLabel qlabel (qform, "qlabel", AM);
356 mtfstring = CATGETS(Set_AgentLabel, 230, "Query");
357 XtVaSetValues(qlabel, XmNlabelString, (XmString)mtfstring, NULL);
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());
364 edit_cascade.SubMenuId (edit_menu);
367 ON_ACTIVATE (f_search_btn, search_activate);
368 ON_ACTIVATE (cancel, cancel);
369 ON_ACTIVATE (clear, clear);
370 ON_ACTIVATE (scope, scope);
372 // f_query_text.SetFocusCallback (this,
373 // (WWL_FUN) &QueryEditor::modify_verify);
374 // f_query_text.SetModifyVerifyCallback (this,
375 // (WWL_FUN) &QueryEditor::modify_verify);
377 // Set minimum sizes.
381 form.DefaultButton (f_search_btn);
382 form.ShadowThickness (0);
384 form.InitialFocus (pane);
385 pane.InitialFocus (f_query_area);
386 qform.PaneMinimum (f_query_text.Height());
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;
397 // Swap the entries in the pane around. Have to do this now
398 // to get initial sizes right.
399 qform.PositionIndex (1);
404 UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
405 UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
406 UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
408 search_scope_mgr().option_menu(this);
412 // /////////////////////////////////////////////////////////////////
414 // /////////////////////////////////////////////////////////////////
417 QueryEditor::search_activate()
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));
427 fprintf(stderr, "(DEBUG) human_readable=\"%s\"\n", human_readable);
430 UAS_SearchScope *scope =
431 (UAS_SearchScope *) WXmPushButton (f_scope_option.MenuHistory()).UserData();
434 // Search manager owns query from this point on. Don't delete it here.
435 search_mgr().parse_and_search (human_readable, scope);
437 catch (demoException &, demo) {
438 message_mgr().demo_failure(demo);
442 free(human_readable);
447 // /////////////////////////////////////////////////////////////////
448 // cancel - close the window
449 // /////////////////////////////////////////////////////////////////
452 QueryEditor::cancel()
458 // /////////////////////////////////////////////////////////////////
459 // empty term tracking routines
460 // /////////////////////////////////////////////////////////////////
463 QueryEditor::increment_null_terms()
465 if (f_null_terms == 0)
466 f_search_btn.SetSensitive (False);
468 // printf ("QueryEditor setting null_terms to %d\n", f_null_terms);
472 QueryEditor::decrement_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);
481 // /////////////////////////////////////////////////////////////////
482 // clear - clear the current query
483 // /////////////////////////////////////////////////////////////////
492 // /////////////////////////////////////////////////////////////////////////
493 // scope - activate search scope dialog
494 // /////////////////////////////////////////////////////////////////////////
498 search_scope_mgr().display();
502 // /////////////////////////////////////////////////////////////////
503 // query_changed - regenerate the text version
504 // /////////////////////////////////////////////////////////////////
507 QueryEditor::query_changed()
509 // Need to duplicate string returned, because it is in static data space.
511 const char *human_readable =
512 f_query_view->query_group()->generate_readable();
514 const char *human_readable =
515 f_query_view->query_group()->
516 generate_query (QueryGroup::QUERY_TYPE_INFIX);
519 //g_allow_query_text_change = TRUE;
520 f_query_text.Value ((char *) human_readable);
521 //g_allow_query_text_change = FALSE;
525 // /////////////////////////////////////////////////////////////////
527 // /////////////////////////////////////////////////////////////////
531 QueryEditor::modify_verify (WCallback *wcb)
533 // if (g_allow_query_text_change)
536 // XmTextVerifyPtr tvp = (XmTextVerifyPtr) wcb->CallData();
538 // Editing never allowed.
539 // tvp->doit = False;
541 // message_mgr().warning_dialog (
542 // (char*)UAS_String(CATGETS(Set_Messages, 47,
543 // "This is a display-only field.")));
547 // /////////////////////////////////////////////////////////////////
548 // fill_menu - initially file in the scope option menu
549 // /////////////////////////////////////////////////////////////////
552 QueryEditor::fill_menu()
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;
560 for (; s != NULL; s++)
562 // Add a separator when they change from read only to changable.
563 if (old_read_only != s.item()->read_only())
565 DECLM (WXmSeparator, sep1, f_scope_option.SubMenuId(), "separator");
566 sep1.PositionIndex (position++);
567 old_read_only = FALSE;
569 DECLM (WXmPushButton, scope,f_scope_option.SubMenuId(),s.item()->name());
570 scope.UserData (s.item());
571 scope.PositionIndex (position++);
574 // Do not want first item (Current Section)
578 Widget w = f_scope_option.SubMenuId();
579 WComposite temp_composite(w);
580 WXmPushButton(temp_composite.Children()[0]).Unmanage();
583 Widget w = f_scope_option.SubMenuId();;
587 XtSetArg(args[i], XmNchildren, &wl); i++;
588 XtGetValues(w, args, i);
589 XtUnmanageChild(wl[0]);
592 WXmPushButton(WComposite(f_scope_option.SubMenuId()).Children()[0]).Unmanage();
596 MenuHistory (WComposite(f_scope_option.SubMenuId()).Children()[1]);
598 //UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
599 //UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
600 //UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
602 //search_scope_mgr().option_menu(this);
606 // /////////////////////////////////////////////////////////////////
607 // receive* - handle updates to the list of scopes
608 // /////////////////////////////////////////////////////////////////
611 QueryEditor::receive (ScopeCreated &msg, void* /*client_data*/)
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;
619 if (msg.f_search_scope->read_only())
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
629 // Scan the current menu to find the correct insertion position.
630 UAS_SearchScope *scope;
631 for (; s != NULL; s++, position++)
634 if (scope->read_only() != need_sep)
636 position++; // skip separator
639 if (scope->read_only())
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)
648 ON_DEBUG (printf ("Final SE position = %d\n", position));
650 // Add a separator if this is the first user-defined entry.
651 if (need_sep == TRUE)
653 DECLM (WXmSeparator, separator, f_scope_option.SubMenuId(), "separator");
654 separator.PositionIndex (position);
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);
666 QueryEditor::receive (ScopeDeleted &msg, void* /*client_data*/)
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++)
676 if (XmIsSeparator (kids[i]))
677 separator_pos = i + 1;
678 if (msg.f_search_scope ==
679 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
683 // It had better be in the list!
684 Xassert (i != num_kids);
685 ON_DEBUG (printf (" widget #%d is the button\n", i));
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]);
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)
696 ON_DEBUG (puts (" destroying separator"));
697 XtDestroyWidget (kids[separator_pos-1]);
703 QueryEditor::receive (ScopeRenamed &msg, void* /*client_data*/)
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++)
711 if (msg.f_search_scope ==
712 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
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));
720 // Now find the new insertion position in the list.
722 xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
723 List_Iterator<UAS_SearchScope *> s (scope_list);
725 // find the new position in the list
726 for (; s != NULL; s++)
728 if (s.item() == msg.f_search_scope)
731 if (s.item()->read_only())
733 ON_DEBUG (printf ("QueryEdit: strcmp <%s>\n", s.item()->name()));
734 if (strcmp (msg.f_search_scope->name(), s.item()->name()) < 0)
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);
745 QueryEditor::update_option_menu()
747 WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
748 int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
750 // destroy all toggle buttons in menu
751 for (int i = 0; i < num_kids; i++)
753 XtUnmanageChild (kids[i]);
754 XtDestroyWidget (kids[i]);