OpenIndiana and Solaris port
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Agents / NodeWindowAgentMotif.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: NodeWindowAgentMotif.C /main/94 1998/04/17 11:34:46 mgreess $ */
24 /*
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1994, 1995, 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33 /*
34  *
35  * Copyright (c) 1992 HAL Computer Systems International, Ltd.
36  * All rights reserved.  Unpublished -- rights reserved under
37  * the Copyright Laws of the United States.  USE OF A COPYRIGHT
38  * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
39  * OR DISCLOSURE.
40  * 
41  * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
42  * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.  USE,
43  * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
44  * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
45  * INTERNATIONAL, LTD.
46  * 
47  *                         RESTRICTED RIGHTS LEGEND
48  * Use, duplication, or disclosure by the Government is subject
49  * to the restrictions as set forth in subparagraph (c)(l)(ii)
50  * of the Rights in Technical Data and Computer Software clause
51  * at DFARS 252.227-7013.
52  *
53  *          HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
54  *                  1315 Dell Avenue
55  *                  Campbell, CA  95008
56  * 
57  */
58
59 #include <sstream>
60 #include <iostream>
61 using namespace std;
62
63 #define C_FString
64 #define C_List
65 #define C_NodeViewInfo
66 #define C_TOC_Element
67 #define L_Basic
68
69 #define C_Anchor
70
71 #define C_Agent
72 #define C_GraphicAgent
73 #define C_PrintPanelAgent
74 #define C_HelpAgent
75 #define C_NodeWindowAgent
76 #define C_ListView
77 #define C_BookTab
78 #define C_MarkIcon
79 #define C_AnchorCanvas
80 #define C_MarkCanvas
81 #define C_ScopeMenu
82 #define C_UrlAgent
83 #define C_IcccmAgent
84 #define C_BookmarkEdit
85 #define L_Agents
86
87 #define C_WindowGeometryPref
88 #define L_Preferences
89
90 #define C_PrintMgr
91 #define C_MessageMgr
92 #define C_SearchMgr
93 #define C_SearchResultsMgr
94 #define C_NodeMgr
95 #define C_SearchScopeMgr
96 #define C_PrefMgr
97 #define C_MarkMgr
98 #define C_MapMgr
99 #define C_GlobalHistoryMgr
100 #define C_NodeParser
101 #define C_GhostScriptEventMgr
102 #define C_GraphicsMgr
103 #define C_UrlMgr
104 #define C_LibraryMgr
105 #define C_EnvMgr
106 #define L_Managers
107
108
109 #define C_Path
110 #define C_Node
111 #define C_TOC
112 #define C_Tab
113 #define L_Doc
114
115 #define C_xList
116 #define L_Support
117
118 #define C_PixmapGraphic
119 #define L_Graphics
120
121 #define USES_OLIAS_FONT
122
123 #include "Managers/CatMgr.hh"
124 #include "Managers/WString.hh"
125 #include "Other/XmStringLocalized.hh"
126
127 #include "Marks/MarkInfo.hh"
128
129 #include <X11/cursorfont.h>
130
131 #include "Prelude.h"
132
133 #include "Registration.hh"
134
135 // for DtCanvas Help stuff
136 #include <DtI/Access.h>
137 #include <DtI/XUICreateI.h>
138 #include <DtI/SetListI.h>
139 #include <DtI/CallbacksI.h>
140 #include <DtI/DisplayAreaI.h>
141 #include <DtI/FontI.h>
142 #include <DtI/FontAttrI.h>
143 #include <DtI/RegionI.h>
144
145 #include "OnlineRender/SegClientData.hh"
146
147 #include "utility/mmdb_exception.h"
148
149 #include <Xm/MainW.h>
150 #include <Xm/RowColumn.h>
151 #include <Xm/PushBG.h>
152 #include <Xm/PushB.h>
153 #include <Xm/ToggleBG.h>
154 #include <Xm/ToggleB.h>
155 #include <Xm/CascadeBG.h>
156 #include <Xm/SeparatoG.h>
157 #include <WWL/WTopLevelShell.h>
158 #include <WWL/WXmPushButton.h>
159 #include <WWL/WXmCascadeButtonGadget.h>
160 #include <WWL/WXmForm.h>
161 #include <WWL/WXmRowColumn.h>
162 #include <WWL/WXmMenu.h>
163 #include <WWL/WXmFrame.h>
164 #include <WWL/WXmLabel.h>
165 #include <WWL/WXmToggleButton.h>
166 #include <WWL/WXmArrowButton.h>
167 #include <WWL/WXmSeparator.h>
168 #include <WWL/WXmTextField.h>
169 #include <WWL/WXmDrawingArea.h>
170 #include <WWL/WXmDialogShell.h>
171 #include <WWL/WXmMessageBox.h>
172 #include <Xm/Text.h>
173 #include <Xm/TextF.h>
174
175 #include <ctype.h>
176
177 #if defined(sun)
178 #if defined(SVR4)
179 #define SunOS5
180 #else
181 #define SunOS4
182 #endif
183 #endif
184
185 #if defined(Internationalize) && defined(SunOS5)
186 #include <libintl.h>
187 #endif
188
189
190 #if defined(UseWideChars)
191 # if defined(SunOS4)
192 #   define mbstowcs(a,b,c) Xmbstowcs(a,b,c)
193 #   define wcstombs(a,b,c) Xwcstombs(a,b,c)
194 # elif defined(_IBMR2)
195 #   include <wcstr.h>
196 # endif
197 #endif
198
199 #define ON_ACTIVATE(WOBJ,FUNC) \
200   (WOBJ).SetActivateCallback (this, (WWL_FUN) &CLASS::FUNC)
201 #define ON_ARM(WOBJ,FUNC) \
202   (WOBJ).SetArmCallback (this, (WWL_FUN) &CLASS::FUNC)
203 #define ON_DISARM(WOBJ,FUNC) \
204   (WOBJ).SetDisarmCallback (this, (WWL_FUN) &CLASS::FUNC)
205
206 #define f_node_ptr f_node_view_info->node_ptr()
207   
208 xList<UAS_Pointer<UAS_Common> > g_tab_list;
209
210 extern AppPrintData * l_AppPrintData; 
211
212 extern "C"
213 {
214   typedef void (*resize_cb_ptr)();
215   typedef void (*hypertext_cb_ptr)();
216 }
217
218 #ifdef CV_HYPER_DEBUG
219 void
220 #else
221 static void
222 #endif
223 hypertext_cb (DtHelpDispAreaStruct* pDAS, NodeWindowAgent *agent, 
224               DtHelpHyperTextStruct *callData)
225 {
226 #if defined(_IBMR2) && defined(CV_HYPER_BUG)
227   _DtCvLinkInfo ceHyper ;
228   
229   _DtCvUnit downX, downY, upX, upY ;
230
231   downX = upX = pDAS->timerX ;
232   downY = upY = pDAS->timerY ;
233
234   if (_DtCvSTATUS_OK ==
235       _DtCanvasGetPosLink (pDAS->canvas, downX, downY, upX,
236                            upY, &ceHyper))
237     {
238 #ifdef CV_HYPER_DEBUG
239       cerr << "hypertext callback(" << callData->window_hint << "): " <<
240         ceHyper.specification << endl; 
241 #endif
242       agent->link_to(ceHyper.specification);
243     }
244 #else
245
246   if (callData->window_hint == 0) {
247     if (callData->hyper_type < 0) {
248       UAS_Pointer<Mark>& mark =
249                 ((MarkCanvas*)(callData->specification))->mark_ptr();
250 #ifdef CV_HYPER_DEBUG
251       cerr << "hypertext callback(" << callData->window_hint << "): " <<
252         mark->name() << endl; 
253 #endif
254       mark->edit();
255     }
256     else {
257 #ifdef CV_HYPER_DEBUG
258       cerr << "hypertext callback(" << callData->window_hint << "): " <<
259         callData->specification << endl; 
260 #endif
261       agent->link_to(callData->specification);
262     }
263   }
264 #endif
265 }
266
267 static void
268 resize_cb (NodeWindowAgent *agent)
269 {
270   agent->canvas_resize ();
271 }
272
273 static void
274 h_scroll_callback (Widget,
275                    XtPointer client_data,
276                    XtPointer call_data)
277 {
278   NodeWindowAgent *agent = (NodeWindowAgent*)client_data ; 
279   agent->hscroll (((XmScrollBarCallbackStruct*) call_data)->value) ;
280 }
281
282 static void
283 v_scroll_callback (Widget,
284                    XtPointer client_data,
285                    XtPointer call_data)
286 {
287 #ifdef SCROLL_BOOKMARK_DEBUG
288   cerr << "our callback" << endl;
289 #endif
290   NodeWindowAgent *agent = (NodeWindowAgent*)client_data ; 
291   agent->vscroll (((XmScrollBarCallbackStruct*) call_data)->value) ;
292 }
293
294 static void 
295 v_scroll_notify(void *client_data, unsigned int value)
296 {
297   ((NodeWindowAgent*)client_data)->vscroll (value);
298 }
299
300 static void
301 detach_grCB (Widget, XtPointer client_data, XtPointer )
302 {
303   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
304   agent->detach_gr();
305 }
306
307 static void
308 raise_grCB (Widget w, XtPointer client_data, XtPointer )
309 {
310   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
311   agent->raise_gr();
312 }
313
314 static void
315 attach_grCB (Widget, XtPointer client_data, XtPointer )
316 {
317   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
318   agent->attach_gr();
319 }
320
321 void
322 NodeWindowAgent::attach_gr()
323 {
324   _DtCvSegment *seg ;
325   XtVaGetValues(f_detach_button, XmNuserData, &seg, NULL);
326   SegClientData* pSCD = (SegClientData*)(seg->client_use);
327   UAS_Pointer<Graphic> gr = (Graphic*)pSCD->GraphicHandle();
328   //GraphicAgent *agent = gr->get_agent();
329   //GraphicAgent *agent = graphics_mgr().get_agent(gr->locator());
330
331   if (gr->is_detached())
332   {
333     //agent->attach_graphic();
334     graphics_mgr().reattach_graphic(gr);
335   }
336 }
337
338 void
339 NodeWindowAgent::detach_gr()
340 {
341   _DtCvSegment *seg ;
342   XtVaGetValues(f_detach_button, XmNuserData, &seg, NULL);
343
344   SegClientData* pSCD = (SegClientData*)(seg->client_use);
345   UAS_Pointer<Graphic> gr = (Graphic*)pSCD->GraphicHandle();
346   if (!gr->is_detached())
347     graphics_mgr().detach (f_node_view_info->node_ptr(), gr);
348 }
349
350 void
351 NodeWindowAgent::raise_gr()
352 {
353   _DtCvSegment *seg ;
354   XtVaGetValues(f_detach_button, XmNuserData, &seg, NULL);
355   SegClientData* pSCD = (SegClientData*)(seg->client_use);
356   UAS_Pointer<Graphic> gr = (Graphic*)pSCD->GraphicHandle();
357   //GraphicAgent *agent = gr->get_agent();
358   UAS_String locator_str = gr->locator();
359   GraphicAgent *agent = graphics_mgr().get_agent(locator_str);
360   agent->popup();
361 }
362
363 static void
364 popup_menuCB (Widget, XtPointer client_data, XEvent *event, Boolean*)
365 {
366   XButtonPressedEvent *pevent = (XButtonPressedEvent*)event; 
367
368   if (pevent->type != ButtonPress || pevent->button != Button3)
369     return;
370
371   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
372   agent->popup_menu(pevent);
373 }
374
375 static void
376 go_to_linkCB (Widget, XtPointer client_data, XtPointer )
377 {
378   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
379   agent->go_to_link();
380 }
381
382 static void
383 open_new_nodeCB (Widget, XtPointer client_data, XtPointer )
384 {
385   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
386   agent->open_new_node();
387 }
388
389 // Display a section in current node window
390 void
391 NodeWindowAgent::go_to_link()
392 {
393     link_to((char*)f_link_spec);
394     f_link_spec = NULL;
395 }
396
397 // Display a section in a new Node Window
398 void
399 NodeWindowAgent::open_new_node()
400 {
401   node_mgr().force_new_window();
402   link_to((char*)f_link_spec);
403   f_link_spec = NULL;
404 }
405
406 void
407 NodeWindowAgent::exit_cb()
408 {
409   if (BookmarkEdit::modified_count() > 0)
410     {
411       bool resp;
412       resp = message_mgr().question_dialog (
413                 (char*)UAS_String(CATGETS(Set_Messages, 2,
414                 "Do you want to abandon your changes?")), (Widget)f_shell);
415       if (! resp)
416         return;
417     }
418  
419   message_mgr().quit_dialog (
420         (char*)UAS_String(CATGETS(Set_Messages, 6,
421         "Do you really want to quit Dtinfo?")), (Widget)f_shell);
422
423 }
424
425 // pop up one of three menus:
426 // 1. If cursor is over a graphic, popup detach graphic menu.
427 // 2. If cursor is over hyperlink, popup link preview menu.
428 // 3. Else popup default menu.
429 void
430 NodeWindowAgent::popup_menu(XButtonPressedEvent* event)
431 {
432   _DtCvSegment *seg;
433   _DtCvElemType seg_type;
434   seg = xy_to_seg(event->x, event->y, &seg_type);
435
436 //  if (seg == NULL)
437 //    return;
438
439   // see if it's the graphic detach menu to popup
440   switch(seg_type)
441   {
442     case _DtCvREGION_TYPE:
443     {
444       SegClientData* pSCD =
445                 (SegClientData*)(seg->client_use);
446       UAS_Pointer<Graphic> gr = (Graphic*)pSCD->GraphicHandle();
447       if (gr->is_detached())
448       {
449         XtSetSensitive(f_attach_button, True);
450         XtSetSensitive(f_raise_button, True);
451         XtSetSensitive(f_detach_button, False);
452       }
453       else
454       {
455         XtSetSensitive(f_attach_button, False);
456         XtSetSensitive(f_raise_button, False);
457         XtSetSensitive(f_detach_button, True);
458       }
459       // the userdata for the detach buton is used to transfer
460       // the canvas segment to the detach, attach, raise callbacks.
461       XtVaSetValues(f_detach_button, XmNuserData, seg, NULL);
462       XmMenuPosition(f_detach_menu, event);
463       XtManageChild(f_detach_menu);
464
465       char* gr_type = (char*)gr->content_type();
466       gr_type = strchr(gr_type,'/');
467       if(gr_type)
468         gr_type++;
469
470       char buff[40];
471       snprintf(buff, sizeof(buff), "%s graphic", gr_type);
472       XmTextFieldSetString(f_status_text, buff);
473       break;
474
475     }
476     case _DtCvSTRING_TYPE:
477     {
478       _DtCvLinkInfo ceHyper ;
479       _DtCvUnit downX, downY, upX, upY ;
480
481       downX = upX = event->x;
482       downY = upY = event->y;
483
484       if (XtIsManaged(f_help_dsp_area->vertScrollWid))
485       {
486         downY += f_vscrollbar_offset; // adjust y-pos for scroll bar
487         upY += f_vscrollbar_offset; // adjust y-pos for scroll bar
488       }
489
490       if (_DtCvSTATUS_OK ==
491           _DtCanvasGetPosLink (f_help_dsp_area->canvas,
492                                downX, downY,
493                                upX, upY,
494                                &ceHyper))
495       {
496         f_link_spec = ceHyper.specification;
497         UAS_Pointer<UAS_Common> doc_ptr =
498            f_node_view_info->node_ptr()->create_relative((char*)f_link_spec);
499         // NOTE: create_relative may have failed if the infolib associated
500         //       with spec had been removed. So check doc_ptr before
501         //       calling preview_init
502         if (doc_ptr)
503         {
504           //preview_init(doc_ptr);
505           char title[128];
506           char preview_buffer[256];
507  
508           UAS_String pt = doc_ptr->title();
509           *((char *) memcpy(title, (char *) pt, 127) + 127) = '\0';
510           UAS_String bn = doc_ptr->book_name(UAS_SHORT_TITLE);
511           const char *book_name = (char *) bn;
512           if (book_name != NULL && *book_name != '\0')
513             snprintf (preview_buffer, sizeof(preview_buffer),
514                CATGETS(Set_Messages, 8, "Link to %s: %s"), book_name, title);
515           else
516             snprintf (preview_buffer, sizeof(preview_buffer),
517                CATGETS(Set_Messages, 9, "Link to %s"), title);
518           WXmLabel lb = WXmLabel(f_preview_label);
519           lb.LabelString(WXmString(title));
520   
521           XmTextFieldSetString(f_status_text, preview_buffer);
522           XmMenuPosition(f_preview_menu, event);
523           XtManageChild(f_preview_menu);
524         }
525       }
526       else
527       {
528         XmMenuPosition(f_default_menu, event);
529         XtManageChild(f_default_menu);
530       }
531       break;
532     }
533     default:
534       XmProcessTraversal(f_help_dsp_area->dispWid, XmTRAVERSE_CURRENT);
535       XmMenuPosition(f_default_menu, event);
536       XtManageChild(f_default_menu);
537       break;
538   }
539 }
540
541 // Given an x,y coordinate, return the segment. The segment
542 // type that can be returned is a _DtCvREGION_TYPE or a
543 // _DtCvSTRING.
544 //
545 _DtCvSegment *
546 NodeWindowAgent::xy_to_seg(int x, int y, _DtCvElemType *element)
547 {
548   _DtCvStatus status;
549   _DtCvSegment *seg;
550   _DtCvUnit offx, offy;
551   int xpos, ypos;
552
553   ypos = y;
554   xpos = x;
555
556   if (XtIsManaged(f_help_dsp_area->vertScrollWid))
557     ypos += f_vscrollbar_offset; // adjust y-pos for scroll bar
558   if (XtIsManaged(f_help_dsp_area->horzScrollWid))
559     xpos += f_hscrollbar_offset; // adjust x-pos for scroll bar
560
561   status = _DtCanvasGetSpotInfo(f_help_dsp_area->canvas, xpos, ypos,
562                   &seg, &offx, &offy, element);
563
564   if (status == _DtCvSTATUS_OK)
565     return seg;
566   else
567     return  (_DtCvSegment *)NULL;
568 }
569
570 void
571 NodeWindowAgent::disarm()
572 {
573   unpreview();
574 }
575
576 void
577 NodeWindowAgent::arm()
578 {
579   _DtCvLinkInfo ceHyper ;
580   
581   _DtCvUnit downX, downY, upX, upY ;
582
583   downX = upX = f_help_dsp_area->timerX ;
584   downY = upY = f_help_dsp_area->timerY ;
585
586   if (XtIsManaged(f_help_dsp_area->vertScrollWid))
587   {
588     downY += f_vscrollbar_offset; // adjust y-pos for scroll bar
589     upY += f_vscrollbar_offset; // adjust y-pos for scroll bar
590   }
591
592   if (_DtCvSTATUS_OK ==
593       _DtCanvasGetPosLink (f_help_dsp_area->canvas, downX, downY, upX,
594                            upY, &ceHyper))
595     {
596       UAS_String spec(ceHyper.specification);
597       UAS_Pointer<UAS_Common> doc_ptr =
598                         f_node_view_info->node_ptr()->create_relative(spec);
599       // NOTE: create_relative may have failed if the infolib associated
600       //       with spec had been removed. So check doc_ptr before
601       //       calling preview_init
602       if (doc_ptr)
603         preview_init(doc_ptr); 
604     }
605 }
606
607 void
608 NodeWindowAgent::hscroll (unsigned int value)
609 {
610   f_hscrollbar_offset = value ;
611 }
612
613 void
614 NodeWindowAgent::vscroll (unsigned int value)
615 {
616 #ifdef SCROLL_BOOKMARK_DEBUG
617   cerr << "agent vscroll: " << value << endl;
618 #endif  
619
620   f_vscrollbar_offset = value ;
621
622   List_Iterator <MarkIcon *> i (f_mark_icon_list);
623
624   while (i)
625     {
626       i.item()->TopOffset (i.item()->ypos() - value);
627       i++ ;
628     }
629 }
630
631 static UAS_Pointer<Mark> &
632 g_view_mark()
633 {
634   static UAS_Pointer<Mark> da_mark;
635   return (da_mark);
636 }
637
638
639 #if 0
640 static unsigned
641 find_segment_offset (_DtCvSegment *start, const _DtCvSegment *target,
642                      unsigned &offset);
643 #endif
644
645 static void
646 arm_callback (void *client_data)
647 {
648   ((NodeWindowAgent*)client_data)->arm();
649 }
650 static void
651 disarm_callback (Widget, XtPointer client_data, XtPointer)
652 {
653   ((NodeWindowAgent*)client_data)->disarm();
654 }
655
656 void
657 selection_end_callback(Widget, XtPointer, XtPointer)
658 {
659   SelectionChanged msg ;
660   node_mgr().UAS_Sender<SelectionChanged>::send_message (msg);
661 }
662
663 // For history jump to position stuff:
664 #ifdef jbm
665 AnchorCanvas *g_history_anchor;
666 #endif
667
668 bool g_scroll_to_locator ;
669 char g_top_locator[4096] ;
670
671 // When updating for the purposes of changing style sheets
672 extern bool g_style_sheet_update ;
673
674 static bool g_ignore_wm_delete;
675
676 // /////////////////////////////////////////////////////////////////
677 // ancestral hierarchy handling class
678 // /////////////////////////////////////////////////////////////////
679
680 #define CLASS Ancestor
681
682 class Ancestor : public WWL
683 {
684 public:
685   Ancestor (NodeWindowAgent *nwa, WXmPulldownMenu &p,
686             const char *title, const UAS_Pointer<UAS_Common> &toc_ptr)
687     : f_node_window_agent (nwa),
688       f_button (p, "button", WAutoManage,
689                 WArgList (XmNlabelString, (XtArgVal) WXmString (title), NULL)),
690       f_toc_ptr (toc_ptr)
691     {
692       ON_ACTIVATE (f_button,activate);
693       // Make it look like a label if the user can't select it.
694       // Note bogus assumption of 2 pixel wide shadow thickness. 
695       if ((f_toc_ptr == 0) || f_toc_ptr->data_length() == 0)
696         {
697           f_button.Set (WArgList (XmNshadowThickness, 0,
698                                   XmNmarginWidth, 4,
699                                   XmNmarginHeight, 4,
700                                   NULL));
701         }
702     }
703   virtual ~Ancestor()
704     {
705       f_button.Destroy();
706     }
707   void update (const char *title, UAS_Pointer<UAS_Common> toc_ptr);
708   void activate();
709   
710   NodeWindowAgent  *f_node_window_agent;
711   WXmPushButton     f_button;
712   UAS_Pointer<UAS_Common>      f_toc_ptr;
713 };
714
715 void
716 Ancestor::update (const char *title, UAS_Pointer<UAS_Common> toc_ptr)
717 {
718   if (title != NULL)
719     {
720       f_button.LabelString (title);
721       if ((toc_ptr == 0)|| toc_ptr->data_length() == 0)
722         {
723           f_button.Set (WArgList (XmNshadowThickness, 0,
724                                   XmNmarginWidth, 4,
725                                   XmNmarginHeight, 4,
726                                   NULL));
727         }
728       else
729         {
730           f_button.Set (WArgList (XmNshadowThickness, 2,
731                                   XmNmarginWidth, 2,
732                                   XmNmarginHeight, 2,
733                                   NULL));
734         }
735       f_button.Manage();
736     }
737   else
738     {
739       f_button.Unmanage();
740     }
741   f_toc_ptr = toc_ptr;
742 }
743
744 void
745 Ancestor::activate()
746 {
747     if (f_toc_ptr == (UAS_Pointer<UAS_Common>)NULL) 
748     {
749         return;
750     }
751     UAS_Pointer<UAS_Common> current;
752     current = f_node_window_agent->f_node_view_info->node_ptr();
753
754     // Avoid redisplaying the current document.
755     if (f_toc_ptr == current) 
756     {
757         return;
758     }
759     
760     if (f_toc_ptr != (UAS_Pointer<UAS_Common>)NULL)
761     {
762         node_mgr().set_preferred_window (f_node_window_agent);
763         f_toc_ptr->retrieve();
764     }
765 }
766
767
768 #undef CLASS
769 #define CLASS NodeWindowAgent
770
771 // /////////////////////////////////////////////////////////////////
772 // class constructor
773 // /////////////////////////////////////////////////////////////////
774
775 NodeWindowAgent::NodeWindowAgent (u_int serial_no)
776 : IcccmAgent((void*)this,(data_handler_t)&NodeWindowAgent::do_search_selection),
777   f_node_view_info (NULL),
778   f_shell (NULL),
779   f_help_dsp_area (NULL),
780   f_close(NULL),
781   f_current_ancestor (NULL),
782   f_form(NULL),
783   f_preview_timeout (NULL),
784   f_serial_number(serial_no),
785   f_history_display (FALSE),
786   f_vscrollbar_offset(0),
787   f_hscrollbar_offset(0),
788   f_graphic_segment(NULL),
789   f_graphics_handler(NULL),
790   f_close_sensitive(FALSE)
791 {
792     UAS_Common::request ((UAS_Receiver<UAS_LibraryDestroyedMsg> *) this);
793
794     // request MarkCreated messages
795     mark_mgr().request(this);
796     // request MarkDeleted/Changed etc messages
797     Mark::request (this);
798 }
799
800
801 // /////////////////////////////////////////////////////////////////
802 // class destructor
803 // /////////////////////////////////////////////////////////////////
804
805 NodeWindowAgent::~NodeWindowAgent()
806 {
807   List_Iterator<Ancestor *> i (f_ancestor_list);
808   while (i)
809     {
810       delete i.item();
811       f_ancestor_list.remove (i);
812     }
813
814   List_Iterator<BookTab *> t (f_tab_btn_list);
815   while (t)
816     {
817       delete t.item();
818       f_tab_btn_list.remove (t);
819     }
820
821 #ifdef LICENSE_MANAGEMENT
822   f_node_view_info->node_ptr()->returnlicense();
823 #endif
824
825   cleanup_marks();
826
827   node_mgr().agent_deleted (this);
828
829   // The above call kills all the widgets.  
830   if (f_graphics_handler)
831     delete f_graphics_handler ;
832
833   // clean things up so that the help display area deletion
834   // will not stomp on the memory we free when deleting the nodeviewinfo
835   _DtCanvasDestroy(f_help_dsp_area->canvas);
836   f_help_dsp_area->canvas = NULL ;
837   delete f_node_view_info;
838
839   f_help_dsp_area->canvas = NULL ;
840
841   delete f_scope_menu;
842   delete f_wm_delete_callback;
843   f_shell->Destroy();
844 }
845
846
847 // /////////////////////////////////////////////////////////////////
848 // file Callbacks
849 // /////////////////////////////////////////////////////////////////
850
851 static void
852 exitCB(Widget, XtPointer client_data, XtPointer)
853 {
854   NodeWindowAgent *agent = (NodeWindowAgent*)client_data;
855   agent->exit_cb();
856 #if 0
857   if (BookmarkEdit::modified_count() > 0)
858     {
859       bool resp;
860       resp = message_mgr().question_dialog (
861                 (char*)UAS_String(CATGETS(Set_Messages, 2,
862                                 "Do you want to abandon your changes?")));
863       if (! resp)
864         return;
865     }
866
867   message_mgr().quit_dialog (
868         (char*)UAS_String(CATGETS(Set_Messages, 6,
869                                 "Do you really want to quit Dtinfo?")));
870 #endif
871 }
872
873 // /////////////////////////////////////////////////////////////////
874 // options Callbacks
875 // /////////////////////////////////////////////////////////////////
876
877 static void
878 tool_bar_toggleCB(Widget, XtPointer client_data, XtPointer call_data)
879 {
880   Widget tool_bar = (Widget) client_data;
881   XmToggleButtonCallbackStruct *cdata =
882       (XmToggleButtonCallbackStruct *) call_data;
883
884   if (cdata->set)
885       XtManageChild(tool_bar);
886   else
887       XtUnmanageChild(tool_bar);
888 }
889
890 static void
891 search_area_toggleCB(Widget, XtPointer client_data, XtPointer call_data)
892 {
893   Widget search_area = (Widget) client_data;
894   XmToggleButtonCallbackStruct *cdata =
895       (XmToggleButtonCallbackStruct *) call_data;
896
897   if (cdata->set)
898       XtManageChild(search_area);
899   else
900       XtUnmanageChild(search_area);
901 }
902
903 // /////////////////////////////////////////////////////////////////
904 // windows Callbacks
905 // /////////////////////////////////////////////////////////////////
906
907 static void
908 show_booklistCB(Widget, XtPointer, XtPointer)
909 {
910   UAS_List<UAS_String> env_infolibs(env().infolibs());
911   library_mgr().init(env_infolibs);
912 }
913
914 static void
915 show_mapCB(Widget, XtPointer client_data, XtPointer)
916 {
917   Wait_Cursor bob;
918   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
919   UAS_Pointer<UAS_Common> bogus;
920   map_mgr().display_centered_on (bogus = agent->node_view_info()->node_ptr());
921 }
922
923 static void query_editorCB(Widget, XtPointer, XtPointer);
924 static void mark_listCB(Widget, XtPointer, XtPointer);
925 static void prefsCB(Widget, XtPointer, XtPointer);
926 static void section_historyCB(Widget, XtPointer, XtPointer);
927 static void open_urlCB(Widget, XtPointer, XtPointer);
928 static void search_historyCB(Widget, XtPointer, XtPointer);
929 static void scope_editorCB(Widget, XtPointer, XtPointer);
930
931
932 // /////////////////////////////////////////////////////////////////
933 // create_ui - create the user interface
934 // /////////////////////////////////////////////////////////////////
935
936 void
937 NodeWindowAgent::create_ui()
938 {
939   Widget widget;
940   Arg args[5];
941   int n;
942
943   XmStringLocalized mtfstring;
944   String            string;
945   KeySym            mnemonic;
946
947   UAS_Pointer<UAS_String> textstore;
948
949 //  Widget w = XtCreatePopupShell("nodeview", topLevelShellWidgetClass,
950 //                              (Widget) toplevel(), NULL, 0);
951
952   f_shell = (WTopLevelShell*)(Widget)
953       WTopLevelShell (toplevel(), WPopup, "nodeview");
954
955   window_system().register_shell (f_shell);
956
957   string = CATGETS(Set_NodeWindowAgent, 1, "Dtinfo: Browser");
958   XtVaSetValues((Widget)f_shell, XmNtitle, string, NULL);
959
960   f_wm_delete_callback = 
961       new WCallback (*f_shell, window_system().WM_DELETE_WINDOW(),
962                      this, (WWL_FUN) &NodeWindowAgent::dismiss);
963
964   WindowGeometry wg = pref_mgr().get_geometry (PrefMgr::BrowseGeometry);
965   f_shell->Set(WArgList(XmNwidth, wg.width, XmNheight, wg.height, NULL));
966
967   Widget mainw = XtCreateWidget("mainw", xmMainWindowWidgetClass,
968                                 *f_shell, 0, 0);
969
970   n = 0;
971   XtSetArg(args[n], XmNscrolledWindowChildType, XmMENU_BAR); n++;
972   Widget menu_bar = XmCreateMenuBar(mainw, (char*)"menu_bar", args, n);
973
974   n = 0;
975   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
976   XtSetArg(args[n], XmNscrolledWindowChildType, XmCOMMAND_WINDOW); n++;
977   Widget tool_bar = XtCreateWidget("tool_bar", xmRowColumnWidgetClass,
978                                    mainw, args, n);
979
980   n = 0;
981   XtSetArg(args[n], XmNscrolledWindowChildType, XmMESSAGE_WINDOW); n++;
982   Widget search_area = XtCreateWidget("search_area", xmFormWidgetClass,
983                                       mainw, args, n);
984
985   // Menus
986   Widget fileM = XmCreatePulldownMenu(menu_bar, (char*)"file_menu", 0, 0);
987
988   n = 0;
989   XtSetArg(args[n], XmNsubMenuId, fileM); n++;
990   widget = XtCreateManagedWidget("file", xmCascadeButtonGadgetClass,
991                         menu_bar, args, n);
992   help_agent().add_help_cb(widget);
993
994
995   mtfstring =  CATGETS(Set_AgentLabel, 62, "Browser");
996   mnemonic  = *CATGETS(Set_AgentLabel, 63, "");
997   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
998
999   widget = XtCreateManagedWidget("new", xmPushButtonGadgetClass, fileM, 0, 0);
1000   XtAddCallback(widget, XmNactivateCallback, cloneCB, this);
1001
1002   mtfstring =  CATGETS(Set_AgentLabel, 64, "New Window");
1003   mnemonic  = *CATGETS(Set_AgentLabel, 65, "");
1004   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1005
1006   XtCreateManagedWidget("sep1", xmSeparatorGadgetClass, fileM, 0, 0);
1007
1008   f_print_as = XtCreateManagedWidget("print_as", xmPushButtonGadgetClass,
1009                                      fileM, 0, 0);
1010   XtAddCallback(f_print_as, XmNactivateCallback, print_asCB, this);
1011
1012   mtfstring =  CATGETS(Set_AgentLabel, 72, "Print...");
1013   mnemonic  = *CATGETS(Set_AgentLabel, 71, "P");
1014   XtVaSetValues(f_print_as, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1015
1016   XtCreateManagedWidget("sep2", xmSeparatorGadgetClass, fileM, 0, 0);
1017
1018   widget = XtCreateManagedWidget("show", xmPushButtonGadgetClass, fileM, 0, 0);
1019   XtAddCallback(widget, XmNactivateCallback, show_locatorCB, this);
1020
1021   mtfstring =  CATGETS(Set_AgentLabel, 68, "Show Locator");
1022   mnemonic  = *CATGETS(Set_AgentLabel, 69, "");
1023   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1024
1025   XtCreateManagedWidget("sep3", xmSeparatorGadgetClass, fileM, 0, 0);
1026
1027   n = 0;
1028   XtSetArg(args[n], XmNsensitive, f_close_sensitive); n++;
1029   f_close = XtCreateManagedWidget("close", xmPushButtonGadgetClass,
1030                                   fileM, args, n);
1031   XtAddCallback(f_close, XmNactivateCallback, dismissCB, this);
1032
1033   mtfstring =  CATGETS(Set_AgentLabel, 74, "Close");
1034   mnemonic  = *CATGETS(Set_AgentLabel, 75, "");
1035   XtVaSetValues(f_close, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1036
1037   widget = XtCreateManagedWidget("exit", xmPushButtonGadgetClass, fileM, 0, 0);
1038   XtAddCallback(widget, XmNactivateCallback, exitCB, this);
1039
1040   mtfstring =  CATGETS(Set_AgentLabel, 76, "Exit");
1041   mnemonic  = *CATGETS(Set_AgentLabel, 77, "");
1042   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1043
1044   // search menu
1045   Widget searchM = XmCreatePulldownMenu(menu_bar, (char*)"search_menu", 0, 0);
1046
1047   n = 0;
1048   XtSetArg(args[n], XmNsubMenuId, searchM); n++;
1049   f_search_menu_button = XtCreateManagedWidget("search",
1050                                                xmCascadeButtonGadgetClass,
1051                                                menu_bar, args, n);
1052   help_agent().add_help_cb(f_search_menu_button);
1053
1054   mtfstring =  CATGETS(Set_AgentLabel, 102, "Search");
1055   mnemonic  = *CATGETS(Set_AgentLabel, 103, "");
1056   XtVaSetValues(f_search_menu_button, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1057
1058   widget = XtCreateManagedWidget("on_selection", xmPushButtonGadgetClass,
1059                               searchM, 0, 0);
1060   XtAddCallback(widget, XmNactivateCallback, search_on_selectionCB, this);
1061
1062   mtfstring =  CATGETS(Set_AgentLabel, 78, "On Selection");
1063   mnemonic  = *CATGETS(Set_AgentLabel, 79, "");
1064   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1065
1066   widget = XtCreateManagedWidget("query_editor", xmPushButtonGadgetClass,
1067                               searchM, 0, 0);
1068   XtAddCallback(widget, XmNactivateCallback, query_editorCB, 0);
1069
1070   mtfstring =  CATGETS(Set_AgentLabel, 80, "Query Editor");
1071   mnemonic  = *CATGETS(Set_AgentLabel, 81, "");
1072   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1073
1074   widget = XtCreateManagedWidget("scope_editor", xmPushButtonGadgetClass,
1075                               searchM, 0, 0);
1076   XtAddCallback(widget, XmNactivateCallback, scope_editorCB, 0);
1077
1078   mtfstring =  CATGETS(Set_AgentLabel, 82, "Scope Editor");
1079   mnemonic  = *CATGETS(Set_AgentLabel, 83, "");
1080   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1081
1082   XtCreateManagedWidget("sep1", xmSeparatorGadgetClass, searchM, 0, 0);
1083
1084   widget = XtCreateManagedWidget("search_history", xmPushButtonGadgetClass,
1085                               searchM, 0, 0);
1086   XtAddCallback(widget, XmNactivateCallback, search_historyCB, 0);
1087
1088   mtfstring =  CATGETS(Set_AgentLabel, 84, "Search History");
1089   mnemonic  = *CATGETS(Set_AgentLabel, 85, "");
1090   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1091
1092   XtCreateManagedWidget("sep2", xmSeparatorGadgetClass, searchM, 0, 0);
1093
1094   f_clear_search_hits =
1095         XtCreateManagedWidget("clear_search", xmPushButtonGadgetClass,
1096                               searchM, 0, 0);
1097   XtAddCallback(f_clear_search_hits, XmNactivateCallback, clear_searchCB, this);
1098
1099   XtVaSetValues(f_clear_search_hits,
1100         XmNlabelString,
1101         (XmString)XmStringLocalized(CATGETS(Set_AgentLabel, 86, "Clear Search Hits")),
1102         XmNmnemonic,
1103         *CATGETS(Set_AgentLabel, 87, ""),
1104         NULL);
1105
1106   XtCreateManagedWidget("sep3", xmSeparatorGadgetClass, searchM, 0, 0);
1107
1108   f_search_prev = XtCreateManagedWidget("search_prev",
1109                                         xmPushButtonGadgetClass, searchM, 0, 0);
1110   XtAddCallback(f_search_prev, XmNactivateCallback, search_previousCB, this);
1111
1112   mtfstring =  CATGETS(Set_AgentLabel, 98, "Previous Search");
1113   mnemonic  = *CATGETS(Set_AgentLabel, 99, "");
1114   XtVaSetValues(f_search_prev, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1115
1116   f_search_next = XtCreateManagedWidget("search_next",
1117                                         xmPushButtonGadgetClass, searchM, 0, 0);
1118   XtAddCallback(f_search_next, XmNactivateCallback, search_nextCB, this);
1119
1120   mtfstring =  CATGETS(Set_AgentLabel, 100, "Next Search");
1121   mnemonic  = *CATGETS(Set_AgentLabel, 101, "");
1122   XtVaSetValues(f_search_next, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1123
1124   // go menu
1125   Widget goM = XmCreatePulldownMenu(menu_bar, (char*)"go_menu", 0, 0);
1126   n = 0;
1127   XtSetArg(args[n], XmNsubMenuId, goM); n++;
1128   widget = XtCreateManagedWidget("go", xmCascadeButtonGadgetClass,
1129                         menu_bar, args, n);
1130   help_agent().add_help_cb(widget);
1131
1132   mtfstring =  CATGETS(Set_AgentLabel, 104, "Go");
1133   mnemonic  = *CATGETS(Set_AgentLabel, 105, "");
1134   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1135
1136   f_history_prev = XtCreateManagedWidget("history_prev",
1137                                          xmPushButtonGadgetClass, goM, 0, 0);
1138   XtAddCallback(f_history_prev, XmNactivateCallback, history_prevCB, this);
1139   XtAddCallback(f_history_prev, XmNarmCallback, preview_history_prevCB, this);
1140   XtAddCallback(f_history_prev, XmNdisarmCallback, unpreviewCB, this);
1141
1142   mtfstring =  CATGETS(Set_AgentLabel, 88, "Back (History)");
1143   mnemonic  = *CATGETS(Set_AgentLabel, 89, "");
1144   XtVaSetValues(f_history_prev, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1145
1146   f_history_next = XtCreateManagedWidget("history_next",
1147                                          xmPushButtonGadgetClass, goM, 0, 0);
1148   XtAddCallback(f_history_next, XmNactivateCallback, history_nextCB, this);
1149   XtAddCallback(f_history_next, XmNarmCallback, preview_history_nextCB, this);
1150   XtAddCallback(f_history_next, XmNdisarmCallback, unpreviewCB, this);
1151
1152   mtfstring =  CATGETS(Set_AgentLabel, 90, "Forward (History)");
1153   mnemonic  = *CATGETS(Set_AgentLabel, 91, "");
1154   XtVaSetValues(f_history_next, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1155
1156   widget = XtCreateManagedWidget("section_history",
1157                               xmPushButtonGadgetClass, goM, 0, 0);
1158   XtAddCallback(widget, XmNactivateCallback, section_historyCB, 0);
1159
1160   mtfstring =  CATGETS(Set_AgentLabel, 92, "History...");
1161   mnemonic  = *CATGETS(Set_AgentLabel, 93, "");
1162   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1163
1164   XtCreateManagedWidget("sep1", xmSeparatorGadgetClass, goM, 0, 0);
1165
1166   f_node_next = XtCreateManagedWidget("section_next",
1167                                       xmPushButtonGadgetClass, goM, 0, 0);
1168   XtAddCallback(f_node_next, XmNactivateCallback, node_nextCB, this);
1169   XtAddCallback(f_node_next, XmNarmCallback, preview_nextCB, this);
1170   XtAddCallback(f_node_next, XmNdisarmCallback, unpreviewCB, this);
1171
1172   mtfstring =  CATGETS(Set_AgentLabel, 96, "Next Section");
1173   mnemonic  = *CATGETS(Set_AgentLabel, 97, "");
1174   XtVaSetValues(f_node_next, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1175
1176   f_node_prev = XtCreateManagedWidget("section_prev",
1177                                       xmPushButtonGadgetClass, goM, 0, 0);
1178   XtAddCallback(f_node_prev, XmNactivateCallback, node_previousCB, this);
1179   XtAddCallback(f_node_prev, XmNarmCallback, preview_previousCB, this);
1180   XtAddCallback(f_node_prev, XmNdisarmCallback, unpreviewCB, this);
1181
1182   mtfstring =  CATGETS(Set_AgentLabel, 94, "Previous Section");
1183   mnemonic  = *CATGETS(Set_AgentLabel, 95, "");
1184   XtVaSetValues(f_node_prev, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1185
1186   XtCreateManagedWidget("sep2", xmSeparatorGadgetClass, goM, 0, 0);
1187
1188   widget = XtCreateManagedWidget("open", xmPushButtonGadgetClass, goM, 0, 0);
1189   XtAddCallback(widget, XmNactivateCallback, open_urlCB, 0);
1190
1191   mtfstring =  CATGETS(Set_AgentLabel, 66, "Open Locator...");
1192   mnemonic  = *CATGETS(Set_AgentLabel, 67, "");
1193   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1194
1195   // marks menu
1196   Widget markM = XmCreatePulldownMenu(menu_bar, (char*)"marks_menu", 0, 0);
1197
1198   n = 0;
1199   XtSetArg(args[n], XmNsubMenuId, markM); n++;
1200   widget = XtCreateManagedWidget("marks", xmCascadeButtonGadgetClass,
1201                         menu_bar, args, n);
1202   help_agent().add_help_cb(widget);
1203
1204   mtfstring =  CATGETS(Set_AgentLabel, 106, "Marks");
1205   mnemonic  = *CATGETS(Set_AgentLabel, 107, "");
1206   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1207
1208   f_create_bmrk = XtCreateManagedWidget("create_bmrk",
1209                                         xmPushButtonGadgetClass,
1210                                         markM, 0, 0);
1211   XtAddCallback(f_create_bmrk, XmNactivateCallback, create_bookmarkCB, this);
1212
1213   XmFontList bmfont;
1214   {
1215     XmFontList font;
1216     XtVaGetValues(f_create_bmrk, XmNfontList, &font, NULL);
1217     bmfont = XmFontListCopy(font);
1218   }
1219
1220   if (window_system().dtinfo_font())
1221     bmfont = XmFontListAppendEntry(bmfont, window_system().dtinfo_font());
1222
1223   mtfstring =  CATGETS(Set_AgentLabel, 108, "Create Bookmark");
1224   mnemonic  = *CATGETS(Set_AgentLabel, 109, "");
1225   XtVaSetValues(f_create_bmrk, XmNlabelString, (XmString)mtfstring,
1226                                XmNmnemonic, mnemonic,
1227                                XmNfontList, bmfont, NULL);
1228
1229   f_create_anno = XtCreateManagedWidget("create_anno",
1230                                         xmPushButtonGadgetClass,
1231                                         markM, 0, 0);
1232   XtAddCallback(f_create_anno, XmNactivateCallback, create_annotationCB, this);
1233
1234   mtfstring =  CATGETS(Set_AgentLabel, 110, "Create Note...");
1235   mnemonic  = *CATGETS(Set_AgentLabel, 111, "");
1236   XtVaSetValues(f_create_anno, XmNlabelString, (XmString)mtfstring,
1237                                XmNmnemonic, mnemonic,
1238                                XmNfontList, bmfont, NULL);
1239
1240   XtCreateManagedWidget("sep1", xmSeparatorGadgetClass, markM, 0, 0);
1241
1242   Widget list_marks = XtCreateManagedWidget("list_marks",
1243                                             xmPushButtonGadgetClass,
1244                                             markM, 0, 0);
1245   XtAddCallback(list_marks, XmNactivateCallback, mark_listCB, 0);
1246
1247   mtfstring =  CATGETS(Set_AgentLabel, 112, "List Marks");
1248   mnemonic  = *CATGETS(Set_AgentLabel, 113, "");
1249   XtVaSetValues(list_marks, XmNlabelString, (XmString)mtfstring,
1250                             XmNmnemonic, mnemonic,
1251                             XmNfontList, bmfont, NULL);
1252
1253   XtCreateManagedWidget("sep2", xmSeparatorGadgetClass, markM, 0, 0);
1254
1255   f_edit_mark = XtCreateManagedWidget("edit_mark",
1256                                       xmPushButtonGadgetClass, markM, 0, 0);
1257   XtAddCallback(f_edit_mark, XmNactivateCallback, edit_markCB, this);
1258
1259   mtfstring =  CATGETS(Set_AgentLabel, 114, "Edit Selection...");
1260   mnemonic  = *CATGETS(Set_AgentLabel, 115, "");
1261   XtVaSetValues(f_edit_mark, XmNlabelString, (XmString)mtfstring,
1262                              XmNmnemonic, mnemonic,
1263                              XmNfontList, bmfont, NULL);
1264
1265   f_move_mark = XtCreateManagedWidget("move_mark",
1266                                       xmPushButtonGadgetClass, markM, 0, 0);
1267   XtAddCallback(f_move_mark, XmNactivateCallback, move_markCB, this);
1268
1269   mtfstring =  CATGETS(Set_AgentLabel, 116, "Move Selection");
1270   mnemonic  = *CATGETS(Set_AgentLabel, 117, "");
1271   XtVaSetValues(f_move_mark, XmNlabelString, (XmString)mtfstring,
1272                              XmNmnemonic, mnemonic,
1273                              XmNfontList, bmfont, NULL);
1274
1275   f_delete_mark = XtCreateManagedWidget("delete_mark",
1276                                         xmPushButtonGadgetClass,
1277                                         markM, 0, 0);
1278   XtAddCallback(f_delete_mark, XmNactivateCallback, delete_markCB, this);
1279
1280   mtfstring =  CATGETS(Set_AgentLabel, 118, "Delete Selection");
1281   mnemonic  = *CATGETS(Set_AgentLabel, 119, "");
1282   XtVaSetValues(f_delete_mark, XmNlabelString, (XmString)mtfstring,
1283                                XmNmnemonic, mnemonic,
1284                                XmNfontList, bmfont, NULL);
1285
1286   // Add the icons to the beginning of the label strings
1287   if (!window_system().nofonts())
1288     {
1289         char icon[3];
1290         icon[1] = OLIAS_SPACE04;
1291         icon[2] = '\0';
1292         XmString string;
1293
1294         icon[0] = OLIAS_BOOKMARK_ICON;
1295         n = 0;
1296         XtSetArg(args[n], XmNlabelString, &string); n++;
1297         XtGetValues(f_create_bmrk, args, n);
1298         n = 0;
1299         XtSetArg(args[n], XmNlabelString,
1300                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1301                                 string)); n++;
1302         XtSetValues(f_create_bmrk, args, n);
1303
1304         icon[0] = OLIAS_ANNOTATION_ICON;
1305         n = 0;
1306         XtSetArg(args[n], XmNlabelString, &string); n++;
1307         XtGetValues(f_create_anno, args, n);
1308         n = 0;
1309         XtSetArg(args[n], XmNlabelString,
1310                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1311                                 string)); n++;
1312         XtSetValues(f_create_anno, args, n);
1313
1314         icon[0] = OLIAS_SPACE16;
1315         n = 0;
1316         XtSetArg(args[n], XmNlabelString, &string); n++;
1317         XtGetValues(f_move_mark, args, n);
1318         n = 0;
1319         XtSetArg(args[n], XmNlabelString,
1320                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1321                                 string)); n++;
1322         XtSetValues(f_move_mark, args, n);
1323
1324         n = 0;
1325         XtSetArg(args[n], XmNlabelString, &string); n++;
1326         XtGetValues(list_marks, args, n);
1327         n = 0;
1328         XtSetArg(args[n], XmNlabelString,
1329                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1330                                 string)); n++;
1331         XtSetValues(list_marks, args, n);
1332
1333         n = 0;
1334         XtSetArg(args[n], XmNlabelString, &string); n++;
1335         XtGetValues(f_edit_mark, args, n);
1336         n = 0;
1337         XtSetArg(args[n], XmNlabelString,
1338                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1339                                 string)); n++;
1340         XtSetValues(f_edit_mark, args, n);
1341
1342         n = 0;
1343         XtSetArg(args[n], XmNlabelString, &string); n++;
1344         XtGetValues(f_delete_mark, args, n);
1345         n = 0;
1346         XtSetArg(args[n], XmNlabelString,
1347                  XmStringConcat(XmStringCreate(icon, (char*)OLIAS_FONT),
1348                                 string)); n++;
1349         XtSetValues(f_delete_mark, args, n);
1350     }
1351
1352   // options menu
1353   Widget optionsM = XmCreatePulldownMenu(menu_bar, (char*)"options_menu", 0, 0);
1354
1355   n = 0;
1356   XtSetArg(args[n], XmNsubMenuId, optionsM); n++;
1357   widget = XtCreateManagedWidget("options", xmCascadeButtonGadgetClass,
1358                         menu_bar, args, n);
1359   help_agent().add_help_cb(widget);
1360
1361   mtfstring =  CATGETS(Set_AgentLabel, 120, "Options");
1362   mnemonic  = *CATGETS(Set_AgentLabel, 121, "");
1363   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1364
1365   widget = XtCreateManagedWidget("preferences", xmPushButtonGadgetClass,
1366                               optionsM, 0, 0);
1367   XtAddCallback(widget, XmNactivateCallback, prefsCB, 0);
1368
1369   mtfstring =  CATGETS(Set_AgentLabel, 122, "Preferences...");
1370   mnemonic  = *CATGETS(Set_AgentLabel, 123, "");
1371   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1372
1373   XtCreateManagedWidget("sep1", xmSeparatorGadgetClass, optionsM, 0, 0);
1374
1375   f_detach_graphic = XtCreateManagedWidget("detach_graphic",
1376                                            xmPushButtonGadgetClass,
1377                                            optionsM, 0, 0);
1378   XtAddCallback(f_detach_graphic, XmNactivateCallback, detach_graphicCB, this);
1379
1380   mtfstring =  CATGETS(Set_AgentLabel, 124, "Detach Graphic");
1381   mnemonic  = *CATGETS(Set_AgentLabel, 125, "");
1382   XtVaSetValues(f_detach_graphic, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1383
1384   XtCreateManagedWidget("sep2", xmSeparatorGadgetClass, optionsM, 0, 0);
1385
1386   Widget tool_barT = XtCreateManagedWidget("show_tool_bar",
1387                                            xmToggleButtonGadgetClass,
1388                                            optionsM, 0, 0);
1389   XtAddCallback(tool_barT, XmNvalueChangedCallback,
1390                 tool_bar_toggleCB, tool_bar);
1391
1392   mtfstring =  CATGETS(Set_AgentLabel, 126, "Show Tool Bar");
1393   mnemonic  = *CATGETS(Set_AgentLabel, 127, "");
1394   XtVaSetValues(tool_barT, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1395
1396   Widget search_areaT = XtCreateManagedWidget("show_search_area",
1397                                               xmToggleButtonGadgetClass,
1398                                               optionsM, 0, 0);
1399   XtAddCallback(search_areaT, XmNvalueChangedCallback,
1400                 search_area_toggleCB, search_area);
1401
1402   mtfstring =  CATGETS(Set_AgentLabel, 128, "Show Search Area");
1403   mnemonic  = *CATGETS(Set_AgentLabel, 129, "");
1404   XtVaSetValues(search_areaT, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1405
1406   // windows menu
1407   Widget windowsM = XmCreatePulldownMenu(menu_bar, (char*)"windows_menu", 0, 0);
1408
1409   n = 0;
1410   XtSetArg(args[n], XmNsubMenuId, windowsM); n++;
1411   widget = XtCreateManagedWidget("windows", xmCascadeButtonGadgetClass,
1412                         menu_bar, args, n);
1413   help_agent().add_help_cb(widget);
1414
1415   mtfstring =  CATGETS(Set_AgentLabel, 130, "Windows");
1416   mnemonic  = *CATGETS(Set_AgentLabel, 131, "");
1417   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1418
1419   widget = XtCreateManagedWidget("booklist", xmPushButtonGadgetClass,
1420                               windowsM, 0, 0);
1421   XtAddCallback(widget, XmNactivateCallback, show_booklistCB, 0);
1422
1423   mtfstring =  CATGETS(Set_AgentLabel, 132, "Book List");
1424   mnemonic  = *CATGETS(Set_AgentLabel, 133, "");
1425   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1426
1427   widget = XtCreateManagedWidget("graphical_map", xmPushButtonGadgetClass,
1428                               windowsM, 0, 0);
1429   XtAddCallback(widget, XmNactivateCallback, show_mapCB, this);
1430
1431   mtfstring =  CATGETS(Set_AgentLabel, 134, "Graphical Map");
1432   mnemonic  = *CATGETS(Set_AgentLabel, 135, "");
1433   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1434
1435
1436   // help menu
1437   Widget helpM = XmCreatePulldownMenu(menu_bar, (char*)"help_menu", 0, 0);
1438   n = 0;
1439   XtSetArg(args[n], XmNsubMenuId, helpM); n++;
1440   widget = XtCreateManagedWidget("help", xmCascadeButtonGadgetClass,
1441                               menu_bar, args, n);
1442   help_agent().add_help_cb(widget);
1443
1444   n = 0;
1445   XtSetArg(args[n], XmNmenuHelpWidget, widget); n++;
1446   XtSetValues(menu_bar, args, n);
1447
1448   mtfstring =  CATGETS(Set_AgentLabel, 143, "Help");
1449   mnemonic  = *CATGETS(Set_AgentLabel, 144, "");
1450   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, XmNmnemonic, mnemonic, NULL);
1451
1452 #define AM WAutoManage
1453
1454   WXmPushButton      on_overview        (helpM,      "on_overview", AM);
1455   WXmSeparator       on_sep1            (helpM,      "on_sep1", AM);
1456   WXmPushButton      on_tasks           (helpM,      "on_tasks", AM);
1457   WXmPushButton      on_reference       (helpM,      "on_reference", AM);
1458   WXmPushButton      on_item            (helpM,      "on_item", AM);
1459   WXmSeparator       on_sep2            (helpM,      "on_sep2", AM);
1460   WXmPushButton      on_help            (helpM,      "on_help"       , AM);
1461   WXmSeparator       on_sep3            (helpM,      "on_sep3", AM);
1462   WXmPushButton      on_about           (helpM,      "on_about"       , AM);
1463
1464
1465   //WXmPushButton      on_window        (helpM,      "on_window"     , AM);
1466 //  WXmPushButton      on_application  (helpM,      "on_application", AM);
1467 //  WXmPushButton      index           (helpM,      "index"         , AM);
1468   //WXmPushButton      on_keys         (helpM,      "on_keys"       , AM);
1469   //WXmPushButton      on_version      (helpM,      "on_version"    , AM);
1470   //ON_ACTIVATE (on_version,            display_version);
1471
1472   mtfstring =  CATGETS(Set_AgentLabel, 257, "Overview");
1473   mnemonic  = *CATGETS(Set_AgentLabel, 258, "");
1474   XtVaSetValues((Widget)on_overview, XmNlabelString, (XmString)mtfstring,
1475                                     XmNmnemonic, mnemonic, NULL);
1476
1477   mtfstring =  CATGETS(Set_AgentLabel, 249, "Tasks");
1478   mnemonic  = *CATGETS(Set_AgentLabel, 250, "");
1479   XtVaSetValues((Widget)on_tasks, XmNlabelString, (XmString)mtfstring,
1480                                     XmNmnemonic, mnemonic, NULL);
1481
1482   mtfstring =  CATGETS(Set_AgentLabel, 251, "Reference");
1483   mnemonic  = *CATGETS(Set_AgentLabel, 252, "");
1484   XtVaSetValues((Widget)on_reference, XmNlabelString, (XmString)mtfstring,
1485                                     XmNmnemonic, mnemonic, NULL);
1486
1487   mtfstring =  CATGETS(Set_AgentLabel, 50, "On Item...");
1488   mnemonic  = *CATGETS(Set_AgentLabel, 51, "");
1489   XtVaSetValues((Widget)on_item, XmNlabelString, (XmString)mtfstring,
1490                                     XmNmnemonic, mnemonic, NULL);
1491
1492   mtfstring =  CATGETS(Set_AgentLabel, 253, "Using Help");
1493   mnemonic  = *CATGETS(Set_AgentLabel, 254, "");
1494   XtVaSetValues((Widget)on_help, XmNlabelString, (XmString)mtfstring,
1495                                     XmNmnemonic, mnemonic, NULL);
1496
1497   mtfstring =  CATGETS(Set_AgentLabel, 255, "About Information Manager");
1498   mnemonic  = *CATGETS(Set_AgentLabel, 256, "");
1499   XtVaSetValues((Widget)on_about, XmNlabelString, (XmString)mtfstring,
1500                                     XmNmnemonic, mnemonic, NULL);
1501
1502
1503 #ifdef EAM
1504   mtfstring =  CATGETS(Set_AgentLabel, 147, "On Window");
1505   mnemonic  = *CATGETS(Set_AgentLabel, 148, "");
1506   XtVaSetValues((Widget)on_window, XmNlabelString, (XmString)mtfstring,
1507                                     XmNmnemonic, mnemonic, NULL);
1508 //  mtfstring =  CATGETS(Set_AgentLabel, 149, "On Application");
1509 //  mnemonic  = *CATGETS(Set_AgentLabel, 150, "");
1510 //  XtVaSetValues((Widget)on_application, XmNlabelString, (XmString)mtfstring,
1511 //                                  XmNmnemonic, mnemonic, NULL);
1512 //  mtfstring =  CATGETS(Set_AgentLabel, 151, "Index");
1513 //  mnemonic  = *CATGETS(Set_AgentLabel, 152, "");
1514 //  XtVaSetValues((Widget)index, XmNlabelString, (XmString)mtfstring,
1515 //                                  XmNmnemonic, mnemonic, NULL);
1516   mtfstring =  CATGETS(Set_AgentLabel, 155, "On Keys");
1517   mnemonic  = *CATGETS(Set_AgentLabel, 156, "");
1518   XtVaSetValues((Widget)on_keys, XmNlabelString, (XmString)mtfstring,
1519                                     XmNmnemonic, mnemonic, NULL);
1520   mtfstring =  CATGETS(Set_AgentLabel, 157, "On Version");
1521   mnemonic  = *CATGETS(Set_AgentLabel, 158. "");
1522   XtVaSetValues((Widget)on_version, XmNlabelString, (XmString)mtfstring,
1523                                     XmNmnemonic, mnemonic, NULL);
1524   
1525 #endif
1526
1527   help_agent().add_activate_help ((Widget)on_overview, (char*)"on_overview");
1528   help_agent().add_activate_help ((Widget)on_tasks, (char*)"on_tasks");
1529   help_agent().add_activate_help ((Widget)on_reference, (char*)"on_reference");
1530   help_agent().add_activate_help ((Widget)on_reference, (char*)"on_reference");
1531   help_agent().add_context_help ((Widget)on_item);
1532   help_agent().add_activate_help ((Widget)on_help, (char*)"on_help");
1533   help_agent().add_activate_help ((Widget)on_about, (char*)"on_about");
1534
1535
1536   // Tools
1537   f_history_prev2 = XtCreateManagedWidget("history_prev",
1538                                           xmPushButtonWidgetClass,
1539                                           tool_bar, 0, 0);
1540   XtAddCallback(f_history_prev2, XmNactivateCallback, history_prevCB, this);
1541   XtAddCallback(f_history_prev2, XmNarmCallback, preview_history_prevCB, this);
1542   XtAddCallback(f_history_prev2, XmNdisarmCallback, unpreviewCB, this);
1543   help_agent().add_help_cb (f_history_prev2);
1544
1545   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 1,
1546                                 "Go to the previous section in history"));
1547   add_quick_help(f_history_prev2, (char*)*textstore);
1548   f_textstore.insert_item(textstore);
1549
1550   f_history_next2 = XtCreateManagedWidget("history_next",
1551                                           xmPushButtonWidgetClass,
1552                                           tool_bar, 0, 0);
1553   XtAddCallback(f_history_next2, XmNactivateCallback, history_nextCB, this);
1554   XtAddCallback(f_history_next2, XmNarmCallback, preview_history_nextCB, this);
1555   XtAddCallback(f_history_next2, XmNdisarmCallback, unpreviewCB, this);
1556   help_agent().add_help_cb (f_history_next2);
1557
1558   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 2,
1559                                 "Go to the next section in history"));
1560   add_quick_help(f_history_next2, (char*)*textstore);
1561   f_textstore.insert_item(textstore);
1562
1563   widget = XtCreateManagedWidget("space",
1564                                 xmLabelGadgetClass,
1565                                 tool_bar, 0, 0);
1566
1567   f_node_prev2 = XtCreateManagedWidget("section_prev",
1568                                        xmPushButtonWidgetClass,
1569                                        tool_bar, 0, 0);
1570   XtAddCallback(f_node_prev2, XmNactivateCallback, node_previousCB, this);
1571   XtAddCallback(f_node_prev2, XmNarmCallback, preview_previousCB, this);
1572   XtAddCallback(f_node_prev2, XmNdisarmCallback, unpreviewCB, this);
1573   help_agent().add_help_cb (f_node_prev2);
1574
1575   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 3,
1576                                 "Go to the previous section in document"));
1577   add_quick_help(f_node_prev2, (char*)*textstore);
1578   f_textstore.insert_item(textstore);
1579
1580   f_node_next2 = XtCreateManagedWidget("section_next",
1581                                        xmPushButtonWidgetClass,
1582                                        tool_bar, 0, 0);
1583   XtAddCallback(f_node_next2, XmNactivateCallback, node_nextCB, this);
1584   XtAddCallback(f_node_next2, XmNarmCallback, preview_nextCB, this);
1585   XtAddCallback(f_node_next2, XmNdisarmCallback, unpreviewCB, this);
1586   help_agent().add_help_cb (f_node_next2);
1587
1588   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 4,
1589                                 "Go to the next section in document"));
1590   add_quick_help(f_node_next2, (char*)*textstore);
1591   f_textstore.insert_item(textstore);
1592
1593   widget = XtCreateManagedWidget("space",
1594                                 xmLabelGadgetClass,
1595                                 tool_bar, 0, 0);
1596
1597   f_search_prev2 = XtCreateManagedWidget("search_prev",
1598                                          xmPushButtonWidgetClass,
1599                                          tool_bar, 0, 0);
1600   XtAddCallback(f_search_prev2, XmNactivateCallback, search_previousCB, this);
1601   help_agent().add_help_cb (f_search_prev2);
1602
1603   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 5,
1604                                 "Go to the previous search match"));
1605   add_quick_help(f_search_prev2, (char*)*textstore);
1606   f_textstore.insert_item(textstore);
1607
1608   f_search_next2 = XtCreateManagedWidget("search_next",
1609                                          xmPushButtonWidgetClass,
1610                                          tool_bar, 0, 0);
1611   XtAddCallback(f_search_next2, XmNactivateCallback, search_nextCB, this);
1612   help_agent().add_help_cb (f_search_next2);
1613
1614   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 6,
1615                                 "Go to the next search match"));
1616   add_quick_help(f_search_next2, (char*)*textstore);
1617   f_textstore.insert_item(textstore);
1618
1619
1620   widget = XtCreateManagedWidget("space",
1621                                 xmLabelGadgetClass,
1622                                 tool_bar, 0, 0);
1623
1624
1625   f_print2 = XtCreateManagedWidget("print", xmPushButtonWidgetClass,
1626                                    tool_bar, 0, 0);
1627   XtAddCallback(f_print2, XmNactivateCallback, printCB, this);
1628   help_agent().add_help_cb (f_print2);
1629
1630   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 7,
1631                                 "Print current section"));
1632   add_quick_help(f_print2, (char*)*textstore);
1633   f_textstore.insert_item(textstore);
1634
1635   widget = XtCreateManagedWidget("booklist", xmPushButtonWidgetClass,
1636                               tool_bar, 0, 0);
1637   XtAddCallback(widget, XmNactivateCallback, show_booklistCB, 0);
1638   help_agent().add_help_cb (widget);
1639
1640   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 8, "Display Book List"));
1641   add_quick_help(widget, (char*)*textstore);
1642   f_textstore.insert_item(textstore);
1643
1644   widget = XtCreateManagedWidget("graphical_map", xmPushButtonWidgetClass,
1645                               tool_bar, 0, 0);
1646   XtAddCallback(widget, XmNactivateCallback, show_mapCB, this);
1647   help_agent().add_help_cb (widget);
1648
1649   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 9,
1650                                         "Display Graphical Map"));
1651   add_quick_help(widget, (char*)*textstore);
1652   f_textstore.insert_item(textstore);
1653
1654   f_locked = pref_mgr().get_boolean (PrefMgr::BrowseLock);
1655   n = 0;
1656   XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
1657
1658   // The opposite state always needs to be the semilocked pixmap. 
1659   if (f_locked)
1660     {
1661         XtSetArg(args[n], XmNset, True); n++;
1662         XtSetArg(args[n], XmNselectPixmap,
1663                  window_system().locked_pixmap(tool_bar)); n++;
1664         XtSetArg(args[n], XmNlabelPixmap,
1665                  window_system().semilocked_pixmap(tool_bar)); n++;
1666       }
1667   else
1668     {
1669         XtSetArg(args[n], XmNset, False); n++;
1670         XtSetArg(args[n], XmNlabelPixmap,
1671                  window_system().unlocked_pixmap(tool_bar)); n++;
1672         XtSetArg(args[n], XmNselectPixmap,
1673                  window_system().semilocked_pixmap(tool_bar)); n++;
1674     }
1675
1676   widget = XtCreateManagedWidget("lock", xmToggleButtonWidgetClass,
1677                               tool_bar, args, n);
1678   XtAddCallback(widget, XmNvalueChangedCallback, lock_toggleCB, this);
1679   help_agent().add_help_cb (widget);
1680
1681   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 10,
1682                 "Pin (unpin) this window, "
1683                 "to prevent (allow) use for new documents."));
1684   add_quick_help(widget, (char*)*textstore);
1685   f_textstore.insert_item(textstore);
1686
1687   mtfstring =  CATGETS(Set_AgentLabel, 159, "Retain");
1688   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1689   
1690   // Work Window
1691   n = 0;
1692   XtSetArg(args[n], XmNscrolledWindowChildType, XmWORK_AREA); n++;
1693   f_form = XtCreateWidget("form", xmFormWidgetClass, mainw, args, n);
1694
1695
1696   f_title_menu = (WXmPulldownMenu*)(Widget)WXmPulldownMenu((WComposite&)f_form, (char*)"title_menu");
1697   n = 0;
1698   XtSetArg(args[n], XmNsubMenuId, (Widget) f_title_menu); n++;
1699   f_title_option = (WXmOptionMenu*)(Widget)
1700                    WXmOptionMenu ((WComposite&)f_form, (char*)"title", AM, args, n);
1701   help_agent().add_help_cb ((Widget)*f_title_option);
1702
1703   f_tab_area = (WXmRowColumn*)(Widget) WXmRowColumn (f_form, "tab_area");
1704   f_tab_area->Manage();
1705
1706   // this needs to be here for reference through the resources (attachments)
1707   Widget message = XtCreateManagedWidget("message", xmFrameWidgetClass,
1708                                          f_form, 0, 0);
1709
1710   // Status line
1711   Pixel fg, bg;
1712   n = 0;
1713   XtSetArg(args[n], XmNforeground, &fg); n++;
1714   XtSetArg(args[n], XmNbackground, &bg); n++;
1715   XtGetValues(message, args, n);
1716   n = 0;
1717   XtSetArg(args[n], XmNforeground, fg); n++;
1718   XtSetArg(args[n], XmNbackground, bg); n++;
1719   f_status_text = XtCreateManagedWidget("text", xmTextFieldWidgetClass,
1720                                         message, args, n);
1721   string = CATGETS(Set_NodeWindowAgent, 2, "To preview a link destination, "
1722                                            "click and hold on the link.");
1723   XtVaSetValues(f_status_text, XmNvalue, string, NULL);
1724
1725 #ifdef DEBUG
1726 #ifdef MONITOR
1727
1728   WXmCascadeButton   windows_cascade (menu_bar,     "windows"       ,   AM);
1729   WXmPulldownMenu    windows_menu    (menu_bar,     (char*)"windows_menu" );
1730   WXmPushButton(windows_menu, "monitor", AM).
1731     SetActivateCallback(this, (WWL_FUN)&NodeWindowAgent::monitor, (void*)1);
1732
1733   WXmPushButton(windows_menu, "monitor_off", AM).
1734     SetActivateCallback(this, (WWL_FUN)&NodeWindowAgent::monitor, 0);
1735
1736 #endif
1737 #endif
1738
1739 #ifdef NODEBUG
1740   WXmCascadeButton   debug_cascade     (menu_bar,   "debug"                );
1741   WXmPulldownMenu    debug_menu        (menu_bar,   (char*)"debug_menu"    );
1742   WXmToggleButton    command_processor (debug_menu, "command_processor", AM);
1743   WXmPushButton      document_id       (debug_menu, "document_id",       AM);
1744 #endif
1745
1746
1747   f_frame = (WXmFrame *)(Widget)WXmFrame (f_form, "frame"      , AM);
1748
1749   XmFontList defaultList = NULL;
1750   n = 0;
1751   XtSetArg (args[n], XmNfontList, &defaultList); ++n;
1752   XtGetValues(f_status_text, args, n);
1753
1754   f_help_dsp_area = (DtHelpDispAreaStruct*)
1755     _DtHelpCreateDisplayArea(WXmForm(*f_frame, "inform", WAutoManage),//parent
1756                              (char*)"display_area",     // name
1757                              _DtHelpSTATIC,     // vert flag
1758                              _DtHelpAS_NEEDED,  // horz flag
1759                              FALSE,             // traversal flag
1760                              1,                 // rows
1761                              1,                 // columns
1762                              (hypertext_cb_ptr) hypertext_cb, // hypertext cb
1763                              (resize_cb_ptr) resize_cb,       // resize cb
1764                              0,                 // exec ok routine
1765                              this,              // client_data
1766                              defaultList        // default font list
1767                              );
1768
1769   assert( f_help_dsp_area && f_help_dsp_area->canvas );
1770
1771   help_agent().add_help_cb (f_help_dsp_area->dispWid);
1772   help_agent().add_help_cb (f_help_dsp_area->vertScrollWid);
1773   help_agent().add_help_cb (f_help_dsp_area->horzScrollWid);
1774
1775   // create detach graphic popup menu
1776   f_detach_menu = XmCreatePopupMenu(
1777                        f_help_dsp_area->dispWid, (char*)"detach_graphic", NULL, 0);
1778   f_detach_button = XmCreatePushButton(f_detach_menu, (char*)"Detach Graphic", NULL, 0);
1779   XtAddCallback(f_detach_button, XmNactivateCallback, detach_grCB, this);
1780   XtManageChild(f_detach_button);
1781   mtfstring =  CATGETS(Set_AgentLabel, 124, "Detach Graphic");
1782   XtVaSetValues(f_detach_button, XmNlabelString, (XmString)mtfstring, NULL);
1783
1784   f_attach_button = XmCreatePushButton(f_detach_menu, (char*)"Attach Graphic", NULL, 0);
1785   XtAddCallback(f_attach_button, XmNactivateCallback, attach_grCB, this);
1786   XtManageChild(f_attach_button);
1787   mtfstring =  CATGETS(Set_AgentLabel, 265, "Attach Graphic");
1788   XtVaSetValues(f_attach_button, XmNlabelString, (XmString)mtfstring, NULL);
1789
1790   f_raise_button = XmCreatePushButton(f_detach_menu, (char*)"Raise Graphic", NULL, 0);
1791   XtAddCallback(f_raise_button, XmNactivateCallback, raise_grCB, this);
1792   XtManageChild(f_raise_button);
1793   mtfstring =  CATGETS(Set_AgentLabel, 264, "Raise Graphic");
1794   XtVaSetValues(f_raise_button, XmNlabelString, (XmString)mtfstring, NULL);
1795
1796   XtAddEventHandler (f_help_dsp_area->dispWid, ButtonPressMask, False, popup_menuCB, (XtPointer)this);
1797
1798
1799   // create link preview popup menu
1800   f_preview_menu = XmCreatePopupMenu(
1801                        f_help_dsp_area->dispWid, (char*)"preview_menu", NULL, 0);
1802
1803   f_preview_label = XmCreateLabel(f_preview_menu, (char*)"pre_label", NULL, 0);
1804   XtManageChild(f_preview_label);
1805
1806   widget = XmCreateSeparator(f_preview_menu, (char*)"sep", NULL, 0);
1807   XtVaSetValues(widget, XmNseparatorType, XmDOUBLE_LINE, NULL);
1808   XtManageChild(widget);
1809
1810   widget = XmCreatePushButton(f_preview_menu, (char*)"widget", NULL, 0);
1811   XtAddCallback(widget, XmNactivateCallback, go_to_linkCB, this);
1812   XtManageChild(widget);
1813   mtfstring =  CATGETS(Set_AgentLabel, 168, "Display Link");
1814   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1815
1816   widget = XmCreatePushButton(f_preview_menu, (char*)"widget", NULL, 0);
1817   XtAddCallback(widget, XmNactivateCallback, open_new_nodeCB, this);
1818   XtManageChild(widget);
1819   mtfstring =  CATGETS(Set_AgentLabel, 64, "New Window");
1820   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1821
1822   // create default popup menu
1823   f_default_menu = XmCreatePopupMenu(
1824                        f_help_dsp_area->dispWid, (char*)"default_menu",NULL, 0);
1825
1826   f_node_next3 = XmCreatePushButton(f_default_menu, (char*)"f_node_next3", NULL, 0);
1827   XtAddCallback(f_node_next3, XmNactivateCallback, node_nextCB, this);
1828   XtManageChild(f_node_next3);
1829   mtfstring =  CATGETS(Set_AgentLabel, 96, "Next Section");
1830   XtVaSetValues(f_node_next3, XmNlabelString, (XmString)mtfstring, NULL);
1831
1832   f_node_prev3 = XmCreatePushButton(f_default_menu, (char*)"f_node_prev3", NULL, 0);
1833   XtAddCallback(f_node_prev3, XmNactivateCallback, node_previousCB, this);
1834   XtManageChild(f_node_prev3);
1835   mtfstring =  CATGETS(Set_AgentLabel, 94, "Previous Section");
1836   XtVaSetValues(f_node_prev3, XmNlabelString, (XmString)mtfstring, NULL);
1837
1838   widget = XmCreateSeparator(f_default_menu, (char*)"sep", NULL, 0);
1839   XtManageChild(widget);
1840
1841   widget = XmCreatePushButton(f_default_menu, (char*)"widget", NULL, 0);
1842   XtAddCallback(widget, XmNactivateCallback, show_locatorCB, this);
1843   XtManageChild(widget);
1844   mtfstring =  CATGETS(Set_AgentLabel, 68, "Show Locator");
1845   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1846
1847   widget = XmCreateSeparator(f_default_menu, (char*)"sep", NULL, 0);
1848   XtManageChild(widget);
1849
1850   widget = XmCreatePushButton(f_default_menu, (char*)"widget", NULL, 0);
1851   XtAddCallback(widget, XmNactivateCallback, printCB, this);
1852   XtManageChild(widget);
1853   mtfstring =  CATGETS(Set_AgentLabel, 70, "Print");
1854   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1855
1856
1857
1858   f_help_dsp_area->vScrollNotify = v_scroll_notify ;
1859   f_help_dsp_area->armCallback   = arm_callback;
1860
1861   f_help_dsp_area->dtinfo = True;
1862
1863   if (MB_CUR_MAX > 1) {
1864
1865     // DtHelpDispAreaStruct cant_begin_chars
1866     WString cant_begin_chars = CATGETS(Set_NodeWindowAgent, 5, "");
1867     f_help_dsp_area->cant_begin_chars = cant_begin_chars.get_wstr();
1868
1869     // DtHelpDispAreaStruct cant_end_chars
1870     WString cant_end_chars = CATGETS(Set_NodeWindowAgent, 6, "");
1871     f_help_dsp_area->cant_end_chars = cant_end_chars.get_wstr();
1872
1873 #ifdef LB_DEBUG
1874     int i;
1875     for (i = 0; f_help_dsp_area->cant_begin_chars[i]; i++);
1876     fprintf(stderr, "(DEBUG) %d chars, cant_begin_chars=%s\n",
1877                                         i, cant_begin_chars.get_mbstr());
1878     for (i = 0; f_help_dsp_area->cant_end_chars[i]; i++);
1879     fprintf(stderr, "(DEBUG) %d chars, cant_end_chars=%s\n",
1880                                         i, cant_end_chars.get_mbstr());
1881 #endif
1882
1883     _DtCanvasLoadMetrics((_DtCvHandle)f_help_dsp_area->canvas);
1884
1885   }
1886   
1887   // install accelerators on f_viewport 
1888   XtInstallAccelerators(f_form, f_search_prev);
1889   XtInstallAccelerators(f_form, f_search_next);
1890   
1891 // piggyback on the Help Area vertical scrollbar so we can scroll our
1892 // mark icons
1893   XtAddCallback (f_help_dsp_area->vertScrollWid,
1894                  XmNdragCallback,
1895                  v_scroll_callback, this);
1896
1897   XtAddCallback (f_help_dsp_area->vertScrollWid,
1898                  XmNincrementCallback,
1899                  v_scroll_callback, this);
1900
1901   XtAddCallback (f_help_dsp_area->vertScrollWid,
1902                  XmNdecrementCallback,
1903                  v_scroll_callback, this);
1904
1905   XtAddCallback (f_help_dsp_area->vertScrollWid,
1906                  XmNpageDecrementCallback,
1907                  v_scroll_callback, this);
1908
1909   XtAddCallback (f_help_dsp_area->vertScrollWid,
1910                  XmNpageIncrementCallback,
1911                  v_scroll_callback, this);
1912
1913   XtAddCallback (f_help_dsp_area->vertScrollWid,
1914                  XmNtoBottomCallback,
1915                  v_scroll_callback, this);
1916
1917   XtAddCallback (f_help_dsp_area->vertScrollWid,
1918                  XmNtoTopCallback,
1919                  v_scroll_callback, this);
1920
1921   XtAddCallback (f_help_dsp_area->vertScrollWid,
1922                  XmNvalueChangedCallback, 
1923                  v_scroll_callback, this);
1924
1925   // piggyback on the Help Area horizontal scrollbar so we can
1926   // track the detached graphic graphic.
1927   XtAddCallback (f_help_dsp_area->horzScrollWid,
1928                  XmNdragCallback,
1929                  h_scroll_callback, this);
1930
1931   XtAddCallback (f_help_dsp_area->horzScrollWid,
1932                  XmNincrementCallback,
1933                  h_scroll_callback, this);
1934
1935   XtAddCallback (f_help_dsp_area->horzScrollWid,
1936                  XmNdecrementCallback,
1937                  h_scroll_callback, this);
1938
1939   XtAddCallback (f_help_dsp_area->horzScrollWid,
1940                  XmNpageDecrementCallback,
1941                  h_scroll_callback, this);
1942
1943   XtAddCallback (f_help_dsp_area->horzScrollWid,
1944                  XmNpageIncrementCallback,
1945                  h_scroll_callback, this);
1946
1947   XtAddCallback (f_help_dsp_area->horzScrollWid,
1948                  XmNtoBottomCallback,
1949                  h_scroll_callback, this);
1950
1951   XtAddCallback (f_help_dsp_area->horzScrollWid,
1952                  XmNtoTopCallback,
1953                  h_scroll_callback, this);
1954
1955   XtAddCallback (f_help_dsp_area->horzScrollWid,
1956                  XmNvalueChangedCallback, 
1957                  h_scroll_callback, this);
1958
1959   
1960   // Request MarkSelectionChanged message for all marks
1961   MarkCanvas::request (this);
1962
1963   node_mgr().UAS_Sender<SelectionChanged>::request (this);
1964
1965
1966   // Search area
1967   widget = XmCreatePulldownMenu(search_area, (char*)"scope_menu", 0, 0);
1968
1969   n = 0;
1970   XtSetArg(args[n], XmNsubMenuId, widget); n++;
1971   XtManageChild(widget = XmCreateOptionMenu(search_area, (char*)"scope", args, n));
1972   help_agent().add_help_cb (widget);
1973
1974   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 60,
1975                                         "Specify search scope"));
1976   add_quick_help(widget, (char*)*textstore);
1977   f_textstore.insert_item(textstore);
1978
1979   mtfstring =  CATGETS(Set_AgentLabel, 59, "Search:");
1980   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
1981
1982   // hookup the ScopeMenu object here
1983   f_scope_menu = new ScopeMenu (widget, TRUE); // (require current section scop) 
1984
1985   n = 0;
1986   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1987   XtSetArg(args[n], XmNleftWidget, widget); n++;
1988
1989   f_search_text = (WXmTextField*)(Widget)
1990       WXmTextField (search_area, "text", AM, args, n);
1991   XtAddEventHandler (*f_search_text, EnterWindowMask, False,
1992                      (XtEventHandler) search_help, (XtPointer) this);
1993   XtAddEventHandler (*f_search_text, LeaveWindowMask, False,
1994                      (XtEventHandler) search_help, (XtPointer) this);
1995   XtAddEventHandler (*f_search_text, FocusChangeMask, False,
1996                      (XtEventHandler) search_help, (XtPointer) this);
1997   ON_ACTIVATE (*f_search_text,          text_callback);
1998   help_agent().add_help_cb (*f_search_text);
1999
2000   widget = XtCreateManagedWidget("scope_editor", xmPushButtonWidgetClass,
2001                               search_area, 0, 0);
2002   XtAddCallback(widget, XmNactivateCallback, scope_editorCB, 0);
2003   help_agent().add_help_cb (widget);
2004
2005   mtfstring =  CATGETS(Set_AgentLabel, 46, "Scope Editor");
2006   XtVaSetValues(widget, XmNlabelString, (XmString)mtfstring, NULL);
2007
2008   textstore = new UAS_String(CATGETS(Set_AgentQHelp, 11,
2009                         "Specify search scope using the Scope Editor"));
2010   add_quick_help(widget, (char*)*textstore);
2011   f_textstore.insert_item(textstore);
2012
2013   // set right attachment here since it cannot be set at creation time
2014   XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
2015   XtSetArg(args[n], XmNrightWidget, widget); n++;
2016   XtSetValues(*f_search_text, args, n);
2017   
2018 #ifdef NODEBUG
2019   /* -------- Debugging setup.  Should be a function. -------- */
2020   
2021   bool debugging = window_system().get_boolean_app_resource("debug");
2022   
2023   if (debugging && False)
2024     debug_cascade.Manage();
2025   debug_cascade.SubMenuId (debug_menu);
2026   ON_ACTIVATE (document_id, document_id_display);
2027 #endif  
2028
2029   XtManageChild(f_form);
2030   XtManageChild(menu_bar);
2031   if (XmToggleButtonGadgetGetState(tool_barT))
2032       XtManageChild(tool_bar);
2033   if (XmToggleButtonGadgetGetState(search_areaT))
2034       XtManageChild(search_area);
2035   XtManageChild(mainw);
2036
2037   setStatus (eSuccess);
2038 }
2039
2040 // /////////////////////////////////////////////////////////////////
2041 // lock_toggle - callback for lock button
2042 // /////////////////////////////////////////////////////////////////
2043
2044 void 
2045 NodeWindowAgent::lock_toggleCB(Widget lock,
2046                                XtPointer client_data, XtPointer call_data)
2047 {
2048   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2049   XmToggleButtonCallbackStruct *cdata =
2050       (XmToggleButtonCallbackStruct*) call_data;
2051   Arg args[3];
2052   int n;
2053   
2054   agent->f_locked = cdata->set;
2055
2056   n = 0;
2057   if (agent->f_locked)
2058     {
2059         XtSetArg(args[n], XmNselectPixmap,
2060                  window_system().locked_pixmap(XtParent(lock))); n++;
2061         XtSetArg(args[n], XmNlabelPixmap,
2062                  window_system().semilocked_pixmap(XtParent(lock))); n++;
2063       }
2064   else
2065     {
2066         XtSetArg(args[n], XmNlabelPixmap,
2067                  window_system().unlocked_pixmap(XtParent(lock))); n++;
2068         XtSetArg(args[n], XmNselectPixmap,
2069                  window_system().semilocked_pixmap(XtParent(lock))); n++;
2070     }
2071   XtSetValues(lock, args, n);
2072   
2073   // NOTE: This needs to be real time, not bogus X event time. [DJB]
2074   agent->f_last_access_time = (unsigned int) cdata->event->xany.serial;
2075 }
2076
2077 // /////////////////////////////////////////////////////////////////
2078 // dismiss - callback for close button
2079 // /////////////////////////////////////////////////////////////////
2080
2081 void
2082 NodeWindowAgent::dismissCB(Widget, XtPointer client_data, XtPointer)
2083 {
2084   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2085   agent->dismiss();
2086 }
2087
2088 void
2089 NodeWindowAgent::dismiss()
2090 {
2091   if (g_ignore_wm_delete)
2092     return;
2093   if (!XtIsSensitive(f_close)) {
2094     exitCB(0, (XtPointer) this, 0);
2095     return;
2096   }
2097   f_shell->Popdown();
2098   delete this;
2099 }
2100
2101 // /////////////////////////////////////////////////////////////////
2102 // search_on_selection - perform query on X selection
2103 // /////////////////////////////////////////////////////////////////
2104
2105 void
2106 NodeWindowAgent::do_search_selection (const char* value, unsigned long)
2107 {
2108 #ifdef SEARCH_SELECTION_DEBUG
2109   fprintf(stderr, "search selection = %s\n", value);
2110 #endif
2111
2112   if (value == NULL || *value == '\0')
2113     return;
2114
2115   unsigned char* p = (unsigned char*)value;
2116   for (; *p; p++)
2117     if (*p < ' ') *p = ' ';
2118   
2119   
2120 #if 0
2121   Xassert (value != NULL);
2122 #ifdef UseWideChars
2123   char* buffer = (char *)value;
2124   TML_CHAR_TYPE *p, *ws = new TML_CHAR_TYPE[strlen(buffer) + 1];
2125   int assert_var = mbstowcs(ws, buffer, strlen(buffer) + 1);
2126   assert( assert_var >= 0 );
2127   for (p = ws; *p; p++) { // looking for control chars
2128     if (*p < (TML_CHAR_TYPE)' ')
2129       *p = ' ';
2130   }
2131   int length = strlen(buffer) + 1;
2132   assert_var = wcstombs(buffer, ws, length);
2133   assert( assert_var >=  0 );
2134   delete[] ws;
2135 #else
2136   char *p = (char *) value;
2137   while (*p != NULL)
2138     {
2139       if (*p < ' ' /* || *p > '~' DTS 13944 */ )
2140         *p = ' ';
2141       p++;
2142     }
2143   // make selection string a literal
2144   
2145   // 1) Scan string for quotes. 
2146   // make room for start and end quotes 
2147   
2148   int buflen = strlen((char *)value) + 3 ;
2149   char *buffer = new char[buflen] ;
2150   
2151   const char *src = (char *)value ;
2152   char *dest = buffer ;
2153   
2154   // make first character a quote 
2155   if (*src != '"')
2156     *dest++ = '"';
2157   else
2158     *dest++ = *src++ ;
2159   
2160   while (*src)
2161     {
2162       if (dest >= (buffer + buflen - 2))
2163         {
2164           buflen += 16 ;
2165           char *newbuf = new char[buflen] ;
2166           int len = buflen - 1;
2167           *((char *) memcpy(newbuf, buffer, len) + len) = '\0';
2168           int depth = dest - buffer ;
2169           delete buffer ;
2170           buffer = newbuf ;
2171           dest = buffer + depth ;
2172         }
2173       if (*src == '"')
2174         *dest++ = '\\' ; // escape the quote 
2175       
2176       *dest++ = *src++ ;
2177     }
2178   if (*(src - 1) == '"')
2179     {
2180       // if it ends with a quote, we escaped it, so remove the escape. 
2181       *(dest - 2)  = '"' ;      
2182       *(dest - 1) = 0 ; // terminate string 
2183     }
2184   else
2185     {
2186       // otherwise add our own quote
2187       *dest++ = '"' ;
2188       *dest = 0 ;
2189     }
2190 #endif
2191 #endif
2192   
2193   char *search_string = (char*)value;
2194   
2195   ON_DEBUG(printf("!! search on selection\n-->%s<--\n", (char*)value));
2196   
2197   f_search_text->Value(search_string);
2198   XmUpdateDisplay (window_system().toplevel());
2199
2200   UAS_SearchScope *scope = f_scope_menu->current_scope();
2201   if (scope)
2202   {
2203     if (scope->search_zones().section())
2204       {
2205         node_mgr().set_preferred_window(this);
2206         search_mgr().search_section(f_node_view_info->node_ptr()->id());
2207 #ifdef CURRENT_SECTION_DEBUG
2208         fprintf(stderr, "(DEBUG) search_section (before search)=%s\n",
2209                                 (char*)search_mgr().search_section());
2210 #endif
2211       }
2212
2213     {
2214       Wait_Cursor bob;
2215       search_mgr().parse_and_search(search_string, scope);
2216       search_mgr().search_section(UAS_String(""));
2217     }
2218   }
2219 }
2220
2221 void
2222 NodeWindowAgent::search_on_selectionCB(Widget, XtPointer client_data,
2223                                        XtPointer call_data)
2224 {
2225   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2226   XmPushButtonCallbackStruct* cdata =
2227       (XmPushButtonCallbackStruct *) call_data;
2228  
2229   get_selection_value(*agent->f_shell, XA_PRIMARY, agent,
2230                       cdata->event->xbutton.time);
2231 }
2232
2233 // /////////////////////////////////////////////////////////////////
2234 // search text callbacks
2235 // /////////////////////////////////////////////////////////////////
2236
2237 void
2238 NodeWindowAgent::text_callback(WCallback *wcb)
2239 {
2240     (void) (XmAnyCallbackStruct*)wcb->CallData();
2241     char *text = XmTextGetString(wcb->GetWidget());
2242     if (text == NULL)
2243       return;
2244
2245     // Allow if debug resource is set, not ifdef DEBUG - 17:25 01/11/93 DJB
2246     UAS_SearchScope* scope = f_scope_menu->current_scope();
2247     if (scope != NULL && *text) // if context makes sense
2248     {
2249       if (scope->search_zones().section())
2250       {
2251         node_mgr().set_preferred_window(this);
2252         search_mgr().search_section(f_node_view_info->node_ptr()->id());
2253 #ifdef CURRENT_SECTION_DEBUG
2254         fprintf(stderr, "(DEBUG) search_section (before search)=%s\n",
2255                                 (char*)search_mgr().search_section());
2256 #endif
2257       }
2258
2259       {
2260         Wait_Cursor bob;
2261         search_mgr().parse_and_search (text, scope);
2262         search_mgr().search_section (UAS_String(""));
2263       }
2264     }
2265
2266     XtFree (text);
2267 }
2268
2269 void
2270 NodeWindowAgent::search_help (Widget, XtPointer client_data,
2271                               XEvent *event, Boolean *)
2272 {
2273
2274   // Make sure the event is what we expect.
2275   if (event->type != EnterNotify && event->type != FocusIn &&
2276       event->type != LeaveNotify && event->type != FocusOut)
2277     return;
2278
2279   NodeWindowAgent* agent = (NodeWindowAgent*)client_data;
2280   if (agent == NULL)
2281     return;
2282
2283   // clear quick help
2284   if (event->type == LeaveNotify || event->type == FocusOut)
2285   {
2286     XmTextFieldSetString(agent->f_status_text, (char*)"");
2287     return;
2288   }
2289
2290
2291   static String help_text       = NULL;
2292   static String default_scope   = NULL;
2293   
2294   if (help_text == NULL) {
2295     UAS_Pointer<UAS_String> str;
2296
2297     str = new UAS_String(CATGETS(Set_AgentQHelp, 64, "Search %s"));
2298     help_text = (char*)*str;
2299     agent->f_textstore.insert_item(str);
2300
2301     str = new UAS_String(CATGETS(Set_NodeWindowAgent, 3, "Information Library"));
2302     default_scope = (char*)*str;
2303     agent->f_textstore.insert_item(str);
2304   }
2305   
2306   // Format the search help string. 
2307   UAS_SearchScope *scope = agent->f_scope_menu->current_scope();
2308   char buffer[128];
2309   if (scope != NULL)
2310     snprintf (buffer, sizeof(buffer), help_text, (char *) scope->name());
2311   else
2312     snprintf (buffer, sizeof(buffer), help_text, default_scope);
2313   
2314   // Finally, display it in the quick help field.
2315   XmTextFieldSetString(agent->f_status_text, buffer);
2316 }
2317
2318
2319 // /////////////////////////////////////////////////////////////////
2320 // history_display
2321 // /////////////////////////////////////////////////////////////////
2322
2323 static void
2324 section_historyCB(Widget, XtPointer, XtPointer)
2325 {
2326   Wait_Cursor bob;
2327   ON_DEBUG (puts ("history_display() called"));
2328   global_history_mgr().display();
2329 }
2330
2331 // /////////////////////////////////////////////////////////////////
2332 // history_previous
2333 // /////////////////////////////////////////////////////////////////
2334
2335 void
2336 NodeWindowAgent::history_prevCB(Widget, XtPointer client_data, XtPointer)
2337 {
2338   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2339   UAS_Pointer<UAS_Common> doc_ptr = agent->f_history_list.previous();
2340   Xassert (doc_ptr != (UAS_Pointer<UAS_Common>)NULL);
2341   
2342 #ifdef jbm
2343   g_history_anchor = agent->f_history_list.previous_anchor();
2344 #endif  
2345   // Set the history_display flag which is checked in the display routine. 
2346   if (!agent->f_locked)
2347     {
2348       agent->f_history_display = TRUE;
2349       agent->record_history_position();
2350       agent->f_history_list.go_back();
2351     }
2352   
2353   node_mgr().set_preferred_window (agent);
2354   doc_ptr->retrieve();
2355 }
2356
2357 // /////////////////////////////////////////////////////////////////
2358 // history_next
2359 // /////////////////////////////////////////////////////////////////
2360
2361 void
2362 NodeWindowAgent::history_nextCB(Widget, XtPointer client_data, XtPointer)
2363 {
2364   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2365   UAS_Pointer<UAS_Common> doc_ptr = agent->f_history_list.next();
2366   Xassert (doc_ptr != (UAS_Pointer<UAS_Common>)NULL);
2367   
2368 #ifdef jbm
2369   g_history_anchor = agent->f_history_list.next_anchor();
2370 #endif
2371   
2372   // Set the history_display flag which is checked in the display routine. 
2373   if (!agent->f_locked)
2374     {
2375       agent->f_history_display = TRUE;
2376       agent->record_history_position();
2377       agent->f_history_list.go_forward();
2378     }
2379   
2380   node_mgr().set_preferred_window (agent);
2381   doc_ptr->retrieve();
2382 }
2383
2384
2385 // /////////////////////////////////////////////////////////////////
2386 // history preview callbacks
2387 // /////////////////////////////////////////////////////////////////
2388
2389 void
2390 NodeWindowAgent::preview_history_nextCB(Widget, XtPointer client_data,
2391                                         XtPointer)
2392 {
2393   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2394   agent->f_preview_document = agent->f_history_list.next();
2395   agent->f_preview_timeout =
2396     new WTimeOut (window_system().app_context(), 550,
2397                   agent, (WTimeOutFunc) &NodeWindowAgent::preview);
2398 }
2399
2400 void
2401 NodeWindowAgent::preview_history_prevCB(Widget, XtPointer client_data,
2402                                         XtPointer)
2403 {
2404   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2405   agent->f_preview_document = agent->f_history_list.previous();
2406   agent->f_preview_timeout =
2407     new WTimeOut (window_system().app_context(), 550,
2408                   agent, (WTimeOutFunc) &NodeWindowAgent::preview);
2409 }
2410
2411
2412 // /////////////////////////////////////////////////////////////////
2413 // initialize_history - add the current node to hist and set arrows
2414 // /////////////////////////////////////////////////////////////////
2415
2416 void
2417 NodeWindowAgent::initialize_history()
2418 {
2419   // Add the new node to the history if it didn't come from the history
2420   // list itself.  Currently this has the effect of truncating the list
2421   // at the user's current position in the list. 
2422   if (!f_history_display)
2423     {
2424       UAS_Pointer<UAS_Common> bogus;
2425       f_history_list.append (bogus = f_node_ptr);
2426     }
2427   else
2428     f_history_display = FALSE;  // reset 
2429   
2430   if (f_history_list.previous() != (UAS_Pointer<UAS_Common>)NULL) {
2431     XtSetSensitive(f_history_prev, True);
2432     XtSetSensitive(f_history_prev2, True);
2433   } else {
2434     XtSetSensitive(f_history_prev, False);
2435     XtSetSensitive(f_history_prev2, False);
2436   }
2437   
2438   if (f_history_list.next() != (UAS_Pointer<UAS_Common>)NULL) {
2439     XtSetSensitive(f_history_next, True);
2440     XtSetSensitive(f_history_next2, True);
2441   } else {
2442     XtSetSensitive(f_history_next, False);
2443     XtSetSensitive(f_history_next2, False);
2444   }
2445 }
2446
2447 // /////////////////////////////////////////////////////////////////
2448 // display_version - display the version dialog
2449 // /////////////////////////////////////////////////////////////////
2450
2451 void
2452 NodeWindowAgent::display_version()
2453 {
2454   UAS_String version = CATGETS(Set_Version, 1, "");
2455   if (*(char*)version) {
2456     message_mgr().info_dialog ((char*)version);
2457   }
2458 }
2459
2460 // /////////////////////////////////////////////////////////////////
2461 // display_search_history
2462 // /////////////////////////////////////////////////////////////////
2463
2464 static void
2465 search_historyCB(Widget, XtPointer, XtPointer)
2466 {
2467   search_mgr().search_history_list_view().display();
2468 }
2469
2470 static void
2471 open_urlCB(Widget, XtPointer client_data, XtPointer)
2472 {
2473   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2474   url_mgr().display(agent);
2475 }
2476
2477 // NOTE: There's got to be an easier way to attach callbacks!?
2478 // Maybe something in the resource file associated with the button?
2479 // There needs to be a central way to address things like a
2480 // search history list view just by knowing where it it.  Maybe
2481 // we should be able to call it's notify proc with some kind
2482 // of message? Like some kind of real O-O or something!?
2483 // 6/23/92 djb
2484
2485
2486 // /////////////////////////////////////////////////////////////////
2487 // update_fonts - user has scaled fonts
2488 // /////////////////////////////////////////////////////////////////
2489
2490 void
2491 NodeWindowAgent::update_fonts (unsigned int serial_number)
2492 {
2493   f_serial_number = serial_number ;
2494   // NOTE: do not call this from within ourselves,
2495   // it is to be called by the NodeMgr - jbm
2496   
2497 }
2498
2499
2500 // /////////////////////////////////////////////////////////////////
2501 // initialize_controls - init ui controls based on current node
2502 // /////////////////////////////////////////////////////////////////
2503
2504 void
2505 NodeWindowAgent::initialize_controls()
2506 {
2507   initialize_hierarchy();
2508   initialize_tabs();
2509   select_tab();
2510   initialize_path();
2511   initialize_history();
2512   
2513   //
2514   // SWM: Need to disable searching if the node we're displaying is
2515   //      not searchable...
2516   //
2517   XtSetSensitive(f_search_menu_button,
2518                  f_node_view_info->node_ptr()->searchable());
2519
2520   bool search_previous_sensitive = FALSE, search_next_sensitive = FALSE;
2521
2522   if (f_node_view_info->node_ptr()->searchable() &&
2523       f_node_view_info->hit_entries() > 0) {
2524     if (f_node_view_info->search_hit_idx() > 0)
2525       search_previous_sensitive = TRUE;
2526     if (f_node_view_info->search_hit_idx() <
2527                                 f_node_view_info->hit_entries() - 1)
2528       search_next_sensitive = TRUE;
2529   }
2530
2531   XtSetSensitive(f_search_prev, search_previous_sensitive);
2532   XtSetSensitive(f_search_prev2, search_previous_sensitive);
2533   XtSetSensitive(f_search_next, search_next_sensitive);
2534   XtSetSensitive(f_search_next2, search_next_sensitive);
2535
2536   XtSetSensitive(f_print2, True);
2537   XtSetSensitive(f_print_as, True);
2538
2539   XtSetSensitive(f_detach_graphic, True);
2540
2541 #ifdef NOTYET
2542   // See if next and previous exist and sensitize buttons accordingly.
2543   if (f_node_handle->node().next_node() != NULL)
2544     {
2545       XtSetSensitive(f_node_next, True);
2546       XtSetSensitive(f_node_next2, True);
2547     }
2548   else
2549     {
2550       XtSetSensitive(f_node_next, False);
2551       XtSetSensitive(f_node_next2, False);
2552     }
2553   
2554   if (f_node_handle->node().previous_node() != NULL)
2555     {
2556       XtSetSensitive(f_node_previous, True);
2557       XtSetSensitive(f_node_previous2, True);
2558     }
2559   else
2560     {
2561       XtSetSensitive(f_node_previous, False);
2562       XtSetSensitive(f_node_previous2, False);
2563     }
2564   
2565   
2566   int i;
2567   /* -------- See if the current node is in the current hierarchy. -------- */
2568   for (i = 9; i >= 0; i--)
2569     {
2570       if (!XtIsManaged (*f_title_button_list[i]))
2571         break;
2572       
2573       if (((NodeHandle *) f_title_button_list[i]->UserData())
2574           ->equals (*f_node_handle))
2575         {
2576           f_title_option->MenuHistory (*f_title_button_list[i]);
2577           select_tab();
2578           return;
2579         }
2580     }
2581   
2582   /* -------- Set up the title option menu for hierarchial path. -------- */
2583   
2584   ON_DEBUG(printf ("*** Unmanaging push buttons in option menu ***\n"));
2585   //  f_title_menu->Unmanage();
2586   for (i = 0; i < 10; i++)
2587     f_title_button_list[i]->Unmanage();
2588   
2589   NodeHandle *current_node = new NodeHandle (*f_node_handle);
2590   
2591   i = 9;
2592   while (current_node != NULL)
2593     {
2594       // NOTE: WWL WXmString needs fixing to take a const char *, djb
2595       const char *current_name = current_node->node().node_name();
2596       
2597       f_title_button_list[i]->
2598         LabelString (WXmString ((char *)current_name));
2599       ON_DEBUG(printf ("*** Remanaging button %d -- %s***\n", i,
2600                        current_name));
2601       f_title_button_list[i]->Manage();
2602       // Free old node associated with the button
2603       delete (NodeHandle *) f_title_button_list[i]->UserData();
2604       f_title_button_list[i]->UserData (current_node);
2605       if (--i < 0)
2606         {
2607           // NOTE: This will need to be fixed, 7/8/92 djb
2608           fputs ("Unreasonable include file nesting!", stderr);
2609           fputs ("  Section hierarchy too deep!!", stderr);
2610           abort();
2611         }
2612       
2613       current_node = current_node->node().parent_node();
2614       if (current_node != NULL)
2615         current_node = new NodeHandle (*current_node);
2616     }
2617   
2618   // OPTION MENU BUGGY STUFF BELOW: 
2619   //  f_title_menu->Manage();
2620   // Work around Motif 1.1 (1.2 ~too?) bug
2621   WXmCascadeButtonGadget opb (XmOptionButtonGadget (*f_title_option));
2622   opb.Unmanage();
2623   // Make the last item the visible one.  See Motif docs.
2624   f_title_option->MenuHistory (*f_title_button_list[9]);
2625   opb.Manage();
2626   //  printf ("*** Done with option menu changes ***\n");
2627   
2628   display_tabs (*((ObjectId *) f_title_button_list[i+1]->UserData()));
2629   select_tab();
2630 #endif
2631 }
2632
2633 // /////////////////////////////////////////////////////////////////////////
2634 // printCB
2635 // /////////////////////////////////////////////////////////////////////////
2636
2637 /*
2638  * ------------------------------------------------------------------------
2639  * Name: LibraryAgent::printCB
2640  *
2641  * Description:
2642  *
2643  *     Called when the user hits "Print" quick button.  Prints without
2644  *     displaying the Print setup dialog.
2645  *     
2646  */
2647 void
2648 NodeWindowAgent::printCB(Widget w, XtPointer client_data, XtPointer)
2649 {
2650     NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2651
2652     //  Get a handle to the AppPrintData allocated in the WindowSystem class
2653
2654     AppPrintData* p = window_system().GetAppPrintData();
2655
2656     //  Need to put this single node on the print list so that
2657     //  reset_ui() can determine the number of nodes being printed 
2658
2659     xList<UAS_Pointer<UAS_Common> > * print_list = new xList<UAS_Pointer<UAS_Common> >;
2660     UAS_Pointer<UAS_Common> bogus;
2661     bogus = agent->f_node_view_info->node_ptr();
2662     print_list->append(bogus);
2663     
2664     p->f_outline_element = NULL;
2665     p->f_print_list = print_list;
2666  
2667     CreatePrintSetup(w, p);
2668
2669     // check if the DtPrintSetupBox ("Print...") has been called yet 
2670
2671     if(p->f_print_data->print_display == (Display*)NULL)
2672     {
2673         
2674         // first time thru print setup, so get default data 
2675         
2676         if (DtPrintFillSetupData(p->f_print_dialog, p->f_print_data)
2677             != DtPRINT_SUCCESS) {
2678
2679             // NOTE: DtPrintFillSetupData() already posts an error
2680             // dialog on failure - no need to post our own.
2681
2682             return ;
2683         }
2684     }
2685  
2686     DoPrint(w, p) ;
2687
2688 }
2689
2690 /*
2691  * ------------------------------------------------------------------------
2692  * Name: LibraryAgent::print_asCB
2693  *
2694  * Description:
2695  *
2696  *     This is called for "Print..." and will always bring up the
2697  *     print setup dialog.
2698  */
2699 void
2700 NodeWindowAgent::print_asCB(Widget w, XtPointer client_data, XtPointer)
2701 {
2702     NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2703
2704     AppPrintData* p = window_system().GetAppPrintData();
2705
2706     //  Need to put this single node on the print list so that
2707     //  reset_ui() can determine the number of nodes being printed 
2708
2709     xList<UAS_Pointer<UAS_Common> > * print_list = new xList<UAS_Pointer<UAS_Common> >;
2710     UAS_Pointer<UAS_Common> bogus;
2711     bogus = agent->f_node_view_info->node_ptr();
2712     print_list->append(bogus);
2713     
2714     p->f_print_list = print_list;
2715     p->f_outline_element = NULL;
2716  
2717     CreatePrintSetup(w, p);
2718     
2719     XtManageChild(p->f_print_dialog); /* popup dialog each time */
2720 }
2721
2722 // /////////////////////////////////////////////////////////////////
2723 // map_activate
2724 // /////////////////////////////////////////////////////////////////
2725
2726 void
2727 NodeWindowAgent::map_activate()
2728 {
2729   Wait_Cursor bob;
2730   UAS_Pointer<UAS_Common> bogus;
2731   map_mgr().display_centered_on (bogus = f_node_ptr);
2732 }
2733
2734
2735 // /////////////////////////////////////////////////////////////////
2736 // search previous 
2737 // /////////////////////////////////////////////////////////////////
2738
2739 void
2740 NodeWindowAgent::search_previousCB(Widget, XtPointer client_data, XtPointer)
2741 {
2742   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2743   agent->search_previous();
2744 }
2745
2746 void
2747 NodeWindowAgent::search_previous()
2748 {
2749     NodeViewInfo::trav_status_t status;
2750     status = f_node_view_info->
2751                 adjust_current_search_hit(NodeViewInfo::PREV);
2752
2753     if (status != NodeViewInfo::NOT_MOVED)
2754       {
2755
2756         if (! XtIsSensitive(f_search_next))
2757           {
2758             XtSetSensitive(f_search_next, True);
2759             XtSetSensitive(f_search_next2, True);
2760           }
2761         if (status == NodeViewInfo::REACH_LIMIT)
2762           {
2763             XtSetSensitive(f_search_prev, False);
2764             XtSetSensitive(f_search_prev2, False);
2765           }
2766
2767         _DtCvUnit width, height;
2768         _DtCanvasResize((_DtCvHandle)f_help_dsp_area->canvas,
2769                                                 _DtCvTRUE, &width, &height);
2770
2771         _DtCanvasRender((_DtCvHandle)f_help_dsp_area->canvas, 0, 0,
2772                 width, height, _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
2773
2774         _DtHelpSearchMoveTraversal((XtPointer)f_help_dsp_area,
2775                                         f_node_view_info->search_hit_idx());
2776       }
2777 }
2778
2779 // /////////////////////////////////////////////////////////////////
2780 // search next
2781 // /////////////////////////////////////////////////////////////////
2782
2783 void
2784 NodeWindowAgent::search_nextCB(Widget, XtPointer client_data, XtPointer)
2785 {
2786   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2787   agent->search_next();
2788 }
2789
2790 void
2791 NodeWindowAgent::search_next()
2792 {
2793     NodeViewInfo::trav_status_t status;
2794     status = f_node_view_info->
2795                 adjust_current_search_hit(NodeViewInfo::NEXT);
2796
2797     if (status != NodeViewInfo::NOT_MOVED)
2798       {
2799
2800         if (! XtIsSensitive(f_search_prev))
2801           {
2802             XtSetSensitive(f_search_prev, True);
2803             XtSetSensitive(f_search_prev2, True);
2804           }
2805         if (status == NodeViewInfo::REACH_LIMIT)
2806           {
2807             XtSetSensitive(f_search_next, False);
2808             XtSetSensitive(f_search_next2, False);
2809           }
2810         
2811         _DtCvUnit width, height;
2812         _DtCanvasResize((_DtCvHandle)f_help_dsp_area->canvas,
2813                                                 _DtCvTRUE, &width, &height);
2814
2815         _DtCanvasRender((_DtCvHandle)f_help_dsp_area->canvas, 0, 0,
2816                 width, height, _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
2817
2818         _DtHelpSearchMoveTraversal((XtPointer)f_help_dsp_area,
2819                                         f_node_view_info->search_hit_idx());
2820       }
2821 }
2822
2823
2824 // /////////////////////////////////////////////////////////////////
2825 // display_search_scope
2826 // /////////////////////////////////////////////////////////////////
2827
2828 static void
2829 scope_editorCB(Widget, XtPointer, XtPointer)
2830 {
2831   search_scope_mgr().display();
2832 }
2833
2834
2835 #ifdef DEBUG
2836 // /////////////////////////////////////////////////////////////////
2837 // routines for items on the debug menu
2838 // /////////////////////////////////////////////////////////////////
2839
2840 void
2841 NodeWindowAgent::document_id_display()
2842 {
2843 }
2844
2845 #endif
2846
2847
2848 // /////////////////////////////////////////////////////////////////
2849 // initialize_tabs - set up the tabs for this book
2850 // /////////////////////////////////////////////////////////////////
2851
2852 void
2853 NodeWindowAgent::initialize_tabs()
2854 {
2855   List_Iterator<UAS_Pointer<UAS_Common> > tabs (g_tab_list);
2856   List_Iterator<BookTab *> btns (f_tab_btn_list);
2857   BookTab *current = NULL;
2858   bool changed = FALSE;
2859   static int old_count = -1;
2860   int count = 0;
2861   
2862   while (tabs)
2863     {
2864       // Update exisiting tab buttons, adding new ones when necessary. 
2865       if (btns)
2866         {
2867           // Only update the tab button if it has changed since last time.
2868           if (btns.item()->tab() == (UAS_Pointer<UAS_Common>)NULL ||
2869               btns.item()->tab() != tabs.item())
2870             {
2871               ON_DEBUG (printf ("  Updating\n"));
2872               current = btns.item();
2873               current->set_tab (tabs.item());
2874               changed = TRUE;
2875             } else {
2876             }
2877           btns++;
2878         }
2879       else
2880         {
2881           ON_DEBUG (printf ("Creating a tab\n"));
2882           // Add a new button.  The tabs have definitely changed.
2883           current = new BookTab (this, *f_tab_area, tabs.item());
2884           f_tab_btn_list.append (current);
2885           changed = TRUE;
2886         }
2887       count++;
2888       g_tab_list.remove (tabs); // remove item and increment iterator 
2889     }
2890   
2891   // Unset any remaining buttons.
2892   UAS_Pointer<UAS_Common> null_tab;
2893   for (; btns; btns++)
2894     {
2895       if (btns.item()->tab() != (UAS_Pointer<UAS_Common>)NULL)
2896         {
2897           ON_DEBUG (printf ("Emptying a tab\n"));
2898           btns.item()->set_tab (null_tab);
2899           changed = TRUE;
2900         }
2901     }
2902   
2903   if (!changed)
2904     return;
2905   
2906   ON_DEBUG (printf ("Tabs have changed (%d)\n", count));
2907   
2908   // Make the tab area appear or disappear as needed.
2909   if (count == 0 && (old_count > 0 || old_count == -1))
2910     f_frame->TopOffset (-12);
2911   else if (count > 0 && old_count <= 0)
2912     f_frame->TopOffset (-4);
2913   
2914   // Work around bogus Motif bug that prevents things from resizing
2915   // correctly if the tabs change but there's still the same number.
2916   if (old_count == count)
2917     {
2918       current->Unmanage();
2919       current->Manage();
2920     }
2921   else
2922     {
2923       old_count = count;
2924     }
2925 }
2926
2927
2928 // /////////////////////////////////////////////////////////////////
2929 // select_tab - if current node has a tab, select that tab
2930 // /////////////////////////////////////////////////////////////////
2931
2932 void
2933 NodeWindowAgent::select_tab()
2934 {
2935   List_Iterator<BookTab *> btns (f_tab_btn_list);
2936   UAS_Pointer<UAS_Common> d;
2937   
2938   while (btns && XtIsManaged (*btns.item()))
2939     {
2940       btns.item()->select_if_same (d = f_node_view_info->node_ptr());
2941       btns++;
2942     }
2943 }
2944
2945 // /////////////////////////////////////////////////////////////////
2946 // preview_init
2947 // /////////////////////////////////////////////////////////////////
2948
2949 void
2950 NodeWindowAgent::preview_init (UAS_Pointer<UAS_Common> &doc_ptr)
2951 {
2952   // NOTE: Link preview timeout shouldn't be hardcoded! DJB 10/7/92
2953   f_preview_document = doc_ptr;
2954   f_preview_timeout =
2955     new WTimeOut (window_system().app_context(), 550,
2956                   this, (WTimeOutFunc) &NodeWindowAgent::preview);
2957 }
2958
2959
2960 // /////////////////////////////////////////////////////////////////
2961 // preview - display the link preview
2962 // /////////////////////////////////////////////////////////////////
2963
2964 void
2965 NodeWindowAgent::preview (WTimeOut *)
2966 {
2967   char title[128];
2968   char preview_buffer[256];
2969   
2970   UAS_String pt = f_preview_document->title();
2971   *((char *) memcpy(title, (char *) pt, 127) + 127) = '\0';
2972   UAS_String bn = f_preview_document->book_name(UAS_SHORT_TITLE);
2973   const char *book_name = (char *) bn;
2974   if (book_name != NULL && *book_name != '\0')
2975     snprintf (preview_buffer, sizeof(preview_buffer),
2976               CATGETS(Set_Messages, 8, "Link to %s: %s"), book_name, title);
2977   else
2978     snprintf (preview_buffer, sizeof(preview_buffer),
2979               CATGETS(Set_Messages, 9, "Link to %s"), title);
2980   XmTextFieldSetString(f_status_text, preview_buffer);
2981   f_preview_timeout = NULL;
2982   f_preview_document = NULL;
2983 }
2984
2985
2986 // /////////////////////////////////////////////////////////////////
2987 // unpreview
2988 // /////////////////////////////////////////////////////////////////
2989
2990 void
2991 NodeWindowAgent::unpreviewCB(Widget, XtPointer client_data, XtPointer)
2992 {
2993     NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
2994     agent->unpreview();
2995 }
2996
2997 void
2998 NodeWindowAgent::unpreview()
2999 {
3000   // Cancel document preview...
3001   if (f_preview_timeout != NULL)
3002     {
3003       // If the timeout hasn't triggered delete it and clear the document. 
3004       delete f_preview_timeout;
3005       // XXX SWM -- zero out the timeout
3006       f_preview_timeout = NULL;
3007     }
3008   else
3009     {
3010       // If the timeout has already happened, just clear the preview area. 
3011       XmTextFieldSetString(f_status_text, (char*)"");
3012     }
3013 }
3014
3015
3016
3017 // /////////////////////////////////////////////////////////////////
3018 // create_annotation/bookmark - create a new user mark
3019 // /////////////////////////////////////////////////////////////////
3020
3021 void
3022 NodeWindowAgent::create_annotationCB(Widget, XtPointer client_data, XtPointer)
3023 {
3024   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
3025   agent->make_bookmark(True);
3026 }
3027
3028 void
3029 NodeWindowAgent::create_bookmarkCB(Widget, XtPointer client_data, XtPointer)
3030 {
3031   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
3032   agent->make_bookmark(False);
3033 }
3034
3035 int
3036 NodeWindowAgent::make_bookmark (Boolean edit, MarkCanvas* refmark)
3037 {
3038   Wait_Cursor bob;
3039
3040   UAS_Pointer<UAS_Common> d;
3041
3042   UAS_String bm_name, bm_anno;
3043
3044   int status = -1; // default return status (fail)
3045
3046   if (refmark == NULL)
3047   {
3048     char *name;
3049     _DtCanvasGetSelection(f_help_dsp_area->canvas,
3050                           _DtCvSELECTED_TEXT, ((_DtCvPointer *)(void*)&name));
3051
3052 #ifdef BOOKMARK_DEBUG
3053     cerr << "Bookmark Name: [" << name << "]" << endl;
3054 #endif
3055
3056     //Xassert (name != NULL);
3057     if (name == NULL)
3058     {
3059       message_mgr().error_dialog ((char*)UAS_String(CATGETS(Set_Messages, 10,
3060                         "Dtinfo is unable to create this bookmark.")),
3061                           (Widget)f_shell);
3062       return status;
3063     }
3064
3065     // replace control char with a space
3066     for (unsigned char* p = (unsigned char*)name; *p; p++)
3067       *p = (*p < ' ') ? ' ' : *p;
3068
3069     int len, next_mblen;
3070     for (len = 0, next_mblen = 0; len < 40 && name[len]; len += next_mblen)
3071     {
3072       if ((next_mblen = mblen(name + len, MB_CUR_MAX)) < 0)
3073         break;
3074       else if (len + next_mblen > 40)
3075         break;
3076     }
3077     name[len] = 0;
3078
3079     bm_name = name;
3080
3081     free (name);
3082   }
3083   else {
3084     bm_name = refmark->mark_ptr()->name();
3085     bm_anno = refmark->mark_ptr()->notes();
3086   }
3087
3088 #ifdef BOOKMARK_DEBUG
3089    cerr << "Creating mark <" << (char*)bm_name << ">" << endl;
3090 #endif
3091
3092   _DtCvSegPts **segs = NULL ;
3093   mtry
3094   {
3095       int ret_x, ret_y ;
3096       // find the selection segment and offset
3097       _DtCanvasGetSelectionPoints(f_help_dsp_area->canvas,
3098                                   &segs, 
3099                                   &ret_x, &ret_y); // ret_x, ret_y
3100
3101       // NOTE: have to allow for segments that are added in by the
3102       // style sheet -> check appflag1
3103       // also have to account for it at the other end as well
3104
3105       if (segs == NULL || *segs == NULL)
3106         throw(CASTEXCEPT Exception());
3107
3108       // sort segments in order of vcc offset
3109       _DtCvSegPts** segpts_iter;
3110       for (segpts_iter = segs; *segpts_iter; segpts_iter++) {
3111         _DtCvSegPts* *p = segpts_iter + 1;
3112         for (; *p; p++)
3113         {
3114           if ((NodeViewInfo::segment_to_vcc((*segpts_iter)->segment) >
3115                NodeViewInfo::segment_to_vcc((*p)->segment)))
3116           {
3117             _DtCvSegPts* anon = *segpts_iter;
3118             *segpts_iter = *p;
3119             *p = anon;
3120           }
3121         }
3122       }
3123
3124 #ifdef BOOKMARK_DEBUG
3125       for (segpts_iter = segs; *segpts_iter; segpts_iter++) {
3126         _DtCvSegPts& segpts = **segpts_iter;
3127         fprintf(stderr, "(DEBUG) offset=%d,len=%d\n",
3128                                 segpts.offset, segpts.len);
3129       }
3130 #endif
3131
3132       MarkInfo markinfo(bm_name, bm_anno);
3133
3134       _DtCvSegPts* prev_segpts = NULL;
3135       unsigned int vcc         = 0;
3136       unsigned int length      = 0;
3137       unsigned int offset      = 0;
3138
3139       unsigned int i;
3140       for (i = 0; segs[i]; i++)
3141       {
3142         _DtCvSegPts* segpts = segs[i];
3143
3144         if (prev_segpts && prev_segpts->segment != segpts->segment) {
3145
3146           // new segment, save the previous one
3147           markinfo.insert_item(UAS_Pointer<MarkUnitInfo>(
3148                 new MarkUnitInfo(vcc, offset, length, prev_segpts->segment)));
3149
3150           if (NodeViewInfo::segment_to_vcc(segpts->segment)==(unsigned int)-1)
3151           {
3152             // ignore it, initialize
3153             vcc = length = offset = 0;
3154             prev_segpts = NULL;
3155             continue;
3156           }
3157           else {
3158             offset = segpts->offset;
3159             vcc = NodeViewInfo::segment_to_vcc(segpts->segment);
3160             length = 0;
3161           }
3162         }
3163         else if (prev_segpts) {
3164           if (segpts->offset > prev_segpts->offset + prev_segpts->len)
3165               length += segpts->offset - (prev_segpts->offset +
3166                                           prev_segpts->len);
3167         }
3168         else {
3169           offset = segpts->offset;
3170           vcc = NodeViewInfo::segment_to_vcc(segpts->segment);
3171         }
3172
3173         length += segpts->len;
3174
3175         prev_segpts = segpts;
3176       }
3177
3178       if (prev_segpts)
3179         markinfo.insert_item(UAS_Pointer<MarkUnitInfo>(
3180                 new MarkUnitInfo(vcc, offset, length, prev_segpts->segment)));
3181
3182       // remove bad (vcc < 0) MarkUnitInfo from markinfo
3183       MarkInfo bad_markinfo;
3184       for (i = 0; i < markinfo.length(); i++) {
3185         UAS_Pointer<MarkUnitInfo>& mui = markinfo[i];
3186         if (mui->vcc() == (unsigned int)-1)
3187           bad_markinfo.insert_item(mui);
3188       }
3189
3190       for (i = 0; i < bad_markinfo.length(); i++)
3191         markinfo.remove_item(bad_markinfo[i]);
3192
3193 #ifdef BOOKMARK_DEBUG
3194       for (i = 0; i < markinfo.length(); i++)
3195       {
3196         MarkUnitInfo& mui = *markinfo[i];
3197         fprintf(stderr, "(DEBUG) item%d: vcc=%d,offset=%d,length=%d\n",
3198                         i, mui.vcc(), mui.offset(), mui.length());
3199       }
3200 #endif
3201
3202 #ifdef BOOKMARK_DEBUG      
3203       cerr << "selection at: ( " << ret_x << ", " << ret_y << ")" << endl;
3204 #endif
3205
3206       // find the offset of the first segment from the top of the node
3207       // NOTE - should really do it from the nearest locator
3208
3209       if (markinfo.length() > 0)
3210       {
3211           // persistent mark info should be a list of
3212           // vcc of the segment, internal offset, internal length
3213
3214           UAS_Pointer<Mark> mark =
3215             mark_mgr().create_mark (d = f_node_ptr,
3216                                     AnchorCanvas(f_node_ptr->locator(),
3217                                                  markinfo),
3218                                     (char*)markinfo.name(),
3219                                     (char*)markinfo.anno());
3220
3221           if (edit && (mark != (UAS_Pointer<Mark>)NULL))
3222           {
3223               mark->edit();
3224           }
3225
3226           XtSetSensitive(f_create_bmrk, False);
3227           XtSetSensitive(f_create_anno, False);
3228
3229           status = 0; // success
3230     }
3231     else if (bad_markinfo.length() > 0)
3232         message_mgr().error_dialog (
3233                 (char*)UAS_String(CATGETS(Set_NodeWindowAgent, 7,
3234                 "The selected text is dynamically inserted and cannot\n"
3235                 "be used alone to create a bookmark reference. Either\n"
3236                 "select other text near the point, or include more of\n"
3237                 "the surrounding text.")),
3238                           (Widget)f_shell);
3239     else
3240         throw(CASTEXCEPT Exception());
3241   }
3242   mcatch_any()
3243   {
3244       if (! refmark)
3245         message_mgr().error_dialog ((char*)UAS_String(CATGETS(Set_Messages, 10,
3246                 "Dtinfo is unable to create this bookmark.")),
3247                           (Widget)f_shell);
3248   }
3249   end_try;
3250
3251   if (segs) {
3252       for (int i = 0; segs[i]; i++)
3253         free (segs[i]);
3254       free (segs);
3255   }
3256
3257   return status;
3258 }
3259
3260
3261 // /////////////////////////////////////////////////////////////////
3262 // selection_changed - do stuff based on the current selection
3263 // /////////////////////////////////////////////////////////////////
3264
3265 void
3266 NodeWindowAgent::selection_changed()
3267 {
3268 #ifdef SELECTION_DEBUG
3269   cerr << "NodeWindowAgent::selection_changed()" << endl;
3270 #endif
3271   SelectionChanged msg ;
3272   UAS_Sender<SelectionChanged>::send_message (msg);
3273 }
3274
3275 bool
3276 NodeWindowAgent::selection_contains_graphic()
3277 {
3278   _DtCvStatus status ;
3279   _DtCvSegPts **segs ;
3280
3281   status=
3282       _DtCanvasGetSelectionPoints(f_help_dsp_area->canvas, // canvas
3283                                   &segs,                  // returned segments
3284                                   NULL, NULL);         // ret_x, ret_y
3285
3286   if ((_DtCvSTATUS_OK == status) && (NULL != segs))
3287     {
3288       for (int i = 0 ; segs[i] ; i++)
3289         if (_DtCvIsSegRegion(segs[i]->segment))
3290           {
3291             return TRUE ;
3292           }
3293     }
3294   return FALSE ;
3295 }
3296
3297
3298 void
3299 NodeWindowAgent::receive (SelectionChanged &, void* /*client_data*/)
3300 {
3301 #ifdef SELECTION_DEBUG
3302   cerr << "NodeWindowAgent::receive(<SelectionChanged>) --> " ;
3303   if (f_help_dsp_area->primary)
3304     cerr << "true" << endl;
3305   else
3306     cerr << "false" << endl;
3307   if (f_help_dsp_area->text_selected)
3308     cerr << "text_selected: true" << endl;
3309   else
3310     cerr << "text_selected: false" << endl;
3311 #endif
3312
3313 #if 1
3314   Boolean sensitivity  = f_help_dsp_area->text_selected;
3315 #else
3316   // primary is the wrong flag to use here--it is always
3317   // true (except before the first time text has been selected),
3318   // so the create mark menu is always active.
3319   Boolean sensitivity  = f_help_dsp_area->primary ;
3320 #endif
3321
3322   XtSetSensitive(f_create_bmrk, sensitivity);
3323   XtSetSensitive(f_create_anno, sensitivity);
3324
3325   if (MarkCanvas::selected_mark() &&
3326       MarkCanvas::selected_mark()->agent() == this)
3327   {
3328 #ifdef MOVE_MARK_DEBUG
3329     fprintf(stderr, "(DEBUG) agent=0x%x move_mark sensitivity=%d\n",
3330                                         (void*)this, sensitivity);
3331 #endif
3332     XtSetSensitive(f_move_mark, sensitivity);
3333   }
3334   
3335 #ifdef JBM
3336   // Update the move function if a Mark is selected somewhere. 
3337   if (MarkCanvas::selected_mark() != NULL)
3338     f_move_mark->SetSensitive (sensitivity);
3339 #endif
3340   
3341
3342 #ifdef EAM
3343   if (sensitivity)
3344     XtSetSensitive(f_detach_graphic, selection_contains_graphic());
3345   else
3346     XtSetSensitive(f_detach_graphic, False);
3347 #endif
3348 }
3349
3350
3351 // /////////////////////////////////////////////////////////////////
3352 // mark_selection_changed
3353 // /////////////////////////////////////////////////////////////////
3354
3355 void
3356 NodeWindowAgent::receive (MarkSelectionChanged &message, void* /*client_data*/)
3357 {
3358   Boolean sensitivity;
3359   if (message.f_selection_type == MarkSelectionChanged::SELECT)
3360     sensitivity = True;
3361   else
3362     sensitivity = False;
3363   
3364   // Update edit and delete controls based on mark selection.
3365   // We only consider marks that are selected in our viewport. 
3366   if (MarkCanvas::selected_mark()->agent() == this)
3367     {
3368       XtSetSensitive(f_edit_mark, sensitivity);
3369       XtSetSensitive(f_delete_mark, sensitivity);
3370       XtSetSensitive(f_move_mark,
3371                      sensitivity && f_help_dsp_area->text_selected);
3372
3373       if (sensitivity)
3374         select_mark_in_canvas(MarkCanvas::selected_mark(), message.f_move_to);
3375       else
3376         deselect_mark_in_canvas(MarkCanvas::selected_mark());
3377     }
3378   
3379 #ifdef JBM
3380   // Update the move function only if our viewport has the selection.d 
3381   if (f_viewport_agent->selection_range() != NULL)
3382     f_move_mark->SetSensitive (sensitivity);
3383 #endif
3384 }
3385
3386 void
3387 NodeWindowAgent::deselect_mark_in_canvas(MarkCanvas *mark)
3388 {
3389   if (mark == NULL)
3390     return;
3391
3392   _DtCvPointInfo point_info;
3393
3394   point_info.client_data = mark;        // this is how we
3395                                         // identify it
3396   
3397   _DtCanvasActivatePts (f_help_dsp_area->canvas, // canvas
3398                         _DtCvACTIVATE_MARK_OFF,  // mask
3399                         &point_info,             // mark identification
3400                         NULL,                    // *ret_y1
3401                         NULL                     // *ret_y2
3402                         );
3403 }
3404
3405 void
3406 NodeWindowAgent::select_mark_in_canvas(MarkCanvas *mark_to_show, bool show_it)
3407 {
3408 #ifdef BOOKMARK_SELECT_DEBUG
3409   cerr << "select_mark_in_canvas" << endl;
3410 #endif
3411   _DtCvUnit ret_x, ret_y, ret_baseline, ret_height ;
3412
3413   _DtCvStatus status = 
3414     _DtCanvasMoveTraversal(f_help_dsp_area->canvas, // canvas
3415                            _DtCvTRAVERSAL_MARK,     // traverse to id
3416                            _DtCvFALSE,              // no wrapping of traversal
3417                            _DtCvTRUE,               // render - what should this be?
3418                            mark_to_show,            // mark id
3419                            &ret_x, 
3420                            &ret_y, 
3421                            &ret_baseline, 
3422                            &ret_height);
3423
3424   _DtCvPointInfo point_info ;
3425   
3426   List_Iterator <MarkCanvas *> m (f_mark_list);
3427   
3428   for (; m; m++)
3429   {
3430     point_info.client_data = m.item();  // this is how we
3431                                         // identify it
3432
3433     _DtCanvasActivatePts (f_help_dsp_area->canvas, // canvas
3434                         _DtCvACTIVATE_MARK_OFF,  // mask
3435                         &point_info,             // mark identification
3436                         NULL,                    // *ret_y1
3437                         NULL                     // *ret_y2
3438                         );
3439   }
3440
3441   point_info.client_data = mark_to_show;
3442
3443     _DtCanvasActivatePts (f_help_dsp_area->canvas,
3444                           _DtCvACTIVATE_MARK_ON, // mask
3445                           &point_info,           // info
3446                           0,                     // ret_y1
3447                           0                      // ret_y2
3448                           );
3449   // if requested, attempt to bring it into focus
3450
3451   // this may make more sense to move it into the canvas code, but I'm
3452   // first trying to do it from the application level
3453
3454   if ((_DtCvSTATUS_OK == status) && show_it)
3455     {
3456       if ((ret_y > (f_help_dsp_area->firstVisible + 10)) &&
3457           (ret_y <= (f_help_dsp_area->firstVisible + f_help_dsp_area->dispUseHeight)))
3458         {
3459           /* already on screen */
3460           /* do nothing */
3461         }
3462       else
3463         {
3464           _DtCvUnit the_position = ret_y ;
3465           if ((the_position + f_help_dsp_area->dispUseHeight) > f_help_dsp_area->maxYpos)
3466             {
3467               // avoid going beyond top of last page
3468               the_position = f_help_dsp_area->maxYpos - f_help_dsp_area->dispUseHeight ;
3469             }
3470           else
3471             {
3472               the_position -= 2/3 * f_help_dsp_area->dispUseHeight ;
3473             }
3474           if (the_position < 0)
3475             the_position = 0 ;
3476
3477 #ifdef BOOKMARK_JUMP_DEBUG
3478           cerr << "Clean and draw at: " << the_position << "\twas: " << f_help_dsp_area->firstVisible << endl;
3479 #endif
3480           f_help_dsp_area->firstVisible = the_position ;
3481
3482           // adjust the scrollbar
3483           Arg arg[1] ; 
3484           XtSetArg(arg[0], XmNvalue, the_position);
3485           XtSetValues(f_help_dsp_area->vertScrollWid, arg, 1);
3486           
3487           // call the scrollbar notify callback because we adjusted it
3488           if (f_help_dsp_area->vScrollNotify)
3489             (f_help_dsp_area->vScrollNotify)(this, the_position);
3490
3491         }
3492     }
3493 }
3494
3495 // /////////////////////////////////////////////////////////////////
3496 // edit_mark - edit the selected mark
3497 // /////////////////////////////////////////////////////////////////
3498
3499 void
3500 NodeWindowAgent::edit_markCB(Widget, XtPointer, XtPointer)
3501 {
3502   Xassert (MarkCanvas::selected_mark() != NULL);
3503   MarkCanvas::selected_mark()->mark_ptr()->edit();
3504 }
3505
3506
3507 // /////////////////////////////////////////////////////////////////
3508 // delete_mark - delete the selected mark
3509 // /////////////////////////////////////////////////////////////////
3510 void
3511 NodeWindowAgent::delete_markCB(Widget, XtPointer client_data, XtPointer)
3512 {
3513   NodeWindowAgent* agent = (NodeWindowAgent*)client_data;
3514   agent->delete_mark();
3515 }
3516
3517 void
3518 NodeWindowAgent::delete_mark()
3519 {
3520   Xassert (MarkCanvas::selected_mark() != NULL);
3521   mtry
3522     {
3523       MarkCanvas::selected_mark()->mark_ptr()->remove();
3524
3525       XtSetSensitive(f_create_bmrk, False);
3526       XtSetSensitive(f_create_anno, False);
3527     }
3528   mcatch_any()
3529     {
3530       message_mgr().error_dialog (
3531                 (char*)UAS_String(CATGETS(Set_Messages, 11,
3532                         "Dtinfo is unable to delete this bookmark.")),
3533                           (Widget)f_shell);
3534     }
3535   end_try;
3536 }
3537
3538
3539 // /////////////////////////////////////////////////////////////////
3540 // move_mark - move the selected mark to the selected text region
3541 // /////////////////////////////////////////////////////////////////
3542
3543 void
3544 NodeWindowAgent::move_mark()
3545 {
3546   // f_move_mark must be insensetive if there's no mark selected
3547   if (MarkCanvas::selected_mark() == NULL ||
3548       MarkCanvas::selected_mark()->agent() != this) {
3549 #ifdef BOOKMARK_DEBUG
3550     cerr << "bookmark not selected in this reading window" << endl;
3551 #endif
3552     return;
3553   }
3554
3555   if (! (make_bookmark(False, MarkCanvas::selected_mark()) < 0))
3556     delete_mark();
3557 }
3558
3559 void
3560 NodeWindowAgent::move_markCB(Widget, XtPointer client_data, XtPointer)
3561 {
3562   NodeWindowAgent* agent = (NodeWindowAgent*)client_data;
3563   agent->move_mark();
3564
3565 #ifdef JBM
3566   Xassert (MarkCanvas::selected_mark() != NULL);
3567   Xassert (f_viewport_agent->selection_range() != NULL);
3568   UAS_Pointer<Mark> mark_ptr = MarkTml::selected_mark()->mark_ptr();
3569   Wait_Cursor bob;
3570   // Create a new mark based on the old one at the new location.
3571   mtry
3572     {
3573       f_viewport_agent->mark_creator (this); // 94/10/27 yuji bug fix for TC-530
3574       UAS_Pointer<UAS_Common> d;
3575       mark_mgr().move_mark (d = f_node_ptr,
3576                             AnchorCanvas (f_viewport_agent->selection_range()),
3577                             mark_ptr);
3578     }
3579   mcatch_any()
3580     {
3581       message_mgr().error_dialog (
3582                 (char*)UAS_String(CATGETS(Set_Messages, 12,
3583                         "Dtinfo is unable to remove this bookmark.")),
3584                           (Widget)f_shell);
3585     }
3586   end_try;
3587 #endif
3588 }
3589
3590 void
3591 NodeWindowAgent::set_min_size()
3592 {
3593   Dimension width, height, vwidth, vheight;
3594   
3595   f_shell->Get (WArgList (XmNheight, (XtArgVal) &height,
3596                           XmNwidth, &width, NULL));
3597
3598   Widget wid = XtParent(XtParent(f_help_dsp_area->dispWid));
3599   WXmFrame(wid).Get(
3600                     WArgList (XmNheight, (XtArgVal) &vheight,
3601                               XmNwidth, &vwidth, NULL)
3602                     );
3603   
3604   
3605   ON_DEBUG (printf ("shell size = %d x %d\n", width, height));
3606   ON_DEBUG (printf ("viewport size = %d x %d\n", vheight, vwidth));
3607   
3608   f_shell->Set (WArgList (XmNminHeight, height - vheight + 60,
3609                           XmNminWidth, width - vwidth + 170, NULL));
3610 }
3611
3612 void
3613 NodeWindowAgent::detach_graphicCB(Widget, XtPointer client_data, XtPointer)
3614 {
3615   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
3616   agent->detach_graphic();
3617 }
3618
3619 void
3620 NodeWindowAgent::dialog_mapped (Widget w, XtPointer client_data,
3621                           XEvent *, Boolean *)
3622 {
3623   XmUpdateDisplay (w);
3624
3625   *((int *) client_data) = TRUE;
3626 }
3627
3628
3629 void
3630 NodeWindowAgent::detach_graphic()
3631 {
3632   Wait_Cursor wc ; 
3633   XEvent event;
3634   static Cursor pick_cursor;
3635
3636
3637   // Display an instructional dialog.
3638   WXmMessageDialog
3639     info_dialog ((Widget)f_shell, (char*)"detach_msg",
3640                  WArgList (XmNdialogType, XmDIALOG_INFORMATION, NULL));
3641   WXmDialogShell shell (info_dialog.Parent());
3642   // set window title
3643   String string = CATGETS(Set_Messages, 72, "Dtinfo: Detach Graphic");
3644   XtVaSetValues((Widget)shell, XmNtitle, string, NULL);
3645   info_dialog.MessageString (
3646         (char*)UAS_String(CATGETS(Set_Messages, 73, "Click on graphic")));
3647   XtUnmanageChild (info_dialog.OkPB());
3648   XtUnmanageChild (info_dialog.HelpPB());
3649
3650   XtVaSetValues((Widget)info_dialog, XmNdefaultPosition, False, NULL);
3651
3652   // Wait for the dialog to appear.
3653   int mapped = FALSE;
3654   info_dialog.Manage();
3655   XtAddEventHandler (info_dialog, ExposureMask, False,
3656                      dialog_mapped, (XtPointer) &mapped);
3657   XtAppContext app_context = window_system().app_context();
3658   while (!mapped)
3659   {
3660     XtAppNextEvent (app_context, &event);
3661     XtDispatchEvent (&event);
3662   }
3663
3664   pick_cursor = XCreateFontCursor (window_system().display(), XC_crosshair);
3665   Widget target = XmTrackingEvent ((Widget)f_shell, pick_cursor, False, &event);
3666
3667   if(target != NULL && target == f_help_dsp_area->dispWid)
3668   {
3669     _DtCvSegment *seg;
3670     _DtCvElemType element;
3671     seg = xy_to_seg(event.xbutton.x, event.xbutton.y, &element);
3672     if (seg && element == _DtCvREGION_TYPE)
3673     {
3674       SegClientData* pSCD = (SegClientData*)(seg->client_use);
3675       UAS_Pointer<Graphic> gr = (Graphic*)pSCD->GraphicHandle();
3676
3677     if (!gr->is_detached())
3678         graphics_mgr().detach (f_node_view_info->node_ptr(), gr);
3679     }
3680   }
3681
3682   // Nuke the dialog.
3683   info_dialog.Unmanage();
3684   XtDestroyWidget (info_dialog.Parent());
3685 }
3686
3687 // /////////////////////////////////////////////////////////////////
3688 // show_locator
3689 // /////////////////////////////////////////////////////////////////
3690
3691 void
3692 NodeWindowAgent::show_locatorCB(Widget, XtPointer closure, XtPointer)
3693 {
3694   NodeWindowAgent *agent = (NodeWindowAgent *)closure;
3695   agent->show_locator();
3696 }
3697
3698 void
3699 NodeWindowAgent::show_locator()
3700 {
3701   // initially this only gets the locator for the current section
3702   // and does not go into a section
3703   char buffer[BUFSIZ];
3704   //const char *locator = f_node_ptr->locator();
3705   UAS_String locator_str = f_node_ptr->id();
3706   const char *locator = (const char *)locator_str;
3707   snprintf (buffer, sizeof(buffer),
3708            CATGETS(Set_NodeWindowAgent, 4,
3709                    "The locator for this section is %s"), locator);
3710   XmTextFieldSetString(f_status_text, buffer);
3711   XmTextFieldSetSelection(f_status_text,
3712                           strlen(buffer) - strlen(locator),
3713                           strlen(buffer), CurrentTime);
3714 }
3715
3716
3717 // /////////////////////////////////////////////////////////////////////////
3718 // Preferences
3719 // /////////////////////////////////////////////////////////////////////////
3720
3721 static void
3722 prefsCB(Widget, XtPointer, XtPointer)
3723 {
3724   pref_mgr().display();
3725 }
3726
3727 // /////////////////////////////////////////////////////////////////
3728 // list_marks - pop up the marks list
3729 // /////////////////////////////////////////////////////////////////
3730
3731 static void
3732 mark_listCB(Widget, XtPointer, XtPointer)
3733 {
3734   mark_mgr().display_mark_list();
3735 }
3736
3737 // /////////////////////////////////////////////////////////////////////////
3738 // Query Editor
3739 // /////////////////////////////////////////////////////////////////////////
3740
3741 static void
3742 query_editorCB(Widget, XtPointer, XtPointer)
3743 {
3744   Wait_Cursor wc ;
3745   search_mgr().display_editor();
3746 }
3747
3748 void
3749 NodeWindowAgent::clear_searchCB(Widget, XtPointer client_data, XtPointer)
3750 {
3751   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
3752   agent->clear_search_hits_activate();
3753 }
3754
3755 void
3756 NodeWindowAgent::clear_search_hits_activate()
3757 {
3758     f_node_view_info->clear_search_hits();
3759
3760     _DtCvUnit width, height;
3761
3762     _DtCvStatus status;
3763     status = _DtCanvasResize((_DtCvHandle)f_help_dsp_area->canvas,
3764                                                 _DtCvTRUE, &width, &height);
3765
3766     if (status == _DtCvSTATUS_OK)
3767     {
3768         XClearArea(XtDisplay(f_help_dsp_area->dispWid),
3769                    XtWindow(f_help_dsp_area->dispWid),
3770                    0, 0, 0, 0, TRUE);
3771
3772         _DtCanvasRender((_DtCvHandle)f_help_dsp_area->canvas, 0, 0,
3773                         width, height, _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
3774     }
3775 #ifdef DEBUG
3776     else if (status == _DtCvSTATUS_NONE)
3777         fprintf(stderr, "(WARNING) re-layout did not occur.\n");
3778     else if (status == _DtCvSTATUS_BAD)
3779         fprintf(stderr, "(ERROR) there were problems during re-layout.\n");
3780     else
3781         fprintf(stderr, "(ERROR) unknown code returned.\n");
3782 #endif
3783
3784     if (XtIsSensitive(f_search_next)) {
3785         XtSetSensitive(f_search_next, False);
3786         XtSetSensitive(f_search_next2, False);
3787     }
3788     if (XtIsSensitive(f_search_prev)) {
3789         XtSetSensitive(f_search_prev, False);
3790         XtSetSensitive(f_search_prev2, False);
3791     }
3792
3793     if (XtIsSensitive(f_clear_search_hits))
3794         XtSetSensitive(f_clear_search_hits, False);
3795 }
3796
3797
3798 #ifdef DEBUG
3799 #ifdef MONITOR
3800 extern "C" {
3801   extern void moncontrol(int)  ;
3802 }
3803 void
3804 NodeWindowAgent::monitor(WCallback *wcb)
3805 {
3806   moncontrol((int)wcb->CallData());
3807 }
3808 #endif
3809 #endif
3810
3811
3812 // /////////////////////////////////////////////////////////////////
3813 // display
3814 // /////////////////////////////////////////////////////////////////
3815
3816 void
3817 NodeWindowAgent::display (UAS_Pointer<UAS_Common> &node_ptr)
3818 {
3819   bool first_time = False;
3820   
3821   if (f_shell == NULL)
3822     {
3823       create_ui();
3824       first_time = TRUE;
3825     }
3826   
3827 #ifdef JBM
3828   f_viewport_agent->pre_display();
3829 #endif
3830   
3831   // Clear the old DisplayData.  This is necessary because we
3832   // are about to delete the value that it is set to. 
3833   //  f_viewport->DisplayData (NULL);  not necessary, I think  DJB
3834   
3835   // Grab the scrolled position of the old node and save it in the history.
3836   // If the node was displayed from the history, don't bother, because the
3837   // position has already been recorded since the history had to be advanced. 
3838   if (!f_history_display && !g_style_sheet_update)
3839     record_history_position();
3840   
3841   
3842   int sameNode = f_node_view_info && f_node_view_info->node_ptr() == node_ptr;
3843   if (sameNode && !g_style_sheet_update && !f_history_display) {
3844 //    extern char g_top_locator[];
3845 #ifdef JBM
3846     // need to change this to pass in the locator to SetTopic so the
3847     // Canvas knows where to scroll to when it displays
3848     f_viewport_agent->show_locator (0, g_top_locator);
3849 #endif
3850   } else {
3851
3852     if (f_node_view_info) {
3853       _DtCvTopicInfo topic;
3854       memset(&topic, 0, sizeof(_DtCvTopicInfo));
3855       _DtCanvasSetTopic(f_help_dsp_area->canvas, &topic, _DtCvFALSE,
3856                         NULL, NULL, NULL);
3857
3858       // deleting this object causes massive error messages on novell
3859
3860       delete f_node_view_info;
3861       f_node_view_info = NULL;
3862
3863     }
3864     
3865     // Create a new view for the specified node.
3866     
3867     // exporting the display area so that the CanvasRenderer has
3868     // access to it to load the fonts 
3869     
3870     extern DtHelpDispAreaStruct *gHelpDisplayArea ;
3871     gHelpDisplayArea = f_help_dsp_area ;
3872
3873     //  if (f_node_view_info == NULL)
3874     //  {
3875     //      f_node_view_info = new NodeViewInfo(node_ptr);
3876     //      f_node_view_info = node_mgr().load(node_ptr);
3877     //  }
3878     
3879     f_node_view_info = node_mgr().load(node_ptr);
3880     
3881     
3882     XtAddCallback (f_help_dsp_area->dispWid, 
3883                    XmNdisarmCallback, selection_end_callback,
3884                    (XtPointer)this);    
3885
3886     XtAddCallback (f_help_dsp_area->dispWid,
3887                    XmNdisarmCallback, disarm_callback, (XtPointer)this);
3888   }
3889   
3890   UAS_Pointer<UAS_List<UAS_TextRun> >
3891         current_search_hits = search_mgr().current_hits();
3892
3893   if (current_search_hits != (UAS_Pointer<UAS_List<UAS_TextRun> >)NULL)
3894   {
3895       f_node_view_info->set_search_hits(current_search_hits);
3896
3897       if (! XtIsSensitive(f_clear_search_hits))
3898         XtSetSensitive(f_clear_search_hits, True);
3899   }
3900
3901   f_node_view_info->comp_pixel_values(
3902                                         XtDisplay(f_help_dsp_area->dispWid),
3903                                         f_help_dsp_area->colormap
3904
3905                                      );
3906   
3907   _DtCvTopicInfo *topic = f_node_view_info->topic();
3908   SetTopic(topic);
3909   
3910   initialize_controls();
3911   
3912   if (f_graphics_handler) {
3913     delete f_graphics_handler;
3914     f_graphics_handler = NULL;
3915   }
3916   f_graphics_handler = new GraphicsHandler (this);
3917   // tell the pixmaps what viewport they are attached to 
3918   //List_Iterator<UAS_Pointer<Graphic> > cursor(&f_node_view_info->graphics());
3919   //for (; cursor; cursor++)
3920     //{
3921       //cursor.item()->pixmap_graphic()->register_handler(f_graphics_handler);
3922     //}
3923
3924
3925   char buffer[256];
3926   *((char *) memcpy(buffer, "Dtinfo: ", 8) + 8) = '\0';
3927   int slen = strlen(buffer);
3928   *((char *) memcpy(buffer + slen,
3929                     f_node_view_info->node_ptr()->book_name (UAS_LONG_TITLE),
3930                     127) + 127) = '\0';
3931   f_shell->Title (buffer);
3932   f_shell->IconName (buffer);
3933   
3934   
3935   if (!g_style_sheet_update)
3936     {
3937       f_shell->Popup();
3938       if (first_time)
3939         {
3940           set_min_size(); // NOTE: this really needs to happen before the popup!! 
3941           XLowerWindow (XtDisplay (*f_tab_area), XtWindow (*f_tab_area));
3942         }
3943       
3944       f_shell->DeIconify();
3945     }
3946   
3947   if (first_time == TRUE) {
3948     XtUnmanageChild(f_form);
3949     XtRealizeWidget(f_form);
3950     XtManageChild(f_form);
3951   }
3952
3953   bool move_to_mark = TRUE;
3954     
3955   if (current_search_hits != (UAS_Pointer<UAS_List<UAS_TextRun> >)NULL 
3956       && f_node_view_info->hit_entries() > 0) 
3957   {
3958       _DtHelpSearchMoveTraversal((XtPointer)f_help_dsp_area, 0);
3959       
3960       move_to_mark = FALSE;
3961   }
3962
3963   // do bookmarks
3964   do_bookmarks(move_to_mark);
3965
3966   if (first_time && *g_top_locator) // Try again... (really Canvas bug)
3967   {
3968     node_mgr().set_preferred_window (this);
3969
3970     bool locked = f_locked; // force display in this window
3971     f_locked = FALSE;
3972
3973     node_ptr->retrieve();
3974
3975     f_locked = locked;
3976
3977     return;
3978   }
3979   else {
3980     // reset sub-component specifier here at last
3981     *g_top_locator = 0;
3982   }
3983
3984   _DtHelpCleanAndDrawWholeCanvas(f_help_dsp_area);
3985 }
3986
3987 void 
3988 NodeWindowAgent::do_bookmarks(bool move_to_mark)
3989 {
3990   unsigned bookmark_errors = 0 ;
3991   xList<UAS_Pointer<Mark> > marks ;
3992   UAS_Pointer<UAS_Common> bogus ;
3993   bogus = f_node_view_info->node_ptr() ;
3994   mark_mgr().get_marks (bogus, marks);
3995   List_Iterator<UAS_Pointer<Mark> > i (marks);
3996   
3997   MarkCanvas *jump_to = NULL ;
3998
3999 #ifdef BOOKMARK_DEBUG
4000   cerr << "id = : " << bogus->id() << endl;
4001   cerr << "** Marks: " << marks.length() << " **" << endl;
4002 #endif
4003   while (i)
4004     {
4005       mtry {
4006         MarkCanvas *mc = add_mark (i.item());
4007         if (g_view_mark() == i.item())
4008           jump_to = mc ;
4009       }
4010       mcatch_any()
4011         {
4012 #ifdef BOOKMARK_DEBUG     
4013           cerr << "error adding bookmark " << i.item()->name() << endl;
4014 #endif
4015           bookmark_errors++ ;
4016         }
4017       end_try ;
4018
4019       i++ ;
4020     }
4021   if (bookmark_errors > 0)
4022     {
4023       message_mgr().error_dialog (
4024                 (char*)UAS_String(CATGETS(Set_Messages, 10,
4025                         "Dtinfo is unable to create this bookmark.")),
4026                           (Widget)f_shell);
4027     }
4028 #ifdef BOOKMARK_JUMP_DEBUG
4029   if (g_view_mark() != 0)
4030     cerr << "have jump" << endl;
4031   else
4032     cerr << "have NO jump" << endl;
4033 #endif
4034
4035   show_mark (jump_to, move_to_mark);
4036 }
4037
4038
4039 // /////////////////////////////////////////////////////////////////
4040 // clone - clone the current node
4041 // /////////////////////////////////////////////////////////////////
4042
4043 void
4044 NodeWindowAgent::cloneCB(Widget, XtPointer client_data, XtPointer)
4045 {
4046   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
4047   node_mgr().force_new_window();
4048   agent->f_node_view_info->node_ptr()->retrieve();
4049 }
4050
4051
4052 // /////////////////////////////////////////////////////////////////
4053 // initialize_hierarchy - init the ancestral hierarchy control
4054 // /////////////////////////////////////////////////////////////////
4055
4056 void
4057 NodeWindowAgent::initialize_hierarchy()
4058 {
4059   List_Iterator<Ancestor *> i (f_ancestor_list);
4060   UAS_Pointer<UAS_Common> toc_ptr = f_node_view_info->node_ptr();
4061   int t;
4062   
4063   // If there's no TOC document for this node, use the node title.
4064   UAS_String tt = f_node_view_info->node_ptr()->title();
4065   if (toc_ptr == (UAS_Pointer<UAS_Common>)NULL)
4066     {
4067       if (i)
4068         i.item()->update ((char *) tt, NULL);
4069       else
4070         {
4071           Ancestor *a = new Ancestor (this, *f_title_menu,
4072                                       (char *) tt,
4073                                       NULL);
4074           // Each time an entry is activated we must reset the hierarchy
4075           // control in case the node in this window does not change. 
4076           ON_ACTIVATE (a->f_button, reset_hierarchy);
4077           f_ancestor_list.append (a);
4078           // Reset the iterator so that the rest are properly unmanaged. 
4079           i.reset();
4080                        }
4081       i++;
4082     }
4083   else
4084     {
4085       // See if the node is in the current hierarchy.
4086       while (i && XtIsManaged (i.item()->f_button))
4087         {
4088           if (i.item()->f_toc_ptr == toc_ptr)
4089             {
4090               // Found it -- set the menu history and return.
4091               f_current_ancestor = i.item();
4092               f_title_option->MenuHistory (f_current_ancestor->f_button);
4093               // Finish the traversal and get the tabs from here on up.
4094               while (i && XtIsManaged (i.item()->f_button))
4095                 {
4096                   toc_ptr = i.item()->f_toc_ptr;
4097                   UAS_List<UAS_Common> tabList = toc_ptr->book_tab_list();
4098                   t = tabList.length();
4099                   while (t-- > 0)
4100                     g_tab_list.insert (tabList[t]);
4101                   i++;
4102                 }
4103               return;
4104             }
4105           i++;
4106         }
4107       
4108       // Didn't find it, so revise the current hierarchy.
4109       // The hierarcy list is stored from the last entry to the
4110       // first because we have to traverse the hierarchy from
4111       // top to bottom, but we can only traverse a list forward.
4112       // Therefore, the XmNpositionIndex of the button must be
4113       // set to 0 in the resource file so that new buttons are
4114       // always inserted at the beginning of the popup menu. 
4115       int depth = 0;
4116       i.reset();
4117       while (toc_ptr != (UAS_Pointer<UAS_Common>)NULL)
4118         {
4119           // Update existing entries until we run out, then start
4120           // adding new entries. 
4121           UAS_String ttt = toc_ptr->title();
4122           if (i)
4123             {
4124               i.item()->update ((char *) ttt, toc_ptr);
4125               i++;
4126             }
4127           else
4128             {
4129               Ancestor *a =
4130                 new Ancestor (this, *f_title_menu, (char *) ttt, toc_ptr);
4131               ON_ACTIVATE (a->f_button, reset_hierarchy);
4132               f_ancestor_list.append (a);
4133             }
4134           // 15 is the magic maximum TOC depth... 
4135           if (++depth > 15)
4136             {
4137               message_mgr().error_dialog(
4138                 (char*)UAS_String(CATGETS(Set_Messages, 13, "File a Bug")),
4139                           (Widget)f_shell);
4140               break;
4141             }
4142           
4143           // Push the tabs for each TOC entry onto the tab list.
4144           // The list is assumed to be empty at the start of this method.
4145           UAS_List<UAS_Common> tabList = toc_ptr->book_tab_list ();
4146           t = tabList.length();
4147           while (t-- > 0)
4148             {
4149               ON_DEBUG (puts ("Inserting in g_tab_list"));
4150               g_tab_list.insert (tabList[t]);
4151             }
4152           
4153           toc_ptr = toc_ptr->parent();
4154         }
4155     }
4156   
4157   // Clear and unmanage the leftover buttons, if any.
4158   for (; i; i++)
4159     i.item()->update (NULL, NULL);
4160   
4161   // Set the menu history to the current node entry.
4162   i.reset();
4163   // Work around Motif 1.2 bug
4164   WXmCascadeButtonGadget opb (XmOptionButtonGadget (*f_title_option));
4165   opb.Unmanage();
4166   f_current_ancestor = i.item();
4167   f_title_option->MenuHistory (f_current_ancestor->f_button);
4168   opb.Manage();
4169 }
4170
4171
4172 void
4173 NodeWindowAgent::reset_hierarchy()
4174 {
4175   // If the MenuHistory of the title_menu doesn't match what we
4176   // set it to, then we must reset it.
4177   // This can happen if the window is locked and the user chooses
4178   // a node form the ancestral hierarchy, or if an entry in the
4179   // ancestral hierarchy is not a Node document. 
4180   Widget actual = f_title_option->MenuHistory();
4181   Widget expected = f_current_ancestor->f_button;
4182   if (actual != expected)
4183     f_title_option->MenuHistory (expected);
4184 }
4185
4186
4187 // /////////////////////////////////////////////////////////////////
4188 // path handling stuff
4189 // /////////////////////////////////////////////////////////////////
4190
4191 void
4192 NodeWindowAgent::initialize_path()
4193 {
4194     UAS_Pointer<UAS_Common> path = f_node_view_info->node_ptr();
4195   
4196     if ((path != (UAS_Pointer<UAS_Common>)NULL)
4197         && (path->next() != (UAS_Pointer<UAS_Common>)NULL)) {
4198         XtSetSensitive(f_node_next, True);
4199         XtSetSensitive(f_node_next2, True);
4200         XtSetSensitive(f_node_next3, True);
4201     } else {
4202         XtSetSensitive(f_node_next, False);
4203         XtSetSensitive(f_node_next2, False);
4204         XtSetSensitive(f_node_next3, False);
4205     }
4206     
4207     if ((path != (UAS_Pointer<UAS_Common>)NULL) && 
4208         (path->previous() != (UAS_Pointer<UAS_Common>)NULL)) {
4209         XtSetSensitive(f_node_prev, True);
4210         XtSetSensitive(f_node_prev2, True);
4211         XtSetSensitive(f_node_prev3, True);
4212     } else {
4213         XtSetSensitive(f_node_prev, False);
4214         XtSetSensitive(f_node_prev2, False);
4215         XtSetSensitive(f_node_prev3, False);
4216     }
4217 }
4218
4219 void
4220 NodeWindowAgent::refresh(const UAS_Pointer<Graphic>& pg)
4221 {
4222 #ifdef JBM
4223   f_viewport_agent->refresh(pg);
4224 #endif
4225 }
4226
4227 void
4228 NodeWindowAgent::preview_nextCB(Widget, XtPointer client_data, XtPointer)
4229 {
4230   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
4231   agent->f_preview_document = agent->f_node_view_info->node_ptr()->next();
4232   agent->f_preview_timeout =
4233     new WTimeOut (window_system().app_context(), 550,
4234                   agent, (WTimeOutFunc) &NodeWindowAgent::preview);
4235 }
4236
4237 void
4238 NodeWindowAgent::preview_previousCB(Widget, XtPointer client_data, XtPointer)
4239 {
4240   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
4241   agent->f_preview_document = agent->f_node_view_info->node_ptr()->previous();
4242   agent->f_preview_timeout =
4243     new WTimeOut (window_system().app_context(), 550,
4244                   agent, (WTimeOutFunc) &NodeWindowAgent::preview);
4245 }
4246
4247
4248 void
4249 NodeWindowAgent::node_nextCB(Widget, XtPointer client_data, XtPointer)
4250 {
4251   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
4252   // If this callback is called, the node must have a next. 
4253   node_mgr().set_preferred_window (agent);
4254   agent->f_node_view_info->node_ptr()->next()->retrieve();
4255 }
4256
4257 void
4258 NodeWindowAgent::node_previousCB(Widget, XtPointer client_data, XtPointer)
4259 {
4260   NodeWindowAgent *agent = (NodeWindowAgent *)client_data;
4261   // If this callback is called, the node must have a previous. 
4262   node_mgr().set_preferred_window (agent);
4263   agent->f_node_view_info->node_ptr()->previous()->retrieve();
4264 }
4265
4266
4267 // /////////////////////////////////////////////////////////////////
4268 // add_quick_help
4269 // /////////////////////////////////////////////////////////////////
4270
4271 void
4272 NodeWindowAgent::add_quick_help (Widget w, const char* help_text)
4273 {
4274   if (help_text == NULL || *help_text == '\0') {
4275     XtVaSetValues(w, XmNuserData, NULL, NULL);
4276     return;
4277   }
4278   else
4279     XtVaSetValues(w, XmNuserData, (void*)this, NULL);
4280
4281   // Now add the event handlers to display the quick help.
4282   XtAddEventHandler (w, EnterWindowMask, False, quick_helpEH, (XtPointer)help_text);
4283   XtAddEventHandler (w, LeaveWindowMask, False, quick_helpEH, (XtPointer)help_text);
4284   XtAddEventHandler (w, FocusChangeMask, False, quick_helpEH, (XtPointer)help_text);
4285 }
4286
4287
4288 // /////////////////////////////////////////////////////////////////
4289 // quick_help
4290 // /////////////////////////////////////////////////////////////////
4291
4292 void
4293 NodeWindowAgent::quick_helpEH (Widget w, XtPointer client_data,
4294                           XEvent *event, Boolean *)
4295 {
4296   // Ok, now we can display the help text. 
4297   Arg args[2];
4298   int n;
4299   NodeWindowAgent *agent;
4300
4301   n = 0;
4302   XtSetArg(args[n], XmNuserData, &agent); n++;
4303   XtGetValues(w, args, n);
4304
4305   // display quick help if moving into widget or clear quick help
4306   // if moving out of widget.
4307   if (event->type == EnterNotify || event->type == FocusIn)
4308     XmTextFieldSetString(agent->f_status_text, (char*)client_data);
4309   else if (event->type == LeaveNotify || event->type != FocusOut)
4310     XmTextFieldSetString(agent->f_status_text, (char*)"");
4311 }
4312
4313
4314 // /////////////////////////////////////////////////////////////////
4315 // record_history_position - save the scrolled node position
4316 // /////////////////////////////////////////////////////////////////
4317
4318 // This routine recors the scrolled position of the currently
4319 // displayed node in the current position of the local hist list. 
4320
4321 void
4322 NodeWindowAgent::record_history_position()
4323 {
4324 #ifdef JBM
4325   // If the node isn't going to be replaced, forget it.
4326   if (f_locked || f_node_view_info == NULL)
4327     return;
4328   
4329   model_pos *top = f_viewport_agent->top_model_pos();
4330   if (top != NULL) // just in case 
4331     {
4332       model_range range;
4333       range.set_start (*top);
4334       range.set_end (*top);
4335       f_history_list.set_anchor (new AnchorCanvas (&range));
4336     }
4337 #ifdef DEBUG
4338   else // this shouldn't happen
4339     {
4340       // Save the anchor, since expose events in the viewport with the
4341       // message dialog up will attempt to scroll to the (bogus) anchor. 
4342       AnchorCanvas *save = g_history_anchor;
4343       g_history_anchor = NULL;
4344       message_mgr().info_dialog ("Can't get scroll position for history.",
4345                           (Widget)f_shell);
4346       g_history_anchor = save;
4347     }
4348 #endif
4349 #endif
4350 }
4351
4352 void
4353 NodeWindowAgent::re_display()
4354 {
4355 #ifdef JBM
4356   AnchorCanvas *save_anchor = g_history_anchor ;
4357   AnchorCanvas *anchor = NULL ;
4358   g_history_anchor = NULL ;
4359   // set up to display it at current position 
4360   model_range range ;
4361   model_pos *top = f_viewport_agent->top_model_pos();
4362   if (top != NULL) // just in case 
4363     {
4364       range.set_start (*top);
4365       range.set_end (*top);
4366       // g_history anchor is set to NULL during display
4367       anchor = new AnchorCanvas(&range);
4368       g_history_anchor = anchor;
4369     }
4370 #ifdef DEBUG
4371   else // this shouldn't happen
4372     {
4373       // Save the anchor, since expose events in the viewport with the
4374       // message dialog up will attempt to scroll to the (bogus) anchor. 
4375       AnchorCanvas *save = g_history_anchor;
4376       g_history_anchor = NULL;
4377       message_mgr().info_dialog ("Can't get scroll position for re-display.");
4378       g_history_anchor = save;
4379     }
4380 #endif
4381   
4382   bool lock_flag = f_locked ;
4383   f_locked = False ; // have to force it to happen regardless of lock 
4384   
4385   mtry
4386     {
4387       
4388       node_mgr().set_preferred_window(this); // make re-display happen in this window 
4389       f_node_view_info->node_ptr()->retrieve(); // same node 
4390       
4391       f_locked = lock_flag ;
4392       
4393     }
4394   mcatch_any()
4395     {
4396       delete anchor ;
4397       g_history_anchor = save_anchor ;
4398       rethrow;
4399     }
4400   end_try;
4401   delete anchor;
4402   g_history_anchor = save_anchor; 
4403 #endif
4404 }
4405
4406 void
4407 NodeWindowAgent::SetTopic(_DtCvTopicPtr topic)
4408 {
4409   cleanup_marks();
4410
4411   /*
4412      this routine was paraphrased from _DtHelpDisplayAreaSetList
4413    */
4414
4415   _DtHelpClearSelection(f_help_dsp_area);
4416
4417   _DtCvUnit ret_width, ret_height, ret_y = 0;
4418
4419   { // set topic with component SGML id set
4420     if (g_top_locator[0] != 0)
4421       topic->id_str = g_top_locator ;
4422
4423     _DtCanvasSetTopic(f_help_dsp_area->canvas, topic, _DtCvFALSE,
4424                                &ret_width, &ret_height, &ret_y);
4425 #ifdef CV_HYPER_DEBUG
4426     cerr << "top locator=" << topic->id_str << ' ' 
4427          << "firstVisible=" << ret_y << endl;
4428 #endif
4429    // This statement was for debug purposes only and is no
4430    // longer needed.
4431    // if (status != _DtCvSTATUS_OK)
4432    //   cerr << "(ERROR) _DtCanvasSetTopic failed, error# " << status << endl;
4433   }
4434
4435   f_vscrollbar_offset = ret_y ;
4436
4437   /*
4438    SetMaxPositions (f_help_dsp_area, ret_width, ret_height);
4439    */
4440   f_help_dsp_area->maxX = ret_width ;
4441   f_help_dsp_area->maxYpos = ret_height +
4442     f_help_dsp_area->marginHeight ;
4443
4444   f_help_dsp_area->firstVisible = ret_y ;
4445
4446   (void) _DtHelpSetScrollBars (f_help_dsp_area, 
4447                                f_help_dsp_area->dispWidth,
4448                                f_help_dsp_area->dispHeight); 
4449 }
4450
4451 // helper functions for create_canvas_mark
4452 // finds the next string segment after the
4453 // given segment
4454
4455 // this is highly inefficient when we have to start
4456 // finding parents, as there are no up pointers in the tree so we walk
4457 // down from the top each time, but this should be rare, and probably
4458 // is more efficient in time (and definitely space) than keeping a
4459 // stack of the parents
4460
4461
4462 #if 0
4463 static _DtCvSegment *
4464 contains(_DtCvSegment *root, _DtCvSegment *segment)
4465 {
4466   // need to find the parent container of
4467   // the given segment
4468   
4469   if (_DtCvIsSegContainer(root))
4470     {
4471       _DtCvSegment *seglist = root->handle.container.seg_list ;
4472       while (seglist)
4473         {
4474           if (seglist == segment)
4475             return root ;
4476
4477           if (_DtCvIsSegContainer(seglist))
4478             {
4479               _DtCvSegment *tseg = contains(seglist, segment);
4480               if (tseg)
4481                 return tseg ;
4482             }
4483
4484           seglist = seglist->next_seg ;
4485         }
4486     }
4487
4488     return 0 ;
4489
4490 }
4491
4492 static _DtCvSegment *
4493 find_string_seg(_DtCvSegment *segment)
4494 {
4495   // finds the next string segment moving
4496   // forward from (and counting) segment
4497
4498   if (!segment)
4499     return 0 ;
4500
4501   while (segment && !_DtCvIsSegString(segment))
4502     {
4503       if (_DtCvIsSegContainer (segment))
4504         {
4505           _DtCvSegment *rseg = find_string_seg(segment->handle.container.seg_list);
4506           if (rseg)
4507             return rseg ;
4508         }
4509       segment = segment->next_seg ;
4510     }
4511   return segment ;
4512 }
4513
4514 static 
4515 _DtCvSegment *
4516 next_string_segment(_DtCvSegment *root, _DtCvSegment *start)
4517 {
4518   _DtCvSegment *rseg = 0;
4519
4520
4521   rseg = find_string_seg(start->next_seg); // recursive procedure
4522
4523   if (rseg)
4524     return rseg ;
4525
4526   // walk up the tree
4527   while (!rseg)
4528     {
4529       start = contains(root, start);
4530       assert (_DtCvIsSegContainer (start));
4531       if (!start)
4532         throw (CASTEXCEPT Exception());
4533           
4534       return next_string_segment(root, start);
4535     }
4536
4537   return 0;
4538 }
4539 #endif
4540
4541
4542
4543 #define CURRENT_FORMAT "TML-1"
4544
4545 inline unsigned min(unsigned a, unsigned b)
4546 {
4547   return a < b ? a : b ;
4548 }
4549
4550 MarkCanvas *
4551 NodeWindowAgent::create_canvas_mark(_DtCvHandle  canvas,
4552                                     NodeViewInfo *nvinfo,
4553                                     UAS_Pointer<Mark> &mark)
4554 {
4555   if (canvas == NULL || nvinfo == NULL || mark == (UAS_Pointer<Mark>)NULL)
4556     return NULL;
4557
4558   const Anchor &anchor = mark->anchor();
4559
4560   if (strcmp (anchor.format(), CURRENT_FORMAT) != 0)
4561     return NULL;
4562   
4563   MarkInfo markinfo;
4564
4565   UAS_String location(anchor.location());
4566
4567   UAS_String locator, marks_loc;
4568   location.split(';', locator, marks_loc);
4569 #ifdef BOOKMARK_DEBUG
4570   fprintf(stderr, "(DEBUG) marked section=\"%s\"\n", (char*)location);
4571 #endif
4572
4573   UAS_List<UAS_String> marks_loc_list;
4574   marks_loc_list = marks_loc.splitFields(',');
4575
4576   unsigned int i;
4577   for (i = 0; i < marks_loc_list.length(); i++)
4578   {
4579     UAS_String& mark_loc = *marks_loc_list[i];
4580     unsigned int vcc, offset, length;
4581
4582     sscanf((char*)mark_loc, "%u\t%u\t%u", &vcc, &offset, &length);
4583
4584     markinfo.insert_item(UAS_Pointer<MarkUnitInfo>(
4585                 new MarkUnitInfo(vcc, offset, length, NULL)));
4586 #ifdef BOOKMARK_DEBUG
4587     fprintf(stderr, "(DEBUG) marked position=(%u,%u,%u)\n",
4588                                         vcc, offset, length);
4589 #endif
4590   }
4591
4592   if (markinfo.length() == 0)
4593     return NULL;
4594
4595   _DtCvSegPts **segs = new _DtCvSegPts*[markinfo.length() + 1];
4596   memset(segs, 0, (markinfo.length() + 1) * sizeof(_DtCvSegPts*));
4597
4598   for (i = 0; i < markinfo.length(); i++)
4599   {
4600     MarkUnitInfo& mui = *markinfo[i];
4601
4602     segs[i] = new _DtCvSegPts;
4603
4604     segs[i]->segment = nvinfo->get_segment(mui.vcc());
4605     segs[i]->offset  = mui.offset() ;
4606     segs[i]->len     = mui.length();
4607   }  
4608
4609   MarkCanvas *mark_canvas =
4610                 new MarkCanvas(mark, this, markinfo[0]->offset(), 0);
4611
4612   // place the mark in the Canvas 
4613       
4614   _DtCvPointInfo point_info;
4615       
4616   point_info.client_data = mark_canvas ;
4617   point_info.segs =  segs ;
4618       
4619 #ifdef BOOKMARK_DEBUG
4620   _DtCvSegPts** iter = segs;
4621   for (; *iter; iter++) {
4622         cerr << "relative offset=" << (*iter)->offset << " " <<
4623                 "len=" << (*iter)->len << " " <<
4624                 (char*)(*iter)->segment->handle.string.string << endl;
4625   }
4626 #endif
4627
4628   int ret_y1, ret_y2 ;
4629
4630   _DtCvStatus status = _DtCanvasActivatePts(canvas, 
4631                         _DtCvACTIVATE_MARK /* | _DtCvACTIVATE_MARK_ON */,
4632                                         &point_info, &ret_y1, &ret_y2);
4633   (void) _DtCanvasProcessSelection(canvas, 0, 0, _DtCvSELECTION_CLEAR);
4634
4635 #ifdef MARK_ON_DEBUG
4636   status  = _DtCanvasActivatePts(canvas,
4637                              _DtCvACTIVATE_MARK_ON, 0, 0, 0);
4638 #endif
4639
4640   // clean up segpts
4641   for (i = 0; i < markinfo.length(); i++)
4642     delete segs[i];
4643
4644   delete segs ;
4645       
4646 #ifdef BOOKMARK_DEBUG
4647   if (status == _DtCvSTATUS_BAD)
4648     cerr << "Activate Pts --> bad return" << endl;
4649   else
4650     cerr << "Activate Pts y1( " << ret_y1 << "), y2( " << ret_y2 << ")" << endl;
4651 #endif    
4652   
4653   if (status == _DtCvSTATUS_BAD) {
4654     delete mark_canvas ;
4655     mark_canvas = NULL;
4656   }
4657   else
4658     mark_canvas->y_position (ret_y1);
4659   
4660   return mark_canvas ;
4661 }
4662
4663 #if 0
4664 static unsigned
4665 find_segment_offset (_DtCvSegment *start, const _DtCvSegment *target,
4666                      unsigned &offset)
4667 {
4668   // find the offset of the target segment from the starting point
4669   // offset is accumulated recursively
4670   
4671   if (start == target)
4672   {
4673     return 1 ;
4674   }
4675   else if(start == NULL)
4676   {
4677     return False;
4678   }
4679   
4680   Boolean found = False ;
4681   switch (start->type & _DtCvPRIMARY_MASK)
4682     {
4683     case _DtCvCONTAINER:
4684       found = find_segment_offset (start->handle.container.seg_list,
4685                                    target, offset);
4686       break ;
4687     case _DtCvSTRING:
4688       {
4689 #ifdef BOOKMARK_DEBUG
4690         //cerr << "[" << offset << "]\t" << start->handle.string.string << endl;
4691 #endif
4692         // do not count this string if it was added data
4693         if (!(start->type & _DtCvAPP_FLAG1))
4694           offset += strlen( (const char *)(start->handle.string.string) ) ;
4695       }
4696       break ;
4697     case _DtCvTABLE:
4698       {
4699         for (int i = 0; start->handle.table.cells[i] != NULL; i++)
4700         {
4701           found = find_segment_offset (start->handle.table.cells[i],
4702                                        target, offset);
4703           if (found)
4704              break;
4705         }
4706       }
4707       break;
4708     }
4709   
4710   if (!found && start->next_seg)
4711     return find_segment_offset (start->next_seg, target, offset);
4712   
4713   return found ;
4714 }
4715 #endif
4716
4717 void
4718 NodeWindowAgent::link_to (const char *locator)
4719 {
4720   UAS_String loc(locator);
4721   UAS_Pointer<UAS_Common> target =
4722                 f_node_view_info->node_ptr()->create_relative (loc);
4723
4724   // NOTE: create_relative may fail if the infolib associated with
4725   //       has been removed. If so, do not try to retrieve.
4726   if (target) {
4727     node_mgr().set_preferred_window (this);
4728   
4729     int len = MIN(strlen((char*)loc), 4096 - 1);
4730     *((char *) memcpy(g_top_locator, (char*)loc, len) + len) = '\0';
4731   
4732     target->retrieve() ;
4733   }
4734 }
4735
4736 void
4737 NodeWindowAgent::canvas_resize()
4738 {
4739 #ifdef RESIZE_DEBUG
4740   cerr << "canvas_resize" << endl;
4741 #endif  
4742   
4743   layout_mark_icons();
4744 }
4745
4746 int g_blew_away_marks_too_bad_you_lose_dts_14590;
4747 void
4748 NodeWindowAgent::layout_mark_icons()
4749 {
4750   if (f_help_dsp_area == NULL)
4751     return;
4752
4753   f_vscrollbar_offset = f_help_dsp_area->firstVisible;
4754
4755   if (f_mark_list.length() == 0)
4756     return;
4757   
4758   /* -------- Delete any existing icons. -------- */
4759   
4760   g_blew_away_marks_too_bad_you_lose_dts_14590 = 1 ; // inform marks chooser 
4761
4762   // first we destroy all the icons
4763 #if 1
4764   while (f_mark_icon_list.length() > 0) {
4765 #ifdef BOOKMARK_DEBUG
4766     fprintf(stderr, "(DEBUG) still %d remain, removing icon...\n",
4767                     f_mark_icon_list.length());
4768 #endif
4769     List_Iterator<MarkIcon *> iter (f_mark_icon_list);
4770     delete iter.item();
4771     f_mark_icon_list.remove(iter);
4772   }
4773 #else
4774   List_Iterator <MarkIcon *> i (f_mark_icon_list);
4775   
4776   while (i)
4777     {
4778       delete i.item();
4779       f_mark_icon_list.remove (i);
4780     }
4781 #endif
4782   
4783   /* -------- Now re-layout the icons from the list 'o Marks. -------- */
4784   
4785   // first we have to compute the new location of each MarkCanvas
4786   
4787   _DtCvMarkPos **return_positions = NULL;
4788   _DtCanvasGetMarkPositions(f_help_dsp_area->canvas,
4789                             &return_positions);
4790   
4791   for (int mpi = 0 ; return_positions[mpi]; mpi++)
4792     {
4793       _DtCvMarkPos *mark_pos = return_positions[mpi] ;
4794 #ifdef BOOKMARK_DEBUG
4795       cerr << "Recalc Mark Pos:" << mark_pos->y1 << endl;
4796 #endif
4797       ((MarkCanvas*) mark_pos->client_data)->y_position (mark_pos->y1);
4798
4799       free(mark_pos);
4800     }
4801   free(return_positions);
4802   
4803   // The list of MarkCanvas objects is already in order of occurance
4804   // in the node, so we can just process them in order to create
4805   // the revised set of MarkIcons.
4806   
4807   
4808   List_Iterator <MarkCanvas *> m (f_mark_list);
4809   MarkIcon *mark_icon = NULL;
4810 //MarkCanvas  *jump_to = NULL;
4811   
4812   while (m)
4813     {
4814       if (g_view_mark() == m.item()->mark_ptr())
4815         {
4816           g_view_mark() = NULL;
4817 //        jump_to = m.item();
4818         }
4819
4820       MarkIcon *mi = NULL;
4821       List_Iterator<MarkIcon *> iter (f_mark_icon_list);
4822       while (iter)
4823       {
4824         mi = iter.item();
4825
4826         if (mi && m.item()->y_position() > mi->ypos() - mi->Height()
4827                && m.item()->y_position() < mi->ypos() + mi->Height()) {
4828           mi->append(m.item());
4829           break;
4830         }
4831
4832         mi = NULL;
4833         iter++;
4834       }
4835
4836       if (mi == NULL) {
4837         mark_icon =
4838             new MarkIcon (XtParent (XtParent (f_help_dsp_area->dispWid)),
4839                           *f_shell, m.item(),
4840                           m.item()->y_position(), f_vscrollbar_offset);
4841
4842         f_mark_icon_list.append (mark_icon);
4843       }
4844
4845       m++;
4846     }
4847 }
4848
4849 void
4850 NodeWindowAgent::show_mark(MarkCanvas *jump_to, bool move_to)
4851 {
4852   if (jump_to)
4853    {
4854       // Make sure the mark has an icon
4855       if (jump_to->mark_icon() != NULL)
4856         {
4857           jump_to->select(move_to);
4858         }
4859       else
4860         {
4861           message_mgr().warning_dialog (
4862                 (char*)UAS_String(CATGETS(Set_Messages, 14,
4863                         "The bookmark cannot be displayed.")),
4864                           (Widget)f_shell);
4865         }
4866     }
4867 }
4868
4869
4870 // /////////////////////////////////////////////////////////////////
4871 // cleanup_marks
4872 // /////////////////////////////////////////////////////////////////
4873
4874 void
4875 NodeWindowAgent::cleanup_marks()
4876 {
4877   // Delete all items in these lists.
4878   List_Iterator<MarkIcon *> mi (f_mark_icon_list);
4879   while (mi)
4880     {
4881       delete mi.item();
4882       f_mark_icon_list.remove (mi);
4883     }
4884   
4885   List_Iterator<MarkCanvas *> mt (f_mark_list);
4886   while (mt)
4887     {
4888       delete mt.item();
4889       f_mark_list.remove (mt);
4890     }
4891 }
4892
4893
4894 void
4895 NodeWindowAgent::receive (MarkCreated &message, void* /*client_data*/)
4896 {
4897 #ifdef BOOKMARK_DEBUG
4898   cerr << "receive <Mark Created>" << endl;
4899 #endif
4900   // Make sure the Mark in question is dispalyed in this Viewport. 
4901   if (message.f_mark_ptr->doc_ptr() != f_node_ptr) {
4902     // Nov 11 '94 yuji - Another doc_ptr may refer to the same contents.
4903     char *locator = strdup(message.f_mark_ptr->doc_ptr()->locator());
4904     if (strcmp(locator, f_node_ptr->locator())) {
4905       free(locator);
4906       return;
4907     }
4908     free(locator);
4909   }
4910   
4911   add_mark (message.f_mark_ptr);
4912 }
4913 void
4914 NodeWindowAgent::receive (MarkDeleted &message, void* /*client_data*/)
4915 {
4916 #ifdef BOOKMARK_DEBUG
4917   cerr << "receive <Mark Deleted>" << endl;
4918 #endif
4919   delete_mark_visuals (message.f_mark_ptr) ; 
4920 }
4921
4922
4923 // /////////////////////////////////////////////////////////////////
4924 // delete_mark - delete the MarkTml and maybe icon of a Mark
4925 // /////////////////////////////////////////////////////////////////
4926
4927 void
4928 NodeWindowAgent::delete_mark_visuals (UAS_Pointer<Mark> &mark_ptr)
4929 {
4930   List_Iterator <MarkCanvas *> m (f_mark_list);
4931   
4932   // Try to find the corresponding MarkCanvas object in the mark list. 
4933   while (m)
4934     {
4935       if (mark_ptr == m.item()->mark_ptr())
4936         {
4937           MarkCanvas *mark_canvas = m.item();
4938           
4939           // Deselect the Mark first if necessary.
4940           if (mark_canvas->selected())
4941             mark_canvas->deselect();
4942           
4943           
4944           // turn traversal off
4945           _DtCanvasMoveTraversal(f_help_dsp_area->canvas,
4946                                  _DtCvTRAVERSAL_OFF, // cmd
4947                                  _DtCvTRUE,          // wrap
4948                                  _DtCvTRUE,          // render
4949                                  0, 0, 0, 0, 0);
4950
4951
4952           // Remove It from the DtCanvas
4953           
4954           _DtCvPointInfo point_info ;
4955           point_info.client_data = mark_canvas; // this is how we
4956                                                 // identify it
4957           
4958
4959           _DtCanvasActivatePts (f_help_dsp_area->canvas, // canvas
4960                                 _DtCvDEACTIVATE,         // mask
4961                                 &point_info,             // mark identification
4962                                 NULL,                    // *ret_y1
4963                                 NULL                     // *ret_y2
4964                                 );
4965           
4966           // Disconnect the MarkCanvas from the MarkIcon. 
4967           MarkIcon *mark_icon = mark_canvas->mark_icon();
4968           if (mark_icon != NULL)
4969             mark_icon->remove (mark_canvas);
4970           
4971           // Delete the MarkCanvas object and remove it from the list. 
4972           f_mark_list.remove (m);
4973           delete mark_canvas;
4974           
4975           // Delete the MarkIcon when no more Marks are associated with it. 
4976           if (mark_icon && mark_icon->mark_count() == 0)
4977             {
4978               f_mark_icon_list.remove (mark_icon);
4979               delete mark_icon;
4980             }
4981
4982           // turn traversal back on
4983           // turn traversal off
4984           _DtCanvasMoveTraversal(f_help_dsp_area->canvas,
4985                                  _DtCvTRAVERSAL_ON, // cmd
4986                                  _DtCvTRUE,         // wrap
4987                                  _DtCvTRUE,         // render
4988                                  0, 0, 0, 0, 0);
4989           return;
4990         }
4991       m++;
4992     }
4993 }
4994
4995 // /////////////////////////////////////////////////////////////////
4996 // add_mark
4997 // /////////////////////////////////////////////////////////////////
4998
4999 MarkCanvas *
5000 NodeWindowAgent::add_mark (UAS_Pointer<Mark> &mark_ptr)
5001 {
5002   MarkCanvas *mark_canvas = create_canvas_mark(f_help_dsp_area->canvas,
5003                                                f_node_view_info,
5004                                                mark_ptr);
5005   if (mark_canvas == NULL)
5006     return mark_canvas;
5007   
5008   // Insert the mark into the Mark list.
5009   // The list is ordered by starting position of the Mark. 
5010   List_Iterator<MarkCanvas *> m (f_mark_list);
5011   while (m && mark_canvas->offset() > m.item()->offset())
5012     m++;
5013   
5014   f_mark_list.insert_before (m, mark_canvas);
5015   
5016   /* -------- Make an icon appear for the new Mark. -------- */
5017   
5018   // First see if there's already an overlapping icon at the proper position.
5019   // Start by finding the icons on either side of this one. 
5020   
5021   List_Iterator<MarkIcon *> i (f_mark_icon_list);
5022
5023   while (i && mark_canvas->offset() > i.item()->offset())
5024     {
5025       i++;
5026     }
5027
5028   unsigned int ypos = mark_canvas->y_position();
5029
5030   MarkIcon *mi = NULL;
5031   List_Iterator<MarkIcon *> iter (f_mark_icon_list);
5032   while (iter) {
5033
5034       mi = iter.item();
5035
5036       if (mi && ypos > mi->ypos() - mi->Height() 
5037              && ypos < mi->ypos() + mi->Height())
5038       {
5039         // Add to the end of the icon Mark list. 
5040         mi->append (mark_canvas);
5041         break;
5042       }
5043
5044       mi = NULL;
5045       iter++;
5046   }
5047
5048   if (mi == NULL) {
5049     MarkIcon *mark_icon = 
5050         new MarkIcon (XtParent (XtParent (f_help_dsp_area->dispWid)), 
5051                       *f_shell,
5052                       mark_canvas, ypos, f_vscrollbar_offset); 
5053     f_mark_icon_list.insert_before (i, mark_icon);
5054   }
5055
5056 #ifdef BOOKMARK_DEBUG
5057   {
5058     _DtCvMarkPos **return_positions = NULL;
5059     _DtCanvasGetMarkPositions(f_help_dsp_area->canvas,
5060                               &return_positions);
5061
5062     for (int i = 0; return_positions[i]; i++)
5063     {
5064       _DtCvMarkPos* mark_pos = return_positions[i];
5065       fprintf(stderr, "(DEBUG) _DtCvMarkPos %dth ypos=%d\n", i,
5066                                                              mark_pos->y1);
5067       free(mark_pos);
5068     }
5069     free(return_positions);
5070   }
5071 #endif
5072
5073   return mark_canvas ;
5074 }
5075
5076 // /////////////////////////////////////////////////////////////////
5077 // code to initiate a mark view
5078 // /////////////////////////////////////////////////////////////////
5079
5080 class MarkViewer : public UAS_Receiver<ViewMark>
5081 {
5082 public:
5083   MarkViewer()
5084     { Mark::request (this); }
5085 private:
5086   void receive (ViewMark &message, void *client_data);
5087 };
5088
5089 void
5090 MarkViewer::receive (ViewMark &message, void* /*client_data*/)
5091 {
5092   // Slight hack... Set a global that tells the ViewportAgent to
5093   // select and jump to the specified mark when the corresponding
5094   // node is displayed (see "jump_to" below).  15:17 02-Dec-93 DJB
5095   mtry
5096     {
5097       g_view_mark() = message.f_mark_ptr;
5098
5099       UAS_Pointer<UAS_Common>& section = message.f_mark_ptr->doc_ptr();
5100       if (section == (UAS_Pointer<UAS_Common>)NULL)
5101         throw(CASTEXCEPT Exception());
5102
5103       section->retrieve();
5104     }
5105   mcatch_noarg(demoException &)
5106     {
5107       // this is a hack. what should happen, is that the catch_any below this
5108       // should only be catching a specific (or set of) exception so that others
5109       // can pass through - 14:32 06/ 1/94 - jbm
5110       rethrow ;
5111     }
5112   mcatch_any()
5113     {
5114       message_mgr().info_dialog (
5115                 (char*)UAS_String(CATGETS(Set_Messages, 15,
5116                                 "The bookcase is not accessible.")));
5117     }
5118   end_try;
5119 }
5120
5121 static MarkViewer g_mark_viewer;
5122
5123
5124 void
5125 NodeWindowAgent::receive (UAS_LibraryDestroyedMsg &msg, void* /*client_data*/)
5126 {
5127   //cerr << "NodeWindowAgent::receive (UAS_LibraryDestroyedMsg)\n";
5128   UAS_Pointer<UAS_Common> myNode = f_node_view_info->node_ptr();
5129   
5130   //
5131   //  First, if we're displaying a node from the dead library,
5132   //  just commit suicide.
5133   //
5134   if (myNode != 0 && myNode->get_library() == msg.fLib) {
5135     myNode = 0;         // Just to be safe.
5136     delete this;
5137     return;
5138   }
5139   
5140   //
5141   //  We're not displaying a node from the dead library,
5142   //  however, our local history list might contain such
5143   //  entries. Need to search the list and blow them away NOW.
5144   //
5145   f_history_list.library_removed (msg.fLib);
5146
5147   if (f_history_list.previous() != (UAS_Pointer<UAS_Common>)NULL) {
5148     XtSetSensitive(f_history_prev, True);
5149     XtSetSensitive(f_history_prev2, True);
5150   } else {
5151     XtSetSensitive(f_history_prev, False);
5152     XtSetSensitive(f_history_prev2, False);
5153   }
5154   
5155   if (f_history_list.next() != (UAS_Pointer<UAS_Common>)NULL) {
5156     XtSetSensitive(f_history_next, True);
5157     XtSetSensitive(f_history_next2, True);
5158   } else {
5159     XtSetSensitive(f_history_next, False);
5160     XtSetSensitive(f_history_next2, False);
5161   }
5162 }
5163
5164 // find the segment that contains a graphic
5165
5166 static 
5167 _DtCvSegment *find_graphic(_DtCvSegment *segment, const Graphic *gr)
5168 {
5169   if (NULL == segment)
5170     return NULL ;
5171
5172   switch (segment->type & _DtCvPRIMARY_MASK)
5173     {
5174     SegClientData* pSCD;
5175     case _DtCvREGION:
5176       pSCD = (SegClientData*)segment->client_use;
5177       if (((Graphic*)pSCD->GraphicHandle())->locator() ==
5178           ((Graphic*)gr)->locator())
5179         return segment ;
5180       break;
5181     case _DtCvCONTAINER:
5182       {
5183         _DtCvSegment *found =
5184           find_graphic(segment->handle.container.seg_list, gr);
5185         if (found)
5186           return found ;
5187       }
5188       break ;
5189     }
5190   return find_graphic (segment->next_seg, gr);
5191 }
5192
5193 void 
5194 NodeWindowAgent::detach(UAS_Pointer<Graphic> &gr)
5195 {
5196   replace (gr);
5197   _DtCvSegment *grseg;
5198
5199   // get graphic segment
5200   grseg = find_graphic(f_node_view_info->topic()->seg_list, gr);
5201   if (grseg == NULL)
5202     return;
5203
5204   SegClientData* pSCD = (SegClientData*)(grseg->client_use);
5205   UAS_Pointer<Graphic> curr_gr = (Graphic*)pSCD->GraphicHandle();
5206   curr_gr->set_detached(TRUE);
5207   //curr_gr->set_agent(gr->get_agent());
5208   
5209 }
5210
5211 void 
5212 NodeWindowAgent::reattach(UAS_Pointer<Graphic> &gr)
5213 {
5214   _DtCvSegment *grseg;
5215
5216   // get graphic segment
5217   grseg = find_graphic(f_node_view_info->topic()->seg_list, gr);
5218   if (grseg == NULL)
5219     return;
5220
5221   SegClientData* pSCD = (SegClientData*)(grseg->client_use);
5222   UAS_Pointer<Graphic> nodeview_gr = (Graphic*)pSCD->GraphicHandle();
5223   nodeview_gr->set_detached(FALSE);
5224   //curr_gr->set_agent(gr->get_agent());
5225   //replace (gr);
5226   replace (nodeview_gr);
5227 }
5228
5229 void 
5230 NodeWindowAgent::replace(UAS_Pointer<Graphic> &gr)
5231 {
5232   // have to find the graphic in the canvas, remove it from the canvas
5233   // and replace it with the detached graphic graphic.
5234   _DtCvSegment *grseg =
5235     find_graphic(f_node_view_info->topic()->seg_list, gr); 
5236
5237   if(grseg == NULL)
5238   {
5239     return;
5240   }
5241   _DtHelpDARegion     *pReg = (_DtHelpDARegion*) grseg->handle.region.info ;
5242   DtHelpGraphicStruct *pGS  = (DtHelpGraphicStruct *) pReg->handle ;
5243
5244   pGS->pix = gr->graphic()->pixmap();
5245   pGS->width = gr->graphic()->width();
5246   pGS->height = gr->graphic()->height();
5247   
5248   grseg->handle.region.width = pGS->width ;
5249   grseg->handle.region.height = pGS->height ;
5250
5251   // inform our canvas that it needs to re-render
5252   _DtCvUnit width = 0, height = 0;
5253   _DtCanvasResize((_DtCvHandle)f_help_dsp_area->canvas,
5254                            _DtCvTRUE, &width, &height);
5255   // There's no C/RE APIs provided to set maxYpos correctly
5256   // after canvas reformatting contents, so dtinfo manually
5257   // does it for now...
5258   f_help_dsp_area->maxYpos = f_help_dsp_area->marginHeight + height;
5259
5260   // now get the canvas wiped out
5261   XClearArea(XtDisplay(f_help_dsp_area->dispWid),
5262              XtWindow(f_help_dsp_area->dispWid),
5263              0, 0, 0, 0, TRUE);
5264
5265   _DtHelpSetScrollBars(f_help_dsp_area, f_help_dsp_area->dispWidth,
5266                                         f_help_dsp_area->dispHeight);
5267
5268   // _DtCanvasRender is supposed to re-render the canvas
5269   _DtCanvasRender((_DtCvHandle)f_help_dsp_area->canvas, 0, 0,
5270                 width, height, _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
5271   if (XtIsManaged(f_help_dsp_area->vertScrollWid))
5272   {
5273      // reset the scrollbar offset
5274      Arg arg[1] ; 
5275      XtSetArg(arg[0], XmNvalue, &f_vscrollbar_offset);
5276      XtGetValues(f_help_dsp_area->vertScrollWid, arg, 1);
5277   }
5278
5279   // mark icons need to be re-positioned
5280   layout_mark_icons();
5281 }
5282
5283 /*
5284  * Graphics  Handler
5285  */
5286
5287 GraphicsHandler::GraphicsHandler(NodeWindowAgent *agent)
5288 : f_agent(agent)
5289 {
5290   graphics_mgr().UAS_Sender<DetachGraphic>::
5291                  request((UAS_Receiver<DetachGraphic>*)this);
5292   graphics_mgr().UAS_Sender<ReAttachGraphic>::
5293                  request((UAS_Receiver<ReAttachGraphic>*)this);
5294 }
5295
5296 GraphicsHandler::~GraphicsHandler()
5297 {
5298 }
5299
5300 void
5301 GraphicsHandler::display_graphic(UAS_Pointer<Graphic> &gr)
5302 {
5303   UAS_Sender<DisplayGraphic>::send_message(DisplayGraphic(gr));
5304 }
5305
5306 void
5307 GraphicsHandler::receive(DetachGraphic &message, void* /*client_data*/)
5308 {
5309   UAS_Sender<DisplayGraphic>::request(message.agent());
5310   if(message.agent()->node_ptr()->id() == 
5311      f_agent->node_view_info()->node_ptr()->id())
5312   {
5313     f_agent->detach(message.graphic());
5314   }
5315 }
5316
5317 void
5318 GraphicsHandler::receive(ReAttachGraphic &message, void* /*client_data*/)
5319 {
5320   f_agent->reattach(message.graphic());
5321 }
5322