Merge branch 'master' into cde-next
[oweals/cde.git] / cde / lib / DtHelp / History.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 /* $XConsortium: History.c /main/10 1996/11/22 12:25:49 cde-hp $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        History.c
28  **
29  **   Project:     Cache Creek (Rivers) Project
30  **
31  **   Description: Creates an instance of a Cache Creek History Dialog.
32  ** 
33  **
34  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
35  **
36  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
37  **  (c) Copyright 1993, 1994 International Business Machines Corp.
38  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  **  (c) Copyright 1993, 1994 Novell, Inc.
40  **
41  **
42  ****************************************************************************
43  ************************************<+>*************************************/
44 #include <sys/param.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <X11/Intrinsic.h>
49 #include <X11/Shell.h>
50 #include <X11/Xutil.h>
51 #include <X11/keysymdef.h>
52
53 /* These includes work in R4 and R5 */
54 #include <Xm/MwmUtil.h>
55 #include <Xm/Protocols.h>
56
57 #include <Xm/Xm.h>
58 #include <Xm/XmP.h>
59 #include <Xm/TextF.h>
60 #include <Xm/Form.h>
61 #include <Xm/LabelG.h>
62 #include <Xm/ScrolledW.h>
63 #include <Xm/SeparatoG.h>
64 #include <Xm/PushBG.h>
65 #include <Xm/List.h>
66 #include <Xm/DialogS.h>
67
68 /* Dt  Includes */
69 #include "Access.h"
70 #include "bufioI.h"
71
72 #include <Dt/Help.h>
73 #include "DisplayAreaI.h"
74 #include "StringFuncsI.h"
75 #include "HelposI.h"
76 #include "HistoryI.h"
77 #include "HelpDialogI.h"
78 #include "HelpDialogP.h"
79 #include "HelpUtilI.h"
80 #include "HelpAccessI.h"
81 #include "FormatI.h"
82
83
84 /*
85  * Local Includes
86  */
87
88
89 static void CloseHistoryCB (
90     Widget w,
91     XtPointer client_data,
92     XtPointer call_data);
93 static void ProcessTopicSelectionCB(
94     Widget w,
95     XtPointer client_data,
96     XtPointer call_data);
97 static void ProcessVolumeSelectionCB(
98     Widget w,
99     XtPointer client_data,
100     XtPointer call_data);
101 static void CreateHistoryDialog(
102     Widget nw);
103 static DtHistoryListStruct *AddItemToHistoryList(
104      DtHistoryListStruct **pHead,
105      XmString  title,
106      int topicType,
107      Boolean *duplicateItem);
108 static DtTopicListStruct *PullTopicListFromSelVolumeList(
109      Widget nw);
110 static void UpdateTopicList(
111     DtHistoryListStruct *pHistoryList,
112     Widget nw,
113     int topicType);    
114 static Boolean IsTopicInHistoryList(
115     DtTopicListStruct *pTopicList,
116     XmString topicTitle);
117
118 /************************************************************************
119  * Function: CloseHistoryCB()
120  *
121  *      Close the History Dialog
122  *
123  ************************************************************************/
124 static void CloseHistoryCB (
125     Widget w,
126     XtPointer client_data,
127     XtPointer call_data)
128 {
129   DtHelpDialogWidget hw = (DtHelpDialogWidget) client_data;
130  
131   /* We unmap the history dialog */
132   XtUnmanageChild(hw->help_dialog.history.historyWidget);
133   
134   /* Re-sensatize the search button so the user can select it agan */
135   XtSetSensitive(hw->help_dialog.menu.historyBtn, TRUE);
136   XtSetSensitive(hw->help_dialog.browser.btnBoxHistoryBtn, TRUE);
137 }
138
139
140 /*****************************************************************************
141  * Function:        Boolean _DtHelpDisplayHistoryInfo(Widget nw);
142  *                             
143  * 
144  * Parameters:      nw        Specifies the name of the current help dialog 
145  *                            widget.
146  *
147  * Return Value:
148  *
149  * Purpose:         Displays the pre-created history dialog.
150  *
151  *****************************************************************************/
152 void _DtHelpDisplayHistoryInfo(
153     Widget nw)
154 {
155
156   DtHelpDialogWidget hw = (DtHelpDialogWidget) nw;
157  
158   if (hw->help_dialog.history.historyWidget == NULL)
159      CreateHistoryDialog((Widget) hw);
160   
161    /* if its not managed, manage it */
162    if ( XtIsManaged(hw->help_dialog.history.historyWidget) == False )
163    {
164       /* manage and map the History Dialog */
165       XtManageChild(hw->help_dialog.history.historyWidget);
166       XtMapWidget(XtParent((Widget)hw->help_dialog.history.historyWidget));
167    }
168    else  /* if it is managed, bring it forward */
169    {
170      Widget parent = XtParent(hw->help_dialog.history.historyWidget);
171      XRaiseWindow ( XtDisplay(parent), XtWindow(parent) );
172    }
173 }
174
175
176
177 /*****************************************************************************
178  * Function:        Boolean IsTopicInHistoryList(nw)
179  *                             
180  * 
181  * Parameters:      nw        Specifies the name of the current help dialog 
182  *                            widget.
183  *
184  * Return Value:
185  *
186  * Purpose:         checks the current topic list for a matching value, and
187  *                  returns true if found, false if not.
188  *
189  *****************************************************************************/
190 static Boolean IsTopicInHistoryList(
191     DtTopicListStruct *pTopicList,
192     XmString topicTitle)
193 {
194
195   Boolean done=FALSE;
196   
197   while (!done && (pTopicList != NULL))
198     {
199       if (XmStringCompare (topicTitle, pTopicList->topicTitleLbl) == True)
200          done= TRUE;
201       pTopicList = pTopicList->pNext;
202     }
203
204   return(done);
205
206 }
207
208 \f
209 /*****************************************************************************
210  * Function:        void UpdateTopicList(
211  *                     DtHistoryListStruct *pTopics,
212  *                     Widget topicList
213  *
214  *
215  *
216  * Parameters:  
217  *
218  * Return Value:    Void.
219  *
220  * Purpose:         Cleans and recreates a new topic list
221  *
222  *****************************************************************************/
223 static void UpdateTopicList(
224     DtHistoryListStruct *pHistoryList,
225     Widget nw,
226     int topicType)    
227 {
228    int i;
229    int n;
230    Arg args[5];
231    XmString labelString;
232    XmString *items;
233    DtTopicListStruct *pTopicList=NULL;
234    DtHelpDialogWidget hw = (DtHelpDialogWidget) nw;
235    
236
237    /* Flush the current history topic list */
238    XmListDeselectAllItems(hw->help_dialog.history.topicList);
239    XmListDeleteAllItems(hw->help_dialog.history.topicList);
240
241    /* Grab the top of our current topic list from our history list struct */
242    pTopicList = pHistoryList->pTopicHead;
243    
244    /* Loop through and build up a new visible topics list */
245    items = (XmString *) XtMalloc(sizeof(XmString) * pHistoryList->totalNodes);
246    for (i = 0; i < pHistoryList->totalNodes; i++)
247      {
248        items[i]   = pTopicList->topicTitleLbl;
249        pTopicList = pTopicList->pNext;
250      }
251
252    XtSetArg(args[0], XmNitems,items);
253    XtSetArg(args[1], XmNitemCount, pHistoryList->totalNodes);
254    XtSetValues(hw->help_dialog.history.topicList, args, 2);
255
256    XtFree((char *)items);
257
258    /* Now, modify the label if we need to */
259
260    switch (topicType)
261      {
262        case DtHELP_TYPE_TOPIC:
263          labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
264                             (3, 8,"Help Topics Visited:")));
265          break;  
266
267
268        case DtHELP_TYPE_FILE:
269          labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
270                             (3, 9,"Help Files Visited:")));
271          break;
272
273
274        case DtHELP_TYPE_MAN_PAGE:
275          labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
276                             (3, 10,"Man Pages Visited:")));
277          break;
278
279
280       case DtHELP_TYPE_STRING:
281       case DtHELP_TYPE_DYNAMIC_STRING:
282         labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
283                             (3, 11,"Help Messages Visited:")));
284          break;
285  
286       default:  
287         /* Bogus type, how did we ever get here ??? */
288         break;
289
290     }  /* End Switch Statement */
291
292    n = 0;
293    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
294    XtSetValues (hw->help_dialog.history.topicsListLabel, args, n);
295    XmStringFree(labelString);
296
297
298 }
299
300 \f
301 /*****************************************************************************
302  * Function:        void ProcessVolumeSelectionCB(Widget w,
303  *                                              XtPointer client_data,
304  *                                              XtPointer call_data);
305  *
306  *
307  *
308  * Parameters:  
309  *
310  * Return Value:    Void.
311  *
312  * Purpose:         Process user selection of an item in the Volume List
313  *                  of the history dialo.
314  *
315  *****************************************************************************/
316 static void ProcessVolumeSelectionCB(
317     Widget w,
318     XtPointer client_data,
319     XtPointer call_data)
320 {
321    XmListCallbackStruct *selectedItem = (XmListCallbackStruct *) call_data;
322    DtHelpDialogWidget hw = (DtHelpDialogWidget) client_data;
323    DtHistoryListStruct *pTemp= NULL;
324    int topicPosition=0;  
325    int i;   
326    XmString labelString;
327    int * topicPosList = NULL;
328    int   topicCnt = 0;
329    Boolean mod = False;
330    Arg          args[2];
331    XmFontList   fontList;
332
333    /* Determin the item selected in the volume list */
334    topicPosition = selectedItem->item_position;
335
336    /* To fix the bug of having no volume selected, check
337       whether user clicked again on the currently selected item,
338       deselecting it and leaving no other selected, and just
339       reselect that item and do nothing else */
340    /* for reasons unknown, selectedItem->selected_item_positions
341       doesnt seem properly initialized and leads to a core dump;
342       so use XmListGetSelectedPos() instead */
343    if (   False == XmListGetSelectedPos(w, &topicPosList, &topicCnt)
344        && NULL == topicPosList )
345    {
346       XmListSelectPos(w,topicPosition,False); /* False=dont notify */
347       return;                               /* RETURN */
348    }
349    XtFree((char *)topicPosList);
350
351    /* and find that item in our list */
352    pTemp = hw->help_dialog.history.pHistoryListHead;
353    for (i=1;i < topicPosition; i++)
354       pTemp = pTemp->pNext;
355   
356   
357    UpdateTopicList(pTemp, (Widget)hw, pTemp->topicType);
358       
359    /* Look to see if we have the current visible topic matches something in
360     * in the topic list. If so, highlight the item in the topic list
361     */
362    XtSetArg(args[0], XmNfontList, &fontList);
363    XtGetValues(hw->help_dialog.history.topicList, args, 1);
364
365    if (   _DtHelpFormatTopicTitle (hw->help_dialog.help.pDisplayArea,
366                                    hw->help_dialog.display.volumeHandle,
367                                    hw->help_dialog.display.locationId,
368                                    &labelString, &fontList, &mod) != 0 
369        || NULL == labelString)
370    {
371        labelString = XmStringCreateLocalized(hw->help_dialog.display.locationId);
372    }
373
374    if (True == mod)
375    {
376        /* must set the fontlist, otherwise this will cause a dangle later. */
377        XtSetArg(args[0], XmNfontList, fontList);
378        XtSetValues(hw->help_dialog.history.topicList, args, 1);
379        XmFontListFree(fontList);
380    }
381
382    XmListSelectItem(hw->help_dialog.history.topicList,labelString, FALSE);
383    XmListSetBottomItem(hw->help_dialog.history.topicList,labelString);
384    XmStringFree(labelString);
385 }
386
387
388
389
390 \f
391 /*****************************************************************************
392  * Function:        void ProcessTopicSelectionCB(Widget w,
393  *                                              XtPointer client_data,
394  *                                              XtPointer call_data);
395  *
396  *
397  *
398  * Parameters:  
399  *
400  * Return Value:    Void.
401  *
402  * Purpose:         Process user selection of an item in the History List.
403  *
404  *****************************************************************************/
405 static void ProcessTopicSelectionCB(
406     Widget w,
407     XtPointer client_data,
408     XtPointer call_data)
409 {
410    XmListCallbackStruct *selectedItem = (XmListCallbackStruct *) call_data;
411    DtHelpDialogWidget hw = (DtHelpDialogWidget) client_data;
412    
413    DtTopicListStruct *pTemp= NULL;
414    int topicPosition=0;  
415    int i;
416
417
418    /* First, find out what item is currently selected in our 
419     * volume list.  From this, we can get the proper topic list to
420     * travers.
421     */
422
423    pTemp = PullTopicListFromSelVolumeList((Widget)hw); 
424
425    if (pTemp == NULL)
426      {
427        /*FIX: We have a problem, this should never happen; decide what to do*/
428        return;
429      }
430
431
432    /* Determin the item selected and find that item in our list */
433    topicPosition = selectedItem->item_position;
434    
435    for (i=1;i < topicPosition; i++)
436       pTemp = pTemp->pNext;
437   
438    hw->help_dialog.display.helpType = pTemp->topicType;
439
440    if (hw->help_dialog.display.helpType != DtHELP_TYPE_TOPIC)
441      {
442        if (hw->help_dialog.display.topicTitleLbl != NULL)
443            XmStringFree(hw->help_dialog.display.topicTitleLbl);
444        hw->help_dialog.display.topicTitleLbl =
445                                         XmStringCopy(pTemp->topicTitleLbl);
446      }
447    
448
449    switch (pTemp->topicType)
450      {
451        case DtHELP_TYPE_TOPIC:
452          /* Look and see if we need to update our helpVolue to a new value */
453          if (   pTemp->helpVolume != NULL
454              && (   hw->help_dialog.display.helpVolume == NULL
455                  || strcmp(hw->help_dialog.display.helpVolume,pTemp->helpVolume) != 0))
456          {
457            XtFree(hw->help_dialog.display.helpVolume);
458            hw->help_dialog.display.helpVolume  = XtNewString(pTemp->helpVolume);
459          
460            /* Set our help volume flag so we open the proper volume */
461            hw->help_dialog.ghelp.volumeFlag         = FALSE;
462          }
463
464          XtFree(hw->help_dialog.display.locationId);
465          hw->help_dialog.display.locationId = XtNewString(pTemp->locationId);
466         
467          /* set the topicType flag to process correctly */
468          hw->help_dialog.display.helpType = DtHELP_TYPE_TOPIC;
469
470          break;
471
472        case DtHELP_TYPE_STRING:
473          XtFree(hw->help_dialog.display.stringData);
474          hw->help_dialog.display.stringData = XtNewString(pTemp->locationId);
475         
476          /* set the topicType flag to process correctly */
477          hw->help_dialog.display.helpType = DtHELP_TYPE_STRING;
478
479          break;
480   
481        case DtHELP_TYPE_DYNAMIC_STRING:
482          XtFree(hw->help_dialog.display.stringData);
483          hw->help_dialog.display.stringData = XtNewString(pTemp->locationId);
484         
485          /* set the topicType flag to process correctly */
486          hw->help_dialog.display.helpType = DtHELP_TYPE_DYNAMIC_STRING;
487
488          break;
489
490        case DtHELP_TYPE_MAN_PAGE:
491          XtFree(hw->help_dialog.display.manPage);
492          hw->help_dialog.display.manPage = XtNewString(pTemp->locationId);
493         
494          /* set the topicType flag to process correctly */
495          hw->help_dialog.display.helpType = DtHELP_TYPE_MAN_PAGE;
496
497          break;
498
499        case DtHELP_TYPE_FILE:
500          XtFree(hw->help_dialog.display.helpFile);
501          hw->help_dialog.display.helpFile = XtNewString(pTemp->locationId);
502         
503          /* set the topicType flag to process correctly */
504          hw->help_dialog.display.helpType = DtHELP_TYPE_FILE;
505
506          break;
507
508        default:  
509  
510         /* ERROR-MESSAGE */
511         /* We should never get here, because we using the proper types */
512         return;
513
514     }  /* End Switch Statement */
515   
516     _DtHelpSetupDisplayType(hw, FALSE, DtHISTORY_AND_JUMP);   
517
518 }
519
520
521
522
523
524 /*****************************************************************************
525  * Function:        void CreateHistoryDialog(
526  *                             Widget nw);
527  *
528  *
529  * Parameters:      helpDialogWidget   Specifies the current Help Dialog to 
530  *                                     create the history dialog for.
531  *
532  *
533  * Return Value:   
534  *
535  * Purpose:         Create and display an instance of a history dialog.
536  *
537  *****************************************************************************/
538 static void CreateHistoryDialog(
539     Widget nw)
540 {
541   Widget historyForm;
542   Widget volumeListLabel;
543   Widget separator;
544   Widget cancelBtn, helpBtn;
545   Widget historyShell;
546   
547
548   XmString labelString;
549   Arg args[20];
550   int n;
551   char * title;
552   DtHelpListStruct *pHelpInfo;
553   int offset=0;
554   Dimension btnHeight=0;
555   Dimension widgetBorderHeight=0;
556
557   DtHelpDialogWidget hw = (DtHelpDialogWidget) nw ;
558
559   /*  Create the shell and form used for the dialog.  */
560
561    title = XtNewString(((char *)_DTGETMESSAGE(3, 1,"Help - History Browser")));
562    n = 0;
563    XtSetArg (args[n], XmNtitle, title);                                 n++;
564    XtSetArg (args[n], XmNallowShellResize, TRUE);                       n++;
565    historyShell = XmCreateDialogShell((Widget) hw, "historyShell", args, n);
566    XtFree(title);
567
568    /* Set the useAsyncGeo on the shell */
569    n = 0;
570    XtSetArg (args[n], XmNuseAsyncGeometry, True); n++;
571    XtSetValues (XtParent(historyShell), args, n);
572
573
574    n = 0;
575    XtSetArg (args[n], XmNmarginWidth, 1);                               n++;
576    XtSetArg (args[n], XmNmarginHeight, 1);                              n++;
577    XtSetArg (args[n], XmNshadowThickness, 1);                           n++;
578    XtSetArg (args[n], XmNshadowType, XmSHADOW_OUT);                     n++;
579    XtSetArg (args[n], XmNautoUnmanage, False);                          n++;
580    historyForm = XmCreateForm (historyShell, "historyForm", args, n);
581
582  
583    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
584                             (3, 2,"Help Volumes Visited:")));
585    n = 0;
586    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
587    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
588    XtSetArg (args[n], XmNleftOffset, 5);                                n++;
589    XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);                 n++;
590    XtSetArg (args[n], XmNtopOffset, 10);                                n++;
591    volumeListLabel = 
592          XmCreateLabelGadget (historyForm, "volumeListLabel", args, n);
593    XtManageChild (volumeListLabel);
594    XmStringFree (labelString);
595
596
597    /* Create our history scrolled list */
598    n = 0;
599    XtSetArg (args[n], XmNlistSizePolicy, XmCONSTANT);                   n++;
600    XtSetArg (args[n], XmNselectionPolicy, XmSINGLE_SELECT);             n++;
601    XtSetArg (args[n], XmNresizable, FALSE);                             n++;
602    hw->help_dialog.history.volumeList =
603             XmCreateScrolledList (historyForm, "historyVolumeList", args, n);
604    XtManageChild (hw->help_dialog.history.volumeList);
605
606    XtAddCallback (hw->help_dialog.history.volumeList, 
607                  XmNsingleSelectionCallback, 
608                  (XtCallbackProc)ProcessVolumeSelectionCB, (XtPointer) hw);
609    
610    /* Set the constraints on our scrolled list */
611    n = 0;
612    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
613    XtSetArg (args[n], XmNtopWidget, volumeListLabel);                   n++;
614    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
615    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
616    XtSetArg (args[n], XmNleftOffset, 10);                               n++;
617    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
618    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
619    XtSetValues (XtParent (hw->help_dialog.history.volumeList), args, n);
620
621
622    /* Create the Result Label and scrolled list */
623
624    /* Create Result List Label */
625    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
626                      (3, 8,"Help Topics Visited:")));
627    n = 0;
628    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
629    XtSetArg (args[n], XmNtopWidget, 
630                   XtParent(hw->help_dialog.history.volumeList));        n++;
631    XtSetArg (args[n], XmNtopOffset, 10);                                n++;
632    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
633    XtSetArg (args[n], XmNleftOffset, 10);                               n++;
634    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
635    hw->help_dialog.history.topicsListLabel = 
636          XmCreateLabelGadget (historyForm, "topicsListLabel", args, n);
637    XtManageChild (hw->help_dialog.history.topicsListLabel);
638    XmStringFree (labelString);
639
640
641    /* Create our volume topics list */
642    n = 0;
643    XtSetArg (args[n], XmNlistSizePolicy, XmCONSTANT);                   n++;
644    XtSetArg (args[n], XmNselectionPolicy, XmSINGLE_SELECT);             n++;
645    XtSetArg (args[n], XmNresizable, FALSE);                             n++;
646    hw->help_dialog.history.topicList =
647             XmCreateScrolledList (historyForm, "historyTopicList", args, n);
648    XtManageChild (hw->help_dialog.history.topicList);
649
650    XtAddCallback (hw->help_dialog.history.topicList, 
651                   XmNsingleSelectionCallback, 
652                   (XtCallbackProc)ProcessTopicSelectionCB,
653                   (XtPointer) hw);
654   
655    XtAddCallback (hw->help_dialog.history.topicList, 
656                   XmNdefaultActionCallback, 
657                   (XtCallbackProc)ProcessTopicSelectionCB,
658                   (XtPointer) hw);
659
660    /* Set the constraints on our scrolled list */
661    n = 0;
662    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
663    XtSetArg (args[n], XmNtopWidget, hw->help_dialog.history.topicsListLabel);   n++;
664    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
665    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
666    XtSetArg (args[n], XmNleftOffset, 10);                               n++;
667    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
668    XtSetArg (args[n], XmNrightOffset, 10);                              n++;
669    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
670    XtSetArg (args[n], XmNbottomOffset, 70);                             n++;
671    XtSetValues (XtParent (hw->help_dialog.history.topicList), args, n);
672
673   
674    /*  Create a separator between the buttons  */
675
676    n = 0;
677    XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);                n++;
678    XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);               n++;
679    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
680    XtSetArg (args[n], XmNtopWidget,
681                         XtParent(hw->help_dialog.history.topicList));   n++;
682    XtSetArg (args[n], XmNtopOffset, 8);                         n++;
683    separator =  XmCreateSeparatorGadget (historyForm, "separator", args, n);
684    XtManageChild (separator);
685
686
687    /*  Create the action buttons along the bottom */
688    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
689                             (3, 3,"Close")));
690    n = 0;
691    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
692    XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
693    XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
694    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
695    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
696    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
697    XtSetArg (args[n], XmNmarginHeight, 4);                              n++;
698    XtSetArg (args[n], XmNmarginWidth, 6);                               n++;
699    /*XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);            n++;
700     *XtSetArg (args[n], XmNbottomOffset, 3);                            n++;
701     */
702    cancelBtn = XmCreatePushButtonGadget (historyForm, "cancelBtn", args, n);
703    
704    XtAddCallback(cancelBtn, XmNactivateCallback, 
705                 (XtCallbackProc)CloseHistoryCB, (XtPointer) hw);
706              
707    XtManageChild (cancelBtn);
708    XmStringFree (labelString);
709
710    XtSetArg (args[0], XmNdefaultButton, cancelBtn);
711    XtSetValues (historyForm, args, 1);
712
713    /* set the cancel button (for KCancel) */
714    n = 0;
715    XtSetArg (args[n], XmNcancelButton, cancelBtn); n++;
716    XtSetValues (historyForm, args, n);
717
718
719    /* Build the Help button */
720
721    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
722                             (3, 4,"Help")));
723    n = 0;
724    XtSetArg (args[n], XmNlabelString, labelString);                     n++;
725    XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
726    XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
727    XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET);               n++;
728    XtSetArg (args[n], XmNtopWidget, separator);                         n++;
729    XtSetArg (args[n], XmNtopOffset, 5);                                 n++;
730    XtSetArg (args[n], XmNmarginHeight, 4);                              n++;
731    XtSetArg (args[n], XmNmarginWidth, 6);                               n++;
732    helpBtn = XmCreatePushButtonGadget (historyForm, "helpBtn", args, n);
733    XtManageChild (helpBtn);
734
735    /* Setup and add our help callback for this button */
736    pHelpInfo = _DtHelpListAdd(DtHELP_historyHelpBtn_STR,
737                         (Widget) hw, &hw->help_dialog.help, 
738                         &hw->help_dialog.help.pHelpListHead);
739    XtAddCallback (helpBtn, XmNactivateCallback,
740                   _DtHelpCB, (XtPointer) pHelpInfo);
741    
742    XmStringFree (labelString);
743
744
745    /*  Adjust the decorations for the dialog shell of the dialog  */
746     n = 0;
747     XtSetArg(args[n], XmNmwmFunctions,  
748              MWM_FUNC_MOVE |MWM_FUNC_RESIZE);                           n++;
749     XtSetArg (args[n], XmNmwmDecorations, 
750              MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH);   n++;
751     XtSetValues (historyShell, args, n);
752     
753    /* calculate and set the buttons' positions on the form */
754    {
755    Widget btnList[2];
756    unsigned long avgWidth = 73; /* default size, in 10ths of pixel */
757    Dimension formWidth;
758    XmFontList fontList = NULL;
759    Atom xa_ave_width;
760 #define BTN_MARGINS   4
761 #define BETW_BTN_SPC  5
762
763    XtSetArg(args[0], XmNfontList, &fontList);
764    XtGetValues(hw->help_dialog.history.topicList, args, 1);
765
766    btnList[0] = cancelBtn;
767    btnList[1] = helpBtn;
768
769    /* get the average width of the topic list's font */
770    xa_ave_width = XmInternAtom(XtDisplay(cancelBtn), "AVERAGE_WIDTH", False);
771    _DtHelpXmFontListGetPropertyMax(fontList, xa_ave_width, &avgWidth);
772
773    /* xa_ave_width is given in 10ths of a pixel; convert to pixels by div thru 10 */
774    /* we want a 25 column minimum width */
775    formWidth = avgWidth * 25 / 10;
776
777    _DtHelpSetButtonPositions(btnList, 2, formWidth, BTN_MARGINS, BETW_BTN_SPC);
778    }
779
780    /* Perform the final form layout so our dialog resizes correctly. */
781    /* Get height of: bottom buttons and separator */
782    n = 0;
783    XtSetArg(args[n], XmNheight, &btnHeight);                    n++;
784    XtSetArg(args[n], XmNborderWidth, &widgetBorderHeight);      n++;
785    XtGetValues(cancelBtn, args, n);
786    offset = btnHeight + widgetBorderHeight + 15;
787                     /* 20 =='s fudge factor */
788   
789    n = 0;
790    XtSetArg(args[n], XmNborderWidth, &widgetBorderHeight);      n++;
791    XtSetArg(args[n], XmNheight, &btnHeight);                    n++;
792    XtGetValues(separator, args, n);
793    offset += btnHeight + widgetBorderHeight;
794  
795
796
797    /* make the bottom attachment for the seporator such that things will fit,
798     * and the dialog will size properly.
799     */
800    n = 0;
801    XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);              n++;
802    XtSetArg (args[n], XmNbottomOffset, offset);                         n++;
803    XtSetValues (XtParent (hw->help_dialog.history.topicList), args, n); 
804    
805    /* We may have some history values already, so update our newlly 
806     * created scrolled list widget.
807     */
808    
809   
810    /* Add the popup position callback to our history dialog */
811    XtAddCallback (historyShell, XmNpopupCallback, (XtCallbackProc)_DtHelpMapCB,
812                   (XtPointer) XtParent(hw));
813  
814    /* Add our help callback to the shell of the dialog  */
815    pHelpInfo = _DtHelpListAdd(DtHELP_historyShell_STR,
816                         (Widget) hw, &hw->help_dialog.help, 
817                         &hw->help_dialog.help.pHelpListHead);
818    XtAddCallback(historyForm, XmNhelpCallback,
819                  _DtHelpCB, (XtPointer) pHelpInfo);
820    
821   /* Assign our new search dialog to our widget instance */
822   hw->help_dialog.history.historyWidget = historyForm;
823
824 }
825
826
827
828 \f
829 /*****************************************************************************
830  * Function:        void _DtHelpUpdateHistoryList(char *locationId,
831  *                                 int topicType,
832  *                                 Widget nw);  
833  *
834  *
835  * Parameters:      parent      Specifies the ID string for the new topic we
836  *                              are going to display in the HelpDialog widget.
837  *
838  *                  helpDialogWidget  Specifies the current help dialog widget.
839  *
840  * Return Value:    Void.
841  *
842  * Purpose:         Updates the Path Display area on top of the help
843  *                  dialog.
844  *
845  *****************************************************************************/
846 void _DtHelpUpdateHistoryList(
847     char *locationId,
848     int topicType,
849     Boolean vol_changed,
850     Widget nw)
851 {
852   DtHistoryListStruct *pCurrentHistoryList=NULL;
853   XmString   topicTitle       = NULL;
854   XmString   currentItemTitle = NULL;
855   Boolean allocTopic=FALSE;
856   Boolean dupItem=FALSE;
857   Boolean changedSelectedVolume=FALSE;
858   Boolean mod=FALSE;
859   XmFontList    fontList;
860   Arg           args[2];
861
862   DtHelpDialogWidget hw = (DtHelpDialogWidget) nw;
863
864
865    /* Lets just build a history dialog so we can start populating it. 
866     * We won't manage it tell we need it 
867     */
868    if (hw->help_dialog.history.historyWidget == NULL)
869      CreateHistoryDialog((Widget) hw);
870
871   /* Find out what type of topic we are currently processing */
872   switch (topicType)
873     {
874       case DtHELP_TYPE_TOPIC:
875
876         /*
877          * get the font list for the volume list.
878          */
879         XtSetArg(args[0], XmNfontList, &fontList);
880         XtGetValues(hw->help_dialog.history.topicList, args, 1);
881
882         /* First we get the current topics Title */
883         allocTopic = True;
884         mod        = False;
885         if (_DtHelpFormatTopicTitle (hw->help_dialog.help.pDisplayArea,
886                                         hw->help_dialog.display.volumeHandle,
887                                         locationId, &topicTitle,
888                                         &fontList, &mod) != 0
889                 || NULL == topicTitle)
890             topicTitle = XmStringCreateLocalized(locationId);
891
892         if (mod == True)
893           {
894             XtSetArg(args[0], XmNfontList, fontList);
895             XtSetValues(hw->help_dialog.history.topicList, args, 1);
896             XmFontListFree(fontList);
897           }
898
899         /*
900          * get the font list for the volume list.
901          */
902         XtSetArg(args[0], XmNfontList, &fontList);
903         XtGetValues(hw->help_dialog.history.volumeList, args, 1);
904
905         /* Second, we get the current volume title */
906         mod = False;
907         _DtHelpFormatVolumeTitle (hw->help_dialog.help.pDisplayArea,
908                                  hw->help_dialog.display.volumeHandle,
909                                  &currentItemTitle, &fontList, &mod);   
910
911         if(currentItemTitle == NULL &&
912                                 NULL != hw->help_dialog.display.helpVolume)
913           currentItemTitle = XmStringCreateLocalized(
914                                         hw->help_dialog.display.helpVolume);
915         if (mod == True)
916           {
917             XtSetArg(args[0], XmNfontList, fontList);
918             XtSetValues(hw->help_dialog.history.volumeList, args, 1);
919             XmFontListFree(fontList);
920           }
921
922         break;  
923
924
925       case DtHELP_TYPE_FILE:
926         currentItemTitle = XmStringCreateLocalized(
927                                 ((char *)_DTGETMESSAGE(3, 5, "Help Files")));
928         topicTitle       = hw->help_dialog.display.topicTitleLbl;
929         break;
930
931
932       case DtHELP_TYPE_MAN_PAGE:
933         currentItemTitle = XmStringCreateLocalized(
934                                 ((char *)_DTGETMESSAGE(3, 6, "Man Pages")));
935         topicTitle       = hw->help_dialog.display.topicTitleLbl;
936         break;
937
938
939       case DtHELP_TYPE_STRING:
940       case DtHELP_TYPE_DYNAMIC_STRING:
941         currentItemTitle = XmStringCreateLocalized(
942                                 ((char *)_DTGETMESSAGE(3, 7, "Help Messages")));
943         topicTitle       = hw->help_dialog.display.topicTitleLbl;
944         break;
945  
946       default:  
947         /* Bogus type, how did we ever get here ??? */
948         break;
949
950     }  /* End Switch Statement */
951
952
953   /* Now add this item to the history list if necessary.  This fuction
954    * will return a pointer to the current working history list item.
955    */
956    pCurrentHistoryList = AddItemToHistoryList(
957                                 &(hw->help_dialog.history.pHistoryListHead),
958                                 currentItemTitle, topicType, &dupItem);
959
960    if (dupItem != TRUE)
961      {
962        /* We can skip this if it already exists in our history list,else
963         * we add the new history item  to the top of the scrolled window
964         */
965         XmListAddItem(hw->help_dialog.history.volumeList,currentItemTitle, 1);
966         XmListSelectPos(hw->help_dialog.history.volumeList,1, FALSE);
967      }
968    else /* dupItem == True */
969      {
970        /* We changed to a diferent volume or help type so force it selected */
971        XmListSelectItem(hw->help_dialog.history.volumeList,
972                                                 currentItemTitle, FALSE);
973        changedSelectedVolume = TRUE;
974        if (NULL != currentItemTitle)
975            XmStringFree(currentItemTitle);
976      }
977
978   /* Now add this item to the proper Topic List. */
979   if (pCurrentHistoryList != NULL)
980     {
981
982       if (!IsTopicInHistoryList(pCurrentHistoryList->pTopicHead, topicTitle))
983         {
984           /* Add the new topic to the history top of the history list */
985           _DtHelpTopicListAddToHead(locationId, topicTitle,topicType, 
986                              DtHISTORY_LIST_MAX,
987                              hw->help_dialog.display.helpVolume,
988                              &(pCurrentHistoryList->pTopicHead),
989                              &(pCurrentHistoryList->pTopicTale),
990                              &(pCurrentHistoryList->totalNodes),
991                              hw->help_dialog.backtr.scrollPosition);
992
993           XmUpdateDisplay((Widget) hw);
994           UpdateTopicList(pCurrentHistoryList, (Widget)hw, topicType);
995
996       
997           /* Force the top item to be selected */
998           XmListSelectPos(hw->help_dialog.history.topicList,1, FALSE);
999         }
1000       else
1001         {
1002           if (changedSelectedVolume)
1003             {
1004               if (TRUE == vol_changed)
1005                   UpdateTopicList(pCurrentHistoryList, (Widget)hw, topicType);
1006               XmListSelectItem(hw->help_dialog.history.topicList,topicTitle,
1007                              FALSE);
1008               /* Make sure the item is visible */
1009             }
1010         }
1011     }
1012   if (allocTopic == True)
1013       XmStringFree(topicTitle);
1014 }
1015
1016
1017
1018 /*****************************************************************************
1019  * Function:        static DtHistoryListStruct *AddItemToHistoryList(
1020  *                                
1021  * Parameters:
1022  *              title   Specifies the XmString of the title.  If
1023  *                      'duplicateItem' returns False, the caller
1024  *                      must not modify or free this parameter.
1025  *
1026  *
1027  * Return Value:   Pointer to the current history list node that we are going
1028  *                 to add the item.
1029  *
1030  * Purpose:        Add or update our history list with a new item
1031  *
1032  *****************************************************************************/
1033 static DtHistoryListStruct *AddItemToHistoryList(
1034      DtHistoryListStruct **pHead,
1035      XmString  title,
1036      int topicType,
1037      Boolean *duplicateItem)
1038 {
1039   DtHistoryListStruct *pTemp=NULL;
1040   Boolean done=FALSE;
1041
1042    /*
1043     * Walk the list.
1044     */
1045    pTemp = (*pHead); 
1046    *duplicateItem = False;
1047  
1048    while (!done && (pTemp != NULL))
1049      {
1050        if (XmStringCompare (title, pTemp->itemTitle) == True)
1051           {
1052             /* We have a match, so lets use it */
1053             *duplicateItem = TRUE;
1054             done = TRUE;
1055           }
1056        else
1057          pTemp = pTemp->pNext;
1058
1059      }
1060
1061    if (pTemp == NULL)
1062      {
1063        /* We did not find a match, so lets add one to the top of 
1064         * our current list.
1065         */
1066        pTemp =(DtHistoryListStruct *) XtMalloc((sizeof(DtHistoryListStruct)));
1067     
1068        
1069        pTemp->itemTitle        = title;
1070        pTemp->totalNodes       = 0;
1071        pTemp->topicType        = topicType;
1072        pTemp->pNext            = (*pHead);
1073        pTemp->pTopicHead       = NULL;
1074        pTemp->pTopicTale       = NULL;
1075
1076        /* Re-Assign our head pointer to point to the new 
1077         * head of the list
1078         */
1079        (*pHead) = pTemp;
1080      }
1081
1082   return (pTemp);
1083
1084 }
1085
1086
1087 /*****************************************************************************
1088  * Function:        static DtHistoryListStruct PullTopicListFromSelVolumeList
1089  *                                
1090  *
1091  *
1092  *
1093  * Return Value:   Pointer to the current history list node that we are going
1094  *                 to add the item.
1095  *
1096  * Purpose:        Add or update our history list with a new item
1097  *
1098  *****************************************************************************/
1099 static DtTopicListStruct *PullTopicListFromSelVolumeList(
1100      Widget nw)
1101 {
1102   DtHelpDialogWidget hw = (DtHelpDialogWidget) nw;
1103   DtHistoryListStruct *pTemp=NULL;
1104   Boolean itemsSelected=FALSE;
1105   int positionCount;
1106   int *positionList;  /* Should always be only one item */
1107   int i;
1108
1109   
1110   pTemp = hw->help_dialog.history.pHistoryListHead;
1111
1112   /* Find out what item is currently selected in our visited volumes list */
1113
1114   itemsSelected = XmListGetSelectedPos(hw->help_dialog.history.volumeList,
1115                                             &positionList, &positionCount);
1116
1117   if (itemsSelected)
1118     {
1119       /* We should get in here every time */
1120          
1121       for (i=1;i < positionList[0]; i++)
1122         pTemp = pTemp->pNext;
1123
1124       free(positionList);  
1125       return (pTemp->pTopicHead);
1126     }
1127   else
1128     {
1129       free(positionList);
1130       return (NULL);
1131       /* error condition we must account for */
1132     }
1133
1134  
1135 }
1136
1137
1138
1139