/*************************************************************************
 * File: $Source: /usr/usrs/xsource/xmfm/RCS/filecb.c,v $
 * Author: Jan Newmarch
 * Last modified: $Date: 1992/11/10 05:12:29 $
 * Version: $Revision: 1.6 $
 * Purpose: This file handles the file operations as callbacks from the
 *	File menu buttons
 *
 * Revision history:
 *	5 Aug 92	fixed failure to clear Toolbar on copy, move, new
 *      25 Aug 92       removed : from dialog names for resource manager
 *	16 Oct 92	caddr_t changed to XtPointer
 *       3 Nov 92       lint-ed
 ************************************************************************/ 

#include "copyright.h"
 
/*************************************************************************
 * System includes
 ************************************************************************/ 
#include <stdio.h> 
#ifdef vax11c
#include "param.h"
#else
#include <sys/param.h>
#endif /* vax11c */

#include <Xm/CascadeB.h>     
#include <Xm/FileSB.h>      
#include <Xm/Label.h>
#include <Xm/PushB.h>    
#include <Xm/RowColumn.h>    
#include <Xm/SelectioB.h>    
#include <Xm/ScrolledW.h>
#include <Xm/ScrollBar.h>

/*************************************************************************
 * Local includes
 ************************************************************************/ 
#include "filecb.h"
#include "const.h"
#include "xmvararg.h"
#include "types.h"

/*************************************************************************
 * Functions exported
 ************************************************************************/ 
extern void FileNewFileCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);
extern void FileNewDirCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);
extern void FileCopyCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);
extern void FileMoveCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);
extern void FileCloseCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);
extern void FileExitCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);

extern void ResetFilesInPanes (
#ifdef UseFunctionPrototypes
	dir_pane_info *dpi
#endif
);

/*************************************************************************
 * Variables exported
 ************************************************************************/ 

/*************************************************************************
 * Extern variables
 ************************************************************************/ 

/*************************************************************************
 * Extern functions
 ************************************************************************/ 
extern void WarningDialog (
#ifdef UseFunctionPrototypes
	Widget parent, char *prompt, int modal, int *answer
#endif
);
extern void DestroyDialogCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer c1, XtPointer c2
#endif
);
extern DirectoryMgr *GetFilesInDir (
#ifdef UseFunctionPrototypes
	void
#endif
);
extern void invert_colours (
#ifdef UseFunctionPrototypes
	Widget w
#endif
);
extern void ClearToolbar (
#ifdef UseFunctionPrototypes
	Widget *toolbar
#endif
);
extern void FileButtonPressedCB (
#ifdef UseFunctionPrototypes
	Widget w, XtPointer client_data, XtPointer call_data
#endif
);

/*************************************************************************
 * Forward functions
 ************************************************************************/ 

/*************************************************************************
 * Local variables
 ************************************************************************/ 
int pane_count = 1;	/* mumber of window panes open */

/*************************************************************************
 * Function: FileExitCB ()
 * Purpose: terminate the entire application
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: Exit button pressed in file menu
 * Postcondition:
 ************************************************************************/ 

/* ARGSUSED */
void FileExitCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
Widget		w;		/*  widget id		*/ 
XtPointer		client_data;	/*  data from applicaiton   */ 
XtPointer		call_data;	/*  data from widget class  */ 

#endif
{ 
	int answer;

	/*	Terminate the application. 
	*/ 
	WarningDialog(w, "This will exit xmfm", True, &answer);
	if (answer == OK_ANSWER)
		exit (0);
} 
 

/*************************************************************************
 * Function: FindFileInPane()
 * Purpose: given file name, find the widget button with that name
 * In parameters: file_name, files
 * Out parameters: button
 * Precondition:
 * Postcondition: button points to widget with file_name
 ************************************************************************/ 
static void FindFileInPane 
#ifdef UseFunctionPrototypes
	(char *file_name, aWidgetList *files, Widget *button)
#else
	(file_name, files, button)
	char *file_name;
	aWidgetList *files;
	Widget *button;

#endif
{	pane_button_info *pbi;

	/* traverse current list. list ends on NULL
	   or when we hit an unmanaged widget
	*/
	while (files != NULL && XtIsManaged (files -> widget))
	{	XtVaGetValues (files -> widget, 
				XmNuserData, &pbi,
				NULL);
		if (strcmp (file_name, pbi -> name) == 0)
		{	/* found button */
			*button = files -> widget;
			return;
		}
		files = files -> next;
	}
	*button = NULL;
}

/*************************************************************************
 * Function: MoveScrolledWindowToFile ()
 * Purpose: set the scrolled window so that this file shows selected in it
 * In parameters: fle_name, dpi
 * Out parameters:
 * Precondition:
 * Postcondition:
 ************************************************************************/ 
static void 
MoveScrolledWindowToFile 
#ifdef UseFunctionPrototypes
	(char *file_name, dir_pane_info *dpi)
#else
	(file_name, dpi)
	char *file_name;
	dir_pane_info *dpi;

#endif
{
	Widget file_button;
	Widget vert_sb;
	Widget w;
	Position x, y;
	Dimension width, height;
	int max, min, value;
	int slider, incr, page;

	if (file_name == NULL)
		return;

	/* deselect old file */
	if (dpi -> file_selected != NULL)
	{
		invert_colours (dpi -> file_button_selected);
		ClearToolbar (dpi -> files_toolbar);
	}
	/* find the file_name in one of the three panes */
	file_button = NULL;
	FindFileInPane (file_name, dpi -> dirs_buttons, &file_button);
	if (file_button == NULL)
		FindFileInPane (file_name, dpi -> files_buttons, &file_button);
	if (file_button == NULL)
		FindFileInPane (file_name, dpi -> executables_buttons, &file_button);
	if (file_button == NULL)
		/* couldn't find it anywhere */
		return;
	
	/* select button, and set actions (a bit kludgy) */
	FileButtonPressedCB (file_button, NULL, NULL);

	/* where is it in row col? */
	XtVaGetValues (file_button,
		XmNx, &x, XmNy, &y, NULL);
	XtVaGetValues (XtParent (file_button),
		XmNwidth, &width,
		XmNheight, &height,
		NULL);

	/* find the vertical slider */
	w = XtParent (file_button);
	while ( !XtIsSubclass (w, xmScrolledWindowWidgetClass))
		w = XtParent (w);
	XtVaGetValues (w,
			XmNverticalScrollBar, &vert_sb,
			NULL);
	/* set the vertical slider to proportion of rowcol*/
	if (vert_sb == NULL)
		return;
	XtVaGetValues (vert_sb,
		XmNminimum, &min,
		XmNmaximum, &max,
		NULL);
	XmScrollBarGetValues (vert_sb, &value, &slider,
		&incr, &page);
	value = min + ((max - min) * y) / height;

	/* make sure we leave space for slider */
	if (value > max - slider)
		value = max - slider;

	XmScrollBarSetValues (vert_sb, value, slider,
		incr, page, True);
}

/*************************************************************************
 * Function: ResetPanesAndSelectFile ()
 * Purpose: update pane (if needed) to show file changes, and
 * 	select new file (if possible)
 * In parameters: file_name, dpi
 * Out parameters:
 * Precondition:
 * Postcondition:
 ************************************************************************/ 
void
ResetPanesAndSelectFile 
#ifdef UseFunctionPrototypes
	(dir_pane_info *dpi, char *file_name)
#else
	(dpi, file_name)
	dir_pane_info *dpi;
	char *file_name;

#endif
{	DirectoryMgr *dm;

	/* now reset panes and select this file ... */
	/* should only do this if (a) new worked, and (b) in current dir */

	if (dpi -> file_selected != NULL)
	{	invert_colours (dpi -> file_button_selected);
		dpi -> file_selected = NULL;
		ClearToolbar (dpi -> files_toolbar);
	}

        DirectoryMgrClose (dpi -> directory_manager);
        dm = GetFilesInDir ();
        dpi -> directory_manager = dm;
	ResetFilesInPanes (dpi);
	MoveScrolledWindowToFile (file_name, dpi);
}

/*************************************************************************
 * Function: NewFileOkCB ()
 * Purpose: create a new file in curent directory
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: Ok Button pressed in New File dialog
 * Postcondition: new file created, or user informed of error
 ************************************************************************/

/* ARGSUSED */ 
static void 
NewFileOkCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	XmString xmstr;
	char *file_name;
	char command[MAXPATHLEN];
	dir_pane_info *dpi;

	XtVaGetValues (w, 
			XmNtextString, (XtArgVal) &xmstr,
			XmNuserData, (XtArgVal) &dpi,
			NULL);
	XtChdir (DirectoryPath (DirectoryMgrDir (dpi -> directory_manager)));

	XmStringGetLtoR (xmstr, XmSTRING_DEFAULT_CHARSET, &file_name);
	strcpy (command, "sh -c echo >");
	strcat (command, file_name);
	system (command);

	XtUnmanageChild (w);
	XtDestroyWidget (XtParent (w));

	ResetPanesAndSelectFile (dpi, file_name);
}


/*************************************************************************
 * Function: NewDirOkCB ()
 * Purpose: create a new dir in current directory
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: OK button pressed in New Dir dialog
 * Postcondition: new dir created, or user informed of error
 ************************************************************************/ 

/* ARGSUSED */
static void 
NewDirOkCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	XmString xmstr;
	char *dir_name;
	char command[MAXPATHLEN];
	dir_pane_info *dpi;

	XtVaGetValues (w, 
			XmNtextString, &xmstr,
			XmNuserData, (XtArgVal) &dpi,
			NULL);
	XtChdir (DirectoryPath (DirectoryMgrDir (dpi -> directory_manager)));

	XmStringGetLtoR (xmstr, XmSTRING_DEFAULT_CHARSET, &dir_name);
	strcpy (command, "mkdir ");
	strcat (command, dir_name);
	system (command);

	XtUnmanageChild (w);
	XtDestroyWidget (XtParent (w));

	/* now reset panes and select this directory ... */
	ResetPanesAndSelectFile (dpi, dir_name);
}


/*************************************************************************
 * Function: MoveFileOkCB ()
 * Purpose: 
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: OK button pressed in Move File dialog
 * Postcondition: file moved to new file, which is got from a prompt
 ************************************************************************/

/* ARGSUSED */ 
static void 
MoveFileOkCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	XmString xmstr;
	char *new_file;
	char command[MAXPATHLEN];
	dir_pane_info *dpi;

	XtVaGetValues (w, 
			XmNtextString, &xmstr,
			XmNuserData, (XtArgVal) &dpi,
			NULL);
	XtChdir (DirectoryPath (DirectoryMgrDir (dpi -> directory_manager)));

	XmStringGetLtoR (xmstr, XmSTRING_DEFAULT_CHARSET, &new_file);
	strcpy (command, "mv ");
	strcat (command, dpi -> file_selected);
	strcat (command, " ");
	strcat (command, new_file);
	strcat (command, " < /dev/null");
	system (command);

	XtUnmanageChild (w);
	XtDestroyWidget (XtParent (w));

	/* now reset panes and select this file ... */
	ResetPanesAndSelectFile (dpi, new_file);
}

/*************************************************************************
 * Function: CopyFileOkCB
 * Purpose: 
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: OK button pressed in Copy File dialog
 * Postcondition: file copied to new file, which is got from a prompt
 ************************************************************************/ 

/* ARGSUSED */
static void 
CopyFileOkCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	XmString xmstr;
	char *new_file;
	char command[MAXPATHLEN];
	dir_pane_info *dpi;

	XtVaGetValues (w, 
			XmNtextString, (XtArgVal) &xmstr,
			XmNuserData, (XtArgVal) &dpi,
			NULL);
	XtChdir (DirectoryPath (DirectoryMgrDir (dpi -> directory_manager)));

	XmStringGetLtoR (xmstr, XmSTRING_DEFAULT_CHARSET, &new_file);

	/* -r option allows us to copy directories as well as files: */
	strcpy (command, "cp -r ");
	
	strcat (command, dpi -> file_selected);
	strcat (command, " ");
	strcat (command, new_file);
	strcat (command, " < /dev/null");
	system (command);

	/* now reset panes and select this file ... */
	ResetPanesAndSelectFile (dpi, new_file);

	XtUnmanageChild (w);
	XtDestroyWidget (XtParent (w));
}

/*************************************************************************
 * Function: FileNewFileCB ()
 * Purpose: create a dialog to ask for new file name
 *	with callbacks to handle OK (create file), Cancel
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: New file button pressed in File menu
 * Postcondition: New File.. dialog showing
 ************************************************************************/

/* ARGSUSED */ 
void
FileNewFileCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	Widget new_file;
	XtArgVal user_data;
	Widget help_button;

	XtVaGetValues (w, XmNuserData, &user_data, NULL);
	new_file = XmVaCreatePromptDialog (w, "new file name",
				XmNuserData, user_data, NULL);
	XtAddCallback (new_file, XmNokCallback, NewFileOkCB, NULL);
	XtAddCallback (new_file, XmNcancelCallback, DestroyDialogCB, NULL);

	help_button = XmSelectionBoxGetChild (new_file,
				XmDIALOG_HELP_BUTTON);
	XtUnmanageChild (help_button);

	XtManageChild(new_file);
}



/*************************************************************************
 * Function: FileNewDirCB ()
 * Purpose: create a dialog to ask for a new directory name
 *	with callbacks to handle OK (create dir), Cancel
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: New Dir button pressed in File menu
 * Postcondition: dialog showing
 ************************************************************************/ 

/* ARGSUSED */
void
FileNewDirCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	Widget new_dir;
	Widget help_button;
	XtArgVal user_data;

	XtVaGetValues (w, XmNuserData, &user_data, NULL);
	new_dir = XmVaCreatePromptDialog (w, "new dir name",
			XmNuserData, user_data,
			NULL);
	XtAddCallback (new_dir, XmNokCallback, NewDirOkCB, NULL);
	XtAddCallback (new_dir, XmNcancelCallback, DestroyDialogCB, NULL);

	help_button = XmSelectionBoxGetChild (new_dir,
				XmDIALOG_HELP_BUTTON);
        XtUnmanageChild (help_button);

	XtManageChild(new_dir);
}




/*************************************************************************
 * Function: FileMoveCB ()
 * Purpose: move a file to new prompted name
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: Move button pressed in file menu
 * Postcondition: dialog showing asking for new file name
 ************************************************************************/ 

/* ARGSUSED */
void
FileMoveCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	Widget new_file;
	dir_pane_info *dpi;
	int dummy;

	XtVaGetValues (w, XmNuserData, &dpi, NULL);
	if (dpi -> file_selected == NULL)
	{
		WarningDialog (w, "Must select a file to move",
				True, &dummy);
		return;
	}

	new_file = XmVaCreatePromptDialog (w, "Move to what file?",
				XmNuserData, dpi, NULL);
	XtAddCallback (new_file, XmNokCallback, MoveFileOkCB, NULL);
	XtAddCallback (new_file, XmNcancelCallback, DestroyDialogCB, NULL);
	XtManageChild(new_file);
}


/*************************************************************************
 * Function: FileCopyCB ()
 * Purpose: copy a file to new name
 * In parameters: w, client_data, call_data
 * Out parameters:
 * Precondition: Copy button pressed in File menu
 * Postcondition: dialog showing asking for new file name
 ************************************************************************/ 

/* ARGSUSED */
void
FileCopyCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	Widget new_file;
	dir_pane_info *dpi;
	int dummy;

	XtVaGetValues (w, XmNuserData, &dpi, NULL);
	if (dpi -> file_selected == NULL)
	{
		WarningDialog (w, "Must select a file to copy",
				True, &dummy);
		return;
	}

	new_file = XmVaCreatePromptDialog (w, "Copy to what file?",
				XmNuserData, dpi, NULL);
	XtAddCallback (new_file, XmNokCallback, CopyFileOkCB, NULL);
	XtAddCallback (new_file, XmNcancelCallback, DestroyDialogCB, NULL);
	XtManageChild(new_file);
}


/*************************************************************************
 * Function: FileCloseCB ()
 * Purpose: close a pane on a directory
 *	if last pane, application exits after user confirmation
 * In parameters: w, client_data, call_data
 * Out parameters: 
 * Precondition: Close button pressed in File menu
 * Postcondition: current pane destroyed
 ************************************************************************/ 

/* ARGSUSED */
void
FileCloseCB 
#ifdef UseFunctionPrototypes
	(Widget w, XtPointer client_data, XtPointer call_data)
#else
	(w, client_data, call_data)  
	Widget		w;		/*  widget id		*/ 
	XtPointer		client_data;	/*  data from applicaiton   */ 
	XtPointer		call_data;

#endif
{	int answer;

	if (pane_count == 1)
	{
		WarningDialog(w, "This will exit xmfm", True, &answer);
		if (answer == OK_ANSWER)
			exit (0);
		return;
	}
	
	/* hop up to dropdown shell */
	while ( !XtIsShell (w))
		w = XtParent (w);
	/* and to the main window */
	w = XtParent (w);
	/* hop up to toplevel shell */
	while ( !XtIsShell (w))
		w = XtParent (w);
	XtDestroyWidget (w);

	/* memory leaks in here - should reclaim
	   dpi stuff, DirMgr, etc
	*/
	
	pane_count--;
}


