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