 /*
  * Khoros: $Id: clipboard.c,v 1.4 1992/03/20 22:42:36 dkhoros Exp $
  */

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

 /*
  * $Log: clipboard.c,v $
 * Revision 1.4  1992/03/20  22:42:36  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 "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name:  clipboard.c                           <<<<
   >>>>                                                       <<<<
   >>>>   description:                                        <<<<
   >>>>                                                       <<<<
   >>>>      routines:  xvl_paste_glyphs()		      <<<<
   >>>>      		xvl_cut_glyphs()		      <<<<
   >>>>      		xvl_copy_glyphs()		      <<<<
   >>>>      		xvl_duplicate_glyphs()		      <<<<
   >>>>      		xvl_delete_glyphs()		      <<<<
   >>>>      		xvl_select_glyphs()		      <<<<
   >>>>      		xvl_unselect_glyphs()		      <<<<
   >>>>      		xvl_raise_glyphs()		      <<<<
   >>>>      		xvl_lower_glyphs()		      <<<<
   >>>>      		xvl_save_glyphs()		      <<<<
   >>>>      		xvl_distribute_glyphs()		      <<<<
   >>>>      		xvl_procedure_glyphs()		      <<<<
   >>>>      		xvl_show_clipboard()		      <<<<
   >>>>      		xvl_undo_delete()		      <<<<
   >>>>                                                       <<<<
   >>>> modifications:					      <<<<
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */




/************************************************************
*
* Routine Name: xvl_paste_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_paste_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph, *new_glyph;
	GlyphList *glyphlist, *newlist = NULL;


	/*
	 *  Make sure that the clipboard workspace exists before using the edit
	 *  feature.
	 */
	if (clipboard == NULL)
	{
	   xvf_error_wait("Error!  There is currently no clipboard workspace \
from which to paste glyphs.   Please use the ClipboardForm in your X defaults \
file to specify the clipboard form.  Or make sure that the KHOROS_HOME/repos/\
cantata/clipboard.form file is present.", "xvl_paste_glyphs", NULL);
	   return;
	}

	/*
	 *  Make sure that there are glyphs in the clipboard workspace before
	 *  trying to copy them into the current workspace.
	 */
	if (clipboard->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
the clipboard workspace.  Please put glyphs into the clipboard workspace before\
 trying to copy them into the current workspace.", "xvl_paste_glyphs", NULL);
	   return;
	}

	/*
	 *  Unselect the glyphs in the current workspace, before copying the
	 *  selected clipboard glyphs into this workspace.
	 */
	xvl_unselect_glyphs(workspace);
	glyphlist = clipboard->selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   new_glyph = xvl_copy_glyph(glyph, workspace, False, 0, 0);
	   if (new_glyph != NULL)
	      newlist = xvl_add_to_glyphlist(new_glyph, newlist);

	   glyph->xpos += 10;
	   glyph->ypos += 10;
	   glyphlist = glyphlist->next;
	}
	xvf_adjust_form_indices(workspace->glyphform);
	xvl_copy_connections(clipboard->selected, newlist);
}



/************************************************************
*
* Routine Name: xvl_cut_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_cut_glyphs(workspace)

Workspace *workspace;
{
	GlyphList *glyphlist, *selected;
	Glyph	  *glyph;


	/*
	 *  Make sure that the clipboard workspace exists before using the edit
	 *  feature.
	 */
	if (clipboard == NULL)
	{
	   xvf_error_wait("Error!  There is currently no clipboard workspace \
from which to edit glyphs.   Please use the ClipboardForm in your X defaults \
file to specify the clipboard form.  Or make sure that the KHOROS_HOME/repos/\
cantata/clipboard.form file is present.", "xvl_cut_glyphs", NULL);
	   return;
	}

	/*
	 *  Make sure that there are glyphs to be copied before going off and
	 *  moving them into the clipboard workspace.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to move them into the \
clipboard workspace.", "xvl_cut_glyphs", NULL);
	   return;
	}

	/*
	 *  First clear the clipboard workspace before moving the workspace's
	 *  selected glyphs into the clipboard.
	 */
	xvl_clear_workspace(clipboard);

	/*
	 *  First off we need to delete all glyph connections that will not
	 *  be moving into the clipboard (ie. only allow connections between
	 *  glyphs that are on the selected list.
	 */
	selected = xvl_copy_glyphlist(workspace->selected);
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_cut_connections(glyph, selected);
	   glyphlist = glyphlist->next;
	}

	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_move_glyph(glyph, clipboard, True);
	   glyphlist = glyphlist->next;
	}
	xvl_destroy_glyphlist(selected);
}



/************************************************************
*
* Routine Name: xvl_delete_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_delete_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist, *selected;
	Workspace *undo_workspace;


	/*
	 *  Make sure that there are glyphs to be copied before going off and
	 *  deleting them from the current workspace.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to delte them from the \
current workspace.", "xvl_delete_glyphs", NULL);
	   return;
	}

	/*
	 *  If there is no undo workspace or this is the clipboard then
	 *  go ahead and destroy the glyphs, otherwise move them into the
	 *  temporary workspace.
	 */
	undo_workspace = workspace->undo_workspace;
	if (undo_workspace == NULL || clipboard == workspace)
	{
	   selected = xvl_copy_glyphlist(workspace->selected);
	   glyphlist = selected;
	   while (glyphlist != NULL)
	   {
	      glyph = glyphlist->glyph;
	      xvl_destroy_glyph(glyph, True);
	      glyphlist = glyphlist->next;
	   }
	   return;
	}

	/*
	 *  First clear the undo workspace before moving the workspace's
	 *  selected glyphs into the temporary undo workspace.
	 */
	xvl_clear_workspace(undo_workspace);

	/*
	 *  First off we need to delete all glyph connections that will not
	 *  be moving into the undo workspace (ie. only allow connections
	 *  between glyphs that are on the selected list.
	 */
	selected = xvl_copy_glyphlist(workspace->selected);
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_cut_connections(glyph, selected);
	   glyphlist = glyphlist->next;
	}

	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_move_glyph(glyph, undo_workspace, True);
	   glyphlist = glyphlist->next;
	}
	xvl_destroy_glyphlist(selected);
	xvl_update_undo(workspace);
}



/************************************************************
*
* Routine Name: xvl_copy_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_copy_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph, *new_glyph;
	GlyphList *glyphlist, *newlist = NULL;


	/*
	 *  Make sure that the clipboard workspace exists before using the edit
	 *  feature.
	 */
	if (clipboard == NULL)
	{
	   xvf_error_wait("Error!  There is currently no clipboard workspace \
from which to edit glyphs.   Please use the ClipboardForm in your X defaults \
file to specify the clipboard form.  Or make sure that the KHOROS_HOME/repos/\
cantata/clipboard.form file is present.", "xvl_copy_glyphs", NULL);
	   return;
	}

	/*
	 *  Make sure that there are glyphs to be copied before going off and
	 *  copying them into the clipboard workspace.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to copy them into the \
clipboard workspace.", "xvl_copy_glyphs", NULL);
	   return;
	}

	/*
	 *  First clear the clipboard workspace before copying the workspace's
	 *  selected glyphs into the clipboard.
	 */
	xvl_clear_workspace(clipboard);


	glyphlist = workspace->selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   new_glyph = xvl_copy_glyph(glyph, clipboard, False, 10, 10);
	   if (new_glyph != NULL)
	      newlist = xvl_add_to_glyphlist(new_glyph, newlist);

	   glyphlist = glyphlist->next;
	}
	xvf_adjust_form_indices(clipboard->glyphform);
	xvl_copy_connections(workspace->selected, newlist);
}



/************************************************************
*
* Routine Name: xvl_duplicate_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_duplicate_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph, *new_glyph;
	GlyphList *glyphlist, *selected;


	/*
	 *  Make sure that there are glyphs to be duplicated before going off
	 *  and copying them into the clipboard workspace.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to duplicate them in the \
current workspace.", "xvl_duplicate_glyph", NULL);
	   return;
	}

	selected = xvl_copy_glyphlist(workspace->selected);
	xvl_unselect_glyphs(workspace);

	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   new_glyph = xvl_copy_glyph(glyph, workspace, True, 10, 10);
	   glyphlist = glyphlist->next;

	   if (new_glyph != NULL)
	   {
	      workspace->selected = xvl_add_to_glyphlist(new_glyph,
			workspace->selected);
	      xvl_update_selected(new_glyph);
	   }
	}
	xvl_copy_connections(selected, workspace->selected);
	xvl_destroy_glyphlist(selected);
}



/************************************************************
*
* Routine Name: xvl_select_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_select_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist;


	glyphlist = workspace->glyphs;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   workspace->selected = xvl_add_to_glyphlist(glyph,
			workspace->selected);
	   xvl_update_selected(glyph);
	   glyphlist = glyphlist->next;
	}
}



/************************************************************
*
* Routine Name: xvl_unselect_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_unselect_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist, *selected;


	selected = xvl_copy_glyphlist(workspace->selected);
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   workspace->selected = xvl_delete_from_glyphlist(glyph,
			workspace->selected);
	   xvl_update_selected(glyph);
	   glyphlist = glyphlist->next;
	}
	xvl_destroy_glyphlist(selected);
}



/************************************************************
*
* Routine Name: xvl_raise_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_raise_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist;


	/*
	 *  Make sure that there are glyphs to be raised before going off and
	 *  raising them.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to raise them within the \
current workspace.", "xvl_raise_glyphs", NULL);
	   return;
	}

	glyphlist = workspace->selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   XRaiseWindow(XtDisplay(glyph->toplevel), XtWindow(glyph->toplevel));
	   glyphlist = glyphlist->next;
	}
}



/************************************************************
*
* Routine Name: xvl_lower_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_lower_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist;


	/*
	 *  Make sure that there are glyphs to be lowered before going off and
	 *  lowering them.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to lower them within the \
current workspace.", "xvl_lower_glyphs", NULL);
	   return;
	}
	glyphlist = workspace->selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   XLowerWindow(XtDisplay(glyph->toplevel), XtWindow(glyph->toplevel));
	   glyphlist = glyphlist->next;
	}
}



/************************************************************
*
* Routine Name: xvl_save_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_save_glyphs(workspace)

Workspace *workspace;
{
	char	temp[512];
	char	*name, *prompt = "Workspace filename:";


	/*
	 *  Make sure that there are glyphs to be saved before going off and
	 *  saving them.
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to save them for the \
current workspace.", "xvl_save_glyphs", NULL);
	   return;
	}

	/*
	 *  Prompt for the name of the saved workspace.
	 */
	name = temp;
	sprintf(name, "selected.wksp");
	if (xvf_query_wait("Choose filename for selected glyphs to be saved \
under.", &prompt, "SAVE", &name, 1, 40) != NULL)
	{
	   xvl_save_workspace(workspace, workspace->selected, name, True);
	}
}



/************************************************************
*
* Routine Name: xvl_distribute_glyphs
*
*      Purpose: This routine is used to change the location in
*		which the currently selected glyphs will be executed.
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_distribute_glyphs(workspace)

Workspace *workspace;
{
	Workspace	*attributes;


	/*
	 *  Make sure that there are glyphs to be distributed before going off
	 *  and requesting the machine in which to remote exec
	 */
	if (workspace->selected == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs selected in \
this workspace.  Please select glyphs before trying to change the machine in \
which they will be executed.", "xvl_distribute_glyphs", NULL);
	   return;
	}

	/*
	 *  Make sure that remote execution is enabled.
	 */
	attributes = xvl_get_attributes(workspace);
	if (attributes->remote_execution == False)
	{
	   xvf_error_wait("Error!  Remote execution of glyphs is currently not \
enabled for this workspace.  Please turn remote execution 'on' before trying \
to change the machine in which the currently selected glyphs will be executed.",
			"xvl_distribute_glyphs", NULL);
	   return;
	}
	xvl_change_machine(workspace->selected);
}



/************************************************************
*
* Routine Name: xvl_procedure_glyphs
*
*      Purpose: This routine is used to 
*
*        Input: workspace    -  the workspace to set the mapping
*
*       Output: 
*
*    CALLED BY:
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_procedure_glyphs(workspace)

Workspace *workspace;
{
	Glyph	  *glyph, *parent;
	Workspace *procedure;
	GlyphList *glyphlist, *selected;

	char	temp[512];
	char	*name, *prompt = "Procedure name:";


	/*
	 *  Prompt for the name of the saved workspace.
	 */
	name = temp;
	sprintf(name, "procedure");
	if (xvf_query_wait("Choose the name for the new procedure.", &prompt,
			"CREATE", &name, 1, 40) == NULL)
	{
	   return;
	}

	if ((parent = xvl_build_glyph(workspace, PROCEDURE, name, True, -1, -1))
			== NULL)
	{
	   xvf_error_wait("Error!  Unable to build a procedure in which to \
store the currently selected glyphs.  Therefore no sub-procedure will be \
created.", "xvl_procedure_glyphs", NULL);
	   return;
	}

	/*
	 *  Move the currently selected glyphs from this workspace to the
	 *  newly created procedure.  Also, create a copy of the selected
	 *  glyphs that were moved so that we can see if we need to make
	 *  external connections for the new procedure.
	 */
	selected = xvl_copy_glyphlist(workspace->selected);
	procedure = parent->val.macro;
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_move_glyph(glyph, procedure, True);
	   glyphlist = glyphlist->next;
	}

	/*
	 *  Race thru the glyphs and see if we need to create any external
	 *  connections now that we have moved the glyphs.  Local connections
	 *  may now become external.
	 */
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_create_connections(glyph, selected);
	   glyphlist = glyphlist->next;
	}
	xvl_destroy_glyphlist(selected);
}



/************************************************************
*
* Routine Name: xvl_show_clipboard
*
*      Purpose: This routine is used to show the map the clipboard
*		workspace.
*
*        Input: none
*
*       Output: none
*
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_show_clipboard()
{
	xvf_form  *form;


	/*
	 *  Make sure that the clipboard workspace exists before using the edit
	 *  feature.
	 */
	if (clipboard == NULL)
	{
	   xvf_error_wait("Error!  There is currently no clipboard workspace \
to be shown.   Please use the ClipboardForm in your X defaults \
file to specify the clipboard form.  Or make sure that the KHOROS_HOME/repos/\
cantata/clipboard.form file is present.", "xvl_show_clipboard", NULL);
	   return;
	}

	/*
	 *  Otherwise get the clipboard menuform and set the glyph_state to
	 *  False so that xvf_map_form() will map the form.  Then call 
	 *  xvl_update_all_clipboard() to update all the clipboard icons.
	 */
	form = clipboard->menuform;
	form->glyph_state = False;
	xvf_map_form(form);
	xvl_update_all_clipboard(main_workspace);
}



/************************************************************
*
* Routine Name: xvl_undo_delete
*
*      Purpose: This routine is used to undo the last delete
*		performed in the workspace.
*
*        Input: none
*
*       Output: none
*
*
*   WRITTEN BY: Mark Young
*
*
*************************************************************/


xvl_undo_delete(workspace)

Workspace *workspace;
{
	Glyph	  *glyph;
	GlyphList *glyphlist, *selected;
	Workspace *undo_workspace;


	undo_workspace = workspace->undo_workspace;
	if (undo_workspace == NULL)
	{
	   xvf_error_wait("Error!  There is currently no temporary workspace \
in which deleted glyphs are stored.   Therefore there will never be any glyphs \
to be un-deleted.  This should not happen since if temporary workspace exists \
then the user interface should not allow you to call this function.",
		"xvl_undo_delete", NULL);
	   return;
	}

	/*
	 *  Make sure that there are glyphs to be copied before going off and
	 *  deleting them from the current workspace.
	 */
	if (undo_workspace->glyphs == NULL)
	{
	   xvf_error_wait("Error!  There are currently no glyphs to be \
un-deleted.  This should not happen since if no glyphs are to restored then \
the user interface should not allow you to call this function.",
		"xvl_undo_delete", NULL);
	   return;
	}

	/*
	 *  move the glyphs back into the workspace.
	 */
	selected = xvl_copy_glyphlist(undo_workspace->glyphs);
	glyphlist = selected;
	while (glyphlist != NULL)
	{
	   glyph = glyphlist->glyph;
	   xvl_move_glyph(glyph, workspace, True);
	   glyphlist = glyphlist->next;
	}
	xvl_destroy_glyphlist(selected);

	/*
	 *  clear the workspace to make sure that all memory is freed and
	 *  that the undo_workspace is empty.
	 */
	xvl_clear_workspace(undo_workspace);
	xvl_update_undo(workspace);
	xvl_redraw_connections(workspace);
}
