Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Agents / SearchResultsAgentMotif.C
1 /*      Copyright (c) 1994,1995,1996 FUJITSU LIMITED    */
2 /*      All Rights Reserved                             */
3
4 /*
5  * $TOG: SearchResultsAgentMotif.C /main/17 1998/04/17 11:35:18 mgreess $
6  *
7  * Copyright (c) 1991 HaL Computer Systems, Inc.  All rights reserved.
8  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
9  * States.  Use of a copyright notice is precautionary only and does not
10  * imply publication or disclosure.
11  * 
12  * This software contains confidential information and trade secrets of HaL
13  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
14  * wihtout the prior express written permission of HaL Computer Systems, Inc.
15  * 
16  *                         RESTRICTED RIGHTS LEGEND
17  * Use, duplication, or disclosure by the Government is subject to
18  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
19  * Technical Data and Computer Software clause at DFARS 252.227-7013.
20  *                        HaL Computer Systems, Inc.
21  *                  1315 Dell Avenue, Campbell, CA  95008
22  *"
23  */
24
25 #include "UAS.hh"
26
27
28 #define C_TOC_Element
29 #define C_Atomizer
30 #define L_Basic
31
32 #define C_ResultID
33 #define L_OliasSearch
34
35 #define C_PrefMgr
36 #define C_SearchMgr
37 #define C_SearchResultsMgr
38 #define C_MessageMgr
39 #define C_NodeMgr
40 #define C_LibraryMgr
41 #define L_Managers
42
43 #define C_SearchResultsAgent
44 #define C_NodeListAgent
45 #define C_HelpAgent
46 #define L_Agents
47
48 #define USES_OLIAS_FONT
49
50 #include "Other/XmStringLocalized.hh"
51 #include "Managers/CatMgr.hh"
52 #include "Managers/WString.hh"
53
54 #include <Prelude.h>
55 #include <iostream.h>
56
57 #include "Registration.hh"
58
59 #include <WWL/WXmList.h>
60 #include <WWL/WXmForm.h>
61 #include <WWL/WXmLabel.h>
62 #include <WWL/WXmText.h>
63 #include <WWL/WXmToggleButton.h>
64 #include <WWL/WXmPushButton.h>
65 #include <WWL/WXmPanedWindow.h>
66
67 #ifdef SVR4
68 #ifndef USL
69 #include <libintl.h>
70 #endif
71 #endif
72
73 static Boolean g_allow_query_text_change;
74
75 #define INITIAL_FILL_SIZE 1000
76 #define INCREMENTAL_FILL_SIZE 100
77
78
79 // /////////////////////////////////////////////////////////////////
80 // init
81 // /////////////////////////////////////////////////////////////////
82
83 void
84 SearchResultsAgent::init()
85 {
86   NodeListAgent::init();
87 }
88
89
90 // /////////////////////////////////////////////////////////////////
91 // form_result_string
92 // /////////////////////////////////////////////////////////////////
93
94 // Hard Coded pixel offset (from left margin) where Node Title Starts in
95 // result list - 14:36 07/26/93 - jbm
96 #define SECTION_OFFSET 150
97
98 XmString
99 SearchResultsAgent::form_result_string (UAS_Pointer<UAS_SearchResultsEntry> re)
100 {
101   static char relevancy[3];
102   if (relevancy[1] == '\0')
103     {
104       if (window_system().nofonts())
105         relevancy[1] = ' ';
106       else
107         relevancy[1] = OLIAS_SPACE08;
108     }
109
110   // Scale all weights from to the range 0 to 8.  While 8 / scale
111   // may look like a constant, it cannot be factored because integer
112   // arithmetic rounding might adversely affect the results.  DJB
113   relevancy[0] = OLIAS_RELEVANCY_ICON;
114   if (f_scale != 0)
115     relevancy[0] += (char) ((re->relevance() * 8 ) / f_scale);
116
117
118   WXmString rel  (relevancy, OLIAS_FONT);
119
120   WXmString book;
121   WXmString name;
122
123   if (re->book()!= "")
124     {
125       book = (char *) re->book();
126       name = (char *) re->section();
127     }
128   else
129     {
130       // backward compatibility 
131
132       UAS_Pointer<UAS_Common> doc_ptr = UAS_Common::create (re->id());
133       UAS_String bn = doc_ptr->book_name (UAS_SHORT_TITLE);
134       UAS_String tt = doc_ptr->title();
135       book = bn;
136       name = tt;
137     }  
138
139   int section_offset = f_list->Width() / 3;
140
141   int allowance = section_offset - book.Width(f_list->FontList());
142   WXmString space;
143   if (allowance > 0) {
144     // NOTE: space is hardcoded and will cause problems if font changes
145     // -10:24 07/12/93 - jbm 
146     XmString xmstr = window_system().make_space(allowance, *f_list);
147     space = xmstr;
148     XmStringFree(xmstr);
149   }
150   else {
151
152     char* dots = "...";
153
154     WXmString temp_xmstring = book + WXmString(dots);
155     char *temp_str = (char*)temp_xmstring;
156
157     WString temp_WString(temp_str);   
158     wchar_t* buf = (wchar_t*) temp_WString;
159     wchar_t* ptr = buf + wcslen(buf) - (strlen(dots)+1);
160
161     WXmString stake;
162     WString wdots(dots);
163     do
164     {
165         char* str;      
166         memcpy(ptr--, (wchar_t*)wdots, (strlen(dots)+1) * sizeof(wchar_t));
167
168         stake = str = WString(buf).get_mbstr();
169
170         allowance = section_offset - stake.Width(f_list->FontList());
171
172         delete[] str;
173     }
174     while (allowance <= 0 && ptr >= buf);
175
176 #if 0
177     while (*ptr <= (wchar_t)' ' && ptr >= buf)
178     {
179         char* str;
180         memcpy(ptr--, (wchar_t*)wdots, (strlen(dots)+1) * sizeof(wchar_t));
181
182         stake = str = WString(buf).get_mbstr();
183         allowance = section_offset - stake.Width(f_list->FontList());
184
185         delete[] str;
186     }
187 #endif
188
189     XmString xmstr = window_system().make_space(allowance, *f_list);
190     space = xmstr;
191     XmStringFree(xmstr);
192
193     book = stake;
194   }
195
196   // Entire string must be disowned to prevent destructor of temporary
197   // object from freeing its XmString. 
198
199   XmString string = (rel + book + space + name).disown();
200
201   return (string);
202 }
203
204
205 // /////////////////////////////////////////////////////////////////
206 // display
207 // /////////////////////////////////////////////////////////////////
208
209 inline int
210 imin(int x, int y)
211 {
212   return x < y ? x : y ;
213 }
214
215 void
216 SearchResultsAgent::resizeCB(Widget, XtPointer client_data, XEvent*, Boolean*)
217 {
218   SearchResultsAgent* agent = (SearchResultsAgent*)client_data;
219
220   agent->resize();
221 }
222
223 void
224 SearchResultsAgent::compose_header()
225 {
226   WXmLabel* header =
227         (WXmLabel*)XtNameToWidget((Widget)*f_list_form, "header");
228
229   WXmString bookString = CATGETS(Set_AgentLabel, 184, "Book");
230   WXmString sectString = CATGETS(Set_AgentLabel, 185, "Section");
231
232   WXmString bookPostfix(
233         window_system().make_space(
234                 f_list->Width() / 3 - bookString.Width(header->FontList()),
235                 *header
236         ),
237         False);
238
239   WXmString header_string = bookString + bookPostfix + sectString;
240
241   header->LabelString((XmString)header_string);
242 }
243
244 void
245 SearchResultsAgent::resize()
246 {
247   UAS_List<UAS_SearchResultsEntry>& rlist =
248                 *(f_results->results()->create_results(0, f_count));
249
250   fill_list(rlist);
251
252   compose_header();
253 }
254
255 void
256 SearchResultsAgent::display (ResultID *results)
257 {
258   if (f_shell == NULL)
259     create_window();
260
261   f_results = results;
262
263   UAS_SearchEngine &se = search_mgr().search_engine();
264
265   // get window up quick 
266
267   f_docs_to_display = imin(results->ndocs(), pref_mgr().get_int(PrefMgr::MaxSearchHits));
268
269 #if 0
270   if (INITIAL_FILL_SIZE < f_docs_to_display)
271     f_count = INITIAL_FILL_SIZE;
272   else
273     f_count = f_docs_to_display ;
274 #else
275   // INITIAL_FILL_SIZE(1000) is greater than the maximum of preference
276   // so, f_docs_to_display never exceeds INITIAL_FILL_SIZE
277   f_count = f_docs_to_display;
278 #endif
279
280   UAS_Pointer<UAS_List<UAS_SearchResultsEntry> > tmpList =
281                           results->results()->create_results(0, f_count);
282   UAS_List<UAS_SearchResultsEntry>& rlist =
283                 *(UAS_List<UAS_SearchResultsEntry> *)tmpList;
284
285   // All entries scaled by the weight of the first because it is
286   // be the max weight for the list. 
287   assert( rlist[0] != 0);
288   f_scale = rlist[0]->relevance ();
289
290   // NOTE: Using bogus internal string below: 
291   if (f_scale == 0)
292     message_mgr().warning_dialog (
293         (char*)UAS_String(CATGETS(Set_Messages, 69,
294                         "Search results weighting are not available.")));
295   
296   /* -------- Display the number of hits. -------- */
297   char buffer[80];
298
299   sprintf (buffer, "%d of %d sections",
300            f_docs_to_display, results->ndocs());
301   f_hits_label->LabelString (buffer);
302   sprintf (buffer, "%s",
303                 (char *)*(UAS_String*)(results->results()->scope_name()));
304   f_scope_label->LabelString (buffer);
305
306   /* -------- Display the text of the query. -------- */
307   g_allow_query_text_change = True;
308
309   f_query_text->Value ((char*)*(UAS_String*)(results->results()->query()));
310
311   g_allow_query_text_change = False;
312
313   f_popped_up = TRUE;
314   NodeListAgent::display();
315
316   fill_list(rlist);
317   compose_header();
318
319   if (pref_mgr().get_boolean (PrefMgr::DisplayFirstHit))
320     {
321       f_list->SelectPos (1, True);
322     }
323   else
324     {
325       f_list->DeselectAllItems();
326       f_display.SetSensitive (False);
327     }
328
329   XtAddEventHandler((Widget)*f_list_form, StructureNotifyMask, False,
330                                 resizeCB, (XtPointer)this);
331 }
332
333
334 // /////////////////////////////////////////////////////////////////
335 // fill_list_wp
336 // /////////////////////////////////////////////////////////////////
337
338 Boolean
339 SearchResultsAgent::fill_list_wp (XtPointer /*client_data*/)
340 {
341 #if 0
342   return ((SearchResultsAgent *) client_data)->fill_list();
343 #else
344   return True;
345 #endif
346 }
347
348
349 // /////////////////////////////////////////////////////////////////
350 // fill_list
351 // /////////////////////////////////////////////////////////////////
352
353 Boolean
354 SearchResultsAgent::fill_list(UAS_List<UAS_SearchResultsEntry>& rlist)
355 {
356   static XmString string_table[INITIAL_FILL_SIZE];
357   XmString *t = string_table;
358
359   int string_count = 0 ;
360   for (int i = 0; i < rlist.length(); i ++) {
361       string_count++ ;
362       *t++ = form_result_string (rlist[i]);
363   }
364
365   f_list->SetPos (1);
366   f_list->Set (WArgList (XmNitems, (XtArgVal) string_table,
367                          XmNitemCount, f_count,
368                          NULL));
369
370   for (i = 0 ; i < string_count; i++) {
371      XmStringFree(string_table[i]);
372      string_table[i] = NULL;
373   }
374
375 #if 0
376   static XmString string_table [INCREMENTAL_FILL_SIZE];
377   XmString *t = string_table;
378
379   int number, num_remaining = f_docs_to_display - f_count;
380
381   if (INCREMENTAL_FILL_SIZE < num_remaining)
382     number = INCREMENTAL_FILL_SIZE;
383   else
384     number = num_remaining;
385
386   UAS_Pointer<UAS_List<UAS_SearchResultsEntry> > tmpList =
387                           f_results->results()->create_results(f_count, number);
388   UAS_List<UAS_SearchResultsEntry> & rlist =
389                         *(UAS_List<UAS_SearchResultsEntry>*)tmpList;
390
391   int i;
392   for (i = 0; i < rlist.length(); i ++) {
393     *t++ = form_result_string (rlist[i]);
394   }
395   // 0 means add at last position in the list. 
396   XmListAddItems (*f_list, (XmString *) string_table, number, 0);
397
398   f_count += number;
399
400   for (i = 0 ; i < number; i++)
401     XmStringFree ((XmString) string_table[i]);
402
403   // Return True if the list is complete, False otherwise.
404   if (f_count == f_docs_to_display)
405     {
406       f_work_proc_id = NULL;
407       return (True);
408     }
409   else
410     {
411       return (False);
412     }
413 #else
414   return True;
415 #endif
416 }
417
418
419 // /////////////////////////////////////////////////////////////////
420 // create_window
421 // /////////////////////////////////////////////////////////////////
422
423 void
424 SearchResultsAgent::create_window()
425 {
426   create_base_window ("results");
427
428   XmStringLocalized mtfstring;
429   String            string;
430
431   string = CATGETS(Set_SearchResultsAgent, 1, "Dtinfo: Search Results");
432   XtVaSetValues((Widget)*f_shell, XmNtitle, string, NULL);
433
434   help_agent().add_activate_help(f_help, "results_help");
435
436 #define AM WAutoManage
437   // NOTE: need form to contain things in the same row 'cause of resizing
438   // rtp
439 #if 1
440   f_retain_toggle =
441     new WXmToggleButton (*f_form, "retain", AM,
442                          WArgList (XmNlabelPixmap,
443                                    (XtArgVal)window_system().unlocked_pixmap(*f_form),
444                                    XmNselectPixmap,
445                                    window_system().semilocked_pixmap(*f_form),
446                                    NULL));
447 #else
448   f_retain_toggle =  new WXmToggleButton (*f_form,     "retain",         AM);
449 #endif
450   WXmLabel retrieved (*f_form, "retrieved", AM);
451   f_hits_label = (WXmLabel*)(Widget) WXmLabel (*f_form,    "num_hits", AM);
452   WXmLabel scope (*f_form, "scope", AM);
453   f_scope_label = (WXmLabel*)(Widget) WXmLabel (*f_form,   "scope_name", AM);
454   WXmLabel query_label (*f_form, "query_label", AM);
455
456   mtfstring = CATGETS(Set_AgentLabel, 219, "Retrieved:");
457   XtVaSetValues(retrieved, XmNlabelString, (XmString)mtfstring, NULL);
458   mtfstring = CATGETS(Set_AgentLabel, 194, "File a Bug");
459   XtVaSetValues((Widget)f_hits_label, XmNlabelString, (XmString)mtfstring, NULL);
460   mtfstring = CATGETS(Set_AgentLabel, 220, "Scope:");
461   XtVaSetValues(scope, XmNlabelString, (XmString)mtfstring, NULL);
462   mtfstring = CATGETS(Set_AgentLabel, 194, "File a Bug");
463   XtVaSetValues((Widget)f_scope_label, XmNlabelString, (XmString)mtfstring, NULL);
464   mtfstring = CATGETS(Set_AgentLabel, 221, "Query:");
465   XtVaSetValues(query_label, XmNlabelString, (XmString)mtfstring, NULL);
466   
467   Widget textw = XmCreateScrolledText (*f_pane, "query_text", NULL, 0);
468   f_query_text = new WXmText (textw);
469   f_query_text->Manage();
470 //  WXmPushButton      editq           (*f_panel,       "edit_query",     AM);
471
472   f_retain_toggle->SetValueChangedCallback
473     (this, (WWL_FUN) &SearchResultsAgent::retain_changed);
474   set_retain_default();
475   
476   {
477     CXmForm pane (*f_pane);
478     WArgList args;
479
480     pane.TopWidget (query_label, args);
481     pane.TopAttachment (XmATTACH_WIDGET, args);
482     pane.Set (args.Args(), args.NumArgs());
483   }
484
485   static char relevancy[3];
486   if (relevancy[0] == '\0')
487     {
488       relevancy[0] = OLIAS_RELEVANCY_ICON;
489       if (window_system().nofonts())
490         relevancy[1] = ' ';
491       else
492         relevancy[1] = OLIAS_SPACE08;
493     }
494
495   // set up column labels (Book, Section) 
496   WXmLabel header       (*f_list_form, "header", AM);
497
498   { // header needs dtinfo space font
499     XmFontList header_font = XmFontListCopy(header.FontList());
500
501     if (window_system().dtinfo_space_font())
502       header_font = XmFontListAppendEntry(header_font,
503                                           window_system().dtinfo_space_font());
504
505     header.FontList(header_font);
506   }
507
508   int offset = WXmString(relevancy, OLIAS_FONT).Width(f_list->FontList());
509   header.LeftOffset(offset); 
510
511   WXmPrimitive prim(XtParent(*f_list));
512   prim.TopWidget(header);
513   prim.TopAttachment(XmATTACH_WIDGET);
514
515   f_pane->Manage();
516   f_form->Manage();
517   
518   f_list->SetSingleSelectionCallback (this,
519                               (WWL_FUN) &SearchResultsAgent::select_item);
520   f_list->SetBrowseSelectionCallback (this,
521                               (WWL_FUN) &SearchResultsAgent::select_item);
522   f_list->SetDefaultActionCallback (this,
523                             (WWL_FUN) &SearchResultsAgent::view_activate);
524   f_display.SetActivateCallback (this,
525                             (WWL_FUN) &SearchResultsAgent::view_activate);
526   f_query_text->SetModifyVerifyCallback (this,
527                             (WWL_FUN) &SearchResultsAgent::modify_verify);
528
529   XmProcessTraversal (f_display, XmTRAVERSE_CURRENT);
530 #undef AM
531 }
532
533 // /////////////////////////////////////////////////////////////////
534 // select_item
535 // /////////////////////////////////////////////////////////////////
536
537 // NOTE: perhaps this should be in the base class?? 6/12/92 djb 
538
539 void
540 SearchResultsAgent::select_item (WCallback *wcb)
541 {
542   XmListCallbackStruct *lcs = (XmListCallbackStruct *) wcb->CallData();
543
544   f_selected_item = lcs->item_position - 1;
545
546   ON_DEBUG (printf ("Selected item #%d\n", f_selected_item);)
547
548   f_display.SetSensitive (True);
549 }
550
551
552 // /////////////////////////////////////////////////////////////////
553 // view_activate
554 // /////////////////////////////////////////////////////////////////
555
556 void
557 SearchResultsAgent::view_activate (WCallback *)
558 {
559   if (f_list->SelectedItemCount() != 1)
560     return;
561
562   Wait_Cursor bob;
563
564   UAS_String target;
565
566   UAS_List<UAS_SearchResultsEntry> & rlist = f_results->results()->results();
567
568   search_mgr().current_hits (rlist[f_selected_item]->create_matches());
569   target = rlist[f_selected_item]->id();
570
571   UAS_Pointer<UAS_Common> doc_ptr = UAS_Common::create (target);
572
573   UAS_String temp_str = doc_ptr->lid();
574   if (library_mgr().lib_exist(temp_str)) {
575       doc_ptr->retrieve();
576   }
577   else {
578       message_mgr().warning_dialog (
579           (char*)UAS_String(CATGETS(Set_Messages, 51,
580           "The document or section requested is not available.")));
581   }
582 }
583
584 // /////////////////////////////////////////////////////////////////
585 // retain_changed
586 // /////////////////////////////////////////////////////////////////
587
588 void
589 SearchResultsAgent::retain_changed (WCallback *wcb)
590 {
591   XmToggleButtonCallbackStruct &tbcs =
592     *((XmToggleButtonCallbackStruct *) wcb->CallData());
593
594   f_retain = tbcs.set;
595
596   if (f_retain)
597     f_retain_toggle->WObject::Set (WArgList (XmNselectPixmap,
598                                     window_system().locked_pixmap(wcb->GetWidget()),
599                                     XmNlabelPixmap,
600                                     window_system().semilocked_pixmap(wcb->GetWidget()),
601                                     NULL));
602   else
603     f_retain_toggle->WObject::Set (WArgList (XmNselectPixmap,
604                                     window_system().semilocked_pixmap(wcb->GetWidget()),
605                                     XmNlabelPixmap,
606                                     window_system().unlocked_pixmap(wcb->GetWidget()),
607                                     NULL));
608 }
609
610 // /////////////////////////////////////////////////////////////////
611 // close_window
612 // /////////////////////////////////////////////////////////////////
613
614 void
615 SearchResultsAgent::close_window (WCallback *wcb)
616 {
617   if (f_popped_up == FALSE)
618     return;
619   f_popped_up = FALSE;
620
621   NodeListAgent::close_window (wcb);
622   search_results_mgr().deactivate (f_my_ale);
623   
624   set_retain_default();
625 }
626
627 // /////////////////////////////////////////////////////////////////
628 // set_retain_default - set retain to default settings
629 // /////////////////////////////////////////////////////////////////
630
631 void
632 SearchResultsAgent::set_retain_default()
633 {
634   // NOTE: hardcoded for now, user preference later
635
636   f_retain = FALSE;
637   f_retain_toggle->Set (False);
638   f_retain_toggle->WObject::Set (WArgList (XmNselectPixmap,
639                                   window_system().semilocked_pixmap(f_retain_toggle->Parent()),
640                                   XmNlabelPixmap,
641                                   window_system().unlocked_pixmap(f_retain_toggle->Parent()),
642                                   NULL));
643 }
644
645
646 // /////////////////////////////////////////////////////////////////
647 // modify_verify
648 // /////////////////////////////////////////////////////////////////
649
650 void
651 SearchResultsAgent::modify_verify (WCallback *wcb)
652 {
653   if (g_allow_query_text_change)
654     return;
655
656   XmTextVerifyPtr tvp = (XmTextVerifyPtr) wcb->CallData();
657
658   // Editing never allowed. 
659   tvp->doit = False;
660
661   message_mgr().warning_dialog (
662         (char*)UAS_String(CATGETS(Set_Messages, 47,
663                                         "This is a display-only field.")));
664 }