Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / GlobSearch.c
1 /* $TOG: GlobSearch.c /main/21 1999/11/11 10:59:15 mgreess $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:        GlobSearch.c
6  **
7  **   Project:     DtHelp Project
8  **
9  **   Description: Builds and displays an instance of a DtHelp GlobSearch
10  **                Dialog.
11  ** 
12  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
13  **  (c) Copyright 1993, 1994 International Business Machines Corp.
14  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
15  **  (c) Copyright 1993, 1994 Novell, Inc.
16  **
17  **
18  **
19  ****************************************************************************
20  ************************************<+>*************************************/
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <string.h>
24 #if defined(sun)
25 #include <sys/utsname.h>
26 #endif
27 #include <limits.h>
28 #include <stdlib.h>  /* for MB_CUR_MAX */
29 #include <unistd.h>  /* R_OK */
30 #include <locale.h>  /* getlocale(), LOCALE_STATUS */
31 #ifndef NO_REGEX
32 # ifdef NO_REGCOMP
33 #  if defined(SVR4)
34 #   include <libgen.h>          /* for regcmp, regex */
35 #  endif
36 # else
37 #  include <regex.h>            /* for regcomp, regexec */
38 # endif
39 #endif
40
41 #include <Xm/Xm.h>
42 #include <Xm/XmP.h>
43 #include <Xm/Frame.h>
44 #include <Xm/TextF.h>
45 #include <Xm/Form.h>
46 #include <Xm/LabelG.h>
47 #include <Xm/ScrolledW.h>
48 #include <Xm/SeparatoG.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/List.h>
51 #include <Xm/DialogS.h>
52 #include <Xm/MwmUtil.h>
53 #include <Xm/Protocols.h>
54 #include <Xm/RowColumn.h>
55 #include <Xm/SelectioB.h>
56 #include <Xm/ToggleBG.h>
57
58 #include <X11/Intrinsic.h>
59 #include <X11/Shell.h>
60 #include <X11/ShellP.h>
61 #include <X11/Xutil.h>
62 #include <X11/keysymdef.h>
63
64 #include <Dt/Help.h>
65 #include <Dt/HelpDialog.h>
66
67 /*
68  * private includes
69  */
70 #include "Access.h"
71 #include "StringFuncsI.h"
72 #include "DisplayAreaI.h"
73 #include "HelpDialogP.h"
74 #include "HelpDialogI.h"
75 #include "HelpAccessI.h"
76 #include "HelpUtilI.h"
77 #include "HelposI.h"
78 #include "GlobSearchI.h"
79 #include "FileListUtilsI.h"
80 #include "FileUtilsI.h"
81 #include "FormatI.h"
82 #include "HelpXlate.h"
83 #include "VolSelectI.h"
84 #include "Lock.h"
85
86 /******** TYPES ***********/
87 typedef enum {
88     SEARCH_RESULTS_STATUS = 1,
89     WORKING_STATUS = 2,
90     SCANNING_STATUS = 3,
91     BLANK_STATUS = 4,
92     NO_VOL_STATUS = 5,
93     FIRST_PROMPT_STATUS = 6
94 } ResultsStatus;
95
96 static Boolean VolumeHasIndexP (
97     _DtHelpGlobSrchSources srchSource,
98     int          helpType,
99     char * baseName);
100 static void DeleteListContents(
101         _DtHelpGlobSearchStuff * srch);
102 static void StatusLabelUpdate(
103     DtHelpDialogWidget hw,
104     ResultsStatus      status,
105     Boolean            forceUpdate,
106     int                intArg);
107 static void ResultsListUpdate(
108     DtHelpDialogWidget hw,
109     _DtHelpFileEntry         newFile);
110 static void StopSearchCB(
111     Widget w,
112     XtPointer clientData,
113     XtPointer callData);
114 static void  VolNameDisplay(
115           DtHelpDialogWidget hw,
116           _DtHelpFileEntry     file,
117           Boolean           insertVol);
118 static int VolHitsDisplay (
119           DtHelpDialogWidget hw,
120           _DtHelpFileEntry     file);
121 static void UpdateSearchVolumesCB(
122     Widget widget,
123     XtPointer clientData,
124     XtPointer callData);
125 static void UpdateSearchStartStatusCB(
126     Widget w,
127     XtPointer clientData,
128     XtPointer callData);
129
130 /********** CONSTANTS *************/
131 #define DIR_SLASH '/'
132 #define EOS       '\0'
133
134 /* message catalog set number for GlobSearch.c */
135 #define GSSET    5
136
137 #define DONT_SET    (-1)              /* used as third value of a Boolean */
138
139 #define HIT_FONT_RES_NAME   "*helpSearchMonoFont"
140 #define HIT_FONT_RES_CLASS  "*HelpSearchMonoFont"
141 #define PREFIX_FONT_SPEC  "-dt-interface user-bold-r-normal-m*-*-*-*-*-m-*-iso8859-1"
142 #define PREFIX_FONT_SPEC1 "-dt-application-bold-r-normal-*-*-140-*-*-m-*-iso8859-1"
143 #define PREFIX_FONT_SPEC2 "-dt-interface user-bold-r-normal-m*-*-*-*-*-m-*-iso8859-1"
144 #define PREFIX_FONT_SPEC3 "courb14"      /* non CDE platforms */
145 #define PREFIX_FONT_TAG   "prefixFontTag"
146
147 #define START_SEARCH_CAT s_GlobSrchDlgBtnCatNum[0]
148 #define START_SEARCH_STR s_GlobSrchDlgBtnStrs[0]
149 #define START_SEARCH_MNEM "S"
150 #define CONT_SEARCH_CAT s_GlobSrchDlgBtnCatNum[1]
151 #define CONT_SEARCH_STR s_GlobSrchDlgBtnStrs[1]
152 #define CONT_SEARCH_MNEM "S"
153 #define STOP_SEARCH_CAT s_GlobSrchDlgBtnCatNum[2]
154 #define STOP_SEARCH_STR s_GlobSrchDlgBtnStrs[2]
155 #define STOP_SEARCH_MNEM "S"
156 #define CLOSE_BTN_CAT s_GlobSrchDlgBtnCatNum[3]
157 #define CLOSE_BTN_STR  s_GlobSrchDlgBtnStrs[3]
158 #define CLOSE_BTN_MNEM  "C"
159 #define HELP_BTN_CAT  s_GlobSrchDlgBtnCatNum[4]
160 #define HELP_BTN_STR  s_GlobSrchDlgBtnStrs[4]
161 #define HELP_BTN_MNEM  "H"
162
163
164 /********** MACROS ************/
165 #define max(a,b)  ((a) > (b) ? (a) : (b))
166
167 /********** Global VARIABLES ************/
168 char _DtHelpDefaultSrchHitPrefixFont[] = PREFIX_FONT_SPEC;
169
170 /********** VARIABLES ************/
171 static const char *DirSlash = "/";
172 static char * s_GlobSrchDlgBtnStrs[] = {
173             "Start Search", 
174             "Continue Search", 
175             "Stop Search",
176             "Close",
177             "Help",
178             NULL };
179 /* catalog index numbers for the strings */
180 static unsigned char s_GlobSrchDlgBtnCatNum[] = {
181              12, 13, 14, 15, 16 };
182
183 static char *     s_PrefixFontListTag = NULL;
184
185 /* Setup for the Retrun Translation set for the text field */
186 static char defaultBtnTranslations[] = "<Key>Return: Activate()";
187 /* static char defaultListTranslations[] = "<Key>Return: Activate()"; */
188 /* static char defaultMgrTranslations[] = "<Key>Return: ManagerParentActivate()"; */
189
190 #if DOC
191 /************************************************************************
192 The startPosition and nextVolPosition values of the DtHelpGlobSrchVol
193 structure are used as follows:
194
195 startPosition:  the position of the volume in the results list
196                 if hitCnt == 0, startPosition is the same value as the
197                 most recent volume with hits
198 nextVolPosition:  the position of the next volume in the results list
199                 if hitCnt == 0, nextVolPosition is the same value as the
200                 most recent volume with hits
201                 The value must be adjusted to include the positions
202                 occupied by hits and topics that are listed for the volume
203
204 These variables are maintained using the AdjustPositionValues()
205 routine, which increment/decrement the position values of all
206 files after the start.  So, when doing a search and display,
207 as results are added to the list, the position values of volumes
208 later in the list are always up to date.
209 ************************************************************************/
210 #endif
211
212 /*======================================================================*/
213 /*======================================================================*/
214 /*======================================================================*/
215 /*======================================================================*/
216  
217 \f
218 /*****************************************************************************
219  * Function:        void MergeFontListIntoWidgetFonts()
220  * 
221  * Parameters:      widget        a widget with a XmNfontList resource
222  *                  newFontsList  font list with fonts to merge into widget
223  *
224  * Return Value:    void
225  *
226  * Purpose:         Merges the fonts from the newFontsList into the fontlist
227  *                  of the widget
228  *
229  *****************************************************************************/
230 static void MergeFontListIntoWidgetFonts(
231      Widget     widget,
232      XmFontList newFontsList)
233 {
234     XmFontList fontList = NULL;
235     XmFontContext context;
236     XmFontListEntry entry;
237     Arg args[2];
238
239     /* get current resultList fontlist */
240     XtSetArg(args[0], XmNfontList, &fontList);
241     XtGetValues(widget,args,1);
242
243     if (NULL == fontList) return;           /* RETURN on error */
244
245     /* work with copy, because FontListAppendEntry() destroys input FL */
246     fontList = XmFontListCopy(fontList);
247
248     /* walk through the volTitlesFontList entries and add them in */
249     XmFontListInitFontContext(&context,newFontsList);
250     for ( entry = XmFontListNextEntry(context);
251           NULL != entry;
252           entry = XmFontListNextEntry(context) )
253     {
254        fontList = XmFontListAppendEntry(fontList,entry);
255     }
256     if (context) XmFontListFreeFontContext(context);
257     
258     /* install the changed list */
259     XtSetArg(args[0], XmNfontList, fontList);
260     XtSetValues(widget,args,1);
261
262     if (fontList) XmFontListFree(fontList);
263 }
264
265 \f
266 /*****************************************************************************
267  * Function:        void UpdateCurVolBtnSens()
268  * 
269  * Parameters:      new          the help widget
270  *
271  * Return Value:    True if cur vol has an index
272  *                  False if not
273  *
274  * Purpose:         Checks on current volume for an index
275                     and sets buttons appropriately
276  *
277  *****************************************************************************/
278 static Boolean UpdateCurVolBtnSens(
279           DtHelpDialogWidget hw,
280           Boolean            selectVolBtn)
281 {
282      XmToggleButtonCallbackStruct status;        /* the call data */
283      Boolean curState;
284      Widget sourceBtn;
285
286      /* set the cur vol btn sensitivity */
287      /* set the volumes/show selection btns by generating a false event */
288      status.reason = XmCR_VALUE_CHANGED;
289      status.set = True;
290      status.event = (XEvent *) 1; /* thwart == NULL test in Update...() */
291
292 #if 0
293      if ( VolumeHasIndexP (
294               hw->help_dialog.srch.srchSources,
295               hw->help_dialog.display.helpType,
296               hw->help_dialog.display.helpVolume) )
297      {
298          curState = True;
299          sourceBtn = hw->help_dialog.srch.curVolRadBtn;
300      }
301      else
302      {
303          curState = False;
304          sourceBtn = hw->help_dialog.srch.allVolRadBtn;
305      }
306      /* ???  XtSetSensitive(hw->help_dialog.srch.curVolRadBtn,curState); */
307      hw->help_dialog.srch.curVolRadBtnSens = curState;
308      if (selectVolBtn) UpdateSearchVolumesCB(sourceBtn,hw,&status);
309 #else
310
311      curState = True;
312      sourceBtn = hw->help_dialog.srch.curVolRadBtn;
313  
314      hw->help_dialog.srch.curVolRadBtnSens = curState;
315      if (selectVolBtn)
316          UpdateSearchVolumesCB(sourceBtn,(XtPointer)hw,(XtPointer)&status);
317 #endif
318
319
320      return curState;
321 }
322  
323 \f
324 /************************************************************************
325  * Function: LoadPrefixFont()
326  *
327  * Loads the prefix font, if that hasn't yet occurred
328  *
329  ************************************************************************/
330 static void LoadPrefixFont(
331           DtHelpDialogWidget hw)
332 {
333    XmFontListEntry entry;
334    XmFontList      curFontList = NULL;
335    XmFontList      newFontList = NULL;
336    char *          fontSpec = NULL;
337    Arg             args[3];
338
339    if (hw->help_dialog.srch.hitsFontLoaded) return;          /* RETURN */
340
341    /* this code is for when the resource is part of the widget */
342    fontSpec = hw->help_dialog.srch.hitPrefixFont;
343
344    /* get current font list */
345    XtSetArg(args[0], XmNfontList, &curFontList);
346    XtGetValues(hw->help_dialog.srch.resultList,args,1);
347
348    /* work with copy, because FontListAppendEntry() destroys input FL */
349    newFontList = XmFontListCopy(curFontList);
350
351    /* load and merge fonts */
352    s_PrefixFontListTag = PREFIX_FONT_TAG;
353    entry = XmFontListEntryLoad(XtDisplay(hw->help_dialog.srch.srchForm),
354              fontSpec,XmFONT_IS_FONT, s_PrefixFontListTag);
355    newFontList = XmFontListAppendEntry(newFontList,entry);
356    XmFontListEntryFree(&entry);
357
358    /* install font */
359    if (NULL == newFontList)
360    {  /* error case */
361       s_PrefixFontListTag = XmFONTLIST_DEFAULT_TAG;
362    }
363    else
364    {
365       /* set new font list */
366       XtSetArg(args[0], XmNfontList, newFontList);
367       XtSetValues(hw->help_dialog.srch.resultList,args,1);
368       if (newFontList) XmFontListFree(newFontList);
369    }
370    hw->help_dialog.srch.hitsFontLoaded = True;
371 }
372
373  
374 \f
375 /************************************************************************
376  * Function: VolumeHasIndexP()
377  *
378  * Looks for the specified volume in the file system and 
379  * tests whether the volume has an index associated with it.
380  *
381  ************************************************************************/
382 static Boolean VolumeHasIndexP (
383     _DtHelpGlobSrchSources srchSource,
384     int          helpType,
385     char *      baseName)
386 {
387    char * path = NULL;
388    _DtHelpVolumeHdl vol;
389    int  keyWordCount = 0;
390    char **currentKeyList = NULL;
391
392    /* if help content isn't a volume, it has no index */
393    if (    _DtHelpGlobSrchCurVolume == srchSource
394         && helpType != DtHELP_TYPE_TOPIC ) 
395        return False;                                     /* RETURN */
396
397    /* try to locate file and its entry, if present */
398    path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, baseName,
399                                   _DtHelpFileSuffixList,False,R_OK);
400    if (_DtHelpOpenVolume(path, &vol) == 0 )
401    {
402       /* Get the keyword list values */
403       keyWordCount = _DtHelpCeGetKeywordList(vol,&(currentKeyList));
404
405       /* no need to free currentKeyList because these are mgd by CE */
406       _DtHelpCloseVolume(vol);
407    }
408
409    XtFree(path);
410    return (keyWordCount > 0);
411 }
412
413
414 \f
415 /************************************************************************
416  * Function: GetVolumeInfoCB()
417  *
418  * Get the info on the volume and return it
419  * Any of the 'out' parameters may be NULL.
420  *
421  ************************************************************************/
422 static Boolean GetVolumeInfoCB (
423     XtPointer  pDisplayArea,  /* in: display area in use */
424     char *     volumePath,    /* in: full path to file */
425     char **    ret_title,     /* out: mallocd doc title text string */
426     XmString * ret_titleXmStr,/* out: mallocd doc title string */
427     char **    ret_docId,     /* out: mallocd doc Id string */
428     char **    ret_timeStamp, /* out: mallocd doc time string */
429     int *      ret_nameKey,   /* out: hash value for fast discimination */
430     XmFontList * io_fontList, /* io: fontList for title */
431     Boolean *  ret_mod)       /* out: has font list been changed */
432 {
433    char empty = EOS;
434    _DtHelpVolumeHdl vol;
435    char * baseName = volumePath;     /* no path component */
436
437    /* calc baseName */
438    if(_DtHelpCeStrrchr(volumePath, DirSlash, MB_CUR_MAX, &baseName)==0)
439         baseName++;
440
441    /* open volume */
442    if ( _DtHelpOpenVolume(volumePath, &vol) != 0 )
443    {  /* if can't open, do best possible */
444       if (ret_titleXmStr) 
445          *ret_titleXmStr = XmStringCreateLocalized(baseName); 
446       if (ret_title) *ret_title= XtNewString(baseName);
447       if (ret_nameKey) *ret_nameKey = _DtHelpCeStrHashToKey(baseName);
448       return False;
449    }
450
451    /** volume is open, now get the data **/
452
453    if (ret_title)
454    {
455       char *   locTitle = NULL;
456
457       /* locTitle is owned by caller */
458       _DtHelpGetAsciiVolumeTitle(pDisplayArea, vol, &locTitle);
459       if (locTitle == NULL)
460          locTitle = XtNewString(baseName);
461       *ret_title = locTitle;
462    }
463
464    if (ret_titleXmStr)
465    {
466       XmString   locTitleXmStr = NULL;
467
468       /* locTitle is owned by caller */
469       _DtHelpFormatVolumeTitle(pDisplayArea,vol,
470                                    &locTitleXmStr,io_fontList,ret_mod);
471       if (locTitleXmStr == NULL)
472          locTitleXmStr = XmStringCreateLocalized(baseName); 
473       *ret_titleXmStr = locTitleXmStr;
474    }
475
476    if (ret_docId || ret_timeStamp)
477    {
478       char * locDocId = NULL;
479       char * locTimeStamp = NULL;
480
481       /* locDocId & locTimeStamp will point to private memory; do not modify */
482       _DtHelpCeGetDocStamp(vol,&locDocId, &locTimeStamp);
483
484       if (ret_docId) 
485          *ret_docId = locDocId ? locDocId : XtNewString(&empty);
486       if (ret_timeStamp) 
487          *ret_timeStamp = locTimeStamp?locTimeStamp:XtNewString(&empty);
488    }
489
490    if (ret_nameKey)
491    {
492       *ret_nameKey = _DtHelpCeStrHashToKey(baseName);
493    }
494
495    _DtHelpCloseVolume(vol);
496
497    return True;
498 }
499
500 \f
501 /************************************************************************
502  * Function: AdjustPositionValues()
503
504  * Adjust the position values of all volumes in the list by the amount given
505  *
506  ************************************************************************/
507 static void AdjustPositionValues(
508    _DtHelpFileList   fileList,
509    int            adjStartAmount,
510    int            adjNextAmount,
511    int            adjustThisFile)
512 {
513    _DtHelpGlobSrchVol * curVol;
514
515    if (   NULL == fileList 
516        || NULL == (curVol = (_DtHelpGlobSrchVol *) fileList->clientData) )
517        return;                                       /* RETURN */
518
519    /* do we need to find first next file that has hits and is in list? */
520    if(False == adjustThisFile)
521    {
522       curVol->nextVolPosition += adjNextAmount;
523       for ( fileList = _DtHelpFileListGetNext(NULL,fileList); /* begin with next */
524             NULL != fileList;
525             fileList = _DtHelpFileListGetNext(NULL,fileList) )
526       {
527          register _DtHelpGlobSrchVol * vol=(_DtHelpGlobSrchVol *)fileList->clientData;
528          if (vol->showVolInList && (vol->hitCnt > 0 || vol->zeroHitsOk) )
529             break;                                   /* BREAK */
530          vol->nextVolPosition += adjNextAmount;
531       }
532       /* all further files require same adj amts */
533       adjStartAmount = adjNextAmount;
534    }
535
536
537    /* add in the adjust amount to all files */
538    for ( /* do nothing */; 
539          NULL != fileList;
540          fileList = _DtHelpFileListGetNext(NULL,fileList) )
541    {
542       register _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) fileList->clientData;
543       if (vol)
544       {
545          vol->startPosition += adjStartAmount;
546          vol->nextVolPosition += adjNextAmount;
547       }
548       /* overwrite, once we've done the first file, if haven't already */
549       adjStartAmount = adjNextAmount;
550    }
551 }
552
553 \f
554 /************************************************************************
555  * Function: HitLoadTopics()
556  *
557  *    Loads the topics referred to by a hit
558  *    Returns: 0 if loaded ok, -1 otherwise
559  ************************************************************************/
560 static int HitLoadTopics (
561           DtHelpDialogWidget hw,
562           _DtHelpFileEntry         file,
563           _DtHelpGlobSrchHit *     hit)
564 {
565     _DtHelpVolumeHdl volHandle;
566     char * *   origTopicIdList = NULL;
567     int        topicCnt;
568     int        i;
569     XmString * titlesList = NULL;
570     char * *   idList = NULL;
571     char * *   fileList = NULL;
572     XmFontList fontList = NULL;
573     Boolean    mod = False;
574     Boolean    allMods = False;
575     Arg        args[5];
576
577     if (hit->topicsLoaded) return 0;                    /* RETURN: ok */
578
579     if (_DtHelpOpenVolume(file->fullFilePath, &volHandle) != 0 ) 
580         return -1;                                      /* RETURN: error */
581
582     topicCnt = _DtHelpCeFindKeyword(volHandle,hit->indexEntry,&origTopicIdList);
583     if (topicCnt <= 0) return -1;                       /* RETURN: error */
584     
585     /* get results font list */
586     XtSetArg(args[0], XmNfontList, &fontList);
587     XtGetValues(hw->help_dialog.srch.resultList,args,1);
588  
589 #if defined(DONT_USE_CDExc22774)
590     /* Don't need to copy, _DtHelpFormatVolumeTitle copies 
591      * before modifying.
592      */
593
594     /* FIX: check whether this is a memory leak.  It isn't if the
595        GetValues of XmFontList returns its own list, not a copy */
596     /* work with copy, because FontListAppendEntry() destroys input FL */
597     fontList = XmFontListCopy(fontList);
598 #endif
599
600     /* get the titles of all topics */
601     for (i=0; i<topicCnt; i++)
602     {
603         XmString titleStr = NULL;
604         Boolean  valid = False;
605         XmFontList lastFontList = NULL;
606
607         /*
608          * mod==True indicates _DtHelpFormatTopicTitle copied fontList
609          * once already.  Save a pointer to it so we can free the font list
610          * if _DtHelpFormatTopicTitle copies it again.
611          */
612         lastFontList = fontList;
613
614         valid = _DtHelpFormatTopicTitle(hw->help_dialog.help.pDisplayArea,
615                     volHandle,origTopicIdList[i], &titleStr, &fontList, &mod);
616
617         if (mod && NULL != lastFontList) XmFontListFree(lastFontList);
618         lastFontList = NULL;
619         allMods |= mod;  /* track for all iterations */
620
621         if(valid!=0 || NULL==titleStr) 
622         {
623            titleStr=XmStringCreateLocalized(origTopicIdList[i]);
624         }  /* if couldn't get title */
625
626         /* note that titleStr is an XmString, not an (Xt) String */
627         titlesList = (XmString *)_DtHelpCeAddPtrToArray (
628                           (void **)titlesList, (void *) titleStr);
629         idList = (char **)_DtHelpCeAddPtrToArray (
630                           (void **)idList,
631                           (void *) XtNewString(origTopicIdList[i]));
632         fileList = (char **)_DtHelpCeAddPtrToArray (
633                           (void **)fileList,
634                           (void *) XtNewString(file->fullFilePath));
635     }  /* for all topics of this index entry */
636
637     /* install font list, if changed */
638     if (allMods)
639     {
640        XtSetArg(args[0], XmNfontList, fontList);
641        XtSetValues(hw->help_dialog.srch.resultList,args,1);
642        if (fontList) XmFontListFree(fontList);
643     }
644
645     /* put results into hit */
646     hit->topicTitles = titlesList;
647     hit->topicIdList = idList;
648     hit->topicFileList = fileList;
649     hit->topicCnt = topicCnt;
650     hit->topicsLoaded = True;
651
652     _DtHelpCloseVolume(volHandle);
653
654     return 0;
655
656
657
658 \f
659 /************************************************************************
660  * Function: HitNameDisplay()
661  *
662  *    Updates the name of the hit, not delete or insert
663  ************************************************************************/
664 static int HitNameDisplay (
665           DtHelpDialogWidget hw,
666           _DtHelpFileEntry     file,
667           _DtHelpGlobSrchHit * hit,
668           int               hitPos,
669           Boolean           insertHit)
670 {
671      char *   expandPrefix;
672      char *   contractPrefix;
673      char *   gotoPrefix;
674      XmString prefixString;
675      XmString labelString;
676      char *   tmpStr;
677      char     buf[30];
678
679      /* FIX: this method of getting/using the prefixes 
680              is a performance nightmare; plus subject to font variability */
681      expandPrefix = (char *)_DTGETMESSAGE (GSSET, 28," +");
682      contractPrefix = (char *)_DTGETMESSAGE (GSSET, 29," -");
683      gotoPrefix = (char *)_DTGETMESSAGE (GSSET, 30,"       ");
684   
685      /* if more than one topic for this index, signal it */
686      tmpStr = gotoPrefix;  /* index entry has one topic */
687      if ( hit->topicCnt > 1 ) 
688      {
689         if (hit->topicsDisplayed)    /* topics currently displayed */
690            tmpStr = contractPrefix;
691         else                         /* topics not displayed */
692            tmpStr = expandPrefix;
693         sprintf(buf, "%s%3d  ", tmpStr, hit->topicCnt); /* 4d too spacy */
694         tmpStr = buf;
695      }
696      LoadPrefixFont(hw);
697      prefixString = XmStringGenerate(tmpStr, s_PrefixFontListTag,
698                                      XmCHARSET_TEXT, NULL);
699      labelString = XmStringConcat(prefixString,hit->indexTitle);
700         /* recall indexTitle is an XmString in the volume's indexXmStrsList */
701
702      /* install/insert the item */
703      if (insertHit)
704         XmListAddItemUnselected(hw->help_dialog.srch.resultList,
705                                  labelString,hitPos);
706      else
707         XmListReplaceItemsPosUnselected(hw->help_dialog.srch.resultList,
708                                  &labelString,1,hitPos);
709
710      XmStringFree(prefixString);
711      XmStringFree(labelString);
712      return (insertHit ? 1 : 0);
713 }
714
715
716 \f
717 /************************************************************************
718  * Function: HitTopicsDisplay()
719  *
720  *    Loads the topics referred to by a hit and displays them
721  *    Returns the number of topics displayed
722  ************************************************************************/
723 static int HitTopicsDisplay (
724           DtHelpDialogWidget hw,
725           _DtHelpFileEntry         file,
726           _DtHelpGlobSrchHit *     hit,
727           int                   firstTopicListPosition)
728 {
729     XmString * pTopicString;
730     XmString prefixString;
731     XmString labelString;
732     XmString *items;
733     char *   tmpStr;
734     int      i;
735
736     if ( False == hit->topicsLoaded && HitLoadTopics(hw,file,hit) < 0 ) 
737        return 0;                                     /* RETURN: error */
738     if ( hit->topicsDisplayed ) return 0;            /* RETURN: ok */
739
740     LoadPrefixFont(hw);
741   /*tmpStr = (char *)_DTGETMESSAGE (GSSET, 32,"  *      ");*/
742     tmpStr = (char *)_DTGETMESSAGE (GSSET, 31,"         ");
743     prefixString = XmStringGenerate(tmpStr, s_PrefixFontListTag,
744                                     XmCHARSET_TEXT, NULL);
745
746     if (hit->topicCnt > 0)
747     {
748         items = (XmString *) XtMalloc (sizeof (XmString) * hit->topicCnt);
749
750         /* put XmString-formatted topic titles into list */
751         for (i = 0, pTopicString = hit->topicTitles; NULL != *pTopicString; 
752                                                 pTopicString++, i++ )
753            items[i] = XmStringConcat(prefixString,*pTopicString);
754
755        XmListAddItemsUnselected(hw->help_dialog.srch.resultList, items,
756                                      hit->topicCnt, firstTopicListPosition);
757        for (i = 0; i < hit->topicCnt; i++)
758            XmStringFree(items[i]);
759        XtFree((char *) items);
760     }
761
762     XmStringFree(prefixString);
763
764     /* set state */
765     hit->topicsDisplayed = True;
766     hit->showTopicsWithHit = True;
767     return hit->topicCnt;
768 }
769
770
771
772 \f
773 /************************************************************************
774  * Function: HitTopicsUndisplay()
775  *
776  *   Releases the topics referred to by a hit and undisplays them
777  *   Returns number of topics removed from display and hit.
778  ************************************************************************/
779 static int HitTopicsUndisplay (
780           DtHelpDialogWidget hw,
781           _DtHelpFileEntry     file,
782           _DtHelpGlobSrchHit * hit,
783           int               firstTopicListPosition)
784 {
785    int      topPos;
786    Arg args[5];
787
788    if ( False == hit->topicsDisplayed ) return 0;           /* RETURN */
789
790    XtSetArg(args[0], XmNtopItemPosition, &topPos);
791    XtGetValues(hw->help_dialog.srch.resultList,args,1);
792
793    /* count the topics -- they are also being collapsed */
794    if (hit->topicCnt > 0) 
795      XmListDeleteItemsPos(hw->help_dialog.srch.resultList,
796                                         hit->topicCnt, firstTopicListPosition);
797
798    hit->topicsDisplayed = False;
799    /* NOTE: don't reset hit->showTopicsWithHit here; require that
800       to be explicitly reset in ProcessResultSelection() */
801
802    XmListSetPos(hw->help_dialog.srch.resultList, topPos);
803
804    return hit->topicCnt;
805 }
806
807
808
809 \f
810 /************************************************************************
811  * Function: HitFree()
812  *
813  *    Frees the memory associated with a hit and returns the next hit
814  *    member of the structure
815  ************************************************************************/
816 static _DtHelpGlobSrchHit * HitFree (
817           _DtHelpGlobSrchHit * hit,
818           Boolean           freeHitItself)
819 {
820    XmString *           nextStr;
821    _DtHelpGlobSrchHit * nextHit;
822
823    if (NULL == hit) return NULL;
824
825    nextHit = hit->next;
826
827    /* Free the mem of the topics id list */
828    _DtHelpCeFreeStringArray(hit->topicIdList);
829    hit->topicIdList = NULL;        /* mem not owned by me */
830
831    /* Free the mem of the topics files list */
832    _DtHelpCeFreeStringArray(hit->topicFileList);
833    hit->topicFileList = NULL;
834
835    /* topicTitles are XmStrings and we can't use FreeStringArray() */
836    for ( nextStr = hit->topicTitles; 
837          NULL != nextStr && NULL != *nextStr; 
838          nextStr++)
839        XmStringFree (*nextStr);
840    XtFree((char *) hit->topicTitles); /* its an XmString * */
841    hit->topicTitles = NULL;
842
843    /* set flags */
844    hit->topicsLoaded = False;
845    hit->topicsDisplayed = False;
846
847    if (freeHitItself)
848      {
849        /* Free the index entry */
850        XtFree(hit->indexEntry);
851        XtFree((String)hit);
852      }
853
854    return nextHit;
855 }
856
857 \f
858 /************************************************************************
859  * Function: HitListFree()
860  *
861  *    Walks along a hit list and frees its contents
862  ************************************************************************/
863 static void HitListFree(
864         _DtHelpGlobSrchVol * vol,
865         Boolean           freeHitsThemselves)
866 {
867    register _DtHelpGlobSrchHit * hit;
868
869    if (NULL == vol) return;                          /* RETURN */
870
871    for ( hit = vol->hitListHead; 
872          NULL != hit; 
873          hit = HitFree(hit,freeHitsThemselves) )
874       { /* nothing */ }
875
876     /* reset search flags */
877     vol->nothingDone = True;
878     vol->topicSearchDone = False;
879     vol->indexSearchDone = False;
880     vol->searchCompleted = False;
881     vol->searchedCnt = 0;
882     vol->gatheredFullIndex = False;
883
884     /* reset hit flags */
885     vol->hitsDisplayed = False;
886     vol->showHitsWithVol = False;
887     vol->zeroHitsOk = False;
888     vol->hitCnt = 0;
889
890     /* reset list display flags */
891     vol->startPosition = 1;
892     vol->nextVolPosition = 1;
893
894     /* dont free indexXmStrsList here because they
895        are reused for every search on this volume */
896     vol->curIndexXmStr = vol->indexXmStrsList;
897
898     /* indexEntriesList,volhandle inited elsewhere */
899
900     if (freeHitsThemselves) 
901     {
902         vol->hitListHead = NULL;
903         vol->hitListTail = NULL;
904     }
905 }
906
907 \f
908 /************************************************************************
909  * Function: HitListFreeAllVolHits()
910  *
911  *    Walks along all the volumes and frees their hits
912  ************************************************************************/
913 static void
914 HitListFreeAllVolHits (
915         DtHelpDialogWidget hw,
916         Boolean            freeFullIndex)
917 {
918    _DtHelpGlobSrchVol * vol;
919    _DtHelpFileEntry     curFile;
920    
921    /* walk the files, freeing all hits and their data */
922    for ( curFile = hw->help_dialog.srch.volListHead;
923          NULL != curFile;
924          curFile = _DtHelpFileListGetNext(NULL,curFile) )
925    {
926        vol = (_DtHelpGlobSrchVol *) curFile->clientData;
927
928        if (NULL == vol) continue;                   /* CONTINUE */
929        if (vol->gatheredFullIndex && freeFullIndex == False) continue;
930        HitListFree(vol,True);         /* True: free hits themselves */
931    }
932    hw->help_dialog.srch.hitsFound = False;
933 }
934
935 \f
936 /************************************************************************
937  * Function: HitListGetNth()
938  *
939  *      Retrieves the Nth entry from the hits contained in the VolList
940  *     
941  *     This code follows the same counting paradigm used when adding
942  *     the items to the srchResultList widget, so that we can just use the
943  *     position value returned by it to retrieve the selected item.
944  *
945  *     This paradigm also counts the presence of a volume as an item
946  *     if it contains any hits, and doesn't count it if it contains
947  *     no hits.  It also counts the topicTitles that are associated
948  *     with a hit and displayed indented beneath it.
949  *
950  *     The position count is 1 based, which corresponds with the 
951  *     XmList approach.
952  *
953  * Return params:
954  *     ret_hit: retuns NULL if an error or a pointer to the hit structure.
955  *     ret_locationId:  returns NULL is position is for the hit
956  *              structure itself, returns a pointer to private
957  *              memory containing the location id if position
958  *              is a topic belonging to the hit.
959  *
960  * Returns: 0 if ok, -1 if error
961  ************************************************************************/
962 static int HitListGetNth (
963     _DtHelpFileList   volListHead,
964     int            position,
965     _DtHelpFileEntry *     ret_file,
966     _DtHelpGlobSrchHit * * ret_hit,
967     char * *            ret_locationId,
968     char * *            ret_helpFile)
969 {
970    _DtHelpGlobSrchHit * hit = NULL;
971    _DtHelpGlobSrchVol * curVol;
972    _DtHelpFileEntry     curFile = NULL;
973    _DtHelpFileEntry     posFile = NULL;
974    char * *          locationIdList = NULL;
975    char * *          fileNameList = NULL;
976    int               curPos;
977    
978    if (NULL == volListHead) goto done;               /* GOTO on error */
979
980    /* walk along the volumes to find the one containing the position
981       Because we need the most recent file with hits before the
982       nextFile that has too high a position, only set posFile when
983       we aren't ready to stop yet and we're on a file with hits. */
984    for ( curFile = volListHead;
985          NULL != curFile;
986          curFile = _DtHelpFileListGetNext(curFile,curFile) )
987    {
988      /* it is impt to use > test so that multiple volumes with the same
989         start position are properly handled.  This occurs when they
990         have no hits in them. */
991      curVol = (_DtHelpGlobSrchVol *) curFile->clientData;
992      if (NULL == curVol) continue;
993 #if 0
994      if (curVol->startPosition > position) break;    /* BREAK */
995      if (curVol->hitCnt > 0) posFile = curFile;      /* recent with hits */
996 #else
997      if (curVol->showVolInList && curVol->nextVolPosition > position) 
998      {
999         posFile = curFile;
1000         break;  /* BREAK */
1001      }
1002 #endif
1003    }
1004    if(NULL == posFile) goto done;                    /* GOTO on error */
1005
1006    /*** walk along the hits to find the one matching the position ***/
1007    curVol = (_DtHelpGlobSrchVol *) posFile->clientData;
1008    curPos = curVol->startPosition;
1009    hit = NULL;
1010    locationIdList = NULL;
1011    fileNameList = NULL;
1012
1013    /* (position == curPos) ==> volume name itself was selected */
1014    if ( curPos < position )
1015    {   /* a hit inside the volume */
1016       if ( curVol->hitsDisplayed )
1017       {
1018          for ( curPos++, hit = curVol->hitListHead;
1019                curPos < position && NULL != hit;
1020                curPos++, hit = hit->next )
1021          {
1022             if (False == hit->topicsDisplayed) continue;      /* CONTINUE */
1023    
1024             /* walk all displayed topics to see if the position is here */
1025             for ( locationIdList=hit->topicIdList,fileNameList=hit->topicFileList;
1026                   NULL != locationIdList[0];
1027                   locationIdList++, fileNameList++ )
1028             {
1029                /* use GOTO to escape with all pointers correct and
1030                   without introducing an additional flag variable */
1031                if (++curPos == position) goto done;      /* GOTO */
1032             }  /* for all locations of a hit before the position */
1033          }  /* for all members of the hit list before the position */
1034       }  /* if hits are currently shown */
1035       else posFile = NULL;            /* an error occurred */
1036    }  /* if position is in the hit list */
1037
1038 done:
1039    if (ret_hit) *ret_hit = hit;
1040    if (ret_file) *ret_file = posFile;
1041    if (ret_locationId)
1042    {
1043      if ( locationIdList ) *ret_locationId = locationIdList[0];
1044      else *ret_locationId = NULL;
1045    }
1046    if (ret_helpFile)
1047    {
1048      if ( fileNameList ) *ret_helpFile = fileNameList[0];
1049      else *ret_helpFile = NULL;
1050    }
1051    /* WARNING: depends on pointers and integers the same size */
1052 #ifdef __osf__
1053    return (NULL == ((ulong_t)hit|(ulong_t)posFile|(ulong_t)locationIdList)) ? -1 : 0;
1054 #else
1055    return (0 == ((int)hit|(int)posFile|(int)locationIdList)) ? -1 : 0;
1056 #endif
1057 }
1058
1059
1060 \f
1061 /************************************************************************
1062  * Function: HitListAddFound()
1063  *
1064  *     Adds a hit to the hit list of the specified volume
1065  *     The hits are added either to the end of the list, 
1066  *     so that the srchResultList presents the items in the order found,
1067  *     or in a sorted order.
1068  *     If a hit on that topic already exists, just the existing
1069  *     hit structure is returned.
1070  *
1071  *  Return Parameters:
1072  *   Ret_hit points to the hit data.  This is not a copy--do not
1073  *     free the pointer.
1074  *     
1075  *  Return value:
1076  *     Returns 0 if no error, -1 if an error occurred.
1077  ************************************************************************/
1078 static int HitListAddFound (
1079     _DtHelpFileEntry     curFile,
1080     XmString             indexTitle,
1081     char *               indexEntry,
1082     Boolean              insertSorted,
1083     _DtHelpGlobSrchHit **ret_hit)
1084 {
1085    _DtHelpGlobSrchHit * prev;
1086    _DtHelpGlobSrchHit * next;
1087    _DtHelpGlobSrchHit * srcHit;
1088    _DtHelpGlobSrchVol * vol;
1089    int               newKey;
1090    extern _CEStrcollProc _DtHelpCeGetStrcollProc();
1091    _CEStrcollProc strcollfn = _DtHelpCeGetStrcollProc();
1092    
1093    if (NULL == curFile) return -1;                 /* RETURN */
1094    vol = (_DtHelpGlobSrchVol *) curFile->clientData;
1095    if (NULL == vol) return -1;                     /* RETURN */
1096
1097    /* walk along the hits, looking for one matching the new hit */
1098    /* recall that position is 1-based */
1099    newKey = _DtHelpCeStrHashToKey(indexEntry);
1100    prev = next = NULL;
1101    if ( insertSorted )     /* find position and check for duplicates */
1102    {
1103       /* walk along list */
1104       for( next = vol->hitListHead;
1105            NULL != next; 
1106            prev = next, next = next->next )
1107       {
1108         register int ret;
1109
1110         /* do a NLS case insensitive compare using NLS collating */
1111         if ( (ret = (*strcollfn)(next->indexEntry,indexEntry)) >= 0 )
1112         {
1113           if (0 == ret)
1114           {
1115              if(ret_hit) *ret_hit = next;
1116              return 0;                                  /* RETURN */
1117           }
1118           /* prev and next are set correctly */
1119           break;                                        /* BREAK */
1120         }
1121       }
1122    }
1123    else     /* check for duplicates */
1124    {
1125       /* walk along list */
1126       for( next = vol->hitListHead;
1127            NULL != next; 
1128            prev = next, next = next->next )
1129       {
1130         if (    newKey == next->indexKey                    /* quick compare */
1131              && strcmp(indexEntry,next->indexEntry) == 0 )  /* long compare */
1132         {
1133           if(ret_hit) *ret_hit = next;
1134           return 0;                                    /* RETURN */
1135         }
1136       }
1137       /* prev and next are set correctly (at end of list) */
1138    }
1139
1140    /* handle a new hit */
1141    srcHit = (_DtHelpGlobSrchHit *)XtCalloc(1,sizeof(_DtHelpGlobSrchHit));
1142    if (NULL == srcHit) return -1;                         /* RETURN */
1143
1144    /* init hit values */
1145    /* leave srcHit->hitCnt == 0 here */
1146    if (NULL == indexTitle)
1147       srcHit->indexTitle = XmStringCreateLocalized(indexEntry);
1148    else
1149       srcHit->indexTitle = indexTitle;
1150    srcHit->indexEntry = XtNewString(indexEntry);
1151    srcHit->indexKey = newKey;
1152    srcHit->volume = curFile;
1153
1154    /* integrate hit into the list */
1155    srcHit->next = next;
1156    if (prev) prev->next = srcHit;
1157    else vol->hitListHead = srcHit;
1158    if (!next) vol->hitListTail = srcHit;
1159
1160    /* add in the volume contribution */
1161    vol->hitCnt++;
1162   
1163    /* return stuff */
1164    if(ret_hit) *ret_hit = srcHit;
1165    return 0;
1166 }
1167
1168
1169 \f
1170 /************************************************************************
1171  * Function: CountSelectedVolumes()
1172  *
1173  *      Counts the number volumes with the searchThisVolume flag set
1174  *      for which the search has yet to complete
1175  *
1176  ************************************************************************/
1177 static int CountSelectedVolumes (
1178     _DtHelpFileList  volListHead,
1179     Boolean countSearchCompletedVolumes)
1180 {
1181   int               count = 0;
1182  
1183   /* walk all volumes */
1184   for ( /* nothing */;
1185         NULL != volListHead;
1186         volListHead = _DtHelpFileListGetNext(NULL, volListHead) )
1187   {
1188     register _DtHelpGlobSrchVol * vol;
1189
1190     /* get the volume info */
1191     vol = (_DtHelpGlobSrchVol *) volListHead->clientData;
1192 /* if (NULL != vol && vol->searchThisVolume && False == vol->searchCompleted)*/
1193     if (vol && vol->searchThisVolume)
1194     {
1195        if (   (False == vol->searchCompleted)
1196            || (countSearchCompletedVolumes && vol->searchCompleted) )
1197           count++;
1198     }
1199   } /* walk all volumes */
1200   return count;
1201 }
1202
1203
1204 \f
1205 /************************************************************************
1206  * Function: GetNextSearchFileAndDisplayCompleted()
1207  *
1208  *      Scans list for next file ready for searching
1209  *      If it encounters a file that has completed it's search
1210  *      and for which the results should be displayed, they are displayed
1211  *
1212  ************************************************************************/
1213 static _DtHelpFileEntry GetNextSearchFileAndDisplayCompleted(
1214                  DtHelpDialogWidget hw,
1215                  _DtHelpFileList          listHead,
1216                  _DtHelpFileEntry         curFile)
1217 {
1218     /* get first file needing work */
1219     for ( curFile = _DtHelpFileListGetNext(listHead, curFile);
1220           NULL != curFile;
1221           curFile = _DtHelpFileListGetNext(NULL, curFile) )
1222     {
1223        register _DtHelpGlobSrchVol * vol;
1224
1225        vol = (_DtHelpGlobSrchVol *) curFile->clientData;
1226        if (NULL == vol) continue;                  /* CONTINUE */
1227
1228        /* if file already searched and should be displayed, then do so */
1229        if (   vol->searchThisVolume && vol->searchCompleted 
1230            && vol->showVolInList && (vol->hitCnt > 0 || vol->zeroHitsOk) )
1231        {
1232           /* record that a hit found */
1233           if (   vol->hitCnt > 0
1234               || (    vol->zeroHitsOk 
1235                   && _DtHelpGlobSrchSelectedVolumes == hw->help_dialog.srch.srchSources))
1236              hw->help_dialog.srch.hitsFound = True;
1237
1238           /* True: adjust count beginning with this file */
1239           AdjustPositionValues(curFile,0,1,True);
1240           ResultsListUpdate(hw,curFile);
1241    
1242           /* display the hits as well? */
1243           if (   vol->showHitsWithVol
1244               || hw->help_dialog.srch.srchSources == _DtHelpGlobSrchCurVolume)
1245           {
1246              VolHitsDisplay(hw,curFile);
1247
1248              /* update the volume label to show state; False--dont insert */
1249              VolNameDisplay(hw,curFile,False);
1250           }
1251        }
1252    
1253        /* if want to search, and need to, then return it */
1254        if (    vol->searchThisVolume && False == vol->searchCompleted 
1255             && vol->showVolInList ) /* don' search unless results will be shown */
1256           break;
1257     }
1258
1259     XmUpdateDisplay((Widget) hw->help_dialog.srch.resultList);
1260     return curFile;
1261 }
1262
1263
1264 \f
1265 /************************************************************************
1266  * Function: AddVolInfoToFile
1267  *
1268  *      Creates a volume info entry for each member of the list
1269  *      and initializes its values
1270  *      If searchStatus is False, all volumes are set.  If its True,
1271  *      all are set if selectedFilesOnly is false, otherwise only
1272  *      selected files are set to true.
1273  *
1274  ************************************************************************/
1275 static void AddVolInfoToFile(
1276         _DtHelpFileEntry file,
1277         Boolean      initialSearchStatus,
1278         Boolean      displayStatus,
1279         Boolean      selectedFilesOnly)
1280 {
1281    _DtHelpGlobSrchVol * vol;
1282
1283    if (NULL == file) return;                     /* RETURN */
1284
1285    vol = (_DtHelpGlobSrchVol *) file->clientData;
1286    if (NULL == vol)
1287    {
1288       vol = (_DtHelpGlobSrchVol *) XtCalloc(1,sizeof(_DtHelpGlobSrchVol));
1289       file->clientData = (XtPointer) vol;
1290       if (NULL == vol) return;       /* RETURN:  memory alloc error */
1291
1292       /* calloc() inited almost everything inside to 0 */
1293       /* set first time creation values */
1294       vol->nothingDone = True;
1295    }
1296
1297    /* now set search and display flags */
1298    vol->searchThisVolume = initialSearchStatus;
1299    vol->showVolInList = displayStatus;
1300    if ( False == file->fileSelected && True == selectedFilesOnly )
1301    {
1302       vol->searchThisVolume = False;
1303       vol->showVolInList = False;
1304    }
1305 }
1306
1307
1308 /************************************************************************
1309  * Function: AddVolInfoToList
1310  *
1311  *      Creates a volume info entry for each member of the list
1312  *      and initializes its values
1313  *      If searchStatus is False, all volumes are set.  If its True,
1314  *      all are set if selectedFilesOnly is false, otherwise only
1315  *      selected files are set to true.
1316  *
1317  ************************************************************************/
1318 static void AddVolInfoToList(
1319         _DtHelpFileList listHead,
1320         Boolean      initialSearchStatus,
1321         Boolean      displayStatus,
1322         Boolean      selectedFilesOnly)
1323 {
1324    /* walk the files and allocate the vol info as needed */
1325    for ( /*nothing*/;
1326          NULL != listHead;
1327          listHead = _DtHelpFileListGetNext(listHead,listHead) )
1328    {
1329        AddVolInfoToFile(listHead,
1330                  initialSearchStatus, displayStatus, selectedFilesOnly);
1331    }
1332 }
1333
1334
1335 \f
1336 /************************************************************************
1337  * Function: SetVolStatus()
1338  *
1339  *      Sets all volumes in the list to the specified search and/or display
1340  *      status values.
1341  *
1342  *      If searchThisVolume is False, all volumes are set.  If its True,
1343  *      all are set if selectedFilesOnly is false, otherwise only
1344  *      selected files are set to true.  If searchThisVolume is False,
1345  *      then the settings remain unchanged in all volumes.
1346  *
1347  ************************************************************************/
1348 static void SetVolStatus(
1349         _DtHelpFileList listHead,
1350         Boolean      searchThisVolume,
1351         Boolean      showVolInList,
1352         Boolean      zeroHitsOk,
1353         Boolean      selectedFilesOnly)
1354 {
1355    /* walk the files and set the status */
1356    for ( /*nothing*/;
1357          NULL != listHead;
1358          listHead = _DtHelpFileListGetNext(listHead,listHead) )
1359    {
1360      _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) listHead->clientData;
1361
1362      if (NULL == vol) continue;
1363
1364      if (    (False == selectedFilesOnly)
1365           || (True == listHead->fileSelected && True == selectedFilesOnly) )
1366      {
1367         /* just set the inclusion and/or display flags; 
1368            don't reset the search progress flags */
1369         vol->searchThisVolume = searchThisVolume;
1370         vol->showVolInList = showVolInList;
1371         vol->zeroHitsOk = zeroHitsOk;
1372      }
1373    }
1374 }
1375
1376 \f
1377 /************************************************************************
1378  * Function: VolNameDisplay()
1379  *
1380  *    Updates the display of the volume name
1381  ************************************************************************/
1382 static void  VolNameDisplay(
1383           DtHelpDialogWidget hw,
1384           _DtHelpFileEntry     file,
1385           Boolean           insertVol)
1386 {
1387    _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) file->clientData;
1388    XmString prefixString;
1389    XmString labelString;
1390    char *   tmpStr;
1391    char     buf[40];
1392
1393    if ( NULL == vol || (False == vol->zeroHitsOk && 0 == vol->hitCnt) )
1394        return;                                      /* RETURN */
1395
1396    /* put volume name into list */
1397    if (vol->hitCnt <= 0) tmpStr = (char *)_DTGETMESSAGE (GSSET, 25," ");
1398    else if (vol->hitsDisplayed) tmpStr = (char *)_DTGETMESSAGE (GSSET, 27,"-");
1399    else tmpStr = (char *)_DTGETMESSAGE (GSSET, 26,"+");   /* >0 hits */
1400    sprintf(buf, "%s%3d ", tmpStr, vol->hitCnt);  /* 4d too spacy */
1401
1402    LoadPrefixFont(hw);
1403    prefixString = XmStringGenerate(buf, s_PrefixFontListTag,
1404                                    XmCHARSET_TEXT, NULL);
1405    labelString = XmStringConcat(prefixString,file->fileTitleXmStr);
1406
1407    /* replace or insert to reflect changed contents */
1408    if (insertVol)
1409       XmListAddItemUnselected(hw->help_dialog.srch.resultList,
1410                                  labelString, vol->startPosition);
1411    else
1412       XmListReplaceItemsPosUnselected(hw->help_dialog.srch.resultList,
1413                                  &labelString, 1, vol->startPosition);
1414
1415    XmStringFree(prefixString);
1416    XmStringFree(labelString);
1417 }
1418
1419 \f
1420 /************************************************************************
1421  * Function: VolHitsDisplay()
1422  *
1423  *    displays the hits associated with a volume
1424  *    Returns the number of new items added to the list
1425  ************************************************************************/
1426 static int VolHitsDisplay (
1427           DtHelpDialogWidget hw,
1428           _DtHelpFileEntry     file)
1429 {
1430      _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) file->clientData;
1431      _DtHelpGlobSrchHit * hit;
1432      int               listPos = vol->startPosition; /* vol item position */
1433      int               itemCnt;
1434
1435      if (True == vol->hitsDisplayed ) return 0;        /* RETURN */
1436
1437      _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1438      if (hw->help_dialog.srch.selectionDlg)
1439         _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1440
1441      /*** walk through the hits and count and display any open hits ***/
1442      for ( hit = vol->hitListHead, itemCnt = 0; 
1443            NULL != hit;
1444            hit = hit->next)
1445      {
1446         itemCnt++;           /* True: insert Hit into list */
1447         HitNameDisplay (hw,file,hit,listPos + itemCnt,True);
1448
1449         /* display topics too? */
1450         if (hit->showTopicsWithHit)
1451         {
1452            int newItems;
1453            newItems = HitTopicsDisplay(hw,file,hit, listPos + itemCnt + 1);
1454            HitNameDisplay (hw,file,hit,listPos + itemCnt,False);
1455            itemCnt += newItems;
1456         }
1457      }
1458
1459      /* new state */
1460      vol->hitsDisplayed = True;
1461      vol->showHitsWithVol = True;
1462      
1463      /* adjust count beginning with next file with hits */
1464      AdjustPositionValues(file, 0, itemCnt, True);
1465
1466      _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1467      if (hw->help_dialog.srch.selectionDlg)
1468         _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1469
1470      return itemCnt;
1471 }
1472
1473
1474 \f
1475 /************************************************************************
1476  * Function: VolHitsUndisplay()
1477  *
1478  *    undisplays the hits associated with a volume
1479  ************************************************************************/
1480 static int VolHitsUndisplay (
1481           DtHelpDialogWidget hw,
1482           _DtHelpFileEntry     file)
1483 {
1484    _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) file->clientData;
1485    _DtHelpGlobSrchHit * hit;
1486    Boolean           nonVisibleItems;
1487    int               listPos = vol->startPosition; /* vol item position */
1488    int               itemCnt;
1489    int               curDelPos;
1490    int               undisItemCnt;
1491    int               visItemCnt;
1492    int               topNonVisPos;
1493    int               topPos;
1494    Arg               args[5];
1495
1496    if (False == vol->hitsDisplayed) return 0;         /* RETURN */
1497
1498    _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1499    if (hw->help_dialog.srch.selectionDlg)
1500       _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1501
1502    XtSetArg(args[0], XmNtopItemPosition, &topPos);
1503    XtSetArg(args[1], XmNvisibleItemCount, &visItemCnt);
1504    XtGetValues(hw->help_dialog.srch.resultList,args,2);
1505
1506    /* these are the num visible items below the volume name */
1507    topNonVisPos = topPos + visItemCnt;   /* 1st non vis pos */
1508
1509    /* num of items that will be undisplayed */
1510    undisItemCnt = vol->nextVolPosition - (vol->startPosition + 1);
1511
1512    /* find out if any items aren't visible */
1513    nonVisibleItems = False;
1514    if ( vol->nextVolPosition > topNonVisPos )
1515       nonVisibleItems = True;
1516
1517    /*** walk through the hits and count and delete any open topics ***/
1518    /* Make two passes:  the first pass deletes all non-visible
1519       items.  The second pass deletes the remaining visible items.
1520       The objective is to make collapse as fast and smooth as expand. */
1521    if (nonVisibleItems)
1522    {  /* delete all items with a position > topNonVisPos */
1523       curDelPos = listPos + 1;   /* starting position */
1524       for ( hit = vol->hitListHead, itemCnt = 0; 
1525             NULL != hit;
1526             hit = hit->next )
1527       {
1528          /* are we still in the visible region? */
1529          if (curDelPos < topNonVisPos)
1530          {
1531             /* move down the list to next hit */
1532             curDelPos++;         /* this hit's item */
1533             /* plus any open topics */
1534             if (hit->topicsDisplayed) curDelPos += hit->topicCnt;
1535             continue;                           /* CONTINUE */
1536          }
1537          /* we're in non-visible region--undisplay hit */
1538          XmListDeletePos(hw->help_dialog.srch.resultList, curDelPos);
1539          /* undisplay any topics */
1540          if ( hit->topicsDisplayed )
1541             itemCnt += HitTopicsUndisplay(hw,file,hit,curDelPos);
1542       }
1543    } /* if non visible items */
1544
1545    /* now delete the remaining visible items */
1546    /* Note that curDelPos is a virtual cursor that helps us
1547       figure out when to stop undisplaying.  Virtually, we''re
1548       moving the cursor down the list with every delete.  Actually,
1549       the rest of the list bumps up one--that''s why we delete
1550       at listPos+1. */
1551  
1552    curDelPos = listPos + 1;   /* starting position */
1553    for ( hit = vol->hitListHead, itemCnt = 0; 
1554          (NULL != hit) && (curDelPos < topNonVisPos);
1555          hit = hit->next )
1556    {
1557       curDelPos++;      /* undisplay hit item */
1558       XmListDeletePos(hw->help_dialog.srch.resultList, listPos + 1);
1559       /* undipslay any open topics */
1560       if ( hit->topicsDisplayed )
1561       {
1562          curDelPos += HitTopicsUndisplay(hw,file,hit,listPos + 1);
1563          XmListSetPos(hw->help_dialog.srch.resultList, topPos);
1564       }
1565    }
1566
1567    /* new state */
1568    vol->hitsDisplayed = False;
1569    /* NOTE: don't reset vol->showHitsWithVol here; require that
1570       to be explicitly reset in ProcessResultSelection() */
1571    
1572    /* adjust count beginning with next file with hits */
1573    AdjustPositionValues(file, 0, -undisItemCnt, True);
1574
1575    XmListSetPos(hw->help_dialog.srch.resultList, topPos);
1576
1577    _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1578    if (hw->help_dialog.srch.selectionDlg)
1579       _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1580
1581    return undisItemCnt;
1582 }
1583
1584
1585 \f
1586 /************************************************************************
1587  * Function: VolListFree()
1588  *
1589  *      Releases all memory used by the volume list
1590  *
1591  ************************************************************************/
1592 static void VolListFree (
1593     _DtHelpGlobSearchStuff * srch)
1594 {
1595   _DtHelpFileList      nextFile;
1596  
1597   /* walk all volumes */
1598   nextFile = srch->volListHead;
1599   while ( NULL != nextFile )
1600   {
1601   _DtHelpGlobSrchVol * vol;
1602   _DtHelpFileList      tmpFile;
1603   XmString *           nextStr;
1604
1605     /* get the volume info */
1606     vol = (_DtHelpGlobSrchVol *) nextFile->clientData;
1607     
1608     /** free vol entry contents and container **/
1609     XtFree(vol->stdLocale);
1610     XtFree(vol->iconv3Codeset);
1611     HitListFree(vol,True);           /* True: free hits themselves */
1612
1613     /* no need to free indexEntriesList because these aren't owned by vol */
1614     vol->indexEntriesList = NULL;
1615
1616     /* free indexXmStrsList */
1617     /* indexXmStrs are XmStrings and we can't use FreeStringArray() */
1618     for ( nextStr = vol->indexXmStrsList;
1619           NULL != nextStr && NULL != *nextStr; 
1620           nextStr++)
1621        XmStringFree (*nextStr);
1622     XtFree((char *) vol->indexXmStrsList); /* its a XmString * */
1623     vol->indexXmStrsList = NULL;
1624
1625     tmpFile = nextFile;
1626     nextFile = _DtHelpFileListGetNext(NULL, nextFile);
1627     _DtHelpFileFreeEntry(tmpFile);     /* also frees the clientData (vol) */
1628   } /* walk all volumes */
1629
1630   /* reset related values */
1631   srch->volListHead = NULL;
1632   srch->curSrchVol = NULL;
1633   srch->volLeftCnt = 0;
1634
1635   /* delete the results */
1636   DeleteListContents(srch);
1637 }
1638
1639
1640 \f
1641 /************************************************************************
1642  * Function: ScanStatusCB
1643  *
1644  *     Updates the status display with the number of volumes found
1645  *     as the scan progresses
1646  *
1647  ************************************************************************/
1648 static void ScanStatusCB(
1649           int           count,
1650           XtPointer     clientData)
1651 {
1652    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
1653
1654    StatusLabelUpdate(hw,SCANNING_STATUS,True,count);
1655 }
1656
1657 \f
1658 /************************************************************************
1659  * Function: VolListBuild
1660  *
1661  *     Frees the old list and builds a new one by scanning the
1662  *     help directories for volumes and adding the associated
1663  *     volume information used for searching.
1664  *
1665  ************************************************************************/
1666 static void VolListBuild(
1667           DtHelpDialogWidget hw,
1668           Boolean               searchStatus,
1669           Boolean               displayStatus,
1670           Boolean               selectedVolumesOnly)
1671 {
1672     Boolean mod;
1673     XmFontList origFontList;
1674
1675     /* turn on hour glass */
1676     _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1677      if (hw->help_dialog.srch.selectionDlg)
1678         _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1679
1680     StatusLabelUpdate(hw,SCANNING_STATUS,True,0);
1681      
1682     origFontList = hw->help_dialog.srch.volTitlesFontList;
1683
1684     /* and rescan the volumes for the new list */
1685    _DtHelpFileListScanPaths( &hw->help_dialog.srch.volListHead,
1686                      &hw->help_dialog.srch.volTitlesFontList,&mod,
1687                      DtHelpVOLUME_TYPE, _DtHelpFileSuffixList, False, 
1688                      GetVolumeInfoCB,hw->help_dialog.help.pDisplayArea,
1689 /* sysPathCompare */ _DtHELP_FILE_NAME, 
1690 /*otherPathCompare*/ _DtHELP_FILE_NAME|_DtHELP_FILE_TIME| _DtHELP_FILE_IDSTR, 
1691 /* sortBy */         _DtHELP_FILE_TITLE, ScanStatusCB, (XtPointer)hw);
1692   
1693     /* if new fonts added to list, add them to the resultList */
1694     if (mod)
1695     {
1696         MergeFontListIntoWidgetFonts( 
1697               hw->help_dialog.srch.resultList,
1698               hw->help_dialog.srch.volTitlesFontList);
1699
1700         if (origFontList) XmFontListFree(origFontList);
1701     }
1702
1703     /* Add on the Vol info and (T,F) allow search on all volumes */
1704     AddVolInfoToList(hw->help_dialog.srch.volListHead, 
1705                            searchStatus, displayStatus, selectedVolumesOnly);
1706
1707     hw->help_dialog.srch.volScanDone = True;
1708
1709     StatusLabelUpdate(hw,BLANK_STATUS,True,0);
1710
1711     /* turn off hour glass */
1712     _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
1713      if (hw->help_dialog.srch.selectionDlg)
1714         _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
1715 }
1716
1717
1718 \f
1719 #if 0 || defined(DEBUG) /* for debug, set to 1 */
1720 /************************************************************************
1721  * Function: OutputVolInfo()
1722  *
1723  *      Output info on all volumes in the list
1724  *
1725  ************************************************************************/
1726 static void OutputVolInfo(
1727         _DtHelpFileList listHead)
1728 {
1729    for ( /*nothing*/;
1730          NULL != listHead;
1731          listHead = _DtHelpFileListGetNext(listHead,listHead) )
1732    {
1733      _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) listHead->clientData;
1734      if (NULL == vol) continue;
1735
1736      /* output the info */
1737      printf("==================\n");
1738      printf("fileName: %s, %s\npathName: %s\n",
1739          listHead->fileName, listHead->fileTitle, listHead->fullFilePath);
1740      printf("searchThisVolume = %d, hitCnt = %d, startPos = %d\n",
1741          (int) listHead->fileSelected,
1742          (int) vol->hitCnt,
1743          (int) vol->startPosition);
1744    }
1745 }
1746 #endif
1747
1748 \f
1749 /************************************************************************
1750  * Function: SearchContinuePossible()
1751  *
1752  *      Test whether the search can be continued from the
1753  *      current state.
1754  *
1755  ************************************************************************/
1756 static Boolean SearchContinuePossible(
1757    DtHelpDialogWidget hw,
1758    char *             srchWord)
1759 {
1760     char *  normSrchWord;
1761     Boolean possible = False;
1762
1763     normSrchWord = XtNewString(srchWord);
1764     _DtHelpCeCompressSpace(normSrchWord);
1765     _DtHelpCeUpperCase(normSrchWord);
1766
1767    /* are we searching on the same word as previous search ? */
1768    /* comparison with srchNormWordStr is correct, given calls to this fn */
1769 /* FIX: use CheckSearchWord()? */
1770    if (   (   hw->help_dialog.srch.fullIndex
1771            || (   NULL != hw->help_dialog.srch.normWordStr
1772                && NULL != normSrchWord
1773                && strcmp(normSrchWord, hw->help_dialog.srch.normWordStr) == 0) )
1774         && NULL != hw->help_dialog.srch.volListHead 
1775         && hw->help_dialog.srch.volLeftCnt > 0 )
1776        possible = True;
1777
1778     XtFree(normSrchWord);
1779     return possible;
1780 }
1781
1782 \f
1783 #ifdef  not_used
1784 /************************************************************************
1785  * Function: SearchOnSameCriteria()
1786  *
1787  *      Test whether the search criteria have changed
1788  *
1789  ************************************************************************/
1790 static Boolean SearchOnSameCriteria(
1791    DtHelpDialogWidget hw,
1792    char *             srchWord)
1793 {
1794     char *  normSrchWord;
1795     Boolean sameCrit = False;
1796
1797     normSrchWord = XtNewString(srchWord);
1798     _DtHelpCeCompressSpace(normSrchWord);
1799     _DtHelpCeUpperCase(normSrchWord);
1800
1801    /* are we searching on the same word as previous search ? */
1802    /* comparison with srchNormWordStr is correct, given calls to this fn */
1803    if (   hw->help_dialog.srch.fullIndex
1804        || (   NULL != hw->help_dialog.srch.normWordStr
1805            && NULL != normSrchWord
1806            && strcmp(normSrchWord, hw->help_dialog.srch.normWordStr) == 0) )
1807        sameCrit = True;
1808
1809     XtFree(normSrchWord);
1810     return sameCrit;
1811 }
1812 #endif /* not_used */
1813
1814
1815
1816 \f
1817 /************************************************************************
1818  * Function: UpdateActionButtonLabel()
1819  *
1820  *      Sets the start button label properly
1821  *
1822  ************************************************************************/
1823 static void UpdateActionButtonLabel(
1824    DtHelpDialogWidget hw,
1825    char * srchWord,
1826    Boolean startContAction)
1827 {
1828    Arg        args[5];
1829    XmString   labelString;
1830    XmString   curLabelString;
1831    String     textString;
1832    /* char *     mnemonic; */
1833
1834    /* if action label is to start or continue */
1835    _DtHelpProcessLock();
1836    if (startContAction)
1837    {
1838       if ( SearchContinuePossible(hw,srchWord) )
1839       {  /* then continue search */
1840          textString=(char *)_DTGETMESSAGE (GSSET, 
1841                                  CONT_SEARCH_CAT,CONT_SEARCH_STR);
1842          labelString = XmStringCreateLocalized(textString);
1843          /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 22,CONT_SEARCH_MNEM));*/
1844       }
1845       else
1846       {  /* otherwise start it */
1847          textString=(char *)_DTGETMESSAGE (GSSET,
1848                                  START_SEARCH_CAT,START_SEARCH_STR);
1849          labelString = XmStringCreateLocalized(textString);
1850          /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 20,START_SEARCH_MNEM));*/
1851       }
1852    }
1853    else    /* action label is to stop */
1854    {
1855       textString = (char *)_DTGETMESSAGE (GSSET, 
1856                                  STOP_SEARCH_CAT,STOP_SEARCH_STR);
1857       labelString = XmStringCreateLocalized(textString);
1858       /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, ??,STOP_SEARCH_MNEM));*/
1859    }
1860    _DtHelpProcessUnlock();
1861
1862    /* get the current state of the button */
1863    XtSetArg(args[0],XmNlabelString,&curLabelString);
1864    XtGetValues (hw->help_dialog.srch.actionBtn, args, 1);
1865
1866    /* update label if it is different; avoid flashing this way */
1867    if ( XmStringCompare(labelString,curLabelString) == False )
1868    {
1869       XtSetArg(args[0],XmNlabelString,labelString);
1870       XtSetArg(args[1], XmNalignment, XmALIGNMENT_CENTER);
1871 /*    XtSetArg(args[2], XmNmnemonic, mnemonic[0]);*/
1872       XtSetValues (hw->help_dialog.srch.actionBtn, args, 2);
1873       XmUpdateDisplay(hw->help_dialog.srch.actionBtn);
1874    }
1875
1876    /* release the memory */
1877    XmStringFree(labelString);
1878    XmStringFree(curLabelString);
1879 }
1880
1881 \f
1882 /*****************************************************************************
1883  * Function:        CheckSearchWord()
1884  *
1885  * Parameters:  
1886  *
1887  * Return Value:    True: word has changed
1888  *                  False: word is same
1889  *
1890  * Purpose:         Checks whether the search word is a new
1891  *                  one or the same as before.  If the same, it frees
1892  *                  the word and returns False.  If new, it moves the
1893  *                  previous word to another variable and installs
1894  *                  the new word in its place, using the srchWord mem.
1895  *                  ...but only if updateWidgetFields is True
1896  *
1897  *****************************************************************************/
1898 static Boolean CheckSearchWord(
1899          DtHelpDialogWidget   hw,
1900          char *                srchWord,
1901          Boolean               updateWidgetFields)
1902 {
1903      wchar_t firstChar;
1904      char *  rawSrchWord;
1905
1906      /* avoid a core dump */
1907      if (   NULL == srchWord )
1908      {
1909         if (    NULL == hw->help_dialog.srch.normWordStr
1910              || hw->help_dialog.srch.normWordStr[0] == 0) 
1911             return False; /* word hasn't changed */
1912         return True;                           /* RETURN: word has changed */
1913      }
1914
1915      _DtHelpCeCompressSpace(srchWord);
1916      rawSrchWord = XtNewString(srchWord);
1917      _DtHelpCeUpperCase(srchWord);
1918      /* FIX: to support regcomp(3), do that here */
1919
1920      /* are we searching on the same word? */
1921      if (    NULL != hw->help_dialog.srch.normWordStr
1922           && strcmp(srchWord, hw->help_dialog.srch.normWordStr) == 0 )
1923      {
1924          XtFree(srchWord);
1925          XtFree(rawSrchWord);
1926 #if 0
1927          /* output a message */
1928          if (    NULL != hw->help_dialog.srch.normWordStr 
1929               && EOS != hw->help_dialog.srch.normWordStr[0])
1930             StatusLabelUpdate(hw,FIRST_PROMPT_STATUS,False,0);
1931 #endif
1932
1933          return False;                           /* RETURN: no change */
1934      }
1935      
1936      if (False == updateWidgetFields) return True; /* RETURN */
1937
1938      /* update search word fields */
1939      XtFree(hw->help_dialog.srch.normWordStr);
1940      XtFree(hw->help_dialog.srch.rawWordStr);
1941      hw->help_dialog.srch.normWordStr = srchWord;
1942      hw->help_dialog.srch.rawWordStr = rawSrchWord;
1943      hw->help_dialog.srch.wordFieldLen = strlen(srchWord); /* note: not nl_strlen 
1944                                   because used on strncmp not nl_strncmp */
1945
1946      /* convert first char to a value for easy access for _DtHelpStrchr() */
1947      if ( mbtowc(&firstChar,srchWord,1) <= 0 ) firstChar = 0;
1948      hw->help_dialog.srch.wordFieldFirstChar = firstChar;
1949
1950      /* output a message */
1951      if (    NULL != hw->help_dialog.srch.normWordStr 
1952           && EOS != hw->help_dialog.srch.normWordStr[0])
1953         StatusLabelUpdate(hw,FIRST_PROMPT_STATUS,False,0);
1954
1955      return True;  /* word changed */
1956 }
1957
1958
1959 \f
1960 /*****************************************************************************
1961  * Function:        PrepSearchSourceData()
1962  *
1963  * Parameters:  
1964  *
1965  * Return Value:    Void.
1966  *
1967  * Purpose:         Based on the current settings of the volume
1968  *                  selection buttons construct or utilitize an
1969  *                  existing volume list for processing.
1970  *                  Determine whether to continue search or
1971  *                  restart by comparing search words and states.
1972  *
1973  *****************************************************************************/
1974 static void PrepSearchSourceData(
1975     DtHelpDialogWidget hw,
1976     char * srchWord)
1977 {
1978      /* try to install the new word; if returns False, word is same 
1979         as before. True = also update widget fields. */
1980      /* This test determines whether we might need to continue. */
1981      if (    hw->help_dialog.srch.fullIndex
1982           || CheckSearchWord(hw,srchWord,True) == False )
1983      {
1984         /* check to see if CheckSearchWord() was called. If it wasn't
1985            then srchWord has not been freed or saved. We will lose the
1986            memory unless we free it here. */
1987         if (hw->help_dialog.srch.fullIndex)
1988             XtFree(srchWord);
1989
1990         /* are we continuing an interrupted search? */
1991         if (    hw->help_dialog.srch.volLeftCnt > 0
1992              && NULL != hw->help_dialog.srch.volListHead )
1993             return;                       /* RETURN: continue with search */
1994
1995         /* if searching full index, False=dont free vol with full index */
1996         if (hw->help_dialog.srch.fullIndex)
1997             HitListFreeAllVolHits(hw,False);
1998         /* else we're searching on the same word, but completed 
1999            previous search.  So reset the volumes to search/display 
2000            according to the current settings of the Volumes radio buttons,
2001            but leave the results intact.
2002         */
2003         /* fall thru to do prep */
2004      }
2005      else /* searching for a different word */
2006      {
2007         /* free all hit-related data and reset flags */
2008         HitListFreeAllVolHits(hw,True);  /*True=free everything*/
2009      }
2010
2011      /*** It's not just a continue.  So, we may be beginning a new search 
2012           or continuing a search based on new volume selection params ***/
2013
2014      /* update display area */
2015      DeleteListContents(&hw->help_dialog.srch);
2016      StatusLabelUpdate(hw,WORKING_STATUS,False,0);
2017
2018      /*** update the volumes list according to sources selected ***/
2019      if ( _DtHelpGlobSrchSelectedVolumes == hw->help_dialog.srch.srchSources )
2020      { 
2021          /* volume list already built when opening selection dialog */
2022          /* (F,F,F,F): disable search,disable display,no 0 hits,for all vols */
2023          SetVolStatus(hw->help_dialog.srch.volListHead,False,False,False,False);
2024          /* (T,T,T,T): enable search, enable display, 
2025                 zero hits ok, only for selected volumes */
2026          SetVolStatus(hw->help_dialog.srch.volListHead,True,True,True,True);
2027      }   /* if selected volumes button */
2028      else if ( _DtHelpGlobSrchAllVolumes == hw->help_dialog.srch.srchSources )
2029      {
2030         /* Scan directories for volumes if necessary */
2031         if (    False == hw->help_dialog.srch.volScanDone
2032              || NULL == hw->help_dialog.srch.volListHead)
2033         {
2034            /* Add on the Vol info; (T,T,F) search, display, all */
2035            VolListBuild(hw,True,True,False);
2036         }
2037
2038         /* (T,T,F,F): enable search,enable display,no 0 hits,for all vols */
2039         SetVolStatus(hw->help_dialog.srch.volListHead,True,True,False,False);
2040      } /* if all volumes button */
2041      else    /*** current volume button ***/
2042      {
2043        char * path;
2044        _DtHelpFileEntry cur;
2045
2046        /* (F,F,F,F): disable search,disable display,no 0 hits,for all vols */
2047        SetVolStatus(hw->help_dialog.srch.volListHead,False,False,False,False);
2048
2049        /* try to locate file and its entry, if present */
2050        path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, hw->help_dialog.display.helpVolume,
2051                                   _DtHelpFileSuffixList,False,R_OK);
2052        cur = _DtHelpFileListGetMatch(hw->help_dialog.srch.volListHead,path,
2053                       GetVolumeInfoCB, _DtHELP_FILE_NAME,
2054                       hw->help_dialog.help.pDisplayArea);
2055
2056        if (NULL == cur && NULL != path)  /*file was located but isn't in list*/
2057        {  /* add it to the list */
2058           Boolean mod;
2059           XmFontList origFontList;
2060
2061           origFontList = hw->help_dialog.srch.volTitlesFontList;
2062
2063           _DtHelpFileListAddFile(&hw->help_dialog.srch.volListHead,
2064                        &hw->help_dialog.srch.volTitlesFontList,&mod,path,NULL,
2065                        GetVolumeInfoCB, _DtHELP_FILE_NAME, _DtHELP_FILE_TITLE,
2066                        hw->help_dialog.help.pDisplayArea);
2067           if (mod)
2068           {
2069              MergeFontListIntoWidgetFonts( 
2070                        hw->help_dialog.srch.resultList,
2071                        hw->help_dialog.srch.volTitlesFontList);
2072
2073              if (origFontList) XmFontListFree(origFontList);
2074           }
2075
2076           /* (F,F,F): disable search, disable display, for all volumes */
2077           AddVolInfoToList(hw->help_dialog.srch.volListHead,False,False,False);
2078           cur = _DtHelpFileListGetMatch(hw->help_dialog.srch.volListHead,path,
2079                       GetVolumeInfoCB, _DtHELP_FILE_NAME,
2080                       hw->help_dialog.help.pDisplayArea);
2081        }
2082
2083        if (cur) /* file present in list */
2084        {
2085           /* enable search and display on this volume */
2086           _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) cur->clientData;
2087           
2088           vol->searchThisVolume = True;
2089           vol->showVolInList = True;
2090           vol->zeroHitsOk = True;    /* show zero hits for search of cur vol */
2091        }
2092        else      /* file not found */
2093        {
2094           /* FIX: put up error dialog and disable the button */
2095           /*printf("Current volume %s not found\n", 
2096                                hw->help_dialog.display.helpVolume);*/
2097        } /* if file found */
2098
2099        XtFree(path);                  /* tests for NULL */
2100      }  /* if selected/all/cur volumes sources */
2101
2102 #if 0 || defined(DEBUG) /* for debug, set to 1 */
2103      OutputVolInfo(hw->help_dialog.srch.volListHead);
2104 #endif
2105
2106      /* get num volumes to process */
2107      hw->help_dialog.srch.volLeftCnt = 
2108              CountSelectedVolumes(hw->help_dialog.srch.volListHead,True);
2109
2110      /* empty the results list */
2111      XmUpdateDisplay(hw->help_dialog.srch.resultList);
2112 }
2113
2114 \f
2115 /************************************************************************
2116  * Function: CloseSearchCB()
2117  *
2118  *      Close the Global Search Dialog
2119  *
2120  ************************************************************************/
2121 static void CloseSearchCB (
2122     Widget w,
2123     XtPointer clientData,
2124     XtPointer callData)
2125 {
2126    _DtHelpGlobSearchStuff * srch = (_DtHelpGlobSearchStuff *) clientData;
2127
2128    /* stop any work proc */
2129    if(srch->workProcId)
2130    {
2131       XtRemoveWorkProc(srch->workProcId);
2132       srch->workProcId = 0;
2133    }
2134
2135    /* unmanage the srchForm dialog but dont destroy it */
2136    if (NULL != srch->srchForm)
2137      {
2138        XtUnmanageChild(srch->srchForm);
2139        XtUnmapWidget(srch->srchForm);
2140      }
2141 }
2142
2143 \f
2144 /*****************************************************************************
2145  * Function:        void DeleteListContents()
2146  *
2147  * Parameters:  
2148  *
2149  * Return Value:    Void.
2150  *
2151  * Purpose:         empties list and resets position values
2152  *
2153  *****************************************************************************/
2154 static void DeleteListContents(
2155         _DtHelpGlobSearchStuff * srch)
2156 {
2157    _DtHelpFileEntry  curFile;
2158
2159    if (NULL != srch->resultList)
2160        XmListDeleteAllItems(srch->resultList);
2161
2162    for ( curFile = srch->volListHead;
2163          NULL != curFile;
2164          curFile = _DtHelpFileListGetNext(NULL,curFile) )
2165    {
2166       register _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) curFile->clientData;
2167       if (NULL == vol) continue;                      /* CONTINUE */
2168
2169       /* if any hits are displayed and any have open topics, 
2170          walk through and close them */
2171       if (    vol->hitsDisplayed 
2172            && ((vol->nextVolPosition - vol->startPosition) != vol->hitCnt) )
2173       {
2174          register _DtHelpGlobSrchHit * hit;
2175          for ( hit = vol->hitListHead;
2176                NULL != hit;
2177                hit = hit->next)
2178          {
2179             hit->topicsDisplayed = False;
2180          }
2181      }
2182
2183       vol->startPosition = 1;
2184       vol->nextVolPosition = 1;
2185       vol->hitsDisplayed = False;
2186    }
2187 }
2188
2189 \f
2190 /*****************************************************************************
2191  * Function:        void StatusLabelUpdate()
2192  *
2193  * Parameters:  
2194  *
2195  * Return Value:    Void.
2196  *
2197  * Purpose:         Installs proper label over results list
2198  *
2199  *****************************************************************************/
2200 static void StatusLabelUpdate(
2201         DtHelpDialogWidget hw,
2202         ResultsStatus      status,
2203         Boolean            forceUpdate,
2204         int                intArg)
2205 {
2206    char *        labelMsg;
2207    XmString      labelString;
2208    XmString      curLabelString;
2209    Arg           args[5];
2210    char          buf[100];
2211
2212 #if 0
2213    /* only update if necessary */
2214    if (status == hw->help_dialog.srch.statusLineUsage && !forceUpdate)
2215       return;
2216 #endif
2217
2218    /* order up the right message */
2219    hw->help_dialog.srch.statusLineUsage = status;
2220    switch (status)
2221    {
2222    case SCANNING_STATUS:
2223        labelMsg = (char *)_DTGETMESSAGE(GSSET, 17,"Scanning for volumes... Found %d");
2224        sprintf(buf,labelMsg,intArg);
2225        labelMsg = buf;
2226        break;                                              /* BREAK */
2227    case WORKING_STATUS:
2228        labelMsg = (char *)_DTGETMESSAGE(GSSET, 18,
2229                                   "Searching... Volumes remaining: %d");
2230        /* we need +1 because of when this message is used */
2231        sprintf(buf,labelMsg,hw->help_dialog.srch.volLeftCnt + 1);
2232        labelMsg = buf;
2233        break;                                              /* BREAK */
2234    case SEARCH_RESULTS_STATUS:
2235        /* if no hits found */
2236        if (hw->help_dialog.srch.hitsFound == False) /*dont use == True*/
2237        {
2238           if (hw->help_dialog.srch.fullIndex)
2239           {
2240              if (hw->help_dialog.srch.srchSources == _DtHelpGlobSrchAllVolumes)
2241                 labelMsg = (char *)_DTGETMESSAGE (GSSET,19,
2242                         "No index entries found.");
2243              else
2244                 labelMsg = (char *)_DTGETMESSAGE (GSSET,50,
2245                         "No index entries found.  Try All Volumes.");
2246           }
2247           else  /* searched on a pattern */
2248           {
2249               labelMsg = (char *)_DTGETMESSAGE (GSSET,51,
2250                         "No index entries found.  Try another word.");
2251           }
2252           /* change focus to the search word.  Traversal is ignored 
2253              if srchWord is desensitized (Contains btn not selected) */
2254
2255           if (XtIsSensitive(hw->help_dialog.srch.wordField))
2256           {
2257             /*
2258              * make sure the text field is editable before sending
2259              * the traversal there.
2260              */
2261             XtSetArg(args[0],XmNeditable,True);
2262             XtSetValues(hw->help_dialog.srch.wordField, args, 1);
2263             XmProcessTraversal
2264                (hw->help_dialog.srch.wordField,XmTRAVERSE_CURRENT);
2265           }
2266           else
2267             XmProcessTraversal
2268                (hw->help_dialog.srch.allVolRadBtn,XmTRAVERSE_CURRENT);
2269
2270        }
2271        else /* if hits found */
2272        {
2273           /* select the appropriate message */
2274           if (hw->help_dialog.srch.fullIndex)
2275           {
2276              labelMsg = (char *)_DTGETMESSAGE(GSSET, 20,"Complete Index");
2277
2278            }
2279           else
2280           {
2281              labelMsg = (char *)_DTGETMESSAGE(GSSET, 21,"Entries with \"%s\"");
2282              sprintf(buf,labelMsg,hw->help_dialog.srch.rawWordStr);
2283              labelMsg = buf;
2284
2285           }
2286              /* change focus to the results list */
2287              XmProcessTraversal(
2288                       hw->help_dialog.srch.resultList,XmTRAVERSE_CURRENT);
2289  
2290
2291       } /* if no hits found else */
2292         
2293        break;                                              /* BREAK */
2294    case NO_VOL_STATUS:
2295        labelMsg = (char *)_DTGETMESSAGE (GSSET, 22,"No volumes selected");
2296        break;                                              /* BREAK */
2297    case FIRST_PROMPT_STATUS:
2298        labelMsg = (char *)_DTGETMESSAGE(GSSET,23,"Select search options above");
2299        break;                                              /* BREAK */
2300    case BLANK_STATUS:
2301    default:
2302       /* DBG: when an empty string, form constraints are wrong; make a space */
2303        labelMsg = " ";
2304        break;                                              /* BREAK */
2305    }
2306
2307    /* make a label string */
2308    labelString = XmStringCreateLocalized(labelMsg);
2309
2310    /* get the current string of the label */
2311    curLabelString = NULL;
2312    XtSetArg(args[0],XmNlabelString,&curLabelString);
2313    XtGetValues (hw->help_dialog.srch.statusLabel, args, 1);
2314
2315    /* update label if it is different; avoid flashing this way */
2316    if (    NULL != curLabelString && NULL != labelString
2317         && XmStringCompare(labelString,curLabelString) == False )
2318    {
2319       /* update msg over results list */
2320       XtSetArg(args[0],XmNlabelString,labelString);
2321       XtSetValues(hw->help_dialog.srch.statusLabel,args,1);
2322    }
2323
2324    XmStringFree(labelString);
2325    XmStringFree(curLabelString);
2326
2327    XmUpdateDisplay(hw->help_dialog.srch.statusLabel);
2328 }
2329
2330
2331
2332 \f
2333 /*****************************************************************************
2334  * Function:        void ResultsListUpdate()
2335  *
2336  * Parameters:  
2337  *
2338  * Return Value:    Void.
2339  *
2340  * Purpose:         empty list and display results status message
2341  *
2342  *****************************************************************************/
2343 static void ResultsListUpdate(
2344         DtHelpDialogWidget   hw,
2345         _DtHelpFileEntry     newFile)
2346 {
2347    _DtHelpFileEntry testFile;
2348
2349    /* check that in fact, there are no results that will be overwritten */
2350    for ( testFile = hw->help_dialog.srch.volListHead;
2351          NULL != testFile;
2352          testFile = _DtHelpFileListGetNext(NULL,testFile) )
2353    {
2354       register _DtHelpGlobSrchVol * vol;
2355       vol = (_DtHelpGlobSrchVol *)testFile->clientData;
2356       if (vol && vol->showVolInList && (vol->hitCnt > 0  || vol->zeroHitsOk))
2357          break;                                            /* BREAK */
2358    }
2359
2360    /* clean the list out if this is the first new result */
2361    /* this presumes that files are processed in order in the list */
2362    if (testFile == newFile)
2363    {
2364       DeleteListContents(&hw->help_dialog.srch);
2365       AdjustPositionValues(newFile,0,1,True); 
2366    }
2367    /* True: insert new item */
2368    VolNameDisplay(hw,newFile,True);
2369
2370    /* Update status label */
2371    StatusLabelUpdate(hw,SEARCH_RESULTS_STATUS,True,0); /* FIX: False */
2372 }
2373
2374
2375 \f
2376 /*****************************************************************************
2377  * Function:        void SearchForPattern()
2378  *
2379  * Parameters:  
2380  *
2381  * Return Value:    True if pattern found, False if not found
2382  *
2383  * Purpose:         Find a pattern in a string
2384  *
2385  * WARNING:         may convert string to uppercase in place
2386  *                  depending on which code is compiled.
2387  *****************************************************************************/
2388 static Boolean SearchForPattern(
2389           char * string,
2390           char * pattern,
2391           int     patternLen)
2392 {
2393 #if defined(NO_REGEX)  /* don't support regex in string searches */
2394        char * hit;
2395
2396        _DtHelpCeUpperCase(string);
2397        /* FIX: make this code much faster by using an improved
2398           pattern search algorithm, such as Rabin-Karp. */
2399        /* hit is set to NULL if no matching char is found */
2400        while (_DtHelpCeStrchr(string, pattern, MB_CUR_MAX, &hit) == 0)
2401        {
2402           if ( strncmp(hit,pattern,patternLen) == 0 )
2403              break;                             /* BREAK */
2404           else
2405              string = hit + mblen(hit,1);
2406        }
2407        return (NULL != hit);                    /* RETURN True or False */
2408 #else /* if NO_REGEX */
2409 # ifndef NO_REGCOMP
2410         regex_t    re;
2411         int        ret = -1;
2412
2413         /* use regexec to pattern match */
2414         /* a 0 return value indicates success */
2415         if ( regcomp(&re,pattern,REG_NOSUB|REG_ICASE|REG_EXTENDED) == 0 )
2416         {
2417            /* a 0 return value indicates success */
2418            ret = regexec(&re,string,0,NULL,0);
2419            regfree(&re);
2420         }
2421         return (ret == 0);                      /* RETURN True or False */
2422 # else  /* NO_REGCOMP */
2423         char *compiledRE;
2424         char *ret = NULL;
2425
2426         /* a non NULL return value indicates success */
2427         compiledRE = (char *)regcmp(pattern, (char *) NULL);
2428         if (compiledRE)
2429         {
2430            /* a non NULL return value indicates success */
2431            ret = regex(compiledRE, string);
2432            free(compiledRE);
2433         }
2434         return (ret != NULL);                   /* RETURN True or False */
2435 # endif /* NO_REGCOMP */
2436 #endif /* if NO_REGEX */
2437 }
2438
2439 \f
2440 /*****************************************************************************
2441  * Function:        void OpenVolForSearch()
2442  *
2443  * Parameters:  
2444  *
2445  * Return Value:    False if an error
2446  *                  True if no error
2447  *
2448  * Purpose:         Opens a volume for searching, 
2449  *                  gets the volume locale, if 
2450  *                  different from system locale,
2451  *                  saves system locale in vol,
2452  *                  installs volume locale
2453  *
2454  *                  Note that the system locale
2455  *****************************************************************************/
2456 static Boolean OpenVolForSearch(
2457            DtHelpDialogWidget  hw,
2458            char *               fullFilePath,
2459            _DtHelpGlobSrchVol * curVol)
2460 {
2461     Boolean openedVolume = False;
2462
2463     /* open the volume if not open */
2464     if ( NULL == curVol->volHandle )
2465     {
2466        _DtHelpOpenVolume(fullFilePath, &curVol->volHandle);
2467        if (NULL == curVol->volHandle) return False;  /* RETURN */
2468
2469        if (curVol->gotLocale == False)
2470        {
2471           curVol->stdLocale = _DtHelpGetVolumeLocale(curVol->volHandle);
2472           /* get the op-specific locales; the strings are default values */
2473           _DtHelpCeXlateStdToOpLocale(DtLCX_OPER_ICONV3,curVol->stdLocale,
2474                         "iso88591",&curVol->iconv3Codeset);
2475           curVol->gotLocale = True;
2476        }
2477        openedVolume = True;
2478
2479        /* get the codeset of the application's locale, if haven't gotten it */
2480        if ( NULL == hw->help_dialog.srch.iconv3Codeset )
2481        {
2482           char * locale = NULL;
2483           _DtHelpCeXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
2484                      setlocale(LC_CTYPE,NULL),&locale,NULL,NULL);
2485           /* get the op-specific locales; the strings are default values */
2486           /* impt: XlateStdToOpLocale() call requires a locale, not a codeset */
2487           _DtHelpCeXlateStdToOpLocale(DtLCX_OPER_ICONV3,locale,
2488                 "iso88591",&hw->help_dialog.srch.iconv3Codeset);
2489           XtFree(locale);
2490        }
2491    
2492        /** only saves or changes the locale if necessary **/
2493        /* create an iconv3 context to convert codeset of */
2494        /* the volume to the codeset of the application */
2495        if ( _DtHelpCeIconvContextSuitable(hw->help_dialog.srch.iconv3Context,
2496                curVol->iconv3Codeset,hw->help_dialog.srch.iconv3Codeset) == False )
2497        {
2498           /* close old, open new */
2499           _DtHelpCeIconvClose(&hw->help_dialog.srch.iconv3Context);  
2500           _DtHelpCeIconvOpen(&hw->help_dialog.srch.iconv3Context,
2501                  curVol->iconv3Codeset,hw->help_dialog.srch.iconv3Codeset,' ',' ');
2502        }
2503     }
2504     /* else volume already open */
2505
2506     /* if just opened volume */
2507     if (openedVolume)
2508     {
2509        /* we just share pointers; when freeing localeWordStr, we need to
2510           test whether they are different before freeing */
2511        hw->help_dialog.srch.localeWordStr = hw->help_dialog.srch.normWordStr;
2512     }
2513
2514     /* get the str coll function, iff needed */
2515     if (NULL == curVol->strcollProc)
2516     {
2517        /* get strcollProc for vol locale */
2518        curVol->strcollProc = _DtHelpCeGetStrcollProc();
2519     }
2520
2521     return True;
2522 }
2523
2524 \f
2525 /*****************************************************************************
2526  * Function:        void CloseVolAfterSearch()
2527  *
2528  * Parameters:  
2529  *
2530  * Return Value:    Void.
2531  *
2532  * Purpose:         Closes a volume opened for searching, 
2533  *                  installs system locale, if diff from volume.
2534  *
2535  *****************************************************************************/
2536 static void CloseVolAfterSearch(
2537            DtHelpDialogWidget  hw,
2538            _DtHelpGlobSrchVol *    curVol)
2539 {
2540     /* close the volume if open */
2541     if ( NULL != curVol->volHandle )
2542     {
2543        _DtHelpCloseVolume(curVol->volHandle);
2544        curVol->volHandle = NULL;
2545        /* free the locale word string, if allocated */
2546        if(hw->help_dialog.srch.localeWordStr!=hw->help_dialog.srch.normWordStr)
2547        {
2548           XtFree(hw->help_dialog.srch.localeWordStr);
2549           hw->help_dialog.srch.localeWordStr = NULL;
2550        }
2551     }
2552    
2553     /* don't free the iconv context...may apply to the next volume */
2554 }
2555
2556
2557 \f
2558 /*****************************************************************************
2559  * Function:        void SearchTopic()
2560  *
2561  * Parameters:  
2562  *
2563  * Return Value:    Void.
2564  *
2565  * Purpose:         Get a single topic and search for the search word in it
2566  *
2567  *****************************************************************************/
2568 static void SearchTopic(
2569    DtHelpDialogWidget hw,
2570    _DtHelpFileEntry     curFile,
2571    _DtHelpGlobSrchVol * curVol,
2572    char *            srchWord,
2573    int               srchWordLen,
2574    int               numSearches)
2575 {
2576 #if 0
2577     int i;
2578
2579     /* if the volume is not open; don't continue */
2580     if ( NULL == curVol->volHandle )
2581        return;                                  /* RETURN */
2582
2583     if ( NULL == curVol->indexEntriesList )
2584        _CEVolumeTopicList(curVol->volHandle,&curVol->indexEntriesList);
2585     if ( NULL == curVol->volHandle || NULL == curVol->indexEntriesList )
2586     {
2587        curVol->topicSearchInProgress = False;
2588        curVol->topicSearchDone = True;
2589        curVol->indexSearchInProgress = True;
2590        if ( NULL == curVol->volHandle ) curVol->searchCompleted = True;
2591        return;                                 /* RETURN */
2592     }
2593
2594     curVol->topicSearchInProgress = True;
2595
2596
2597     /* search the topics */
2598     /* note that indexEntriesList[0] is correct; ptr is incremented */
2599     /* we can increment the pointer because we don't own this memory;
2600        the open volume does. */
2601     for (i=0; 
2602          i < numSearches && NULL != curVol->indexEntriesList[0]; 
2603          i++, curVol->indexEntriesList++ )
2604     {
2605        char * topicTitle = NULL;
2606        Boolean validTopic;
2607
2608        validTopic = _DtHelpGetTopicTitle( curVol->volHandle,
2609                          curVol->indexEntriesList[0],&topicTitle);
2610        if(validTopic)
2611        {
2612           /* look for a hit and process if there was one */
2613           if (SearchForPattern(topicTitle,srchWord,srchWordLen) == True)
2614           {
2615              HitListAddFound(curFile, curVol->indexEntriesList[0], True, NULL);
2616           }
2617        }
2618
2619        /* clean up and advance to next topic */
2620        XtFree(topicTitle);
2621        curVol->searchedCnt++;
2622     }  /* for all topics to search */
2623 #endif
2624
2625     if (    NULL == curVol->indexEntriesList      /* no topics queried */
2626          || NULL == curVol->indexEntriesList[0] ) /* no more topics available */
2627     {
2628        /* hand off to next stage */
2629        curVol->indexEntriesList = NULL;
2630        curVol->topicSearchInProgress = False;
2631        curVol->topicSearchDone = True;
2632        curVol->indexSearchInProgress = True;
2633     }
2634 }
2635
2636
2637
2638 \f
2639 /*****************************************************************************
2640  * Function:        void SearchIndex()
2641  *
2642  * Parameters:  
2643  *
2644  * Return Value:    void
2645  *
2646  * Purpose:         Get a single Index and search for the search word in it
2647  *
2648  * Commentary:      There are two strings for each index entry.
2649  *                  One string is the straight text in
2650  *                  the codeset of the volume.  The
2651  *                  other string is a XmString that
2652  *                  has a font tag that will allow
2653  *                  it to be displayed in the
2654  *                  correct codeset.
2655  *
2656  * Preconditions:   This code requires that the volume to be search
2657  *                  has already been opened [OpenVolForSearch()],
2658  *                  that the locale of the volume has been installed,
2659  *                  and that the search word is in the same code
2660  *                  set as the volume and has been converted to
2661  *                  upper case.
2662  *
2663  *****************************************************************************/
2664 static void SearchIndex(
2665    DtHelpDialogWidget hw,
2666    _DtHelpFileEntry     curFile,
2667    _DtHelpGlobSrchVol * curVol,
2668    _DtHelpCeIconvContext iconvContext,
2669    char *            srchWord,
2670    int               srchWordLen,
2671    int               numSearches)
2672 {
2673     int i;
2674     char * indexEntry = NULL;
2675     size_t entryLen = 100;      /* starting size */
2676     Arg    args[5];
2677
2678     /* if the volume is not open; don't continue */
2679     if ( NULL == curVol->volHandle )
2680        return;                             /* RETURN */
2681
2682     /* get the XmStrings of the entries */
2683     if ( NULL == curVol->indexXmStrsList )
2684     {
2685        XmFontList   fontList = NULL;
2686        Boolean      mod = False;
2687        int          numEntries = 0;
2688
2689        /* get results font list */
2690        XtSetArg(args[0], XmNfontList, &fontList);
2691        XtGetValues(hw->help_dialog.srch.resultList,args,1);
2692
2693 #if 1
2694        /* Don't need to copy, _DtHelpFormatVolumeTitle copies 
2695         * before modifying.
2696         */
2697
2698        /* work with copy, because FontListAppendEntry() destroys input FL */
2699        fontList = XmFontListCopy(fontList);
2700 #endif
2701
2702        /* get the entries */
2703        _DtHelpFormatIndexEntries(hw->help_dialog.help.pDisplayArea,
2704                   curVol->volHandle,&numEntries, &curVol->indexXmStrsList,
2705                   &fontList, &mod);
2706
2707        /* install the changed list */
2708        if (mod)
2709        {
2710           XtSetArg(args[0], XmNfontList, fontList);
2711           XtSetValues(hw->help_dialog.srch.resultList,args,1);
2712           if (fontList) XmFontListFree(fontList);
2713        }
2714     }
2715
2716     /* get the pure strings for searching */
2717     if ( NULL == curVol->indexEntriesList )
2718     {
2719        /* recall that the array and strings pointed to by
2720           the indexEntriesList is owned by the open volume */
2721        _DtHelpCeGetKeywordList(curVol->volHandle,&curVol->indexEntriesList);
2722
2723        /* and re-init curIndexXmStr */
2724        curVol->curIndexXmStr = curVol->indexXmStrsList;
2725     }
2726
2727     if (   NULL == curVol->volHandle 
2728         || NULL == curVol->indexEntriesList
2729         || NULL == curVol->indexXmStrsList )
2730     {
2731        curVol->indexSearchInProgress = False;
2732        curVol->indexSearchDone = True;
2733        curVol->searchCompleted = True;
2734        if ( NULL == curVol->volHandle ) curVol->searchCompleted = True;
2735        return;                                 /* RETURN */
2736     }
2737
2738     curVol->indexSearchInProgress = True;
2739
2740     /* alloc memory for index processing */
2741     indexEntry = XtMalloc(sizeof(char)*(entryLen+1));
2742     if (NULL == indexEntry) return;            /* RETURN */
2743
2744     /* get a index entry */
2745     for (i=0; 
2746          i < numSearches && NULL != curVol->indexEntriesList[0]; 
2747          i++, curVol->indexEntriesList++, curVol->curIndexXmStr++ )
2748     {
2749        /* prevent overflow of buffer */
2750        if (strlen(curVol->indexEntriesList[0]) > entryLen)
2751        {
2752           entryLen = strlen(curVol->indexEntriesList[0]) + 50;
2753           indexEntry = XtRealloc(indexEntry,entryLen+1);
2754           if (NULL == indexEntry) break;          /* BREAK */
2755        }
2756        indexEntry[0] = EOS;  /* init to empty string */
2757
2758        /* look for a hit and process if there was one */
2759        /* if srchWord is NULL, all entries are hits */
2760        /* copy, and possible iconv, the index string into the */
2761        /* the codeset of srchWord (the application) */
2762        if (    NULL == srchWord
2763             || (   _DtHelpCeIconvStr(iconvContext,curVol->indexEntriesList[0],
2764                         &indexEntry, &entryLen,indexEntry,entryLen) == 0
2765                 && SearchForPattern(indexEntry, srchWord, srchWordLen) == True ) )
2766        {
2767           _DtHelpGlobSrchHit * hit;
2768           char * *          topicIdList;
2769
2770           HitListAddFound ( curFile, curVol->curIndexXmStr[0],
2771                              curVol->indexEntriesList[0], True, &hit);
2772
2773           /* topicIdList is set but not allocated & need not be freed */
2774           hit->topicCnt = _DtHelpCeFindKeyword(curVol->volHandle,
2775                                    hit->indexEntry,&topicIdList);
2776        }
2777
2778        /* clean up and advance to next topic */
2779        curVol->searchedCnt++;
2780     }
2781
2782     if (    NULL == curVol->indexEntriesList     /*no topics queried*/
2783          || NULL == curVol->indexEntriesList[0] )/*no more index entries avail*/
2784     {
2785        /* hand off to next stage */
2786        curVol->indexEntriesList = NULL;                 /* init */
2787        curVol->curIndexXmStr = curVol->indexXmStrsList; /* re-init */
2788        curVol->indexSearchInProgress = False;
2789        curVol->indexSearchDone = True;
2790        curVol->searchCompleted = True;
2791     }
2792
2793     XtFree(indexEntry);
2794 }
2795
2796 \f
2797 /*****************************************************************************
2798  * Function:        void SearchVolume()
2799  *
2800  * Parameters:  
2801  *
2802  * Return Value:    Void.
2803  *
2804  * Purpose:         do the search operation
2805  *                  This routine does incremental search--it searchs
2806  *                  a little, then returns to allow further processing.
2807  *                  It is called whenever Xt detects no other events.
2808  *
2809  *****************************************************************************/
2810 static void SearchVolume(
2811          DtHelpDialogWidget hw,
2812         _DtHelpFileEntry        curFile,
2813         _DtHelpGlobSrchVol *    curVol,
2814         int                  numSearches)
2815 {
2816   XmString labelString;
2817   Arg args[10];
2818   char buf[50];
2819
2820   _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
2821   if (hw->help_dialog.srch.selectionDlg)
2822      _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
2823
2824   /* Process according to state */
2825   if ( curVol->nothingDone )
2826   {
2827      curVol->nothingDone = False;
2828      curVol->topicSearchInProgress = True;
2829
2830      /* Update the search status string */
2831      sprintf(buf,(char *)_DTGETMESSAGE(GSSET,18,
2832                                 "Searching... Volumes remaining: %d"),
2833                  hw->help_dialog.srch.volLeftCnt);
2834      labelString = XmStringCreateLocalized(buf);
2835      XtSetArg(args[0],XmNlabelString,labelString);
2836      XtSetValues (hw->help_dialog.srch.statusLabel, args, 1);
2837      XmStringFree(labelString);
2838
2839      XmUpdateDisplay((Widget) hw->help_dialog.srch.statusLabel);
2840   }
2841
2842   OpenVolForSearch(hw,curFile->fullFilePath,curVol);
2843
2844   if ( curVol->topicSearchInProgress )
2845   {
2846      SearchTopic(hw, curFile,curVol,hw->help_dialog.srch.localeWordStr,
2847               hw->help_dialog.srch.wordFieldLen, numSearches);
2848   }
2849
2850   /* NOTE: because this isn't an "else if", we could potentially
2851      search for 2*numSearches; but I know that I've disabled the
2852      topic search.  Furthermore, my code depends upon the possibility
2853      of searching an entire volume in one call to the routine, if
2854      desired, and having an else if would break that.
2855   */
2856   if ( curVol->indexSearchInProgress )
2857   {
2858       char * srchWord;
2859       srchWord = hw->help_dialog.srch.localeWordStr;
2860       /* FullIndex search indicated by a null search word string */
2861       if (hw->help_dialog.srch.fullIndex) srchWord = NULL;
2862       SearchIndex(hw, curFile, curVol, hw->help_dialog.srch.iconv3Context, 
2863               srchWord, hw->help_dialog.srch.wordFieldLen, numSearches);
2864   }
2865
2866   /* If search was completed, update dependent stuff */
2867   if (curVol->searchCompleted)
2868   {
2869      /* handle completion */
2870      CloseVolAfterSearch(hw,curVol);
2871      curVol->indexEntriesList = NULL;       /* mem not owned by GlobSrch */
2872      if (hw->help_dialog.srch.fullIndex)
2873         curVol->gatheredFullIndex = True;
2874      hw->help_dialog.srch.volLeftCnt--;
2875      if (hw->help_dialog.srch.volLeftCnt < 0)
2876         hw->help_dialog.srch.volLeftCnt = 0;
2877   }
2878
2879   _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
2880   if (hw->help_dialog.srch.selectionDlg)
2881      _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
2882
2883 }
2884
2885 \f
2886 /*****************************************************************************
2887  * Function:        void SearchFile()
2888  *
2889  * Parameters:  
2890  *
2891  * Return Value:    Void.
2892  *
2893  * Purpose:         do the search operation on an entire file
2894  *                  It searches the entire file at once
2895  *                  and displays the results in the list.
2896  *
2897  *****************************************************************************/
2898 static void SearchFile(
2899    DtHelpDialogWidget      hw,
2900    _DtHelpFileEntry        file)
2901 {
2902    register _DtHelpGlobSrchVol * vol;
2903
2904    /* get volume info, adding if necessary */
2905    vol = (_DtHelpGlobSrchVol *) file->clientData;
2906    /* (T,T,F): enable search, enable display, any volume */
2907    if (NULL == vol) AddVolInfoToFile(file, True, True, False);
2908    vol = (_DtHelpGlobSrchVol *) file->clientData;
2909    if (NULL == vol) return;
2910
2911    /* conduct search of entire volume in one call */
2912    hw->help_dialog.srch.volLeftCnt = 1;
2913    vol->searchThisVolume = True;
2914    vol->showVolInList = True;
2915    vol->zeroHitsOk = True;
2916    SearchVolume(hw,file,vol,INT_MAX);
2917
2918    /* update status */
2919    StatusLabelUpdate(hw,SEARCH_RESULTS_STATUS,True,0);/*FIX: False*/
2920
2921    /* update the list to show the volume */
2922    AdjustPositionValues(file,0,1,True);
2923    /* True: do insert new item */
2924    VolNameDisplay(hw,file,True);
2925
2926    if (vol->showHitsWithVol)
2927    {
2928       VolHitsDisplay(hw,file);
2929       /* False: don't insert new item */
2930       VolNameDisplay(hw,file,False);
2931    } 
2932 }
2933
2934
2935
2936 \f
2937 /*****************************************************************************
2938  * Function:        void DoBackgroundSearchWP(
2939  *                                  XtPointer clientData)
2940  *
2941  *
2942  *
2943  * Parameters:  
2944  *
2945  * Return Value:    Void.
2946  *
2947  * Purpose:         do the search operation in the background
2948  *                  This routine does incremental search--it searchs
2949  *                  a little, then returns to allow further processing.
2950  *                  It is called whenever Xt detects no other events.
2951  *
2952  *****************************************************************************/
2953 static Boolean DoBackgroundSearchWP(
2954     XtPointer clientData)
2955 {
2956    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
2957   _DtHelpFileEntry curFile;
2958   _DtHelpGlobSrchVol * curVol = NULL;
2959   
2960   if ( 0 == hw->help_dialog.srch.volLeftCnt ) 
2961      goto searchComplete;                                  /* GOTO: done! */
2962
2963   /* get file to work on */
2964   curFile = hw->help_dialog.srch.curSrchVol;
2965   if ( NULL == curFile )
2966   {
2967     curFile = GetNextSearchFileAndDisplayCompleted(
2968                              hw, hw->help_dialog.srch.volListHead, NULL);
2969     if ( NULL == curFile ) goto searchComplete;            /* GOTO: done */
2970     hw->help_dialog.srch.curSrchVol = curFile;
2971   }  /* if no current file */
2972
2973   /* get volume info */
2974   curVol = (_DtHelpGlobSrchVol *) curFile->clientData;
2975
2976 #define NUM_SEARCHES_PER_CALL  30
2977   SearchVolume(hw,curFile,curVol,NUM_SEARCHES_PER_CALL);
2978
2979   /* If search was completed, update dependent stuff */
2980   if (curVol->searchCompleted)
2981   {
2982     /* update the search results list */
2983     /* True: adjust count beginning with this file */
2984     if (curVol->hitCnt > 0 || curVol->zeroHitsOk) 
2985     {
2986        /* record that a hit found */
2987        if (   curVol->hitCnt > 0
2988            || (    curVol->zeroHitsOk 
2989                && _DtHelpGlobSrchSelectedVolumes == hw->help_dialog.srch.srchSources))
2990           hw->help_dialog.srch.hitsFound = True;
2991
2992        /* update the list to show the volume */
2993        AdjustPositionValues(curFile,0,1,True);
2994        ResultsListUpdate(hw,curFile);
2995
2996        /* update the list to show the hits? */
2997        if (hw->help_dialog.srch.srchSources == _DtHelpGlobSrchCurVolume)
2998        {
2999           VolHitsDisplay(hw,curFile);
3000           /* False: don't insert new item */
3001           VolNameDisplay(hw,curFile,False);
3002        }
3003        XmUpdateDisplay((Widget) hw->help_dialog.srch.resultList);
3004     }
3005
3006     /* prepare for next search */
3007     hw->help_dialog.srch.curSrchVol = 
3008                      GetNextSearchFileAndDisplayCompleted(hw,NULL,curFile);
3009
3010   }  /* if search completed */
3011
3012   /* return */
3013   if (   hw->help_dialog.srch.volLeftCnt > 0
3014       || False == curVol->searchCompleted ) 
3015      return False;              /* RETURN: False ==> continue processing */
3016
3017   /* Do this when no more files are left to search */
3018 searchComplete:
3019   {
3020   XmPushButtonCallbackStruct status;
3021
3022   /* zero search data before stopping */
3023   hw->help_dialog.srch.volLeftCnt = 0;                    /* just in case */
3024   hw->help_dialog.srch.curSrchVol = NULL;                 /* just in case */
3025
3026   /* generate a fake event to reset the dialog */
3027   status.reason = XmCR_ACTIVATE;
3028   status.event = NULL;
3029   status.click_count = 1;
3030   StopSearchCB(hw->help_dialog.srch.actionBtn,
3031                (XtPointer)hw,(XtPointer)&status);
3032
3033   return True;              /* RETURN: True ==> stop processing */
3034   }
3035 }
3036
3037
3038 \f
3039 /*****************************************************************************
3040  * Function:        void StartSearchCB(Widget w,
3041  *                                  XtPointer clientData,
3042  *                                  XtPointer callData);
3043  *
3044  *
3045  *
3046  * Parameters:  
3047  *
3048  * Return Value:    Void.
3049  *
3050  * Purpose:         Create a new user bookmark
3051  *
3052  * Warning:  This CB is also used by the volume selection buttons
3053  *           to activate a search when they are selected.  The routine
3054  *           cannot rely upon the w or callData params.  The clientData
3055  *           will always be the help widget.
3056  *****************************************************************************/
3057 static void StartSearchCB(
3058     Widget w,                     /* dont use */
3059     XtPointer clientData,
3060     XtPointer callData)           /* dont use */
3061 {
3062    char       *srchWord = NULL;
3063    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3064    XtAppContext appCntx;
3065    int        n;
3066    Arg        args[5];
3067
3068    /* set state of start button correctly */
3069    UpdateSearchStartStatusCB(NULL, (XtPointer) hw, NULL);
3070
3071    /* if help content isn't a volume, it has no index */
3072    if (    _DtHelpGlobSrchCurVolume == hw->help_dialog.srch.srchSources
3073         && hw->help_dialog.display.helpType != DtHELP_TYPE_TOPIC )
3074       return;                         /* RETURN */
3075
3076    /* retrieve the name */
3077    srchWord = XmTextFieldGetString(hw->help_dialog.srch.wordField);
3078
3079    /* test for empty (also emtpy spaces) and only process if not emtpy */
3080    _DtHelpCeCompressSpace(srchWord);
3081    if (    (strlen(srchWord) > (size_t) 0 || hw->help_dialog.srch.fullIndex)
3082         && hw->help_dialog.srch.workProcId == 0) 
3083    /* test on workProcId prevents multiple activations due to 
3084       race condition on desensitizing the start button */
3085    {
3086      _DtHelpTurnOnHourGlass(XtParent(hw));
3087      _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3088      if (hw->help_dialog.srch.selectionDlg)
3089         _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
3090
3091      /*XtSetSensitive (hw->help_dialog.srch.actionBtn,False);*/
3092      XtSetSensitive (hw->help_dialog.srch.curVolRadBtn,False);
3093      XtSetSensitive (hw->help_dialog.srch.allVolRadBtn,False);
3094      XtSetSensitive (hw->help_dialog.srch.selVolRadBtn,False);
3095      XtSetSensitive (hw->help_dialog.srch.selectBtn,False);
3096
3097 /* 9/26/94: these two XtSetArgs (and following SetValues) cause a core dump
3098    for the SunOS 5.3 optimized executable.  It isn't a problem for the
3099    non-optimized or debuggable versions or any versions on AIX 3.2 or 
3100    HP-UX 9.05. */
3101 #if !defined(sun) && !defined(__osf__)
3102      n = 0;
3103      XtSetArg(args[n],XmNeditable,False);                       n++;
3104      XtSetArg(args[n],XmNcursorPositionVisible,False);          n++;
3105      XtSetValues (hw->help_dialog.srch.wordField, args, n);
3106 #endif
3107      XmUpdateDisplay(hw->help_dialog.srch.srchForm);
3108
3109      /* process the source selection and retain in widget srchWord memory */
3110      PrepSearchSourceData(hw, srchWord);
3111
3112      /* activate search thread; do it even with a 0 count, because the
3113         process reactivates the dialog after search is completed */
3114      appCntx = XtWidgetToApplicationContext((Widget) hw);
3115      hw->help_dialog.srch.workProcId = 
3116              XtAppAddWorkProc(appCntx,DoBackgroundSearchWP, (XtPointer) hw);
3117
3118      hw->help_dialog.srch.searchInProgress = True;
3119
3120      /* dont free srchWord */
3121
3122      /* turn on "Stop" label */
3123      UpdateActionButtonLabel(hw,NULL,False);
3124
3125      _DtHelpTurnOffHourGlass(XtParent(hw));
3126      _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3127      if (hw->help_dialog.srch.selectionDlg)
3128         _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
3129    }
3130    else 
3131    {
3132       if ( strlen(srchWord) == 0 )
3133          StatusLabelUpdate(hw,FIRST_PROMPT_STATUS,False,0);
3134       XtFree(srchWord);
3135    }
3136 }
3137
3138
3139
3140 \f
3141 /*****************************************************************************
3142  * Function:        void StartSelectedVolumeSearchCB(Widget w,
3143  *                                  XtPointer clientData,
3144  *                                  XtPointer callData);
3145  *
3146  *
3147  *
3148  * Parameters:  
3149  *
3150  * Return Value:    Void.
3151  *
3152  * Purpose:         Begin a search on the selected volume
3153  *
3154  *****************************************************************************/
3155 static void StartSelectedVolumeSearchCB(
3156     Widget w,
3157     XtPointer clientData,
3158     XtPointer callData)
3159 {
3160    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3161    _DtHelpFileEntry file;
3162    String        srchWord;
3163    Boolean       noSelectedFiles = True;
3164
3165     /* if not full index search */
3166     if (hw->help_dialog.srch.fullIndex == False)
3167     {
3168        /* get the current contents of the search word field */
3169        srchWord = XmTextFieldGetString(hw->help_dialog.srch.wordField);
3170    
3171        /* test the word ; False=dontUpdate--do this in PrepSearchSourceData() */
3172        if ( CheckSearchWord(hw,srchWord,False) == True )
3173        {   /* word has changed since last search; do a whole new search */
3174            StartSearchCB(NULL,(XtPointer) hw, NULL);
3175            return;                                   /* RETURN */
3176        }
3177    
3178        /* if the text field is empty, do nothing */
3179        if ( strlen(hw->help_dialog.srch.normWordStr) == 0 )
3180            return;                                   /* RETURN */
3181     }
3182
3183     /* set this to true to counteract False if no hits */
3184     hw->help_dialog.srch.hitsFound = True;
3185
3186     /* Word is the same, just the selection has changed. */
3187     /* Determine which one was selected or deselected */
3188     for ( file = hw->help_dialog.srch.volListHead;
3189           NULL != file;
3190           file = _DtHelpFileListGetNext(NULL,file) )
3191     {
3192        register _DtHelpGlobSrchVol * vol;
3193        vol = (_DtHelpGlobSrchVol *) file->clientData;
3194        if (NULL == vol) continue;
3195
3196        /* update flag */
3197        if (file->fileSelected) noSelectedFiles = False;
3198
3199        /* test for contradictory flags; fileSelected reflects dialog list */
3200        if (file->fileSelected != vol->showVolInList)
3201        {
3202           /* file has been deselected */
3203           if (False == file->fileSelected)
3204           {
3205               if (vol->showVolInList)
3206               {
3207                  /* update list: delete hits, topics, and volume title */
3208                  if (vol->hitsDisplayed) VolHitsUndisplay(hw,file);
3209
3210                  /* delete hits first, then volume */
3211                  XmListDeletePos(
3212                           hw->help_dialog.srch.resultList,vol->startPosition);
3213                  AdjustPositionValues(file, 0, -1, True);
3214                  vol->showVolInList = False;
3215                  vol->searchThisVolume = False;
3216               }
3217           }
3218           else /* file has been selected */
3219           {
3220              SearchFile(hw,file);
3221           }  /* if file de/selected */
3222        }  /* if contradictory flags */
3223     }  /* for all volumes */
3224
3225     /* update state */
3226     if (noSelectedFiles) StatusLabelUpdate(hw,NO_VOL_STATUS,True,0);
3227 }
3228
3229
3230 \f
3231 /*****************************************************************************
3232  * Function:        void UpdateSearchStartStatusCB(Widget w,
3233  *                                  XtPointer clientData,
3234  *                                  XtPointer callData);
3235  *
3236  *
3237  *
3238  * Parameters:  
3239  *
3240  * Return Value:    Void.
3241  *
3242  * Purpose:         update the status of the search status button
3243  *        Routine is called whenever text is changed in the search
3244  *        word field.
3245  *
3246  *****************************************************************************/
3247 static void UpdateSearchStartStatusCB(
3248     Widget w,
3249     XtPointer clientData,
3250     XtPointer callData)
3251 {
3252    char       *srchWord = NULL;
3253    /*XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) callData;*/
3254    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3255    Boolean    newState;
3256
3257    /* retrieve the name */
3258    srchWord = XmTextFieldGetString(hw->help_dialog.srch.wordField);
3259
3260    /* test for empty (also emtpy spaces) */
3261    _DtHelpCeCompressSpace(srchWord);
3262
3263    /* FIX: change the locale from the volume locale back to the system 
3264       locale temporarily (if not already in that locale) */
3265    _DtHelpCeUpperCase(srchWord);
3266
3267    /* only sensitize if working on a help volume and word is not emtpy 
3268       or not needed */
3269    newState = True;
3270    if (    (   _DtHelpGlobSrchCurVolume == hw->help_dialog.srch.srchSources
3271             && hw->help_dialog.display.helpType != DtHELP_TYPE_TOPIC)
3272         || (   strlen(srchWord) == (size_t) 0 
3273             && hw->help_dialog.srch.fullIndex == False))
3274        newState = False;
3275    XtSetSensitive (hw->help_dialog.srch.actionBtn,newState);
3276
3277    /* if word has changed from word of previous search, change to Start */
3278    UpdateActionButtonLabel(hw,srchWord,True);
3279
3280    XtFree(srchWord);
3281 }
3282
3283 \f
3284 /*****************************************************************************
3285  * Function:        void StopSearchCB(Widget w,
3286  *                                    XtPointer clientData,
3287  *                                    XtPointer callData);
3288  *
3289  *
3290  *
3291  * Parameters:  
3292  *
3293  * Return Value:    Void.
3294  *
3295  * Purpose:         Stop the search
3296  *
3297  *****************************************************************************/
3298 static void StopSearchCB(
3299     Widget w,
3300     XtPointer clientData,
3301     XtPointer callData)
3302 {
3303    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3304   int     n;
3305   Arg     args[10];
3306   Boolean cur;
3307
3308   /* stop the search thread */
3309   if(hw->help_dialog.srch.workProcId != 0)
3310      XtRemoveWorkProc(hw->help_dialog.srch.workProcId);
3311   hw->help_dialog.srch.workProcId = 0;
3312
3313   hw->help_dialog.srch.searchInProgress = False;
3314
3315   /* update statuses */
3316 #ifdef OLD_WAY
3317    XtSetSensitive (hw->help_dialog.srch.curVolRadBtn,
3318                               hw->help_dialog.srch.curVolRadBtnSens);
3319 #else
3320    XtSetSensitive (hw->help_dialog.srch.curVolRadBtn, TRUE);
3321 #endif
3322   
3323   XtSetSensitive (hw->help_dialog.srch.allVolRadBtn,True);
3324   XtSetSensitive (hw->help_dialog.srch.selVolRadBtn,True);
3325   n = 0;
3326   XtSetArg(args[n],XmNeditable,True);                           n++;
3327   XtSetArg(args[n],XmNcursorPositionVisible,True);              n++;
3328   XtSetValues (hw->help_dialog.srch.wordField, args, n);
3329
3330   /* update select btn status; only when selected and dialog closed */
3331   XtSetArg(args[0],XmNset,&cur);
3332   XtGetValues(hw->help_dialog.srch.selVolRadBtn,args,1);
3333   XtSetSensitive(hw->help_dialog.srch.selectBtn,
3334            cur && (   NULL == hw->help_dialog.srch.selectionDlg
3335                    || !XtIsManaged(hw->help_dialog.srch.selectionDlg) ) );
3336
3337   /* set the action button label appropriately */
3338   UpdateActionButtonLabel(hw,hw->help_dialog.srch.normWordStr,True);
3339
3340   /* post message of results */
3341   StatusLabelUpdate(hw,SEARCH_RESULTS_STATUS,True,0);
3342 }
3343
3344
3345
3346 \f
3347 /*****************************************************************************
3348  * Function:        void ActionButtonCB(Widget w,
3349  *                                    XtPointer clientData,
3350  *                                    XtPointer callData);
3351  *
3352  *
3353  *
3354  * Parameters:  
3355  *
3356  * Return Value:    Void.
3357  *
3358  * Purpose:         Act upon the action
3359  *
3360  *****************************************************************************/
3361 static void ActionButtonCB(
3362     Widget w,
3363     XtPointer clientData,
3364     XtPointer callData)
3365 {
3366   DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3367
3368   if ( hw->help_dialog.srch.searchInProgress == False )
3369      StartSearchCB(w,clientData,callData);
3370   else
3371      StopSearchCB(w,clientData,callData);
3372 }
3373
3374
3375 \f
3376 #ifdef  not_used
3377 /*****************************************************************************
3378  * Function:        void GotoResultCB(Widget w,
3379  *                                              XtPointer clientData,
3380  *                                              XtPointer callData);
3381  *
3382  *
3383  *
3384  * Parameters:  
3385  *
3386  * Return Value:    Void.
3387  *
3388  * Purpose:         Goto a result topic
3389  *
3390  *****************************************************************************/
3391 static void GotoResultCB(
3392     Widget w,
3393     XtPointer clientData,
3394     XtPointer callData)
3395 {
3396    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3397    char *          helpFile = NULL;
3398    int *           topicPosList=NULL;  
3399    int             topicPosition;  
3400    Boolean         status;
3401    int             i;
3402
3403    /* Determine the item selected and find that item in our list */
3404    status = XmListGetSelectedPos(hw->help_dialog.srch.resultList, &topicPosList,&i);
3405
3406    /* if true, an item selected */
3407    if (status && topicPosList)
3408    {
3409      _DtHelpGlobSrchHit * entry = NULL;
3410      _DtHelpFileEntry  file = NULL;
3411      char * locationId = NULL;
3412      topicPosition = topicPosList[0] - 1;       /* convert to 0 based */
3413      XtFree((String)topicPosList);
3414   
3415      /* Get the entry */
3416      HitListGetNth(hw->help_dialog.srch.volListHead,
3417                          topicPosition,&file,&entry,&locationId,&helpFile);
3418
3419      /* jump to selected location */
3420      XtFree(hw->help_dialog.display.locationId);
3421      hw->help_dialog.display.locationId = XtNewString(locationId);
3422      XtFree(hw->help_dialog.display.helpVolume);
3423      hw->help_dialog.display.helpVolume = XtNewString(helpFile);
3424      hw->help_dialog.ghelp.volumeFlag = False;  /* force search for volume */
3425      hw->help_dialog.display.helpType = DtHELP_TYPE_TOPIC;
3426
3427      _DtHelpSetupDisplayType(hw, TRUE, DtHISTORY_AND_JUMP);
3428   }
3429   else
3430   {
3431      if (topicPosList) XtFree((String)topicPosList);
3432
3433      /* FIX: Put up a message to suggest selecting an item first */
3434      /* Don't close the dialog */
3435   }
3436 }
3437 #endif /* not_used */
3438
3439 #if 0  /* save--used in code commented out elsewhere in this file */
3440 \f
3441 /*****************************************************************************
3442  * Function:        void CloseHelpCB()
3443  *
3444  * Parameters:  
3445  *
3446  * Return Value:    Void.
3447  *
3448  * Purpose:         Close and destroy the help widget
3449  *
3450  *****************************************************************************/
3451 static void CloseHelpCB(
3452      Widget          w,
3453      XtPointer       clientData,
3454      XtPointer       callData)
3455 {
3456     XtUnmanageChild(w);
3457     XtDestroyWidget(w);
3458 }
3459 #endif  /* save--used in code commented out elsewhere in this file */
3460
3461 \f
3462 /*****************************************************************************
3463  * Function:        void GotoLocation(hw,helpVolume,location)
3464  *
3465  * Parameters:  
3466  *
3467  * Return Value:    Void.
3468  *
3469  * Purpose:         Goto a topic by opening a new help dialog window
3470  *
3471  *****************************************************************************/
3472 static void  GotoLocation(
3473     DtHelpDialogWidget hw,
3474     char * helpVolume,
3475     char * locationId)
3476 {
3477 #if 0   /* don't delete...useful as reference */
3478   {
3479    Widget helpDlg;
3480    Arg    args[15];
3481    int    n;
3482
3483    /* This opens a new help window on the topic */
3484    n = 0;
3485    XtSetArg( args[n], XmNtitle, "Help" );                        n++;
3486    XtSetArg( args[n], DtNhelpType, DtHELP_TYPE_TOPIC );         n++;
3487    XtSetArg( args[n], DtNlocationId, locationId );               n++;
3488    XtSetArg( args[n], DtNhelpVolume, helpVolume );               n++;
3489    helpDlg = DtCreateHelpDialog(XtParent(hw),"mainHelpDialog",args,n);
3490    XtAddCallback(helpDlg,DtNcloseCallback,CloseHelpCB,helpDlg);
3491    XtManageChild(helpDlg);
3492   }
3493 #else
3494    {
3495      _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3496      if (hw->help_dialog.srch.selectionDlg)
3497         _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
3498
3499      /* jump to selected location in same window */
3500      XtFree(hw->help_dialog.display.locationId);
3501      hw->help_dialog.display.locationId = XtNewString(locationId);
3502      XtFree(hw->help_dialog.display.helpVolume);
3503      hw->help_dialog.display.helpVolume = XtNewString(helpVolume);
3504      hw->help_dialog.ghelp.volumeFlag = False;  /* force search for volume */
3505      hw->help_dialog.display.helpType = DtHELP_TYPE_TOPIC;
3506
3507      _DtHelpSetupDisplayType(hw, TRUE, DtHISTORY_AND_JUMP);
3508
3509      _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3510      if (hw->help_dialog.srch.selectionDlg)
3511         _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.selectionDlg));
3512    }
3513 #endif
3514 }
3515
3516
3517 \f
3518 /*****************************************************************************
3519  * Function:        void ProcessResultSelectionCB(Widget w,
3520  *                                              XtPointer clientData,
3521  *                                              XtPointer callData);
3522  *
3523  *
3524  *
3525  * Parameters:  
3526  *
3527  * Return Value:    Void.
3528  *
3529  * Purpose:         Process user selection of an item in the result List.
3530  *
3531  *****************************************************************************/
3532 static void ProcessResultSelectionCB(
3533     Widget w,
3534     XtPointer clientData,
3535     XtPointer callData)
3536 {
3537    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3538    int *     topicPosList = NULL;  
3539    int       topicPosition;  
3540    Boolean   status;
3541    int       n;
3542
3543    /* Determine the item selected and find that item in our list */
3544    status = XmListGetSelectedPos(
3545               hw->help_dialog.srch.resultList, &topicPosList,&n);
3546
3547    /* if true, an item selected */
3548    if (status && topicPosList)
3549    {
3550      _DtHelpFileEntry     file = NULL;
3551      _DtHelpGlobSrchHit * hit = NULL;
3552      char *            locationId = NULL;
3553      char *            helpFile = NULL;
3554
3555      topicPosition = topicPosList[0];   /* 1 based */
3556      XtFree((String)topicPosList);
3557   
3558      /* Get the entry */
3559      if ( HitListGetNth(hw->help_dialog.srch.volListHead,
3560                        topicPosition,&file,&hit,&locationId,&helpFile) == 0 )
3561      {
3562         _DtHelpTurnOnHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3563
3564         /* deactivate it */
3565         XmListDeselectPos(hw->help_dialog.srch.resultList,topicPosition);
3566
3567         /* was a volume item selected? */
3568         if ( NULL == hit )
3569         {
3570            _DtHelpGlobSrchVol * vol = (_DtHelpGlobSrchVol *) file->clientData;
3571            if (vol->hitCnt > 0) 
3572            {
3573               if (False == vol->hitsDisplayed) 
3574               {
3575                  VolHitsDisplay(hw,file);     /* toggle state */
3576               }
3577               else 
3578               {
3579                  VolHitsUndisplay(hw,file);
3580                  vol->showHitsWithVol = False;
3581               }
3582               /* update the volume label to show the state */
3583               /* False: dont insert hw item */
3584               VolNameDisplay(hw,file,False);
3585            }
3586            /* else don't otherwise handle a 0-hits volume */
3587         }
3588         /* was an expandable index selected */
3589         else if (NULL == locationId && hit->topicCnt > 1)
3590         {
3591            int topicCnt = 0;
3592        
3593            /* if we're turning them on, build a list */
3594            if (False == hit->topicsDisplayed)
3595            {
3596               topicCnt = HitTopicsDisplay(hw,file,hit,topicPosition+1);
3597            }
3598            else
3599            {
3600               topicCnt = - HitTopicsUndisplay(hw,file,hit,topicPosition+1);
3601               hit->showTopicsWithHit = False;
3602            }
3603            /* update the hit label to show the state; False--dont insert */
3604            HitNameDisplay(hw,file,hit,topicPosition,False);
3605        
3606            /* add to all the following */
3607            if (topicCnt != 0)
3608            {
3609               /* adjust count beginning with next file with hits */
3610               AdjustPositionValues(file, 0, topicCnt, True);
3611            }
3612         }
3613         /* a location or index with one topic was selected */
3614         else 
3615         {
3616            /* if a single click, goto the location */
3617            if (hit->topicCnt == 1)
3618            {
3619               if ( HitLoadTopics(hw,file,hit) == 0 )
3620               {
3621                  GotoLocation(hw, file->fullFilePath, hit->topicIdList[0]);
3622                  HitFree(hit,False);     /*release what was loaded 3 lines up*/
3623               }
3624               else
3625               {  /* volume couldn't be opened or some other error */
3626                 /* FIX: error message */
3627               }
3628            } /* if an index with a single topic */
3629            else
3630            { /* a location from an open multi-topic index entry */
3631               GotoLocation(hw, file->fullFilePath, locationId);
3632            }
3633         } /* else index with one topic or topic was selected */
3634
3635         /* finish up processing a selection */
3636         _DtHelpTurnOffHourGlass(XtParent(hw->help_dialog.srch.srchForm));
3637
3638      } /* got the nth item */
3639   }
3640   else  /* could not find the nth hit */
3641   {
3642      if (topicPosList) XtFree((String)topicPosList);
3643   }
3644 }
3645
3646
3647
3648 \f
3649 /*****************************************************************************
3650  * Function:        void CloseVolSelDialogCB(Widget w,
3651  *                                          XtPointer clientData,
3652  *                                          XtPointer callData);
3653  *
3654  * Parameters:  
3655  *
3656  * Return Value:    Void.
3657  *
3658  * Purpose:         Resets the selection dialog variable to NULL
3659  *
3660  *****************************************************************************/
3661 static void CloseVolSelDialogCB(
3662     Widget widget,
3663     XtPointer clientData,
3664     XtPointer callData)
3665 {
3666    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3667
3668    /* unmanage & destroy the dialog zero the variable */
3669    if (    hw->help_dialog.srch.selectionDlg
3670         && XtIsManaged(hw->help_dialog.srch.selectionDlg) )
3671       XtUnmanageChild(hw->help_dialog.srch.selectionDlg);
3672
3673    /* start a search to be sure we got all changes; FIX: need this??? */
3674    /*StartSearchCB(NULL,hw,NULL);*/
3675    XtSetSensitive(hw->help_dialog.srch.selectBtn,True);
3676
3677    /* change focus */
3678    if (hw->help_dialog.srch.hitsFound == True)
3679      XmProcessTraversal(hw->help_dialog.srch.resultList,XmTRAVERSE_CURRENT);
3680    else
3681      XmProcessTraversal(hw->help_dialog.srch.allVolRadBtn,XmTRAVERSE_CURRENT);
3682 }
3683
3684
3685 \f
3686 /*****************************************************************************
3687  * Function:        void CreateVolSelDialog(
3688  *
3689  * Parameters:  
3690  *
3691  * Return Value:    Void.
3692  *
3693  * Purpose:         Creates selection dialog to chose volumes
3694  *
3695  *****************************************************************************/
3696 static void CreateVolSelDialog(
3697             DtHelpDialogWidget hw)
3698 {
3699     Widget    selDlg;
3700     _DtHelpFileDlgChildren dlgChld;
3701     Atom      wm_delete_window;
3702     Arg       args[5];
3703
3704     /* desensitize the button */
3705     XtSetSensitive(hw->help_dialog.srch.selectBtn,False);
3706     
3707     /* only create one */
3708     if ( NULL != hw->help_dialog.srch.selectionDlg ) 
3709     {
3710        XtManageChild(hw->help_dialog.srch.selectionDlg);
3711        return;
3712     }
3713
3714     /* open the modal dialog and let user select the volumes */
3715     selDlg = _DtHelpFileListCreateSelectionDialog(
3716                    hw, hw->help_dialog.srch.srchForm, False,
3717                    (char *)_DTGETMESSAGE (GSSET, 40,
3718                              "Help - Search Volume Selection"),
3719                    &hw->help_dialog.srch.volTitlesFontList,
3720                    hw->help_dialog.srch.volListHead, &dlgChld);
3721     hw->help_dialog.srch.selectionDlg = selDlg;
3722
3723     XtAddCallback(dlgChld.closeBtn, XmNactivateCallback, 
3724                              CloseVolSelDialogCB,(XtPointer)hw);
3725     XtAddCallback(dlgChld.form, XmNunmapCallback, 
3726                              CloseVolSelDialogCB,(XtPointer)hw);
3727
3728     /* set the default response to a WM_DELETE_WINDOW message
3729       to no response instead of UNMAP. */
3730     XtSetArg(args[0], XmNdeleteResponse, XmDO_NOTHING);
3731     XtSetValues(dlgChld.shell, args, 1);
3732     wm_delete_window = XmInternAtom(XtDisplay(dlgChld.shell),
3733                                             "WM_DELETE_WINDOW", FALSE);
3734     XmAddWMProtocolCallback(dlgChld.shell,wm_delete_window,
3735              (XtCallbackProc)CloseVolSelDialogCB, (XtPointer)hw);
3736
3737     XtAddCallback(dlgChld.list, XmNsingleSelectionCallback, 
3738                            StartSelectedVolumeSearchCB, (XtPointer) hw);
3739     XtAddCallback(dlgChld.list, XmNmultipleSelectionCallback, 
3740                            StartSelectedVolumeSearchCB, (XtPointer) hw);
3741     XtAddCallback(dlgChld.list, XmNextendedSelectionCallback, 
3742                            StartSelectedVolumeSearchCB, (XtPointer) hw);
3743     XtAddCallback(dlgChld.list, XmNdefaultActionCallback, 
3744                            StartSelectedVolumeSearchCB, (XtPointer) hw);
3745 }
3746
3747
3748 \f
3749 /*****************************************************************************
3750  * Function:        void OpenSelectDialogCB(Widget w,
3751  *                                          XtPointer clientData,
3752  *                                          XtPointer callData);
3753  *
3754  *
3755  *
3756  * Parameters:  
3757  *
3758  * Return Value:    Void.
3759  *
3760  * Purpose:         Process user selection of the select button
3761  *
3762  *****************************************************************************/
3763 static void OpenSelectDialogCB(
3764     Widget widget,
3765     XtPointer clientData,
3766     XtPointer callData)
3767 {
3768    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3769
3770    /* only build the list of files if it hasn't been done */
3771    if (   False == hw->help_dialog.srch.volScanDone
3772        || NULL == hw->help_dialog.srch.volListHead)
3773    {
3774       /* Add on the Vol info; (T,T,T) search, display, selected only */
3775       VolListBuild(hw,True,True,True);
3776    }
3777
3778    /* FIX: the modal behaviour doesn't seem to be set; is it desired/needed? */
3779    /* don't need to worry about having open twice, since
3780       the dialog is always opened in modal mode from the search dialog */
3781    /* open the dialog and let user select the volumes */
3782    CreateVolSelDialog(hw);
3783 }
3784
3785 \f
3786 /*****************************************************************************
3787  * Function:        void UpdateSearchVolumesCB(Widget w,
3788  *                                             XtPointer clientData,
3789  *                                             XtPointer callData);
3790  *
3791  *
3792  *
3793  * Parameters:  
3794  *
3795  * Return Value:    Void.
3796  *
3797  * Purpose:         Process user selection of a button in the Volumes Radio box
3798  *
3799  *****************************************************************************/
3800 static void UpdateSearchVolumesCB(
3801     Widget widget,
3802     XtPointer clientData,
3803     XtPointer callData)
3804 {
3805    XmToggleButtonCallbackStruct *status = (XmToggleButtonCallbackStruct *) callData;
3806    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3807    Arg args[5];
3808
3809
3810    /* change focus */
3811    
3812    if (hw->help_dialog.srch.hitsFound == True) 
3813      XmProcessTraversal(hw->help_dialog.srch.resultList,XmTRAVERSE_CURRENT);
3814    else
3815      XmProcessTraversal(hw->help_dialog.srch.allVolRadBtn,XmTRAVERSE_CURRENT);
3816
3817
3818
3819    /* if turning off the button, just reinforce the current settings.
3820       This message occurs when an on button is hit again. */
3821    if ( False == status->set )
3822    {
3823      XtSetArg(args[0], XmNset, hw->help_dialog.srch.allVolRadBtn == widget);
3824      XtSetValues(hw->help_dialog.srch.allVolRadBtn,args,1);
3825      XtSetArg(args[0], XmNset, hw->help_dialog.srch.selVolRadBtn == widget);
3826      XtSetValues(hw->help_dialog.srch.selVolRadBtn,args,1);
3827      XtSetArg(args[0], XmNset, hw->help_dialog.srch.curVolRadBtn == widget);
3828      XtSetValues(hw->help_dialog.srch.curVolRadBtn,args,1);
3829      return;
3830    }
3831
3832    /*** if work when something is turned on; ignore the off messages 
3833         except when the button is the selected volumes button; we
3834         want to catch every click on that button */
3835    if (   XmCR_VALUE_CHANGED == status->reason 
3836        && True == status->set 
3837        && NULL != status->event ) /* event is NULL for 1st of the two calls 
3838                                      to this routine that are made when a 
3839                                       button is pressed. */
3840    {
3841      /*** now update the sources value according to button selected ***/
3842      hw->help_dialog.srch.volLeftCnt = 0;  /* change invalidates prior search */
3843      UpdateActionButtonLabel(hw,NULL,True);
3844
3845      XtSetArg(args[0], XmNset, hw->help_dialog.srch.allVolRadBtn == widget);
3846      XtSetValues(hw->help_dialog.srch.allVolRadBtn,args,1);
3847      XtSetArg(args[0], XmNset, hw->help_dialog.srch.curVolRadBtn == widget);
3848      XtSetValues(hw->help_dialog.srch.curVolRadBtn,args,1);
3849      XtSetArg(args[0], XmNset, hw->help_dialog.srch.selVolRadBtn == widget);
3850      XtSetValues(hw->help_dialog.srch.selVolRadBtn,args,1);
3851
3852      /*** selected volumes button activated ***/
3853      if (hw->help_dialog.srch.selVolRadBtn == widget) 
3854      {
3855         /* set state */
3856         hw->help_dialog.srch.srchSources = _DtHelpGlobSrchSelectedVolumes;
3857
3858         /* only build the list of files if it hasn't been done */
3859         if (    False == hw->help_dialog.srch.volScanDone
3860              || NULL == hw->help_dialog.srch.volListHead)
3861         {
3862            /* Add on the Vol info; (T,T,T) search, display, selected only */
3863            VolListBuild(hw,True,True,True);
3864         }
3865
3866         /* (F,F,F,F): disable search,disable display,no 0 hits,for all vols */
3867         SetVolStatus(hw->help_dialog.srch.volListHead,False,False,False,False);
3868         /* (T,T,T,T): enable search, enable display,
3869                     zero hits ok, only for selected volumes */
3870         /* Set these here so that the CountSelectedVolumes() works right */
3871         SetVolStatus(hw->help_dialog.srch.volListHead,True,True,True,True);
3872
3873         /* count all volumes selected, including those already searched */
3874         if (CountSelectedVolumes(hw->help_dialog.srch.volListHead,True)==0)
3875         {
3876            StatusLabelUpdate(hw,NO_VOL_STATUS,False,0);
3877            DeleteListContents(&hw->help_dialog.srch);
3878            CreateVolSelDialog(hw);
3879            /* NOTE: don't start search here, start it from the callback */
3880            /* set state of start button correctly */
3881            UpdateSearchStartStatusCB(NULL, (XtPointer) hw, NULL);
3882         }
3883         else  /* volumes already selected; just display */
3884         {
3885            hw->help_dialog.srch.hitsFound = False; /*DBG*/
3886            StartSearchCB(NULL,(XtPointer) hw, NULL);
3887         }
3888      }   /* if selected volumes button */
3889
3890      /*** all volumes button ***/
3891      else if (hw->help_dialog.srch.allVolRadBtn == widget)
3892      {
3893         /* close the selection dialog, if open */
3894         if (hw->help_dialog.srch.selectionDlg)
3895            XtUnmanageChild(hw->help_dialog.srch.selectionDlg);
3896
3897         /* set sources state */
3898         hw->help_dialog.srch.srchSources = _DtHelpGlobSrchAllVolumes;
3899         hw->help_dialog.srch.hitsFound = False; /*DBG*/
3900         StartSearchCB(NULL,(XtPointer) hw, NULL);
3901      }
3902      /*** current volume button ***/
3903      else
3904      {  
3905         /* close the selection dialog, if open */
3906         if (hw->help_dialog.srch.selectionDlg)
3907            XtUnmanageChild(hw->help_dialog.srch.selectionDlg);
3908
3909         /* set sources state */
3910         hw->help_dialog.srch.srchSources = _DtHelpGlobSrchCurVolume;
3911         hw->help_dialog.srch.hitsFound = False; /*DBG*/
3912         StartSearchCB(NULL,(XtPointer) hw, NULL);
3913      }
3914
3915      /* update the Select... button status */
3916      /* do this last, so that while searching for volumes (VolListBuild),
3917         the button is not active. */
3918      XtSetSensitive(hw->help_dialog.srch.selectBtn,
3919                      (hw->help_dialog.srch.selVolRadBtn == widget) 
3920                   && (   NULL == hw->help_dialog.srch.selectionDlg
3921                       || !XtIsManaged(hw->help_dialog.srch.selectionDlg) ) );
3922
3923    }  /* if value changed */
3924 }
3925
3926
3927 \f
3928 /*****************************************************************************
3929  * Function:        void UpdateIndexSelectionCB(Widget w,
3930  *                                             XtPointer clientData,
3931  *                                             XtPointer callData);
3932  *
3933  *
3934  *
3935  * Parameters:  
3936  *
3937  * Return Value:  Void.
3938  *
3939  * Purpose:       Process user selection of a button in the Entries Radio box
3940  *
3941  *****************************************************************************/
3942 static void UpdateIndexSelectionCB(
3943     Widget widget,
3944     XtPointer clientData,
3945     XtPointer callData)
3946 {
3947    XmToggleButtonCallbackStruct *status = (XmToggleButtonCallbackStruct *) callData;
3948    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
3949    Boolean containsState;
3950    int n;
3951    Arg args[5];
3952
3953    /* change focus */
3954    if (hw->help_dialog.srch.hitsFound == True) 
3955      XmProcessTraversal(hw->help_dialog.srch.resultList,XmTRAVERSE_CURRENT);
3956    else
3957      XmProcessTraversal(hw->help_dialog.srch.allVolRadBtn,XmTRAVERSE_CURRENT);
3958
3959
3960    /* if turning off the button, just reinforce the current settings.
3961       This message occurs when an on button is hit again. */
3962    if ( False == status->set )
3963    {
3964      containsState = (hw->help_dialog.srch.containsRadBtn == widget);
3965      XtSetArg(args[0], XmNset, !containsState);
3966      XtSetValues(hw->help_dialog.srch.fullIndexRadBtn,args,1);
3967      XtSetArg(args[0], XmNset, containsState);
3968      XtSetValues(hw->help_dialog.srch.containsRadBtn,args,1);
3969      return;
3970    }
3971
3972    /*** if work when something is turned on; ignore the off messages 
3973         except when the button is the selected volumes button; we
3974         want to catch every click on that button */
3975    if (   XmCR_VALUE_CHANGED == status->reason 
3976        && True == status->set 
3977        && NULL != status->event ) /* event is NULL for 1st of the two calls 
3978                                      to this routine that are made when a 
3979                                       button is pressed. */
3980    {
3981      /* if search in progress, stop it */
3982      if(hw->help_dialog.srch.searchInProgress||hw->help_dialog.srch.workProcId)
3983      {
3984          XmPushButtonCallbackStruct status;
3985    
3986          /* generate a fake event to reset the dialog */
3987          status.reason = XmCR_ACTIVATE;
3988          status.event = NULL;
3989          status.click_count = 1;
3990          StopSearchCB(hw->help_dialog.srch.actionBtn,
3991                       (XtPointer)hw,(XtPointer)&status);
3992      }
3993
3994      containsState = (hw->help_dialog.srch.containsRadBtn == widget);
3995      XtSetArg(args[0], XmNset, !containsState);
3996      XtSetValues(hw->help_dialog.srch.fullIndexRadBtn,args,1);
3997      XtSetArg(args[0], XmNset, containsState);
3998      XtSetValues(hw->help_dialog.srch.containsRadBtn,args,1);
3999
4000      /* sensitize/desensitize the Contains text field */
4001      XtSetSensitive(hw->help_dialog.srch.wordField,containsState);
4002      n=0;
4003      XtSetArg(args[n],XmNeditable,containsState);                       n++;
4004      XtSetArg(args[n],XmNcursorPositionVisible,containsState);          n++;
4005      XtSetValues(hw->help_dialog.srch.wordField,args,n);
4006
4007      /* set widget status here; do this way bec. srchFullIndex is a bit flag */
4008      hw->help_dialog.srch.fullIndex = (containsState ? False : True); /*flag*/
4009  
4010      /* set state of start button correctly */
4011      UpdateSearchStartStatusCB(NULL, (XtPointer) hw, NULL);
4012
4013      if (containsState)
4014      {  /* if changing to "Containing" */
4015         /* change focus to the search word */ 
4016         XmProcessTraversal(hw->help_dialog.srch.wordField,XmTRAVERSE_CURRENT);
4017         /* user will need to hit CR to initiate search */
4018      }
4019      else
4020      {  /* if changing to full index */
4021         /* indicate that no contains word is valid by deleting it */
4022         /* FIX: I'm concerned that normWordStr & localeWordStr aren't in synch */
4023         XtFree(hw->help_dialog.srch.normWordStr);
4024         hw->help_dialog.srch.normWordStr = NULL;
4025         /* search full index */
4026         StartSearchCB(NULL,(XtPointer) hw, NULL);
4027      }
4028
4029      /* and search to update results to the new state */
4030    } /* if value changed */
4031 }
4032
4033
4034 \f
4035 /*****************************************************************************
4036  * Function:        void ContainsDisarmCB(Widget w,
4037  *                                        XtPointer clientData,
4038  *                                        XtPointer callData);
4039  *
4040  *
4041  *
4042  * Parameters:  
4043  *
4044  * Return Value:  Void.
4045  *
4046  * Purpose:       Process disarm of the contains radio button
4047  *
4048  *****************************************************************************/
4049 static void ContainsDisarmCB(
4050     Widget widget,
4051     XtPointer clientData,
4052     XtPointer callData)
4053 {
4054    XmToggleButtonCallbackStruct *status = (XmToggleButtonCallbackStruct *) callData;
4055    DtHelpDialogWidget hw = (DtHelpDialogWidget) clientData;
4056
4057    /* Force focus to the word field if set. */
4058    if (True==status->set)
4059      XmProcessTraversal(hw->help_dialog.srch.wordField,XmTRAVERSE_CURRENT);
4060 }
4061
4062
4063 \f
4064 /*****************************************************************************
4065  * Function:        CreateCurVolBtnLabel()
4066  *                             
4067  * 
4068  * Parameters:      
4069  *
4070  * Return Value:    True or False if current vol has an index
4071  *
4072  * Purpose:         Creates the label for the current volume button
4073  *
4074  *****************************************************************************/
4075 static Boolean CreateCurVolBtnLabel(
4076      DtHelpDialogWidget hw,
4077      Boolean *          out_curVolAvailable,
4078      XmString *         out_labelString,
4079      char * *           out_mnemonic)
4080 {
4081    char *   path = NULL;
4082    char *   preTitle;
4083    char *   postTitle;
4084    XmString volTitleString = NULL;
4085    XmString preTitleString = NULL;
4086    XmString postTitleString = NULL;
4087    XmString newTitle;
4088    XmString labelString;
4089    char *   mnemonic;
4090    Boolean  curVolAvail;
4091    int      n;
4092    Arg      args[5];
4093
4094 #if 0   /* DBG */
4095    if (out_curVolAvailable) 
4096        *out_curVolAvailable = False;
4097    if (out_labelString) 
4098        *out_labelString = XmStringCreateLocalized("dum");
4099    if (out_mnemonic) 
4100        *out_mnemonic = "";
4101    return False;
4102 #endif
4103
4104    /* if help content is a volume, get the title */
4105    if ( hw->help_dialog.display.helpType == DtHELP_TYPE_TOPIC )
4106    {
4107       /* determine whether a current volume index is available */
4108       curVolAvail = VolumeHasIndexP(
4109                            hw->help_dialog.srch.srchSources,
4110                            hw->help_dialog.display.helpType,
4111                            hw->help_dialog.display.helpVolume);
4112    
4113       /* change False to True to search home dir; may want this */
4114       path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, hw->help_dialog.display.helpVolume,
4115                                      _DtHelpFileSuffixList,False,R_OK);
4116    
4117       /* title needs to be an XmString to use volume's font */
4118       if (path) 
4119       {
4120          XmFontList fontList = NULL;
4121          Boolean    mod = False;
4122    
4123          /* get the font list of the btn */
4124          n = 0;
4125          XtSetArg (args[n], XmNfontList, &fontList);  n++;
4126          XtGetValues (hw->help_dialog.srch.curVolRadBtn, args, n);
4127    
4128 #if defined(DONT_USE_CDExc22774)
4129          /* copy the list before passing it in for modification */
4130          fontList = XmFontListCopy (fontList);
4131 #endif
4132    
4133          GetVolumeInfoCB(hw->help_dialog.help.pDisplayArea,path,
4134                  NULL,&volTitleString,NULL,NULL,NULL,&fontList,&mod);
4135    
4136          /* if font list was changed, install it */
4137          if (mod)
4138          {
4139             /* set the font list of the btn */
4140             n = 0;
4141             XtSetArg (args[n], XmNfontList, fontList);  n++;
4142             XtSetValues (hw->help_dialog.srch.curVolRadBtn, args, n);
4143             if (fontList) XmFontListFree (fontList);
4144          }
4145       }
4146    
4147       /* just in case */
4148       if (NULL == volTitleString)
4149          volTitleString = XmStringCreateLocalized(
4150                   hw->help_dialog.display.helpVolume);
4151    } /* if helpType == TOPIC */
4152    else
4153    { /* if helpType != TOPIC */
4154       curVolAvail = False;
4155       switch (hw->help_dialog.display.helpType)
4156       {
4157       case DtHELP_TYPE_STRING:
4158       case DtHELP_TYPE_DYNAMIC_STRING:
4159          volTitleString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4160                         (GSSET, 32,"Help Message")));
4161          break;
4162       case DtHELP_TYPE_FILE:
4163          volTitleString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4164                         (GSSET, 33,"Help File")));
4165          break;
4166       case DtHELP_TYPE_MAN_PAGE:
4167          volTitleString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4168                         (GSSET, 34,"Manual Page")));
4169          break;
4170       default:
4171          volTitleString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4172                         (GSSET, 35,"Unknown Format")));
4173          break;
4174       } /* switch on helpType */
4175    } /* if helpType != TOPIC */
4176
4177    /* record path in the widget */
4178    XtFree(hw->help_dialog.srch.curVolPath);
4179    hw->help_dialog.srch.curVolPath = path;
4180
4181    /* create title */
4182    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4183                             (GSSET, 3,"Current")));
4184    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 4,"r"));*/
4185    mnemonic = 0;
4186
4187    /* append volume name to title */
4188    preTitle = (char *)_DTGETMESSAGE(GSSET, 60," (");
4189    preTitleString = XmStringCreateLocalized(preTitle);
4190    postTitle = (char *)_DTGETMESSAGE(GSSET, 61,")");
4191    postTitleString = XmStringCreateLocalized(postTitle);
4192
4193    newTitle = XmStringConcat(labelString,preTitleString);
4194    XmStringFree(labelString);
4195    XmStringFree(preTitleString);
4196    labelString = newTitle;
4197
4198    newTitle = XmStringConcat(labelString,volTitleString);
4199    XmStringFree(labelString);
4200    XmStringFree(volTitleString);
4201    labelString = newTitle;
4202
4203    newTitle = XmStringConcat(labelString,postTitleString);
4204    XmStringFree(labelString);
4205    XmStringFree(postTitleString);
4206    labelString = newTitle;
4207
4208    /* set the out values */
4209    if (out_curVolAvailable) *out_curVolAvailable = curVolAvail;
4210    if (out_mnemonic) *out_mnemonic = mnemonic;
4211    if (out_labelString) *out_labelString = labelString;
4212    else XmStringFree(labelString);
4213
4214    return curVolAvail;
4215 }
4216
4217
4218
4219 \f
4220 /*****************************************************************************
4221  * Function:        void CreateGlobSrchDialog()
4222  *                             
4223  * 
4224  * Parameters:      
4225  *
4226  * Return Value:
4227  *
4228  * Purpose:         Creates and displays an instance of the search dialog.
4229  *
4230  *****************************************************************************/
4231 static void CreateGlobSrchDialog(
4232     Widget nw,
4233     char * searchWord)
4234 {
4235    Widget        parentForm;
4236    Widget        separator;
4237    Widget        srchShell;
4238    /* Widget        topWidget; */
4239    Widget        volumesFrame;
4240    Widget        volumesForm;
4241    Widget        showFrame;
4242    Widget        showForm;
4243    Widget        frameTitle;
4244    XmString      labelString;
4245    /* char *        mnemonic; */
4246    Dimension     widgetHeight;
4247    Dimension     widgetBorderHeight;
4248    char *        title;
4249    DtHelpListStruct *pHelpInfo;
4250    Atom           wm_delete_window;
4251    DtHelpDialogWidget hw = (DtHelpDialogWidget) nw ;
4252    XtTranslations btnTransTable;
4253    /* XtTranslations listTransTable; */
4254    /* XtTranslations mgrTransTable; */
4255    Boolean        curVolAvailable;
4256    int            n;
4257    Arg            args[20];
4258
4259    /* get state of the volume */
4260    curVolAvailable = VolumeHasIndexP (
4261                           hw->help_dialog.srch.srchSources,
4262                           hw->help_dialog.display.helpType,
4263                           hw->help_dialog.display.helpVolume);
4264
4265    /* Set up the translations table stuff */
4266    btnTransTable = XtParseTranslationTable(defaultBtnTranslations);
4267    /* listTransTable = XtParseTranslationTable(defaultListTranslations); */
4268    /* mgrTransTable = XtParseTranslationTable(defaultMgrTranslations); */
4269   
4270    /*  Create the shell used for the dialog.  */
4271    title = XtNewString(((char *)_DTGETMESSAGE(GSSET,1,"Help - Index Search")));
4272    n = 0;
4273    XtSetArg (args[n], XmNtitle, title);                                 n++;
4274    XtSetArg (args[n], XmNallowShellResize, True);                       n++;
4275    srchShell = XmCreateDialogShell((Widget) hw, "searchShell", args, n);
4276    XtFree(title);
4277
4278    /* Set the useAsyncGeo on the shell */
4279    n = 0;
4280    XtSetArg (args[n], XmNuseAsyncGeometry, True); n++;
4281    XtSetValues (XtParent(srchShell), args, n);  /* parent is new's shell */
4282 #if 0
4283    /*  Adjust the decorations for the dialog shell of the dialog  */
4284    n = 0;
4285    XtSetArg(args[n], XmNmwmFunctions, 0);                               n++;
4286    XtSetArg (args[n], XmNmwmDecorations, 
4287              MWM_DECOR_BORDER | MWM_DECOR_TITLE);                       n++;
4288    XtSetValues (srchShell, args, n);
4289 #endif
4290
4291    /* Grab the window mgr close and install a close dialog 
4292       callback when closed from dialog WM menu; this prevents
4293       the dialog from closing the host application. */
4294    wm_delete_window = XmInternAtom(XtDisplay(srchShell),
4295                                             "WM_DELETE_WINDOW", FALSE);
4296    XtSetArg(args[0], XmNdeleteResponse, XmDO_NOTHING);
4297    XmAddWMProtocolCallback(srchShell,wm_delete_window,
4298                           CloseSearchCB, (XtPointer)&hw->help_dialog.srch);
4299    XtSetValues(srchShell, args, 1);
4300
4301    /* set the callback that positions the dialog when popped up */
4302    XtAddCallback (srchShell, XmNpopupCallback, 
4303                (XtCallbackProc)_DtHelpMapCB, (XtPointer) XtParent(hw));
4304
4305    /***  Create the form used for the dialog.  ***/
4306    /* setting RESIZE_NONE is important to prevent the resultList from
4307       dynamically resizing as items with various fonts are added and
4308       deleted from it. */
4309    n = 0;
4310    XtSetArg (args[n], XmNmarginWidth, 1);                               n++;
4311    XtSetArg (args[n], XmNmarginHeight, 1);                              n++;
4312    XtSetArg (args[n], XmNshadowThickness, 1);                           n++;
4313    XtSetArg (args[n], XmNshadowType, XmSHADOW_OUT);                     n++;
4314    XtSetArg (args[n], XmNautoUnmanage, False);                          n++;
4315    XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE);                  n++;
4316    parentForm = XmCreateForm (srchShell, "parentForm", args, n);
4317    hw->help_dialog.srch.srchForm = parentForm;
4318
4319    /*==============================================================*/
4320    /****** Create the volumes region ******/
4321    n = 0;
4322    XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);         n++;
4323    XtSetArg (args[n], XmNtopOffset, 5);                         n++;
4324    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);       n++;
4325    XtSetArg (args[n], XmNrightOffset, 5);                       n++;
4326    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);        n++;
4327    XtSetArg (args[n], XmNleftOffset, 5);                        n++;
4328    XtSetArg (args[n], XmNmarginWidth, 5);                       n++;
4329    XtSetArg (args[n], XmNmarginHeight, 2);                      n++;
4330    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);     n++;/*EXP*/
4331    volumesFrame = XmCreateFrame(parentForm, "volFrame", args, n);
4332    XtManageChild (volumesFrame);
4333
4334    /* put form inside frame */
4335    volumesForm = XmCreateForm (volumesFrame, "volumesForm", args, 0);
4336    XtManageChild (volumesForm);
4337
4338    /* create the frame title */
4339    labelString = XmStringCreateLocalized ((_DTGETMESSAGE(GSSET,2, "Search")));
4340    n = 0;
4341    XtSetArg (args[n], XmNlabelString, labelString);             n++;
4342    XtSetArg (args[n], XmNchildType, XmFRAME_TITLE_CHILD);       n++;
4343    XtSetArg (args[n], XmNtraversalOn, False);                   n++;
4344    frameTitle = XmCreateLabelGadget(volumesFrame, "volFrameTitle", args, n);
4345    XtManageChild (frameTitle);
4346    XmStringFree (labelString);
4347
4348    /* create Current Volume radio button */
4349    /* Use a dummy label until CreateCurVolBtnLabel can be used.
4350       It refs the srchCurVolRadBtn widget and other things that need 
4351       initalizing. */
4352
4353    labelString = XmStringCreateLocalized (" ");
4354    n = 0;
4355    XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY);                 n++;
4356    XtSetArg (args[n], XmNset, TRUE);                                    n++;
4357
4358    XtSetArg(args[n], XmNlabelString, labelString);                      n++;
4359    XtSetArg (args[n], XmNmarginHeight, 0);                              n++;
4360    XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);                 n++;
4361    XtSetArg (args[n], XmNtopOffset, 0);                                 n++;
4362    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4363    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4364    /* Attaching to form causes the hilite outline of the button to 
4365       stretch to the form edge when selected.  But it also forces
4366       the form to resize when the current volume title is too big
4367       for the available space. */
4368    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4369    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
4370    XtSetArg (args[n], XmNbottomOffset, 0);                              n++;
4371    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);             n++;
4372    XtSetArg (args[n], XmNhighlightOnEnter, True);                       n++;
4373    hw->help_dialog.srch.curVolRadBtn = 
4374             XmCreateToggleButtonGadget(volumesForm,"srchCurVolRadBtn",args,n);
4375    XtAddCallback(hw->help_dialog.srch.curVolRadBtn,XmNvalueChangedCallback,
4376                  UpdateSearchVolumesCB, (XtPointer) hw);
4377    /* ??? XtSetSensitive (hw->help_dialog.srch.curVolRadBtn,False); */
4378    XtManageChild (hw->help_dialog.srch.curVolRadBtn);
4379    XmStringFree (labelString);
4380
4381    /* create All Volumes radio button */
4382    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4383                         (GSSET, 5,"All Volumes")));
4384    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 7,"A"));*/
4385
4386    n = 0;
4387    XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY);                 n++;
4388    XtSetArg (args[n], XmNset, FALSE);                                   n++;
4389    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4390    XtSetArg (args[n], XmNmarginHeight, 0);                              n++;
4391    XtSetArg (args[n], XmNmarginWidth, 2);                               n++;
4392    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4393    XtSetArg (args[n], XmNtopWidget, hw->help_dialog.srch.curVolRadBtn); n++;
4394    XtSetArg (args[n], XmNtopOffset, 1);                                 n++;
4395    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4396    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4397    XtSetArg(args[n], XmNhighlightOnEnter, True);                        n++;
4398    hw->help_dialog.srch.allVolRadBtn = 
4399             XmCreateToggleButtonGadget(volumesForm,"srchAllVolRadBtn",args, n);
4400    XtAddCallback(hw->help_dialog.srch.allVolRadBtn,XmNvalueChangedCallback,
4401                  UpdateSearchVolumesCB, (XtPointer) hw);
4402    XtManageChild (hw->help_dialog.srch.allVolRadBtn);
4403    XmStringFree (labelString);
4404
4405    /* create Selected Volumes radio button */
4406    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4407                         (GSSET, 6,"Selected")));
4408    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 9,"d"));*/
4409
4410    n = 0;
4411    XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY);                 n++;
4412    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4413    XtSetArg (args[n], XmNmarginHeight, 0);                              n++;
4414    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4415    XtSetArg (args[n], XmNtopWidget, hw->help_dialog.srch.allVolRadBtn); n++;
4416    XtSetArg (args[n], XmNtopOffset, 1);                                 n++;
4417    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4418    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4419    XtSetArg (args[n], XmNbottomOffset, 2);                              n++;
4420    XtSetArg(args[n], XmNhighlightOnEnter, True);                        n++;
4421    hw->help_dialog.srch.selVolRadBtn = 
4422             XmCreateToggleButtonGadget(volumesForm,"srchSelVolRadBtn", args, n);
4423    XtAddCallback(hw->help_dialog.srch.selVolRadBtn,XmNvalueChangedCallback,
4424                  UpdateSearchVolumesCB, (XtPointer) hw);
4425    XtManageChild (hw->help_dialog.srch.selVolRadBtn);
4426    XmStringFree (labelString);
4427
4428
4429    /* Create Selected... button */
4430    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4431                      (GSSET, 7,"Select Volumes...")));
4432
4433    n = 0;
4434    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4435    XtSetArg (args[n], XmNtopOffset, 0);                                 n++;
4436    XtSetArg (args[n], XmNtopWidget, hw->help_dialog.srch.allVolRadBtn); n++;
4437    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4438    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
4439    XtSetArg (args[n], XmNbottomOffset, 2);                              n++;
4440    XtSetArg (args[n], XmNmarginTop, 0);                                 n++;
4441    XtSetArg (args[n], XmNmarginHeight, 3);                              n++;
4442    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4443    hw->help_dialog.srch.selectBtn =
4444                      XmCreatePushButtonGadget(volumesForm,"selectBtn", args, n);
4445    XtAddCallback (hw->help_dialog.srch.selectBtn, XmNactivateCallback,
4446                   OpenSelectDialogCB, (XtPointer) hw);
4447    XtManageChild (hw->help_dialog.srch.selectBtn);
4448    XtSetSensitive (hw->help_dialog.srch.selectBtn,False);
4449    XmStringFree (labelString);
4450
4451    /****** Create the show selection region ******/
4452    n = 0;
4453    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);       n++;
4454    XtSetArg (args[n], XmNtopWidget, volumesFrame);              n++;
4455    XtSetArg (args[n], XmNtopOffset, 5);                         n++;
4456    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);       n++;
4457    XtSetArg (args[n], XmNrightOffset, 5);                       n++;
4458    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);        n++;
4459    XtSetArg (args[n], XmNleftOffset, 5);                        n++;
4460    XtSetArg (args[n], XmNmarginWidth, 5);                       n++;
4461    XtSetArg (args[n], XmNmarginHeight, 2);                      n++;
4462    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);     n++;/*EXP*/
4463    showFrame = XmCreateFrame(parentForm, "showFrame", args, n);
4464    XtManageChild (showFrame);
4465
4466    /* FIX: is this doing enough? Goal: CR activation of FullIndex */
4467    /* Setup the proper translation on the title box widget */
4468    /* XtAugmentTranslations(showFrame, mgrTransTable);   */
4469
4470    /* put form inside frame */
4471    showForm = XmCreateForm (showFrame, "showForm", args, 0);
4472    XtManageChild (showForm);
4473
4474    /* create the frame title */
4475    labelString = XmStringCreateLocalized ((_DTGETMESSAGE(GSSET,8, "Show")));
4476    n = 0;
4477    XtSetArg (args[n], XmNlabelString, labelString);             n++;
4478    XtSetArg (args[n], XmNtraversalOn, False);                   n++;
4479    XtSetArg (args[n], XmNchildType, XmFRAME_TITLE_CHILD);       n++;
4480    frameTitle = XmCreateLabelGadget(showFrame, "showFrameTitle", args, n);
4481    XtManageChild (frameTitle);
4482    XmStringFree (labelString);
4483
4484    /* create the All Entries button */
4485    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4486                         (GSSET, 9,"Complete Index")));
4487
4488    n = 0;
4489    XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY);                 n++;
4490    XtSetArg (args[n], XmNset, True);                                    n++;
4491    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4492    XtSetArg (args[n], XmNmarginHeight, 1);                              n++;
4493    XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);                 n++;
4494    XtSetArg (args[n], XmNtopOffset, 0);                                 n++;
4495    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4496    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4497    XtSetArg (args[n], XmNbottomOffset, 0);                              n++;
4498    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);             n++;
4499    XtSetArg (args[n], XmNhighlightOnEnter, True);                       n++;
4500    hw->help_dialog.srch.fullIndexRadBtn = 
4501             XmCreateToggleButtonGadget(showForm,"srchFullIndexRadBtn",args,n);
4502    XtAddCallback(hw->help_dialog.srch.fullIndexRadBtn,XmNvalueChangedCallback,
4503                  UpdateIndexSelectionCB, (XtPointer) hw);
4504    XtManageChild (hw->help_dialog.srch.fullIndexRadBtn);
4505    XmStringFree (labelString);
4506
4507    /* create Contains radio button */
4508    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4509                         (GSSET, 10,"Entries with:")));
4510    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 16,"n"));*/
4511
4512    n = 0;
4513    XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY);                 n++;
4514    XtSetArg (args[n], XmNset, False);                                   n++;
4515    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4516    XtSetArg (args[n], XmNmarginHeight, 1);                              n++;
4517    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4518    XtSetArg (args[n], XmNtopWidget,hw->help_dialog.srch.fullIndexRadBtn);n++;
4519    XtSetArg (args[n], XmNtopOffset, 1);                                 n++;
4520    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4521    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4522    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4523    XtSetArg (args[n], XmNbottomOffset, 4);                              n++;
4524    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);             n++;
4525    XtSetArg (args[n], XmNhighlightOnEnter, True);                       n++;
4526    hw->help_dialog.srch.containsRadBtn = 
4527             XmCreateToggleButtonGadget(showForm,"srchContainsRadBtn",args,n);
4528    XtAddCallback(hw->help_dialog.srch.containsRadBtn,XmNvalueChangedCallback,
4529                  UpdateIndexSelectionCB, (XtPointer) hw);
4530    XtAddCallback(hw->help_dialog.srch.containsRadBtn,XmNdisarmCallback,
4531                  ContainsDisarmCB, (XtPointer) hw);
4532    XtManageChild (hw->help_dialog.srch.containsRadBtn);
4533    XmStringFree (labelString);
4534
4535    /* create the search name text field */
4536    n = 0;
4537    XtSetArg (args[n], XmNvalue, "");                                    n++;
4538    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4539    XtSetArg (args[n], XmNtopWidget,hw->help_dialog.srch.fullIndexRadBtn); n++;
4540    XtSetArg (args[n], XmNtopOffset, 0);                                 n++;
4541    XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET);              n++;
4542    XtSetArg (args[n], XmNleftWidget,hw->help_dialog.srch.containsRadBtn); n++;
4543    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
4544    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4545    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
4546    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4547    XtSetArg (args[n], XmNbottomOffset, 3);                              n++;
4548    XtSetArg (args[n], XmNhighlightOnEnter, True);                       n++;
4549    XtSetArg (args[n], XmNcursorPositionVisible, False);                 n++;
4550    hw->help_dialog.srch.wordField = 
4551            XmCreateTextField (showForm,"srchWord",args, n);
4552    XtSetSensitive(hw->help_dialog.srch.wordField,False);
4553    XtManageChild (hw->help_dialog.srch.wordField);
4554    /* Because the actionBtn is the default button on the form,
4555       and it activates a search, we do not need to (nor do we want
4556       to, since ActionButtonCB toggles between states) make it
4557       a callback on activation of the text field */
4558    XtAddCallback (hw->help_dialog.srch.wordField, XmNvalueChangedCallback,
4559                   UpdateSearchStartStatusCB, (XtPointer) hw);
4560
4561    /* Setup the proper translation on the text field widget */
4562    XtAugmentTranslations(hw->help_dialog.srch.wordField, btnTransTable);   
4563
4564    /* separator */
4565    /*  Create a separator search specs and result area */
4566    n = 0;
4567    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4568    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4569    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4570    XtSetArg (args[n], XmNtopWidget, showFrame);                         n++;
4571    XtSetArg (args[n], XmNtopOffset, 10);                                n++;
4572    separator =  XmCreateSeparatorGadget (parentForm, "separator", args, n);
4573    XtManageChild (separator);
4574
4575    /*==============================================================*/
4576    /****** result related stuff *******/
4577    /* Create result List Label */
4578    n = 0;
4579    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4580    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
4581    XtSetArg (args[n], XmNtopOffset, 10);                                n++;
4582    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4583    XtSetArg (args[n], XmNleftOffset, 10);                               n++;
4584    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4585    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
4586    XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING);             n++;
4587    hw->help_dialog.srch.statusLabel = 
4588          XmCreateLabelGadget (parentForm, "resultListLabel", args, n);
4589    StatusLabelUpdate(hw,FIRST_PROMPT_STATUS,True,0);     /* installs a label */
4590    XtManageChild (hw->help_dialog.srch.statusLabel);
4591
4592    /* Create our result topics scrolled list (not placed on form) */
4593    n = 0;
4594    XtSetArg (args[n], XmNlistSizePolicy, XmCONSTANT);                   n++;
4595    XtSetArg (args[n], XmNselectionPolicy, XmSINGLE_SELECT);             n++;
4596    XtSetArg (args[n], XmNhighlightOnEnter, True);                       n++;
4597    XtSetArg (args[n], XmNscrollBarDisplayPolicy, XmSTATIC);             n++;
4598    hw->help_dialog.srch.resultList =
4599             XmCreateScrolledList (parentForm, "resultList", args, n);
4600    XtManageChild (hw->help_dialog.srch.resultList);
4601
4602    XtAddCallback (hw->help_dialog.srch.resultList, XmNsingleSelectionCallback, 
4603                   ProcessResultSelectionCB, (XtPointer) hw);
4604    XtAddCallback (hw->help_dialog.srch.resultList, XmNdefaultActionCallback, 
4605                   ProcessResultSelectionCB, (XtPointer) hw);
4606
4607    /* Set the constraints on our scrolled list (place on form) */
4608    n = 0;
4609    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4610    XtSetArg (args[n], XmNtopWidget, hw->help_dialog.srch.statusLabel);  n++;
4611    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
4612    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4613    XtSetArg (args[n], XmNleftOffset, 10);                               n++;
4614    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4615    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
4616    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4617    XtSetArg (args[n], XmNbottomOffset, 70);                             n++;
4618    /* 70 is just a rough value that will be updated with a calculated
4619       value below, after we know the height of the buttons */
4620    XtSetValues (XtParent (hw->help_dialog.srch.resultList), args, n);
4621
4622    /*  Create a separator between the buttons  */
4623    n = 0;
4624    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
4625    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
4626    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4627    XtSetArg (args[n], XmNtopWidget,  
4628                   XtParent (hw->help_dialog.srch.resultList));          n++;
4629    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
4630    separator =  XmCreateSeparatorGadget (parentForm, "separator", args, n);
4631    XtManageChild (separator);
4632
4633    /***** search spec-related stuff *****/
4634    /* Create start button (left of stop button)*/
4635    _DtHelpProcessLock();
4636    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4637           (GSSET, START_SEARCH_CAT,START_SEARCH_STR)));
4638    _DtHelpProcessUnlock();
4639    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 20,START_SEARCH_MNEM));*/
4640
4641    n = 0;
4642    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4643    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
4644    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
4645    /* L & R position set below */
4646    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4647    XtSetArg (args[n], XmNbottomOffset, 5);                              n++;
4648    /*XtSetArg (args[n], XmNmarginHeight, 3);                            n++;*/
4649    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4650    XtSetArg(args[n], XmNhighlightOnEnter, True);                        n++;
4651    hw->help_dialog.srch.actionBtn = 
4652                      XmCreatePushButtonGadget(parentForm,"actionBtn", args, n);
4653    XtAddCallback (hw->help_dialog.srch.actionBtn, XmNactivateCallback, 
4654                   ActionButtonCB, (XtPointer) hw);
4655    XtSetSensitive (hw->help_dialog.srch.actionBtn,False);
4656    XtManageChild (hw->help_dialog.srch.actionBtn);
4657    XmStringFree (labelString);
4658
4659    XtSetArg (args[0], XmNdefaultButton, hw->help_dialog.srch.actionBtn);
4660    XtSetValues (parentForm, args, 1);
4661
4662    /* Build the Cancel Button */
4663    _DtHelpProcessLock();
4664    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
4665                (GSSET, CLOSE_BTN_CAT,CLOSE_BTN_STR)));
4666    _DtHelpProcessUnlock();
4667    /*mnemonic = ((char *)_DTGETMESSAGE(GSSET, 25,CLOSE_BTN_MNEM));*/
4668    n = 0;
4669    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4670    /* L & R position set below */
4671    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4672    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
4673    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
4674    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4675    XtSetArg (args[n], XmNbottomOffset, 5);                              n++;
4676    XtSetArg (args[n], XmNmarginHeight, 3);                              n++;
4677    XtSetArg(args[n], XmNhighlightOnEnter, True);                        n++;
4678    hw->help_dialog.srch.closeBtn = 
4679               XmCreatePushButtonGadget (parentForm, "srchCloseBtn", args, n);
4680    
4681    XtAddCallback(hw->help_dialog.srch.closeBtn, 
4682                XmNactivateCallback, CloseSearchCB,(XtPointer) &hw->help_dialog.srch);
4683   
4684    XtManageChild (hw->help_dialog.srch.closeBtn);
4685    XmStringFree (labelString);
4686
4687    /* Build the Help button */
4688    _DtHelpProcessLock();
4689    labelString = XmStringCreateLocalized((char *)_DTGETMESSAGE
4690                   (GSSET, HELP_BTN_CAT,HELP_BTN_STR));
4691    _DtHelpProcessUnlock();
4692    /*mnemonic = (char *)_DTGETMESSAGE(GSSET, 27,HELP_BTN_MNEM);*/
4693
4694    n = 0;
4695    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
4696    /* L & R position set below */
4697    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
4698    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
4699    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
4700    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4701    XtSetArg (args[n], XmNbottomOffset, 5);                              n++;
4702    XtSetArg (args[n], XmNmarginHeight, 3);                              n++;
4703    XtSetArg(args[n], XmNhighlightOnEnter, True);                        n++;
4704    hw->help_dialog.srch.helpBtn = 
4705           XmCreatePushButtonGadget (parentForm, "srchHelpBtn", args, n);
4706    XtManageChild (hw->help_dialog.srch.helpBtn);
4707    XmStringFree (labelString);
4708
4709    pHelpInfo = _DtHelpListAdd(DtHELP_srchIndexHelpBtn_STR,
4710                         (Widget) hw, &hw->help_dialog.help, 
4711                         &hw->help_dialog.help.pHelpListHead);
4712    XtAddCallback(hw->help_dialog.srch.helpBtn, XmNactivateCallback, 
4713                 _DtHelpCB, (XtPointer) pHelpInfo);
4714   
4715    /*==============================================================*/
4716    /****** finishing touches *******/
4717    /* set the Form cancel button (for KCancel) */
4718    n = 0;
4719    XtSetArg (args[n], XmNcancelButton, hw->help_dialog.srch.closeBtn); n++;
4720    XtSetValues (parentForm, args, n);
4721
4722    { /* position buttons */
4723       /* This code adds up the sizes of the buttons to go into
4724          the bottom row and calculates the form position percentages.
4725          All buttons are the same size, and are able to hold all
4726          the strings that may be dynamically placed in them.
4727          All buttons are 5% apart. */
4728       /* This code is specifically written to handle 3 buttons
4729          and assumes that the first 3 strings are to the ActionBtn */
4730    #define NUMSTRS 5
4731    Dimension maxWidth = 0;
4732    Dimension borderWidth = 0;
4733    Dimension sumWidth = 0;
4734    float scale = 0.0;
4735    float posList[11];  /* need 11 due to algorithm, which uses index 10 */
4736    XmFontList fontList = NULL;
4737    int i;
4738
4739    /* get the fontList for the button */
4740    XtSetArg (args[0], XmNborderWidth, &borderWidth);
4741    XtSetArg (args[1], XmNfontList, &fontList);
4742    XtGetValues (hw->help_dialog.srch.actionBtn, args, 2);
4743
4744 #define BETBUTSPACE 5           /* pixels */
4745    sumWidth = BETBUTSPACE;      /* left side space */
4746    posList[0] = (float) sumWidth;
4747    for (i=0; i<NUMSTRS; i++)
4748    {
4749       XmString labelString;
4750       Dimension width;
4751       _DtHelpProcessLock();
4752       s_GlobSrchDlgBtnStrs[i] = (char *) _DTGETMESSAGE(GSSET,
4753                      s_GlobSrchDlgBtnCatNum[i],s_GlobSrchDlgBtnStrs[i]);
4754       labelString = XmStringCreateLocalized(s_GlobSrchDlgBtnStrs[i]);
4755       _DtHelpProcessUnlock();
4756 #define MARGINS  4        /* pixel margins: 2=L, 2=R */
4757       width = XmStringWidth(fontList,labelString) + borderWidth + MARGINS;
4758       if (i<=2) maxWidth = max(width,maxWidth);
4759       if (i==2) width = maxWidth; /* 1st three labels go in 1st button */
4760       if (i>=2) /* after scanning just labels, do buttons */
4761       { 
4762          sumWidth += width;
4763          posList[i*2+1] = (float) sumWidth;
4764          sumWidth += BETBUTSPACE;
4765          posList[i*2+2] = (float) sumWidth;
4766       }
4767       XmStringFree(labelString);
4768    } /* for calcing widths */
4769
4770    /* scale pixels to percent */
4771    scale = 100.0 / (float) sumWidth;
4772
4773    n = 0;
4774    XtSetArg (args[n], XmNwidth, maxWidth);                              n++;
4775    XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
4776    XtSetArg (args[n], XmNleftPosition, (Dimension) (posList[0]*scale)); n++;
4777    XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
4778    XtSetArg (args[n], XmNrightPosition,(Dimension) (posList[5]*scale)); n++;
4779    XtSetValues (hw->help_dialog.srch.actionBtn, args, n);
4780
4781    n = 0;
4782    XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
4783    XtSetArg (args[n], XmNleftPosition, (Dimension) (posList[6]*scale)); n++;
4784    XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
4785    XtSetArg (args[n], XmNrightPosition,(Dimension) (posList[7]*scale)); n++;
4786    XtSetValues (hw->help_dialog.srch.closeBtn, args, n);
4787
4788    n = 0;
4789    XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
4790    XtSetArg (args[n], XmNleftPosition, (Dimension) (posList[8]*scale)); n++;
4791    XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
4792    XtSetArg (args[n], XmNrightPosition,(Dimension) (posList[9]*scale)); n++;
4793    XtSetValues (hw->help_dialog.srch.helpBtn, args, n);
4794    } /* */
4795
4796    { /* set the proper offset between the bottom of the results list
4797         and the bottom of the form to maintain a constant sized
4798         button bar. */
4799    int offset = 0;
4800
4801    /* first calc offset of list to form bottom based on earlier sizes */
4802 #define KNOWN_OFFSETS_BELOW_LIST 20   /* actually only 15, but 15 fails */
4803    n = 0;
4804    XtSetArg(args[n], XmNborderWidth, &widgetBorderHeight);      n++;
4805    XtSetArg(args[n], XmNheight, &widgetHeight);                 n++;
4806    XtGetValues(hw->help_dialog.srch.actionBtn, args, n);
4807    offset = widgetHeight + 2 * widgetBorderHeight;
4808    XtGetValues(separator, args, n);
4809    offset += widgetHeight + 2 * widgetBorderHeight;
4810    XtGetValues(XtParent(hw->help_dialog.srch.resultList), args, 1);
4811    offset += widgetBorderHeight;
4812    offset += KNOWN_OFFSETS_BELOW_LIST;
4813
4814    /* then set the offset */
4815    n = 0;
4816    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
4817    XtSetArg (args[n], XmNbottomOffset, offset);                         n++;
4818    XtSetValues (XtParent (hw->help_dialog.srch.resultList), args, n);
4819    }
4820
4821    /** force tabs to go to each widget and in right order **/
4822    XtSetArg (args[0], XmNnavigationType, XmSTICKY_TAB_GROUP);
4823    XtSetValues (hw->help_dialog.srch.curVolRadBtn,args,1);
4824    XtSetValues (hw->help_dialog.srch.allVolRadBtn,args,1);
4825    XtSetValues (hw->help_dialog.srch.selVolRadBtn,args,1);
4826    XtSetValues (hw->help_dialog.srch.selectBtn,args,1);
4827    XtSetValues (hw->help_dialog.srch.fullIndexRadBtn,args,1);
4828    XtSetValues (hw->help_dialog.srch.containsRadBtn,args,1);
4829    XtSetValues (hw->help_dialog.srch.wordField,args,1);
4830    XtSetValues (hw->help_dialog.srch.resultList,args,1);
4831    XtSetValues (hw->help_dialog.srch.actionBtn,args,1);
4832    XtSetValues (hw->help_dialog.srch.closeBtn,args,1);
4833    XtSetValues (hw->help_dialog.srch.helpBtn,args,1);
4834
4835    /** put focus on the text field **/
4836    XtSetArg (args[0], XmNinitialFocus, hw->help_dialog.srch.wordField);
4837    XtSetValues (parentForm,args,1);
4838
4839    /* Add the proper help callback to the print dialog shell "F1" support */
4840    pHelpInfo = _DtHelpListAdd(DtHELP_srchIndexShell_STR,
4841                         (Widget) hw, &hw->help_dialog.help, 
4842                         &hw->help_dialog.help.pHelpListHead);
4843    XtAddCallback(parentForm, XmNhelpCallback, 
4844                 _DtHelpCB, (XtPointer) pHelpInfo);
4845 }
4846
4847 \f
4848 /*****************************************************************************
4849  * Function:        updateDisplay()
4850  *                             
4851  * 
4852  * Parameters:      hw:  the help widget
4853  *
4854  * Return Value:    0
4855  *
4856  * Purpose:         forces an update on index search dialog widgets
4857  *
4858  *****************************************************************************/
4859 static int updateDisplay(
4860                 DtHelpDialogWidget hw)
4861 {
4862     XmUpdateDisplay((Widget)hw->help_dialog.srch.actionBtn);/*DBG*/
4863     XmUpdateDisplay((Widget)hw->help_dialog.srch.curVolRadBtn);/*DBG*/
4864     XmUpdateDisplay((Widget)hw->help_dialog.srch.allVolRadBtn);/*DBG*/
4865     XmUpdateDisplay((Widget)hw->help_dialog.srch.selVolRadBtn);/*DBG*/
4866     XmUpdateDisplay((Widget)hw->help_dialog.srch.selectBtn);/*DBG*/
4867     XmUpdateDisplay((Widget)hw->help_dialog.srch.fullIndexRadBtn);/*DBG*/
4868     XmUpdateDisplay((Widget)hw->help_dialog.srch.containsRadBtn);/*DBG*/
4869     XmUpdateDisplay((Widget)hw->help_dialog.srch.wordField);/*DBG*/
4870     XmUpdateDisplay((Widget)hw->help_dialog.srch.statusLabel);/*DBG*/
4871     XmUpdateDisplay((Widget)hw->help_dialog.srch.resultList);/*DBG*/
4872     XmUpdateDisplay((Widget)hw->help_dialog.srch.closeBtn);/*DBG*/
4873     XmUpdateDisplay((Widget)hw->help_dialog.srch.helpBtn);/*DBG*/
4874     XmUpdateDisplay(XtParent((Widget)hw->help_dialog.srch.srchForm));/*DBG*/
4875     return 0;
4876 }
4877
4878
4879 \f
4880 /*****************************************************************************
4881  * Function:        void _DtHelpGlobSrchDisplayDialog()
4882  *                             
4883  * 
4884  * Parameters:      parent      Specifies the parent widget
4885  *                  searchWord  word to put into searchWord field
4886  *        remove this when integrated into DtHelp:
4887  *                  curVolume   volume considered the current volume
4888  *
4889  * Return Value:
4890  *
4891  * Purpose:         Setsup the proper data in the search dialog and 
4892  *                  displays an instance of the search dialog.
4893  *
4894  *****************************************************************************/
4895 void _DtHelpGlobSrchDisplayDialog(
4896     Widget w,
4897     char * searchWord,
4898     char * curVolume)
4899 {
4900    DtHelpDialogWidget hw = (DtHelpDialogWidget) w;
4901    XmToggleButtonCallbackStruct status;        /* the call data */
4902    Widget                       sourceBtn;     /* widget owning event */
4903    Dimension     height;
4904    Dimension     width;
4905    XmString      labelString = NULL;
4906    int           n;
4907    Arg           args[10];
4908
4909    /* make the dialog itself */
4910    if (NULL == hw->help_dialog.srch.srchForm)
4911    {
4912       CreateGlobSrchDialog((Widget) hw,searchWord);
4913
4914       /* create the button label */
4915       CreateCurVolBtnLabel(hw, NULL, &labelString, NULL);
4916       XtSetArg (args[0], XmNlabelString, labelString);
4917       XtSetValues (hw->help_dialog.srch.curVolRadBtn, args, 1);
4918       XmStringFree (labelString);
4919
4920       /*** map widget and update display before doing any searching ***/
4921       /* Make sure the Search Dialog is managed */
4922       XtManageChild(hw->help_dialog.srch.srchForm);
4923       XtMapWidget(hw->help_dialog.srch.srchForm);
4924
4925       /* set focus to contains word */
4926       XmProcessTraversal(hw->help_dialog.srch.wordField,XmTRAVERSE_CURRENT);
4927     
4928       /* force several updates to make sure it is fully displayed and
4929          that height/width are correctly inited */
4930       XmUpdateDisplay(XtParent((Widget)hw->help_dialog.srch.srchForm));
4931       XmUpdateDisplay(XtParent((Widget)hw->help_dialog.srch.srchForm));
4932       XmUpdateDisplay(XtParent((Widget)hw->help_dialog.srch.srchForm));
4933     
4934       /*** now update settings, which may also invoke a search ***/
4935       /* set the cur vol btn sensitivity */
4936       UpdateCurVolBtnSens(hw,True);
4937
4938       /* set default show index state */
4939       /* set full index if current vol has an index, contains word if not */
4940       if (hw->help_dialog.srch.curVolRadBtnSens) /* set in UpdateCurVolBtnSens*/
4941          sourceBtn = hw->help_dialog.srch.fullIndexRadBtn;
4942       else
4943          sourceBtn = hw->help_dialog.srch.containsRadBtn;
4944
4945       /* set the show index state */
4946       status.reason = XmCR_VALUE_CHANGED;
4947       status.set = True;
4948       status.event = (XEvent *) 1; /* thwart == NULL test in Update...() */
4949       UpdateIndexSelectionCB(sourceBtn,(XtPointer)hw,(XtPointer)&status);
4950       StatusLabelUpdate(hw,FIRST_PROMPT_STATUS,False,0);
4951    
4952       updateDisplay(hw);  /* DBG */
4953
4954 #if 0  /* 11/23/94 */
4955       /** Set min size for the dialog **/
4956       n = 0;
4957       XtSetArg(args[n], XmNheight, &height); ++n;
4958       XtSetArg(args[n], XmNwidth, &width);  ++n;
4959       XtGetValues(XtParent((Widget)hw->help_dialog.srch.srchForm), args, n);
4960       n = 0;
4961       XtSetArg(args[n], XmNminHeight, height - 200); ++n;  /* 200: arbitrary */
4962       XtSetArg(args[n], XmNminWidth, width); ++n;
4963       XtSetValues(XtParent((Widget)hw->help_dialog.srch.srchForm), args, n);
4964 #endif
4965    }
4966    else /* properly update dialog to support new word and cur vol */
4967    {
4968       /* fixup current volume, if need be */
4969       _DtHelpGlobSrchUpdateCurVol((Widget)hw);
4970      
4971       /* fixup search word, if need be */
4972       if (NULL != searchWord)
4973       {
4974          String srchWord = XtNewString(searchWord);
4975          /* srchWord is freed or used in CheckSearchWord() */
4976          if (CheckSearchWord(hw,srchWord,True) == True)
4977          {  /* words are different */
4978             /* free all hit-related data and reset flags */
4979             HitListFreeAllVolHits(hw,True);  /*True=free everything*/
4980          }
4981       }
4982     
4983       /* if its not managed, manage it */
4984       if ( XtIsManaged(hw->help_dialog.srch.srchForm) == False )
4985       {
4986          /* manage and map the Search Dialog */
4987          XtManageChild(hw->help_dialog.srch.srchForm);
4988          XtMapWidget((Widget)hw->help_dialog.srch.srchForm);
4989
4990          /* see if the selection dialog was already open */
4991          if (   hw->help_dialog.srch.selectionDlg
4992              && XtIsManaged(hw->help_dialog.srch.selectionDlg) )
4993          {
4994             XtManageChild(hw->help_dialog.srch.selectionDlg);
4995             XtMapWidget(hw->help_dialog.srch.selectionDlg);
4996          }
4997       }
4998       else  /* if it is managed, bring it forward */
4999       {
5000         Widget parent = XtParent(hw->help_dialog.srch.srchForm);
5001         XRaiseWindow ( XtDisplay(parent), XtWindow(parent) );
5002       }
5003    
5004    /* change focus */
5005    
5006    if (hw->help_dialog.srch.hitsFound == True) 
5007      XmProcessTraversal(hw->help_dialog.srch.resultList,XmTRAVERSE_CURRENT);
5008    else
5009      XmProcessTraversal(hw->help_dialog.srch.allVolRadBtn,XmTRAVERSE_CURRENT);
5010
5011
5012
5013    }  /* end if create a new dialog */
5014 }   
5015
5016
5017 \f
5018 /*****************************************************************************
5019  * Function:        void _DtHelpGlobSrchUpdateCurVol()
5020  * 
5021  * Parameters:      new          the help widget
5022  *
5023  * Return Value:
5024  *
5025  * Purpose:         Adjusts the current volume of the dialog
5026  *
5027  *****************************************************************************/
5028 void _DtHelpGlobSrchUpdateCurVol(
5029     Widget w)
5030 {
5031   String path;
5032   DtHelpDialogWidget hw = (DtHelpDialogWidget) w;
5033
5034 #if 1
5035   if (   NULL == hw->help_dialog.srch.srchForm )
5036 #else
5037   if (   NULL == hw->help_dialog.srch.srchForm
5038       || XtIsManaged(hw->help_dialog.srch.srchForm) == False ) 
5039 #endif
5040       return;                                         /* RETURN */
5041
5042   /* get full pathname for the volume */
5043   path = NULL;
5044   if (hw->help_dialog.display.helpVolume)
5045      path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, 
5046                                 /* FIX: will helpVolume have matching path? */
5047                                 hw->help_dialog.display.helpVolume,
5048                                 _DtHelpFileSuffixList,False,R_OK);
5049
5050   if (   _DtHelpGlobSrchCurVolume == hw->help_dialog.srch.srchSources
5051       && hw->help_dialog.display.helpType == DtHELP_TYPE_TOPIC
5052       && NULL != path
5053       && NULL != hw->help_dialog.srch.curVolPath
5054       && _DtHelpFileIsSameP(path,hw->help_dialog.srch.curVolPath,
5055                  GetVolumeInfoCB, _DtHELP_FILE_NAME, 
5056                  hw->help_dialog.help.pDisplayArea) )
5057   {
5058      /* leave current status as is */
5059      XtFree(path);
5060      return;                                        /* RETURN */
5061   }
5062  
5063
5064   /* a different current volume or change of topic */
5065   {
5066      XmString labelString;
5067      Arg    args[5];
5068
5069      /* if still searching previous cur volume, stop any search in progress */
5070      if (    _DtHelpGlobSrchCurVolume == hw->help_dialog.srch.srchSources
5071           && hw->help_dialog.srch.workProcId)
5072      {
5073          /* cancel the search */
5074          StopSearchCB(NULL,(XtPointer) hw, NULL);
5075
5076          /* (F,F,F,F): disable search,disable display,no 0 hits,for all vols */
5077          SetVolStatus(hw->help_dialog.srch.volListHead,False,False,False,False);
5078
5079          /* zero search data */
5080          hw->help_dialog.srch.volLeftCnt = 0;
5081          hw->help_dialog.srch.curSrchVol = NULL;
5082
5083          /* assumption is, that even though the search was incomplete,
5084             nothing bad will happen if we don't free the hit data,
5085             and the search could resume where left off, if necessary. */
5086      }
5087
5088      CreateCurVolBtnLabel(hw, NULL, &labelString, NULL);
5089      XtSetArg(args[0],XmNlabelString,labelString);
5090      XtSetValues(hw->help_dialog.srch.curVolRadBtn,args,1);
5091      XmStringFree(labelString);
5092
5093      /* set the cur vol btn sensitivity */
5094      UpdateCurVolBtnSens(hw,False);
5095
5096      /* set state of start button correctly */
5097      UpdateSearchStartStatusCB(NULL, (XtPointer) hw, NULL);
5098
5099      /* and search if needed */
5100      if ( _DtHelpGlobSrchCurVolume == hw->help_dialog.srch.srchSources )
5101      {
5102         /* if to search a volume, start the search */
5103         if (hw->help_dialog.display.helpType == DtHELP_TYPE_TOPIC)
5104            StartSearchCB(NULL,(XtPointer) hw, NULL);
5105         else /* if current isn't a volume, clear the display & update status */
5106         {
5107            DeleteListContents(&hw->help_dialog.srch);
5108            StatusLabelUpdate(hw,NO_VOL_STATUS,False,0);
5109         }
5110      }
5111   }
5112 }
5113
5114
5115 \f
5116 /*****************************************************************************
5117  * Function:        void _DtHelpGlobSrchInitVars()
5118  * 
5119  * Parameters:      srch        search main data structure
5120  *
5121  * Return Value:
5122  *
5123  * Purpose:         Init the contents of the control data structure
5124  *
5125  *****************************************************************************/
5126 void  _DtHelpGlobSrchInitVars(
5127        _DtHelpGlobSearchStuff * srch)
5128 {
5129     /* set the font resource */
5130     if (srch->hitPrefixFont != _DtHelpDefaultSrchHitPrefixFont)
5131        srch->hitPrefixFont = XtNewString(srch->hitPrefixFont);
5132
5133     /* File Selection Dialog font list */
5134     srch->volTitlesFontList = NULL;
5135
5136     /* Set our search dialog widgets to NULL */
5137     srch->srchForm      = NULL;
5138     srch->actionBtn     = NULL;
5139     srch->curVolRadBtn  = NULL;
5140     srch->allVolRadBtn  = NULL;
5141     srch->selVolRadBtn  = NULL;
5142     srch->selectBtn     = NULL;
5143     srch->fullIndexRadBtn = NULL;
5144     srch->containsRadBtn = NULL;
5145     srch->wordField     = NULL;
5146     srch->statusLabel   = NULL;
5147     srch->resultList    = NULL;
5148     srch->gotoBtn       = NULL;
5149     srch->closeBtn      = NULL;
5150     srch->helpBtn       = NULL;
5151     srch->selectionDlg  = NULL;
5152
5153     /* init dialog content variables */
5154     srch->curVolPath    = NULL;
5155     srch->rawWordStr    = NULL;
5156     srch->normWordStr   = NULL;
5157     srch->localeWordStr = NULL;
5158     srch->wordFieldFirstChar = 0;
5159     srch->wordFieldLen       = 0;
5160     srch->statusLineUsage = 0;  /* empty */
5161
5162     /* init srch processing variables */
5163     srch->iconv3Codeset = NULL;         /* iconv(3)-compatible code set of current locale */
5164     srch->iconv3Context = NULL;
5165     srch->srchSources   = _DtHelpGlobSrchVolumeUndef;      /* radio btn usage */
5166     srch->curSrchVol    = NULL;         /* volume currently in search */
5167     srch->hitsFontLoaded= False;        /* is font loaded? */
5168     srch->volScanDone   = False;        /* is the volume list complete? */
5169     srch->fullIndex     = False;
5170     srch->hitsFound     = False;        /* state of search */
5171     srch->readyToStart  = False;        /* state of search */
5172     srch->searchInProgress= False;      /* state of search */
5173     srch->curVolRadBtnSens = False;
5174     srch->volLeftCnt    = 0;
5175     srch->volListHead   = NULL;         /* info on search topics found */
5176     srch->workProcId    = NULL;
5177 }
5178
5179 \f
5180 /*****************************************************************************
5181  * Function:        void _DtHelpGlobSrchCleanAndClose()
5182  * 
5183  * Parameters:      srch      search main data structure
5184  *                  destroy   flag to signal srch dialog should be destroyed
5185  *
5186  * Return Value:
5187  *
5188  * Purpose:         Free the contents of the control data structure
5189  *
5190  *****************************************************************************/
5191 void  _DtHelpGlobSrchCleanAndClose(
5192        _DtHelpGlobSearchStuff * srch,
5193        Boolean               destroy)
5194 {
5195     /* close conversion context */
5196     _DtHelpCeIconvClose(&srch->iconv3Context);
5197   
5198     /* free the font list */
5199     if(srch->volTitlesFontList)
5200     {
5201          XmFontListFree(srch->volTitlesFontList);
5202          srch->volTitlesFontList = NULL;
5203     }
5204   
5205     /*
5206      * Make sure CloseSearchCB does not try using an invalid
5207      * widget id in its XtUnmanageChild and XtUnmapWidget calls.
5208      */
5209     if (destroy)
5210         srch->srchForm = NULL;
5211
5212     /* make dialog invisible; update sensitivities */
5213     CloseSearchCB(NULL,(XtPointer)srch, NULL);
5214
5215     /* Destroy our index search dialog? */
5216     if (destroy)
5217     {
5218         /* set the font resource */
5219         if (srch->hitPrefixFont != _DtHelpDefaultSrchHitPrefixFont)
5220            XtFree(srch->hitPrefixFont);
5221
5222        /*
5223         * mark widgets as destroyed.
5224         * The XtDestroyWidget that called me will have called the destroy
5225         * callback of the widgets. So I don't have to do anything except
5226         * make sure I know they are destroyed.
5227         */
5228        srch->selectionDlg = NULL;
5229        srch->srchForm     = NULL;
5230        srch->resultList   = NULL;
5231
5232        /* free other data released to search dialog */
5233        VolListFree(srch);
5234
5235        /* free the locale word string, if allocated
5236         * (i.e. diff from normWordStr) */
5237        if(srch->localeWordStr!=srch->normWordStr)
5238        {
5239           XtFree(srch->localeWordStr);
5240           srch->localeWordStr=NULL;
5241        }
5242        XtFree(srch->normWordStr);
5243        srch->normWordStr=NULL;
5244        XtFree(srch->rawWordStr);
5245        srch->rawWordStr=NULL;
5246        XtFree(srch->curVolPath);
5247        srch->curVolPath=NULL;
5248        XtFree(srch->iconv3Codeset);
5249        srch->iconv3Codeset = NULL;
5250     }
5251 }