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