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