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>
91 #define CLASS QueryEditor
92 #include "../Agents/create_macros.hh"
94 #include "utility/mmdb_exception.h"
96 //static bool g_allow_query_text_change;
98 QueryEditor *QueryEditor::f_query_editor;
100 // /////////////////////////////////////////////////////////////////
102 // /////////////////////////////////////////////////////////////////
104 QueryEditor::QueryEditor(UAS_SearchEngine& search_engine)
110 f_query_editor = this;
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());
117 fprintf(stderr, "(DEBUG) search engine capabilities = 0x%x\n",
118 QueryTerm::avail_caps());
123 // /////////////////////////////////////////////////////////////////
124 // display - display the query editor
125 // /////////////////////////////////////////////////////////////////
128 QueryEditor::display()
130 static int count = 0;
145 // /////////////////////////////////////////////////////////////////
146 // new_query - set up interface for a new query
147 // /////////////////////////////////////////////////////////////////
150 QueryEditor::edit_query (QueryGroup *query)
152 static Boolean first_time = True;
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
160 // Create a group with a single term if none provided.
163 query = new QueryGroup();
164 // This QueryTerm is pointed to by the QueryGroup.
165 new QueryTerm (query, NULL, NULL);
170 // re-load the query terms
171 if (f_query_view != NULL)
172 f_query_view->re_load_terms(f_query);
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)
180 QueryGroup *group = f_query_view->query_group();
181 f_query_view->destroy_widgets();
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
192 // Create a group with a single term if none provided.
196 f_query = new QueryGroup();
197 // This QueryTerm is pointed to by the QueryGroup.
198 new QueryTerm (f_query, NULL, NULL);
201 // QueryGroupView holds the pointer to the QueryGroup.
203 new QueryGroupView (f_query, WXmForm ((WObject &) f_query_area));
212 // QueryGroupView holds the pointer to the QueryGroup.
213 f_query_view = new QueryGroupView (f_query, f_query_area);
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
223 PaneMinimum (f_query_area.Height() -
224 WCore (XtParent(XtParent(*f_query_view))).Height() +
225 (2 * f_query_view->Height()));
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()));
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());
238 Dimension excess_height = qform.Height() + f_query_area.Height() -
239 qform.PaneMinimum() - f_query_area.PaneMinimum();
241 ON_DEBUG(printf ("Query Editor excess height = %d\n", excess_height));
243 f_shell.MinHeight (f_shell.Height() - excess_height);
248 //g_allow_query_text_change = TRUE;
249 f_query_text.Value ((char*)"");
250 //g_allow_query_text_change = FALSE;
252 // Move the input focus to the term view.
253 f_query_area.InitialFocus (*f_query_view);
254 // f_query_view->traverse_here();
260 // /////////////////////////////////////////////////////////////////
261 // create_ui - create the query editor user interface
262 // /////////////////////////////////////////////////////////////////
264 #define AM WAutoManage
267 QueryEditor::create_ui()
271 XmStringLocalized mtfstring;
275 f_shell = WTopLevelShell(window_system().toplevel(), WPopup, "query_editor");
276 window_system().register_shell (&f_shell);
278 string = CATGETS(Set_QueryEditor, 1, "Dtinfo: Query Editor");
279 XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
281 // Main form and menu bar.
282 WXmForm form (f_shell, "form" );
283 WXmMenuBar menu_bar (form, (char*)"menu_bar" );
285 WXmPulldownMenu scope_menu (form, (char*)"scope_menu" );
288 XtSetArg(args[n], XmNsubMenuId, (Widget) scope_menu); n++;
289 f_scope_option = WXmOptionMenu (form, (char*)"scope_option", AM, args, n);
291 mtfstring = CATGETS(Set_AgentLabel, 212, "Scope Name");
292 XtVaSetValues(f_scope_option, XmNlabelString, (XmString)mtfstring, NULL);
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);
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);
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);
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);
352 help_agent().add_activate_help (help, (char*)"query_editor_help");
355 WXmPanedWindow pane (form, "pane" );
356 WXmForm qform (pane, "qform" );
357 WXmLabel qlabel (qform, "qlabel", AM);
359 mtfstring = CATGETS(Set_AgentLabel, 230, "Query");
360 XtVaSetValues(qlabel, XmNlabelString, (XmString)mtfstring, NULL);
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());
367 edit_cascade.SubMenuId (edit_menu);
370 ON_ACTIVATE (f_search_btn, search_activate);
371 ON_ACTIVATE (cancel, cancel);
372 ON_ACTIVATE (clear, clear);
373 ON_ACTIVATE (scope, scope);
375 // f_query_text.SetFocusCallback (this,
376 // (WWL_FUN) &QueryEditor::modify_verify);
377 // f_query_text.SetModifyVerifyCallback (this,
378 // (WWL_FUN) &QueryEditor::modify_verify);
380 // Set minimum sizes.
384 form.DefaultButton (f_search_btn);
385 form.ShadowThickness (0);
387 form.InitialFocus (pane);
388 pane.InitialFocus (f_query_area);
389 qform.PaneMinimum (f_query_text.Height());
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;
400 // Swap the entries in the pane around. Have to do this now
401 // to get initial sizes right.
402 qform.PositionIndex (1);
407 UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
408 UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
409 UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
411 search_scope_mgr().option_menu(this);
415 // /////////////////////////////////////////////////////////////////
417 // /////////////////////////////////////////////////////////////////
420 QueryEditor::search_activate()
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));
430 fprintf(stderr, "(DEBUG) human_readable=\"%s\"\n", human_readable);
433 UAS_SearchScope *scope =
434 (UAS_SearchScope *) WXmPushButton (f_scope_option.MenuHistory()).UserData();
437 // Search manager owns query from this point on. Don't delete it here.
438 search_mgr().parse_and_search (human_readable, scope);
440 mcatch (demoException &, demo) {
441 message_mgr().demo_failure(demo);
445 free(human_readable);
450 // /////////////////////////////////////////////////////////////////
451 // cancel - close the window
452 // /////////////////////////////////////////////////////////////////
455 QueryEditor::cancel()
461 // /////////////////////////////////////////////////////////////////
462 // empty term tracking routines
463 // /////////////////////////////////////////////////////////////////
466 QueryEditor::increment_null_terms()
468 if (f_null_terms == 0)
469 f_search_btn.SetSensitive (False);
471 // printf ("QueryEditor setting null_terms to %d\n", f_null_terms);
475 QueryEditor::decrement_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);
484 // /////////////////////////////////////////////////////////////////
485 // clear - clear the current query
486 // /////////////////////////////////////////////////////////////////
495 // /////////////////////////////////////////////////////////////////////////
496 // scope - activate search scope dialog
497 // /////////////////////////////////////////////////////////////////////////
501 search_scope_mgr().display();
505 // /////////////////////////////////////////////////////////////////
506 // query_changed - regenerate the text version
507 // /////////////////////////////////////////////////////////////////
510 QueryEditor::query_changed()
512 // Need to duplicate string returned, because it is in static data space.
514 const char *human_readable =
515 f_query_view->query_group()->generate_readable();
517 const char *human_readable =
518 f_query_view->query_group()->
519 generate_query (QueryGroup::QUERY_TYPE_INFIX);
522 //g_allow_query_text_change = TRUE;
523 f_query_text.Value ((char *) human_readable);
524 //g_allow_query_text_change = FALSE;
528 // /////////////////////////////////////////////////////////////////
530 // /////////////////////////////////////////////////////////////////
534 QueryEditor::modify_verify (WCallback *wcb)
536 // if (g_allow_query_text_change)
539 // XmTextVerifyPtr tvp = (XmTextVerifyPtr) wcb->CallData();
541 // Editing never allowed.
542 // tvp->doit = False;
544 // message_mgr().warning_dialog (
545 // (char*)UAS_String(CATGETS(Set_Messages, 47,
546 // "This is a display-only field.")));
550 // /////////////////////////////////////////////////////////////////
551 // fill_menu - initially file in the scope option menu
552 // /////////////////////////////////////////////////////////////////
555 QueryEditor::fill_menu()
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;
565 // Add a separator when they change from read only to changable.
566 if (old_read_only != s.item()->read_only())
568 DECLM (WXmSeparator, sep1, f_scope_option.SubMenuId(), "separator");
569 sep1.PositionIndex (position++);
570 old_read_only = FALSE;
572 DECLM (WXmPushButton, scope,f_scope_option.SubMenuId(),s.item()->name());
573 scope.UserData (s.item());
574 scope.PositionIndex (position++);
577 // Do not want first item (Current Section)
581 Widget w = f_scope_option.SubMenuId();
582 WComposite temp_composite(w);
583 WXmPushButton(temp_composite.Children()[0]).Unmanage();
586 Widget w = f_scope_option.SubMenuId();;
590 XtSetArg(args[i], XmNchildren, &wl); i++;
591 XtGetValues(w, args, i);
592 XtUnmanageChild(wl[0]);
595 WXmPushButton(WComposite(f_scope_option.SubMenuId()).Children()[0]).Unmanage();
599 MenuHistory (WComposite(f_scope_option.SubMenuId()).Children()[1]);
601 //UAS_SearchScope::request ((UAS_Receiver<ScopeCreated> *) this);
602 //UAS_SearchScope::request ((UAS_Receiver<ScopeDeleted> *) this);
603 //UAS_SearchScope::request ((UAS_Receiver<ScopeRenamed> *) this);
605 //search_scope_mgr().option_menu(this);
609 // /////////////////////////////////////////////////////////////////
610 // receive* - handle updates to the list of scopes
611 // /////////////////////////////////////////////////////////////////
614 QueryEditor::receive (ScopeCreated &msg, void* /*client_data*/)
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;
622 if (msg.f_search_scope->read_only())
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
632 // Scan the current menu to find the correct insertion position.
633 UAS_SearchScope *scope;
634 for (; s != 0; s++, position++)
637 if (scope->read_only() != need_sep)
639 position++; // skip separator
642 if (scope->read_only())
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)
651 ON_DEBUG (printf ("Final SE position = %d\n", position));
653 // Add a separator if this is the first user-defined entry.
654 if (need_sep == TRUE)
656 DECLM (WXmSeparator, separator, f_scope_option.SubMenuId(), "separator");
657 separator.PositionIndex (position);
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);
669 QueryEditor::receive (ScopeDeleted &msg, void* /*client_data*/)
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;
678 for (i = 0; i < num_kids; i++)
680 if (XmIsSeparator (kids[i]))
681 separator_pos = i + 1;
682 if (msg.f_search_scope ==
683 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
687 // It had better be in the list!
688 Xassert (i != num_kids);
689 ON_DEBUG (printf (" widget #%d is the button\n", i));
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]);
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)
700 ON_DEBUG (puts (" destroying separator"));
701 XtDestroyWidget (kids[separator_pos-1]);
707 QueryEditor::receive (ScopeRenamed &msg, void* /*client_data*/)
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();
714 for (i = 0; i < num_kids; i++)
716 if (msg.f_search_scope ==
717 ((UAS_SearchScope *) WXmPushButton (kids[i]).UserData()))
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));
725 // Now find the new insertion position in the list.
727 xList<UAS_SearchScope *> &scope_list = search_scope_mgr().scope_list();
728 List_Iterator<UAS_SearchScope *> s (scope_list);
730 // find the new position in the list
733 if (s.item() == msg.f_search_scope)
736 if (s.item()->read_only())
738 ON_DEBUG (printf ("QueryEdit: strcmp <%s>\n", s.item()->name()));
739 if (strcmp (msg.f_search_scope->name(), s.item()->name()) < 0)
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);
750 QueryEditor::update_option_menu()
752 WidgetList kids = WComposite(f_scope_option.SubMenuId()).Children();
753 int num_kids = WComposite(f_scope_option.SubMenuId()).NumChildren();
755 // destroy all toggle buttons in menu
756 for (int i = 0; i < num_kids; i++)
758 XtUnmanageChild (kids[i]);
759 XtDestroyWidget (kids[i]);