 /*
  * Khoros: $Id: browser.c,v 1.3 1992/03/20 22:49:37 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: browser.c,v 1.3 1992/03/20 22:49:37 dkhoros Exp $";
#endif

 /*
  * $Log: browser.c,v $
 * Revision 1.3  1992/03/20  22:49:37  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 * 
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *----------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "utils.h"	

static  int  browser_mode = 1;
static	int  keywd_access_count = 0;

static Pixmap cr_pixmap;
#define cr_bitmap_width 16
#define cr_bitmap_height 16
static char cr_bitmap_bits[] = {
   0xe0, 0x1f, 0x80, 0x3f, 0x00, 0x3e, 0x00, 0x7c, 0x60, 0x78, 0x70, 0x78,
   0x78, 0x78, 0x3c, 0x78, 0x0e, 0x3c, 0xff, 0x1f, 0xff, 0x0f, 0x0e, 0x00,
   0x3c, 0x00, 0x78, 0x00, 0x70, 0x00, 0x60, 0x00};


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    	    file name: browser.c                      <<<<
   >>>>                                                       <<<<
   >>>>             description: File Browser 		      <<<<
   >>>>                                                       <<<<
   >>>>                xvf_run_browser()		      <<<<              
   >>>>                xvf_create_browser_widget()	      <<<<              
   >>>>                xvf_browser_cb()	      		      <<<<              
   >>>>                xvf_keywords_cb()	      	      <<<<              
   >>>>                xvf_user_defined_browser_cb()	      <<<<              
   >>>>                xvf_quit_browser_cb()   		      <<<<              
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/************************************************************
*
*  Routine Name:  xvf_run_browser
*
*      Purpose:   runs a browser widget, which pops up a widget with a list
*		  of files in the current directory,  followed by a 
*		  text widget of the bottom of the browser.
*		  Allows user to select a file from the list, or type in 
*		  a filename into the bottom text widget.  If a directory
*		  is typed into the bottom text widget, and <cr> hit,
*		  files in list will update to the contents of the
*		  new directory.
*
*	 Input:   label - label of the browser widget
*		  prompt - prompt string to appear at top of browser widget
*		  directory - path to directory in which desired files appear
*
*       Output:
*
*    Called By:   the application program
*
*   Written By:   Mark Young, Stephanie Hallet, & Danielle Argiro
*
*
*************************************************************/

char *xvf_run_browser(prompt, label, directory)

char	*prompt, *label, *directory;
{
	Widget toplevel, xvf_create_browser_widget();
	char   *slash_dir, *xvf_check_slash(), 
		**keywordlist, **xvf_compose_keyword_list();
	int    num;

	if (BROWSER_ON == true)
	{
	   xvf_error_wait("Only one browser widget may be run at a time.",
			  NULL,NULL);
           return(NULL);
        }
	BROWSER_ON = true;
	BROWSER_DONE = false;

	slash_dir = xvf_check_slash(directory);
	short_dir = xvf_strcpy(slash_dir);
	current_dir = xvf_strcpy(slash_dir);

	if (prompt == NULL)
	{
	    if (browser_mode == BrowseDirectory)
		prompt = xvf_strcpy("Select A File");
	    else
		prompt = xvf_strcpy("Select A Keyword");
	}

	if (label == NULL)
	{
	    if (browser_mode == BrowseDirectory)
		label = xvf_strcpy("FILE BROWSER");
	    else
		label = xvf_strcpy("KEYWORD BROWSER");
	}

	if (browser_mode == BrowseDirectory)
	{
	    xvf_browser = xvf_create_browser_list(current_dir);
	    if (xvf_browser == NULL)
	    {
	       BROWSER_ON = false;
               BROWSER_DONE = true;
	       return(NULL);
	    }

	    toplevel  = xvf_create_browser_widget(xvf_browser->list,
				xvf_browser->num, prompt, label);
	}
	else
	{
	    keywordlist = xvf_compose_keyword_list(full_startkey, &num);
	    toplevel    = xvf_create_browser_widget(keywordlist,
				num, prompt, label);

	}

	if (toplevel == NULL)
	{
	   BROWSER_ON = false;
           BROWSER_DONE = true;
	   return(NULL);
	}

	while (!BROWSER_DONE)
	{
	   /* this does XtNextEvent/DispatchEvent*/
	   xvf_process_event();      
	}

	BROWSER_ON = false;

	return(current_file);
}




/************************************************************
*
*  Routine Name:  Widget *xvf_create_browser_widget()
*
*      Purpose:   This routine creates the list widget and maps it to the screen
*		  It takes an array of strings, and uses each string as an item
*		  in the List. The Prompt and Label strings are used to complete
*		  the list widget, and if current is not NULL, it will come up
*		  highlighted.
*
*	 Input:   list - the array of strings that the appl. program needs to
*			 be displayed as elements of the list.
*		  size  - the size of the 'list' array
*		  prompt - a prompt or label to display on the top 
*			   of the list widget
*		  label - the label of the list widget
*
*       Output:
*
*    Called By:   the application program
*
*   Written By:   Danielle Argiro, Stephanie Hallett & Mark Young
*
*
*********************************************************************/

#define Directory_Size 40

Widget xvf_create_browser_widget(list, size, prompt, label)

char *list[];
int   size;
char  *prompt, *label;
{
     Widget toplevel;		/* toplevel widget */
     Widget back;		/* backplane for browser */
     Widget viewport;		/* viewport for browser */
     Widget label_widget;	/* label widget */
     Widget prompt_widget;	/* prompt widget */
     Widget quit_widget;	/* button to quit browser */
     Widget help_widget;	/* button to get help */
     Widget live_pixmap_widget;	/* pixmap representing <cr> */
     char name[512];
     char *top_name, *cap_top_name;
     int   width;

     Arg    arg[25];
     void   xvf_user_defined_browser_cb();
     int i, n, max_strlen, widget_height, wid_width;
     void xvf_help_browser_cb();
     static int count = 1;

     XtTranslations translation;
     static char search_trans_table[] =
	"<Key>0xff0d:      xvf_user_defined_browser_cb() \n\
	Ctrl<Key>x:        beginning-of-file()";

     static XtActionsRec actionTable[] =
     {
	{ "xvf_user_defined_browser_cb",  xvf_user_defined_browser_cb },
     };

     if (label == NULL)
	 label = xvf_strcpy("FILE BROWSER");
      
     if (prompt == NULL)
         prompt = xvf_strcpy("Select a File");
      
     if (list == NULL)
     {  
         fprintf(stderr,"xvf_create_browser_widget:\n");
         fprintf(stderr,"need a list for the list widget!\n");
         return(NULL);
     }

     max_strlen = xvf_strlen(prompt);
     widget_size = max_strlen * F_W;
     if (xvf_strlen(label) > max_strlen) max_strlen = xvf_strlen(label);
     for (i = 0; i < size; i++)
	  if (xvf_strlen(list[i]) > max_strlen) 
	     max_strlen = xvf_strlen(list[i]);


     wid_width = Directory_Size*xvf_font_width;

     sprintf(name,"%d_browse",Browser_cnt);
     Browser_cnt++;
     top_name = xvf_strcpy(name);
     cap_top_name = xvf_cap_first_letter(top_name);

     /* 
      *  create the browser's toplevel widget, and
      *  add the browser toplevel widget to the list of toplevels
      *  that is used with journal playback.
      */
     i = 0;
     XtSetArg(arg[i], XtNscreen, xvf_screen);     i++;
     XtSetArg(arg[i], XtNargc, xvf_ac); 	  i++;
     XtSetArg(arg[i], XtNargv, xvf_av);	       	  i++; 
     XtSetArg(arg[i], XtNinput, true);	       	  i++; 
     XtSetArg(arg[i], XtNwinGravity, StaticGravity);i++;
     toplevel = XtAppCreateShell(top_name,cap_top_name,
				transientShellWidgetClass, xvf_display, arg, i);
     xvf_add_toplevel(toplevel);

     /* 
      * create the backplane widget 
      */
     n = 0;
     XtSetArg(arg[n],XtNresizable,    true);       		   n++;
     XtSetArg(arg[n],XtNfromVert,NULL);				   n++;
     XtSetArg(arg[n],XtNfromHoriz,NULL);			   n++;
     XtSetArg(arg[n],XtNmappedWhenManaged,True);		   n++;
     XtSetArg(arg[n],XtNdefaultDistance,4);	        	   n++; 
     XtSetArg(arg[n],XtNborderWidth,1); 			   n++;
     back = XtCreateManagedWidget("list_back",formWidgetClass,toplevel,arg,n);

     /* 
      * create the label widget 
      */
     n = 0;
     width = wid_width - 10*xvf_font_width;
     XtSetArg(arg[n],XtNwidth, width);				 n++;
     XtSetArg(arg[n],XtNlabel,xvf_strcpy(label)); 		 n++;
     XtSetArg(arg[n],XtNfromHoriz, NULL); 		 	 n++;
     XtSetArg(arg[n],XtNfromVert, NULL); 		 	 n++;
     XtSetArg(arg[n],XtNmappedWhenManaged,True);		 n++;
     XtSetArg(arg[n],XtNborderWidth, 0);			 n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                       n++;
     }

     label_widget = XtCreateManagedWidget("label", labelWidgetClass,
					  back,arg,n);	

     /* 
      * create the prompt widget 
      */
     n = 0;
     XtSetArg(arg[n],XtNlabel,xvf_strcpy(prompt)); 		 n++;
     XtSetArg(arg[n],XtNfromHoriz,NULL);			 n++;
     XtSetArg(arg[n],XtNfromVert,label_widget);  		 n++;  
     XtSetArg(arg[n],XtNwidth,(Dimension)xvf_strlen(prompt)*F_W);n++;
     XtSetArg(arg[n],XtNheight,(Dimension) F_H);n++;
     XtSetArg(arg[n],XtNmappedWhenManaged,True);		 n++;
     XtSetArg(arg[n],XtNborderWidth, 0);			 n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                       n++;
     }
     prompt_widget = XtCreateManagedWidget("prompt", labelWidgetClass,
					     back,arg,n);	

     n = 0;
     XtSetArg(arg[n], XtNfromHoriz, NULL);           n++;
     XtSetArg(arg[n], XtNfromVert,  prompt_widget); n++;
     XtSetArg(arg[n], XtNallowVert, true);           n++;
     viewport = XtCreateManagedWidget("port", viewportWidgetClass, back, 
				       arg, n);

     /*
      *  Make sure the widget height is within some min and max entries.
      *  This will ensure that the browser is not too small or to large.
      */
     if (size < 10)
        widget_height = 10 * F_H;
     else if (size > 30)
        widget_height = 30 * F_H;
     else
        widget_height = (size+1) * F_H;

     /* 
      * create the list widget 
      */
     n = 0;
     XtSetArg(arg[n], XtNresizable, True);              	n++;
     XtSetArg(arg[n], XtNfromHoriz, NULL);			n++;
     XtSetArg(arg[n], XtNfromVert,  prompt_widget);		n++; 
     XtSetArg(arg[n], XtNhorizDistance, (Dimension) 4);		n++;
     XtSetArg(arg[n], XtNheight,(Dimension) widget_height); 	n++;   
     XtSetArg(arg[n], XtNwidth, (Dimension) wid_width);          n++;
     XtSetArg(arg[n], XtNverticalList, true);			n++; 
     XtSetArg(arg[n], XtNdefaultColumns, 1);			n++; 
     XtSetArg(arg[n], XtNforceColumns, true);			n++; 
     XtSetArg(arg[n], XtNlist, list );				n++;   
     XtSetArg(arg[n], XtNlongest, widget_size);			n++;   
     XtSetArg(arg[n], XtNnumberStrings, size);			n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                      n++;
     }
     list_widget = XtCreateManagedWidget("list", listWidgetClass, 
					  viewport, arg, n);

     /* 
      * create text widget in which user may specify 
      * their own string response 
      */
     dir_buffer= xvf_strcpy(current_dir);

     n = 0;
     XtSetArg(arg[n], XtNresizable,    true);       		   n++;
     XtSetArg(arg[n],XtNfromHoriz, NULL);			   n++;
     XtSetArg(arg[n],XtNfromVert,  viewport);      		   n++;
     XtSetArg(arg[n],XtNwidth, (Dimension) wid_width);             n++;
     XtSetArg(arg[n],XtNeditType,XawtextEdit);         	  	   n++;
     XtSetArg(arg[n],XtNstring, short_dir);	         	   n++;
     XtSetArg(arg[n],XtNlength, MaxLength);		 	   n++;
     XtSetArg(arg[n],XtNleftMargin, LEFT_MARGIN);		   n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                      n++;
     }
     string_widget = XtCreateManagedWidget("directory", asciiTextWidgetClass,
					 back, arg, n);
     XtAppAddActions(xvf_app_context, actionTable, XtNumber(actionTable));
     translation = XtParseTranslationTable(search_trans_table);
     XtOverrideTranslations(string_widget, translation);

     /* 
      * create <cr> pixmap after text widget to indicate
      * that it is "live"
      */
     if (count == 1)
         cr_pixmap = XCreateBitmapFromData(xvf_display,
                     XRootWindow(xvf_display, xvf_screen_num),
                     cr_bitmap_bits, cr_bitmap_width, cr_bitmap_height);
     count++;
     n = 0;
     XtSetArg(arg[n],XtNwidth,(Dimension) cr_bitmap_width+4);        n++;
     XtSetArg(arg[n],XtNheight,(Dimension) cr_bitmap_height+1);      n++;
     XtSetArg(arg[n],XtNborderWidth,(Dimension) 0);                  n++;
     XtSetArg(arg[n],XtNbitmap, cr_pixmap);                          n++;
     XtSetArg(arg[n],XtNfromHoriz, string_widget);                   n++;
     XtSetArg(arg[n],XtNfromVert,  viewport);         		     n++;
     XtSetArg(arg[n],XtNresizable, True);                            n++;
     live_pixmap_widget = XtCreateManagedWidget("livepixmap",
                                labelWidgetClass,back,arg,n);


     /* 
      * create help button 
      */
     n = 0;
     XtSetArg(arg[n], XtNfromVert,  NULL);    	   	        n++;
     XtSetArg(arg[n], XtNfromHoriz, label_widget);		n++;
     XtSetArg(arg[n], XtNwidth, 5*xvf_font_width);		n++;
     XtSetArg(arg[n], XtNlabel,"Help"); 		        n++;
     XtSetArg(arg[n], XtNmappedWhenManaged,True);      	        n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                      n++;
     }
     help_widget = XtCreateManagedWidget("Help", commandWidgetClass,
					    back,arg,n);
     XtAddCallback(help_widget, XtNcallback, xvf_help_browser_cb, NULL);

     /* 
      * create quit button 
      */
     n = 0;
     XtSetArg(arg[n], XtNfromVert,  NULL);    	   	        n++;
     XtSetArg(arg[n], XtNfromHoriz, help_widget);		n++;
     XtSetArg(arg[n], XtNwidth, 5*xvf_font_width);		n++;
     XtSetArg(arg[n], XtNlabel,"Quit"); 		        n++;
     XtSetArg(arg[n], XtNmappedWhenManaged,True);      	        n++;
     if (xvf_font != NULL)
     {
        XtSetArg(arg[n],XtNfont,xvf_font);                      n++;
     }
     quit_widget = XtCreateManagedWidget("Quit", commandWidgetClass,
					    back,arg,n);
     XtAddCallback(quit_widget, XtNcallback, xvf_quit_browser_cb, toplevel);

     if (browser_mode == BrowseDirectory)
        XtAddCallback(list_widget, XtNcallback, xvf_browser_cb, NULL);
     else
        XtAddCallback(list_widget, XtNcallback, xvf_keywords_cb, NULL);

     xvf_add_protocol_handler(toplevel, "WM_DELETE_WINDOW", 
			      xvf_quit_browser_cb, toplevel);

     xvf_place_widget(toplevel, NULL);
     return(toplevel);
}




/***************************************************************
*
*   Callback routines used by the browser
*
***************************************************************/

/* callback used to get string from browser list */
void xvf_browser_cb(widget, clientData, callData)  

Widget widget;
caddr_t clientData, callData;
{
	int	     num, i, len, status;
	struct stat  buf;
	XawTextBlock  text_block;
	char	     tmp_file_name[MAXPATHLEN], buff[MAXPATHLEN];
        xvf_browser_list *browser_tmp;
	Widget	     viewport,back,toplevel;
	char	     *tmp, *fullpath, *slash_dir, *save_dir, *xvf_check_slash();
	char	     *xvf_get_directory(), **xvf_compose_keyword_list();
	char	     *vdirname();
  	int check_good_dir();
        Arg  arg[MaxArgs];
        char *string_return;
	char **keywordlist;

        /* cast the pointer to the Callback data */
        XawListReturnStruct *latest = (XawListReturnStruct *) callData;

	if ((strcmp(latest->string, "../") == 0) &&
	    (strncmp(short_dir, "../", 3) != 0))
	{
	    browser_up_dir(short_dir, tmp_file_name, latest->string);
            reset_browser_thumb(widget);
	}
	else if (short_dir[(xvf_strlen(short_dir))-1] == '/')
	    sprintf(tmp_file_name,"%s%s", short_dir,  latest->string);
	else 
	    sprintf(tmp_file_name,"%s/%s", short_dir,  latest->string);


	if (strcmp(latest->string, "-- keywords --") == 0)
	{
	    full_keyword[0] = '\0';
	    if (keywd_access_count == 0)
	        full_startkey[0] = '\0';
	    keywordlist = xvf_compose_keyword_list(full_startkey, &num);
	    XawListUnhighlight(list_widget);
            XawListChange(list_widget, keywordlist, num,widget_size, TRUE);

	    XtRemoveCallback(widget, XtNcallback, xvf_browser_cb, NULL);
            XtAddCallback(widget, XtNcallback, xvf_keywords_cb, NULL);
	    keywd_access_count++;
	    browser_mode = BrowseKeywords;
	    current_file = NULL;
	    tmp_file_name[0] = '\0';
	}
	else 
	{
            save_dir = xvf_strcpy(current_dir);
	    free(short_dir);
            short_dir = xvf_strcpy(tmp_file_name);
	    (void) sprintf(tmp_file_name,"%s%s",current_dir, latest->string);
	    fullpath = vfullpath(tmp_file_name, NULL, NULL);
    
	    if (stat(fullpath, &buf) != -1)  /*  get stats for file */
	    {
	       if ((buf.st_mode & S_IFMT) == S_IFDIR)
	       {
	          slash_dir = xvf_check_slash(fullpath);
	          current_dir = xvf_strcpy(slash_dir);
                  browser_tmp = xvf_create_browser_list(current_dir);
	          if (browser_tmp == NULL)
                  {
	             current_dir = xvf_strcpy(save_dir);
		     short_dir = xvf_strcpy(save_dir);	
		     return;
                  }
	          else
                  {
		     XawListUnhighlight(list_widget);
                     xvf_delete_browser(xvf_browser);
		     xvf_browser = browser_tmp;
		     XawListChange(list_widget, (String *) xvf_browser->list,
			    xvf_browser->num,widget_size, TRUE);
                  }
	          current_dir = xvf_strcpy(short_dir);
	       }
	       else
	       {  
                  if (check_good_dir(fullpath) == true)
	          {
		     if (strcmp(latest->string, "-- keywords --") != 0)
	                current_file = xvf_strcpy(latest->string);
	          }
                  else
	             current_file = xvf_strcpy(short_dir);
	          BROWSER_DONE = true;
	       }
            }
	    else
	    {
	       sprintf(buff,"%s is an invalid directory or file\n",
		       tmp_file_name);
 	       xvf_error_wait(buff,"ERROR"," OK ");
	       if (xvf_strlen(short_dir)>0)
	       {
		   if (short_dir[xvf_strlen(short_dir)-1] == '/')
		       short_dir[xvf_strlen(short_dir)-1] = '\0';
	       }
	       short_dir = vdirname(short_dir);
	       return;
	    }
        i = 0;
        XtSetArg(arg[i], XtNstring, &string_return);    i++;
        XtGetValues(string_widget, arg, i);
        dir_buffer = xvf_strcpy(string_return);

	len = xvf_strlen(dir_buffer);
	text_block.firstPos = 0;
	text_block.length = xvf_strlen(current_dir);
	text_block.ptr = current_dir;
	text_block.format = FMT8BIT;
	status = XawTextReplace(string_widget, (XawTextPosition) 0, 
				(XawTextPosition) len, &text_block);
	if (status == XawEditDone)
	   XawTextDisplay(string_widget);
	}
        reset_browser_thumb(widget);

	if (BROWSER_DONE == true)
	{
           viewport = XtParent(widget);
           back = XtParent(viewport);
           toplevel = XtParent(back);
           xvf_delete_toplevel(toplevel);
	   XtUnmapWidget(toplevel);
	   XtDestroyWidget(toplevel);
	}
	XFlush(XtDisplay(widget));
}


void xvf_keywords_cb(widget, clientData, callData)
Widget widget;
caddr_t clientData, callData;
{
	char buffer[MaxLength]; 
	Widget	     viewport,back,toplevel;
	char **keywordlist, **xvf_compose_keyword_list();
	int  num;

      /* cast the pointer to the Callback data */
        XawListReturnStruct *latest = (XawListReturnStruct *) callData;


	if (((strcmp(latest->string, "<==") == 0) && 
	     (full_startkey[0] == '\0')) || 
	     (strcmp(latest->string, " -- directories --") == 0))
	{
	     xvf_browser = xvf_create_browser_list(current_dir);
	     if (xvf_browser == NULL)
             {
                 BROWSER_ON = false;
                 BROWSER_DONE = true;
		 current_file = NULL;
		 return;
             }
	     full_startkey[0] = '\0';
	     full_keyword[0] = '\0';
	     XawListUnhighlight(list_widget);
	     XawListChange(list_widget, xvf_browser->list,  
			   xvf_browser->num, widget_size, TRUE);
	     XtRemoveCallback(widget, XtNcallback, xvf_keywords_cb, NULL);
             XtAddCallback(widget, XtNcallback, xvf_browser_cb, NULL);
	     browser_mode = BrowseDirectory;

	}

	/* user goes "up" a level in keywords */
	else if (strcmp(latest->string, "<==") == 0)
	{
	     xvf_delete_endkey(full_startkey);
	     xvf_delete_endkey(full_keyword);
	     keywordlist = xvf_compose_keyword_list(full_startkey, &num);
	     XawListUnhighlight(list_widget);
             XawListChange(list_widget, keywordlist, num, widget_size, TRUE);
	}

	/* user selects "leaf" keyword part */
	else if (strchr(latest->string,':') == NULL)
	{
	     if (full_keyword[0] == '\0')
	     {
                 sprintf(buffer, ":%s", latest->string);
	         current_file = xvf_strcpy(buffer);
	     }
	     else
	     {
	         strcat(full_keyword, latest->string);
	         current_file = xvf_strcpy(full_keyword);
	     }
	     BROWSER_DONE = true;
	     xvf_delete_endkey(full_keyword);
	}

	/* user selects "branch" keyword part */
	else
	{
	    strcat(full_startkey, latest->string);
	    keywordlist = xvf_compose_keyword_list(full_startkey, &num);
            XawListUnhighlight(list_widget);
            XawListChange(list_widget, keywordlist, num, widget_size, TRUE);
	    strcat(full_keyword, latest->string);
	}

	if (BROWSER_DONE == true)
	{
           viewport = XtParent(widget);
           back = XtParent(viewport);
           toplevel = XtParent(back);
           xvf_delete_toplevel(toplevel);
	   XtUnmapWidget(toplevel);
	   XtDestroyWidget(toplevel);
	}

	XFlush(XtDisplay(widget));
}


/* callback used to register a user-specified string */
void xvf_user_defined_browser_cb(widget, clientData, callData)

Widget widget;
caddr_t clientData, callData;
{
        char buff[512];
	struct  stat	 buf;
	xvf_browser_list *browser_tmp;
	Widget	back,toplevel;
	char *slash_dir, *xvf_check_slash();
        char *string_return;
        Arg  arg[MaxArgs];
	int  i;

	if (browser_mode == BrowseKeywords)
	{
	    full_startkey[0] = '\0';
	    full_keyword[0] = '\0';
	    XawListUnhighlight(list_widget);
	    XawListChange(list_widget, xvf_browser->list,  
	                  xvf_browser->num, widget_size, TRUE);
	    XtRemoveCallback(list_widget, XtNcallback, xvf_keywords_cb, NULL);
            XtAddCallback(list_widget, XtNcallback, xvf_browser_cb, NULL);
	    browser_mode = BrowseDirectory;
	}

        i = 0;
        XtSetArg(arg[i], XtNstring, &string_return);    i++;
        XtGetValues(string_widget, arg, i);
	
	if (strchr(string_return,':') != NULL)
	{
            xvf_error_wait("Sorry, you may not enter a keyword in this text box.  This text box is for entering directories and file names only.  If you would like to use the Keywords capability, please use the browser list to do so.","ERROR"," OK ");
	    return;

	}

	/*
	 *  get directory or filename out of browser and check for validity
	 */
	dir_buffer = vfullpath(string_return, NULL, NULL);
	short_dir  = xvf_strcpy(string_return);
	if (dir_buffer == NULL)
	{
   	   sprintf(buff, "Error in string '%s'\n", string_return);
	   xvf_error_wait(buff,"ERROR"," OK ");
	}

	if (stat(dir_buffer, &buf) != -1)  /*  get stats for file */
	{
	   if ((buf.st_mode & S_IFMT) == S_IFDIR)
	   {  /* is a directory */
	      slash_dir = xvf_check_slash(dir_buffer);
              browser_tmp = xvf_create_browser_list(slash_dir);
	      if (browser_tmp != NULL)
              {
                 xvf_delete_browser(xvf_browser);
		 xvf_browser = browser_tmp;
		 XawListChange(list_widget, (String *) xvf_browser->list,
                        xvf_browser->num,widget_size,TRUE);
	         current_dir = xvf_strcpy(slash_dir);
	      }
	   }
	   else
	   {
		 current_file = xvf_strcpy(dir_buffer);
                 current_file  = xvf_strcpy(short_dir);
		 BROWSER_DONE = true;
	   }
        }
	else
	{
	   sprintf(buff,"%s is an invalid directory or file\n",dir_buffer);
 	   xvf_error_wait(buff,"ERROR"," OK ");
	}
	if (BROWSER_DONE == true)
	{
           back = XtParent(widget);
           toplevel = XtParent(back);
           xvf_delete_toplevel(toplevel);
	   XtUnmapWidget(toplevel);
	   XtDestroyWidget(toplevel); 
	}
        reset_browser_thumb(list_widget);
}




/***************************************************************
*
*   Callback routines used by both xvf_run_browser_wait 
*
***************************************************************/


/* callback used to quit browser */
void xvf_quit_browser_cb(widget, clientData, callData)

Widget widget;
caddr_t clientData, callData;
{
     	Widget toplevel;

 	toplevel = (Widget) clientData;

	current_file = NULL;
	BROWSER_DONE = true;

	if (BROWSER_DONE == true)
	{
           xvf_remove_protocol_handler(toplevel, "WM_DELETE_WINDOW", 
				       xvf_quit_browser_cb, toplevel);
           xvf_delete_toplevel(toplevel);
	   XtUnmapWidget(toplevel);
	   XtDestroyWidget(toplevel); 
	}
        XSync(XtDisplay(widget), FALSE);
	BROWSER_ON = false;
}

/* callback used to display online help for browser */
void xvf_help_browser_cb(widget, clientData, callData)

Widget widget;
caddr_t clientData, callData;
{
    xvf_create_online_help("KHOROS_HOME/doc/browser/help/Browser", 
                           "Online Help");
}

browser_up_dir(short_dir, file_name, latest_string)
char *short_dir;
char *file_name;
char *latest_string;
{
	int   len;
	char *tmp, *xvf_get_directory();

	if ((len = xvf_strlen(short_dir) - 1) > 0)
	{
	    if (short_dir[len] == '/')
	       short_dir[len] = '\0';

	    if (tmp = strrchr(short_dir,'/'))
	    {
	       *tmp = '\0';
	       sprintf(file_name,"%s/",short_dir);
	    }
	    else
	    {
	   	sprintf(file_name,"%s/%s",short_dir,latest_string);
		tmp = xvf_get_directory(file_name);
	        sprintf(file_name,"%s",tmp);
		free(tmp);
	    }
	}
	else if (xvf_strlen(short_dir) == 1)
	{
	   if (short_dir[0] == '/')
	       sprintf(file_name,"%s", short_dir);
	   else
	   {
	       sprintf(file_name,"%s/%s",short_dir,latest_string);
	       tmp = xvf_get_directory(file_name);
	       sprintf(file_name,"%s",tmp);
	       free(tmp);
	   }
	}
	else
	   sprintf(file_name,"%s",latest_string);
}

reset_browser_thumb(widget)
Widget widget;
{
	Widget viewport, scrollbar = NULL;
	int i;
	Arg arg[MaxArgs];
	viewport = XtParent(widget);
      
/*
	scrollbar = XtNameToWidget(viewport, "vertical");
	if (scrollbar != NULL)
	     XawScrollbarSetThumb(scrollbar, 0.0, 1.0);
*/
	i = 0;
	XtSetArg(arg[i], XtNx, 0);  		i++;
	XtSetArg(arg[i], XtNy, 0);  		i++;
        XtSetValues(viewport, arg, i);
        
}
