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