
 
/***************************************************************************
 *                                                                         *
 * Alberi:  Graphical Language Interface for POSTGRES                      *
 *                                                                         *
 * Copyright (c) 1992, 1993 The University of Georgia Research             *
 *                          Foundation, Inc.                               *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 * Designer and Programmer:  Ruben Robles                                  *
 * Email:  ruben@pollux.cs.uga.edu or rubenr3@aol.com or                   *
 *         rubenr3@psi.com@aol.com                                         *
 *                                                                         *
 * Modified by:		K.J. Kochut                                        *
 *			Department of Computer Science                     *
 *			University of Georgia                              *
 *			Athens, GA 30602                                   *
 *                                                                         *
 * Send comments/fixes/improvements/modifications to:                      *
 *                                                                         *
 *                     kochut@cs.uga.edu                                   *
 *                                                                         *
 ***************************************************************************/


#include <xview/xview.h>
#include <xview/notice.h>
#include <xview/panel.h>

/* slingshot headers */

#include <sspkg/canshell.h>
#include <sspkg/rectobj.h>
#include <sspkg/drawobj.h>
#include <sspkg/tree.h>
#include <sspkg/array.h>
#include <sspkg/list.h>

#include <tmp/c.h>
#include <tmp/libpq-fe.h>

#include "all_ui.h"
#include "externs.h"

#include "constants.h"
#include "grays.h"
#include "funcs.h"

extern Array_tile target_tile;


void show_hide_expression_tree(paint_window, event, canvas_shell, rectobj)
     Xv_window    paint_window;
     Event        *event;
     Canvas_shell canvas_shell;
     Rectobj      rectobj;

{
  int ypos;
  Rectobj owner, temp_owner;
  Canvas_shell the_shell;
  Tree a_tree, temp_tree;
  Rectobj_list *expressions;

   
  ypos = 0; 
 
  a_tree = (Tree) xv_get(rectobj, XV_KEY_DATA, EXPRESSION_TREE);
  the_shell = (Canvas_shell) xv_get(a_tree, XV_OWNER);
  expressions = (Rectobj_list *) xv_get(the_shell, RECTOBJ_CHILDREN);
  list_for( expressions ) { 
    temp_tree = RECTOBJ_LIST_HANDLE(expressions);
    if ( temp_tree != a_tree ) {
      temp_owner = (Rectobj) xv_get(temp_tree, XV_KEY_DATA, ARRAY_ELEMENT);
      xv_set(temp_tree, XV_SHOW, FALSE, NULL);
      xv_set(temp_owner, XV_KEY_DATA, EXPRESSION_HIDE, 0, NULL);
    }
  }

  if ( !((int) xv_get(rectobj, XV_KEY_DATA, EXPRESSION_HIDE)) ) {
    xv_set(a_tree, 
	   XV_SHOW, TRUE, 
	   /* XV_X, 0,
	      XV_Y, 0, */
	   NULL);               
    xv_set(rectobj, XV_KEY_DATA, EXPRESSION_HIDE, 1, NULL);
  }
  else {
    xv_set((Rectobj) xv_get(rectobj, XV_KEY_DATA, EXPRESSION_TREE),
	   XV_SHOW, FALSE, NULL); 
    xv_set(rectobj, XV_KEY_DATA, EXPRESSION_HIDE, 0, NULL);
  }
  owner = (Rectobj) xv_get(rectobj, XV_OWNER);
  window_fit((Canvas_shell) xv_get(owner, XV_KEY_DATA, EXPRESSION_CANVAS));
  window_fit((Frame) xv_get(canvas_shell, XV_OWNER));

}

void
adding_stuff_in_the_array(canvas_shell,
			  rectobj,
			  drop_canvas_shell,
			  drop_rectobj,
			  drop_event)
     Canvas_shell     canvas_shell;
     Rectobj          rectobj;
     Canvas_shell     drop_canvas_shell; /* where you add */
     Rectobj          drop_rectobj;   
     Event           *drop_event;

{
  Tree		tree;
  Drawtext      temptext;
  Drawicon      node1;
  Array_tile    array;
  Menu 		leaf_menu, array_elem_menu;
  Rectobj 	element, drop_guy;
  char 		temp2[128], *parent, *typname, 
  		*temp, *label, *top_label, *generic_pointer;
  int 		ypos;
  Rectobj_list  *a_list;

  a_list = get_selected_list();

  array = (Array_tile) xv_get(drop_canvas_shell, XV_KEY_DATA, THE_ARRAY);
  ypos = 10; 

  list_for(a_list) {
    drop_guy = RECTOBJ_LIST_HANDLE(a_list);
    if( !((int) xv_get(array, XV_KEY_DATA, TYPE)) || 
       ( ((int) xv_get(array, XV_KEY_DATA, TYPE)) &&
	 ((int) xv_get(drop_guy, XV_KEY_DATA, TYPE)) ) ) {    
     
      if ( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
	sprintf(temp2, "%s.%s",
		       (char *) xv_get(drop_guy, XV_KEY_DATA, CLASS),
		       (char *) xv_get(drop_guy, DRAWTEXT_STRING));
      else
	sprintf(temp2, "%s.%s",
		       (char *) xv_get(drop_guy, DRAWTEXT_STRING),
		       "all");  
     top_label = strdup(temp2);
     if ( (int) xv_get(array, XV_KEY_DATA, TYPE) )
       element = (Drawicon) xv_create(array, DRAWICON, 
                    DRAWIMAGE_SVRIMAGE, gray3,
                    DRAWTEXT_STRING, " \/* Boolean expression *\/ ",
                    RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
                    XV_KEY_DATA, EXPRESSION_HIDE, 0,
                    XV_KEY_DATA, COMMAS, 0,
                    NULL); 
     else
       if ( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
         element = (Drawicon) xv_create(array, DRAWICON, 
                    DRAWIMAGE_SVRIMAGE,
			 (Server_image) xv_get(drop_guy, DRAWIMAGE_SVRIMAGE),
                    DRAWTEXT_STRING,
			 top_label,
                    RECTOBJ_DBL_CLICK_PROC,
			 show_hide_expression_tree,
                    XV_KEY_DATA, EXPRESSION_HIDE, 0, NULL);
       else
         element = (Drawicon) xv_create(array, DRAWICON, 
                    DRAWIMAGE_SVRIMAGE, gray5,
                    DRAWTEXT_STRING, top_label,
                    RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
                    XV_KEY_DATA, EXPRESSION_HIDE, 0,
                    NULL);
      if ( (int) xv_get(array, XV_KEY_DATA, TYPE) )
	array_elem_menu = (Menu) xv_create(XV_NULL, MENU,
                                 MENU_TITLE_ITEM,
					   "Qualifier List Element",
                                 MENU_ACTION_ITEM,
					   "Delete",
					   delete_array_elem_proc,
                                 /* MENU_ACTION_ITEM,
				           "Add boolean connector...",
					   add_boolean_proc, */
                                 XV_KEY_DATA, MENU_OWNER, element, NULL);  
      else
	array_elem_menu = (Menu) xv_create(XV_NULL, MENU,
                                 MENU_TITLE_ITEM,
					   "Target List Element",
                                 MENU_ACTION_ITEM,
					   "Name the attribute...",
					   name_retrieve_attr_proc,
                                 MENU_ACTION_ITEM,
					   "Delete",
					   delete_array_elem_proc,
                                 XV_KEY_DATA, MENU_OWNER, element, NULL);
      tree = (Tree) xv_create( (Canvas_shell) xv_get(array,
						     XV_KEY_DATA,
						     EXPRESSION_CANVAS),
			      TREE,
			      XV_SHOW, FALSE,
			      RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
			      RECTOBJ_CHILD_DROP_PROC,
			        adding_stuff_to_the_expression_tree,
			      XV_KEY_DATA, ARRAY_ELEMENT, element, 
			      XV_KEY_DATA, TREE_EMPTY, 1,
			      XV_KEY_DATA, THE_ARRAY, array, 
			      NULL);

      if ( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
	parent = strdup( (char *) xv_get(drop_guy, XV_KEY_DATA, PARENT_NAME) );
      else
	parent = strdup( (char *) xv_get(drop_guy, DRAWTEXT_STRING) );
      if( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
	typname = strdup((char *) xv_get(drop_guy, XV_KEY_DATA, TYPENAME)); 
      else
	typname = strdup("No name");
        
      label = strdup(temp2);
      if ( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
	node1 = (Drawicon) xv_create(tree, DRAWICON, 
			    DRAWIMAGE_SVRIMAGE,
			    (Server_image) xv_get(drop_guy, DRAWIMAGE_SVRIMAGE),
                            DRAWTEXT_STRING, label, 
                            RECTOBJ_ACCEPTS_DROP, TRUE, 
                            RECTOBJ_DROP_PROC,
			      adding_stuff_to_the_expression_tree,
                            XV_KEY_DATA, PARENT_NAME, parent,
                            XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
                            XV_KEY_DATA, TYPENAME, typname,
                            XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
                            XV_KEY_DATA,
			      TYPE,
			      (((int) xv_get(drop_guy, XV_KEY_DATA, TYPE))?1:0),
                            NULL);
      else
	node1 = (Drawicon) xv_create(tree, DRAWICON, 
                            DRAWIMAGE_SVRIMAGE, gray5,
                            DRAWTEXT_STRING, label, 
                            RECTOBJ_ACCEPTS_DROP, TRUE, 
                            RECTOBJ_DROP_PROC,
			      adding_stuff_to_the_expression_tree,
                            XV_KEY_DATA, PARENT_NAME, parent,
                            XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
                            XV_KEY_DATA, TYPENAME, typname,
                            XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
                            XV_KEY_DATA,
			      TYPE,
			      (((int) xv_get(drop_guy, XV_KEY_DATA, TYPE))?1:0),
                            NULL);
      if ( (int) xv_get(drop_guy, XV_KEY_DATA, TYPE) )
        leaf_menu = (Menu) xv_create(XV_NULL, MENU,
                            MENU_TITLE_ITEM,
				     "Attribute",
                            MENU_ACTION_ITEM,
				     "Add operator...", add_unary_opr_proc,
                            MENU_ACTION_ITEM,
				     "Delete", delete_leaf_proc,
                            MENU_ACTION_ITEM,
				     "Name class instance...",
				     name_class_instance_proc,
                            XV_KEY_DATA, MENU_OWNER, node1, NULL);
      else 
        leaf_menu = (Menu) xv_create(XV_NULL, MENU,
                            MENU_TITLE_ITEM,
				    "Attribute",
                            MENU_ACTION_ITEM,
				    "Name class instance...",
				    name_class_instance_proc,
                            MENU_ACTION_ITEM,
				    "Delete", delete_leaf_proc,
                            XV_KEY_DATA, MENU_OWNER, node1, NULL); 
      xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL); /* Menu node attached */

      xv_set(tree, TREE_ADD_LINK, tree, node1, NULL);
 
      xv_set(element,
	     RECTOBJ_MENU, array_elem_menu, 
	     XV_KEY_DATA, EXPRESSION_TREE, tree, 
	     XV_KEY_DATA, EXPRESSION_HIDE, 0,
	     NULL);
    }
  }
  xv_set(drop_canvas_shell, 
	 CANVAS_MIN_PAINT_WIDTH, xv_get(array, XV_WIDTH) + 200,
	 CANVAS_MIN_PAINT_HEIGHT, xv_get(array, XV_HEIGHT) + 100,
	 NULL); 

  window_fit(array);
  window_fit(drop_canvas_shell);
  window_fit((Frame) xv_get(drop_canvas_shell, XV_OWNER)); 

}



void
adding_stuff_to_the_expression_tree(canvas_shell,
				    rectobj,
				    drop_canvas_shell,
				    drop_rectobj,
				    drop_event)
     Canvas_shell     canvas_shell;
     Rectobj          rectobj;
     Canvas_shell     drop_canvas_shell;
     Rectobj          drop_rectobj;   /* expression tree is contained there */
     Event           *drop_event;

{
  Tree  expression;
  char *ops[2];
  char *fnprefix = "Function";
  char *opprefix = "Operator";
  char *temp, *temp2, *typename, *daddy, *generic_char, *a_name;
  Rectobj_list  *inmediate_nodes;
  Rectobj_list  *a_list;
  Drawtext   op;
  Menu node_menu, leaf_menu;
  Rectobj node, addnode, parent_node, the_guy;
  Array_tile array;
  int found, operator, i, j, replace_or_add;

  expression = (Tree) xv_get(drop_rectobj, XV_OWNER);
  ops[0] = "Operator not set";
  ops[1] = "Function not set";
    
  array = (Array_tile) xv_get(expression, XV_KEY_DATA, THE_ARRAY);

  a_list = get_selected_list();
  j = 1;
  if ( ((int) xv_get(rectobj, XV_KEY_DATA, TYPE))
       && ((int) xv_get(drop_rectobj, XV_KEY_DATA, TYPE)) ) {
    replace_or_add = notice_prompt(drop_canvas_shell, NULL,
                                   NOTICE_MESSAGE_STRINGS, 
			      "Add the attribute or replace the current one?",
			      NULL,
                                   NOTICE_BUTTON_YES, "ADD",
                                   NOTICE_BUTTON_NO, "REPLACE", 
                                   NULL);
    if ( replace_or_add == NOTICE_YES ) {
      list_for(a_list) {
	the_guy = RECTOBJ_LIST_HANDLE(a_list);

	if ( ((int) xv_get(the_guy, XV_KEY_DATA, TYPE))
	     && ((int) xv_get(drop_rectobj, XV_KEY_DATA, TYPE)) ) {

	  if ( (int) xv_get(expression, XV_KEY_DATA, TREE_EMPTY) ) {
	    xv_set((Rectobj) xv_get(expression, XV_KEY_DATA, ARRAY_ELEMENT),
                   DRAWIMAGE_SVRIMAGE, gray3, 
                   DRAWTEXT_STRING, " \/* expression *\/ ",
                   NULL); 
	    xv_set(expression, XV_KEY_DATA, TREE_EMPTY, 0, NULL);
	    xv_set((Canvas_shell) xv_get(array, XV_OWNER), 
		   CANVAS_MIN_PAINT_WIDTH, xv_get(array, XV_WIDTH) + 10,
		   CANVAS_MIN_PAINT_HEIGHT, xv_get(array, XV_HEIGHT) + 10,
		   NULL);
	  }

	  temp2 = (char *) malloc(33*sizeof(char) + 1);
	  sprintf(temp2, "%s.%s",
		  (char *) xv_get(the_guy, XV_KEY_DATA, CLASS),
		  (char *) xv_get(the_guy, DRAWTEXT_STRING));

	  typename = strdup((char *) xv_get(the_guy, XV_KEY_DATA, TYPENAME));
    
	  daddy = strdup((char *) xv_get(the_guy, XV_KEY_DATA, PARENT_NAME));
	  
	  a_name = strdup(temp2);
	  addnode = (Drawicon)
	    xv_create(expression, DRAWICON,
		      DRAWIMAGE_SVRIMAGE,
		      (Server_image) xv_get(the_guy, DRAWIMAGE_SVRIMAGE),
		      DRAWTEXT_STRING, a_name,
		      RECTOBJ_ACCEPTS_DROP, TRUE, 
		      RECTOBJ_DROP_PROC, adding_stuff_to_the_expression_tree,
		      XV_KEY_DATA, PARENT_NAME, daddy,
		      XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
		      XV_KEY_DATA, TYPE, 1,
		      XV_KEY_DATA, TYPENAME, typename,
		      XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
		      NULL);
	  inmediate_nodes = (Rectobj_list *) xv_get(expression,
						    TREE_LINK_TO_LIST,
						      drop_rectobj); 
    
	  parent_node = (Rectobj) xv_get(expression,
					 TREE_LINK_FROM, drop_rectobj);

	  found = 0;
	  if ( inmediate_nodes != NULL ) {
	    		/* there're nodes under the current one; isn't a leaf */
	    list_for(inmediate_nodes)
	      j++;

	    if ( ((int) xv_get(drop_rectobj, XV_KEY_DATA, TYPE) == FUNC)
		 || (j < 3)) {
      
	      xv_set(expression, TREE_ADD_LINK, drop_rectobj, addnode, NULL);
	      leaf_menu = (Menu)
		xv_create(NULL, MENU,
			  MENU_TITLE_ITEM, "Attribute",
			  MENU_ACTION_ITEM,
			    "Add operator...", add_unary_opr_proc,
			  MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
			  MENU_ACTION_ITEM,
			    "Name class instance...", name_class_instance_proc,
			  XV_KEY_DATA, MENU_OWNER, addnode,
			  NULL);
	      xv_set(addnode, RECTOBJ_MENU, leaf_menu, NULL);
	      /* There're no free leaves inmediately available;
		 then add another leaf */
	    }
	    else
	      xv_destroy(addnode);

	  }
	  else { /* It's a leaf */
	    node = drop_rectobj;
	    operator =
	      notice_prompt(drop_canvas_shell, NULL, 
			    NOTICE_MESSAGE_STRINGS, "Press the button",
			    "which shows the operation to be performed",
			    NULL,
			    NOTICE_BUTTON, "Operator", 100,
			    NOTICE_BUTTON, "Function", 101,
			    NULL);
	    if ( operator == OPER ) {
         
	      temp = strdup(ops[0]);
	      op = (Drawtext) xv_create(expression, DRAWTEXT, 
					DRAWTEXT_STRING, "Operator not set",
					RECTOBJ_DBL_CLICK_PROC,
					  set_operator_or_function_proc,
					XV_KEY_DATA, NAME_SET, 0,
					RECTOBJ_ACCEPTS_DROP, TRUE, 
					XV_KEY_DATA, TYPE, operator,
					RECTOBJ_DROP_PROC,
					  adding_stuff_to_the_expression_tree,
					NULL);
	    }
	    else {
         
	      temp = strdup(ops[1]);
	      op = (Drawtext)
		xv_create(expression, DRAWTEXT, 
			  DRAWTEXT_STRING, "Function not set",
			  RECTOBJ_DBL_CLICK_PROC, set_operator_or_function_proc,
			  XV_KEY_DATA, NAME_SET, 0,
			  RECTOBJ_ACCEPTS_DROP, TRUE, 
			  XV_KEY_DATA, TYPE, operator,
			  RECTOBJ_DROP_PROC,
			    adding_stuff_to_the_expression_tree,
			  NULL);
	    }        
	    node_menu = (Menu)
	      xv_create(XV_NULL, MENU,
			MENU_TITLE_ITEM, "Operator or Function",
			MENU_ACTION_ITEM,
			  "Name/Change operator...", name_change_opr_proc,
			MENU_ACTION_ITEM,
			  "Name/Change function...", name_change_fun_proc,
			MENU_ACTION_ITEM,
			  "Add constant...", add_constant_proc,
			MENU_ACTION_ITEM, "Delete", delete_node_proc,
			MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
			XV_KEY_DATA, MENU_OWNER, op,
			NULL);

	    leaf_menu =  (Menu)
	      xv_create(XV_NULL, MENU,
			MENU_TITLE_ITEM, "Attribute or constant",
			MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
			MENU_ACTION_ITEM,
			  "Name class instance...", name_class_instance_proc,
			MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
			XV_KEY_DATA, MENU_OWNER, addnode,
			NULL);

	    xv_set(op, RECTOBJ_MENU, node_menu, NULL);
	    xv_set(addnode, RECTOBJ_MENU, leaf_menu, NULL);
	    xv_set(expression, TREE_UNLINK, drop_rectobj, NULL);
	    xv_set(expression, TREE_ADD_LINK, parent_node, op, NULL);
	    xv_set(expression, 
		   TREE_ADD_LINK, op, drop_rectobj, 
		   TREE_ADD_LINK, op, addnode, NULL);
	    
	  }
	  xv_set(drop_canvas_shell, 
		 CANVAS_MIN_PAINT_WIDTH, xv_get(expression, XV_WIDTH) + 20,
		 CANVAS_MIN_PAINT_HEIGHT, xv_get(expression, XV_HEIGHT) + 10,
		 NULL);
    
	}
      }
    } 
    else {
      if ( (int) xv_get(drop_rectobj, XV_KEY_DATA, TYPE) == 1 ) {
					/* is an attribute */
	temp2 = (char *) malloc(33*sizeof(char) + 1);
	sprintf(temp2, "%s.%s",
		(char *) xv_get(rectobj, XV_KEY_DATA, CLASS), 
		(char *) xv_get(rectobj, DRAWTEXT_STRING));

	typename = strdup((char *) xv_get(rectobj, XV_KEY_DATA, TYPENAME));
    
	daddy = strdup((char *) xv_get(rectobj, XV_KEY_DATA, PARENT_NAME));
   
	a_name= strdup(temp2);
	xv_set(drop_rectobj,
	       DRAWIMAGE_SVRIMAGE,
	         (Server_image) xv_get(rectobj, DRAWIMAGE_SVRIMAGE),
	       DRAWTEXT_STRING, a_name,
	       XV_KEY_DATA, PARENT_NAME, daddy,
	       XV_KEY_DATA, TYPENAME, typename,
	       NULL);
      }
    }
  }
  found = 0;
  a_list = (Rectobj_list *) xv_get(expression, TREE_LINK_TO_LIST, expression);
  list_for ( a_list ) {
    the_guy = RECTOBJ_LIST_HANDLE(a_list);
    found++;
  }
  a_name = strdup((char *) xv_get(the_guy, DRAWTEXT_STRING));
  if ( (found == 1)
        && !((int) xv_get((Rectobj) xv_get(expression, XV_KEY_DATA, THE_ARRAY),
			  XV_KEY_DATA, TYPE)) ) {  
    xv_set((Rectobj) xv_get(expression, XV_KEY_DATA, ARRAY_ELEMENT),
	   DRAWIMAGE_SVRIMAGE, gray2, 
	   DRAWTEXT_STRING, " \/* attribute *\/ ",
	   NULL); 
  }
 
}

void
set_operator_or_function_proc(paint_window, event, canvas_shell, rectobj)
     Xv_window     paint_window;
     Event        *event;
     Canvas_shell  canvas_shell;
     Rectobj       rectobj;
{
}


void
delete_leaf_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Tree tree;
  Rectobj rectobj, parent;
  Rectobj_list *all;

  rectobj = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  tree = (Tree) xv_get(rectobj, XV_OWNER);
  parent = (Rectobj) xv_get(tree, TREE_LINK_FROM, rectobj);
  xv_set(tree, TREE_UNLINK, rectobj, NULL);
  all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, parent);
  
 
  if ( (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, tree) == NULL ) {
    xv_set(tree, TREE_ADD_LINK, tree, rectobj, NULL);
  }
  else {
    if ( !all )
      xv_set(tree, TREE_ADD_LINK, parent, rectobj, NULL);
    else {
        
      xv_destroy(rectobj);
      xv_destroy(menu);
    }      
  }
  xv_set((Canvas_shell) xv_get(tree, XV_OWNER), 
         CANVAS_MIN_PAINT_WIDTH, xv_get(tree, XV_WIDTH) + 10,    
         CANVAS_MIN_PAINT_HEIGHT, xv_get(tree, XV_HEIGHT) + 10,
         NULL);
}

void 
delete_node_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Tree tree;
  Rectobj rectobj, temp, parent, array_object;
  Rectobj_list *all;
  int lonely, round;

  lonely = 0;
  round = 0;
  rectobj = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  tree = (Tree) xv_get(rectobj, XV_OWNER);
  parent = (Rectobj) xv_get(tree, TREE_LINK_FROM, rectobj);
  
  xv_set((Canvas_shell) xv_get(tree, XV_OWNER), 
          CANVAS_SHELL_DELAY_REPAINT, TRUE,
          NULL);
  xv_set(tree, TREE_UNLINK, rectobj, NULL);
  if ( (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, tree) == NULL ) { 
    xv_set(tree, TREE_ADD_LINK, tree, rectobj, NULL);
    all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, rectobj);
    list_for ( all ) { /* check to see if only one leaf is hanging down */
      temp = RECTOBJ_LIST_HANDLE(all);
      if ( ((Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, temp) == NULL ) &&
	  ((Rectobj) RECTOBJ_LIST_HANDLE((Rectobj_list *) list_next(all)) == 0)
	  && (!round)) { 
	lonely = 1; 
	list_prev(all);
      }
      round = 1;
    }
    if ( lonely ) { /* take node out and put the leaf in that place */
      char *label;

      all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, rectobj);
      temp = RECTOBJ_LIST_HANDLE(all);
      xv_set(tree, TREE_UNLINK, temp, NULL); 
      xv_set(tree, TREE_ADD_LINK, tree, temp, NULL);
      xv_set(tree, TREE_UNLINK, rectobj, NULL);
      xv_destroy(rectobj);
      xv_destroy(menu);
      array_object = (Rectobj) xv_get(tree, XV_KEY_DATA, ARRAY_ELEMENT);
      label = (char *) xv_get(array_object, DRAWTEXT_STRING);
      if ( strchr( label, '=' ) == NULL )
	xv_set( array_object,
	        DRAWIMAGE_SVRIMAGE,
	           (Server_image) xv_get(temp, DRAWIMAGE_SVRIMAGE), 
	        DRAWTEXT_STRING, (char *) xv_get(temp, DRAWTEXT_STRING),
	        NULL);
      xv_set(tree, XV_KEY_DATA, TREE_EMPTY, 1, NULL);
                                      
    }
    xv_set(tree, XV_SHOW, TRUE, NULL);   
  }
  /*        ^              ^              ^          */
  /*  ------|--------------|--------------|--------- */ 
  /* This node is the only one connected to the root */
  /* *********************************************** */
  /*    Not the only node connected to the root      */
  /*       or not connected to the root              */
  else {
    xv_set(tree, TREE_ADD_LINK, parent, rectobj, NULL);
    all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, rectobj);
    list_for(all) { /* check to see if only one leaf is hanging down */
      temp = RECTOBJ_LIST_HANDLE(all);
      if ( ((Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, temp) == NULL ) &&
	   ((Rectobj) RECTOBJ_LIST_HANDLE((Rectobj_list *) list_next(all)) == 0)
	   && (!round)) { 
	lonely = 1; 
	list_prev(all);
      }
      round = 1;
    }
    if ( lonely ) { /* take node out and put the leaf in that place */
      all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, rectobj);
      temp = RECTOBJ_LIST_HANDLE(all);
      xv_set(tree, TREE_UNLINK, temp, 
	     TREE_UNLINK, rectobj, 
	     TREE_ADD_LINK, parent, temp, 
	     NULL);
      xv_destroy(rectobj);
      xv_destroy(menu);
    } 
    else 
      recursive_delete(tree, rectobj);       
  } 
  xv_set((Canvas_shell) xv_get(tree, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(tree, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(tree, XV_HEIGHT) + 10,
         NULL);
  xv_set((Canvas_shell) xv_get(tree, XV_OWNER), 
	 CANVAS_SHELL_DELAY_REPAINT, FALSE,
	 NULL);
  
  
}

void
recursive_delete(tree, node)
     Tree tree;
     Rectobj node;
{
  Rectobj_list *all;
  Rectobj temp;
  Menu menu;

  all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, node);
  if (all) {
    list_for (all) {
      temp =  RECTOBJ_LIST_HANDLE(all);        
      recursive_delete(tree, temp);        
    }
  } 
  xv_set(tree, TREE_UNLINK, node, NULL);
  menu = (Menu) xv_get(node, RECTOBJ_MENU);
  xv_destroy(node);
  if (menu)
    xv_destroy(menu);
  
}

void
add_unary_opr_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Rectobj the_leaf, the_parent;
  Drawtext the_node; 
  Tree the_expression;
  Menu cooly;
  Canvas_shell orig_shell;
  char *footer;
  
  the_leaf = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_expression = (Tree) xv_get(the_leaf, XV_OWNER);
  the_parent = (Rectobj) xv_get(the_expression, TREE_LINK_FROM, the_leaf);
  orig_shell = xv_get( (Rectobj)
		          xv_get( (Rectobj)
			             xv_get(the_expression,
					    XV_KEY_DATA, ARRAY_ELEMENT),
				  XV_OWNER ),
		       XV_OWNER );

  if ( orig_shell != target_shell )
    xv_set((Rectobj) xv_get(the_expression, XV_KEY_DATA, ARRAY_ELEMENT),
	   DRAWTEXT_STRING, " \/* Expression *\/ ",
	   DRAWIMAGE_SVRIMAGE, gray3,
	   XV_KEY_DATA, TREE_EMPTY, 0,
	   NULL);
  else {
    footer = (char *) xv_get( target_frame, FRAME_LEFT_FOOTER );
    if ( footer && strstr( footer, "replace" ) != NULL ) {
      char new_label[64];
      char *label = (char*) xv_get( (Rectobj) xv_get(the_expression,
						     XV_KEY_DATA, 
						       ARRAY_ELEMENT),
				   DRAWTEXT_STRING );
      if ( strchr( label, '=' ) == NULL ) {
	strcpy( new_label, label );
	strcat( new_label, " = " );
	xv_set((Rectobj) xv_get(the_expression, XV_KEY_DATA, ARRAY_ELEMENT),
	       DRAWTEXT_STRING, strdup( new_label ),
	       DRAWIMAGE_SVRIMAGE, gray3,
	       XV_KEY_DATA, TREE_EMPTY, 0,
	       NULL);
      }
    }
    else
      xv_set((Rectobj) xv_get(the_expression, XV_KEY_DATA, ARRAY_ELEMENT),
	     DRAWTEXT_STRING, " \/* Expression *\/ ",
	     DRAWIMAGE_SVRIMAGE, gray3,
	     XV_KEY_DATA, TREE_EMPTY, 0,
	     NULL);
  }

  the_node = (Drawtext) xv_create(the_expression, DRAWTEXT, 
                                                 DRAWTEXT_STRING, "operator",
                                                 XV_KEY_DATA, NAME_SET, 0,
                                                 XV_KEY_DATA, TYPE, UNARY,
                                                 NULL);
  cooly   =  (Menu) xv_create(XV_NULL, MENU, 
			      MENU_TITLE_ITEM, "Operator",
			      MENU_ACTION_ITEM, 
			        "Add constant...", add_constant_proc,
			      MENU_ACTION_ITEM, 
			        "Name/Change operator...", name_change_opr_proc,
			      MENU_ACTION_ITEM, 
			        "Name/Change function...", name_change_fun_proc,
			      MENU_ACTION_ITEM, 
			        "Name/Change unary operator...", 
			        name_change_unary_proc, 
			      MENU_ACTION_ITEM, "Delete", delete_node_proc,
			      NULL);
  xv_set(the_node, RECTOBJ_MENU, cooly, NULL);
  xv_set(cooly, XV_KEY_DATA, MENU_OWNER, the_node, NULL);
  xv_set(the_expression, TREE_ADD_LINK, the_parent, the_node, NULL);
  xv_set(the_expression, TREE_UNLINK, the_leaf, NULL);
  xv_set(the_expression, TREE_ADD_LINK, the_node, the_leaf, NULL);
  xv_set((Canvas_shell) xv_get(the_expression, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(the_expression, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(the_expression, XV_HEIGHT) + 10,
         NULL);
  
}

void
add_constant_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Rectobj the_node, the_new_leaf;
  Tree the_expression;
  Menu the_menu;
  
  the_node = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_expression = (Tree) xv_get(the_node, XV_OWNER);
  

  the_new_leaf = (Rectobj) xv_create(the_expression, DRAWICON, 
				     DRAWTEXT_STRING, "Constant {Un-assigned}",
				     DRAWIMAGE_SVRIMAGE, gray4,
				     XV_KEY_DATA, TYPE, CONSTANT,
				     XV_KEY_DATA, NAME_SET, 0,
				     NULL);
  the_menu = (Menu) xv_create(XV_NULL, MENU, 
			      MENU_TITLE_ITEM, "Constant",
			      MENU_ACTION_ITEM, 
			        "Assign the constant...", assign_constant_proc,
			      MENU_ACTION_ITEM, 
			        "Add operator", add_unary_opr_proc,
			      MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
			      XV_KEY_DATA, MENU_OWNER, the_new_leaf,
			      NULL);
  xv_set(the_new_leaf, RECTOBJ_MENU, the_menu, NULL);
  xv_set(the_expression, 
	 TREE_ADD_LINK, the_node, the_new_leaf,  
	 NULL);
  xv_set((Canvas_shell) xv_get(the_expression, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(the_expression, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(the_expression, XV_HEIGHT) + 10,
         NULL);
 
}

void
name_change_opr_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  PortalBuffer *p;
  int i, j, k, g, n, m, t, x, ic,s, count;
  char queryp[8192];
  char entry[20];
  char type[2];
  char *left_type, *right_type; 
  Rectobj the_node, the_right_leaf, the_left_leaf;
  Tree the_expression;
  Rectobj_list *leaves;

     
  the_node = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_expression = (Tree) xv_get(the_node, XV_OWNER);
  leaves = (Rectobj_list *) xv_get(the_expression, TREE_LINK_TO_LIST, the_node);
   
  count = 0;
  list_for ( leaves ) { 
	/* Assume there are only two leaves; ignore others and warn about it */
    if ( !count ) { 
      the_left_leaf =  RECTOBJ_LIST_HANDLE(leaves); 
    }
    else if(count == 1) {
      the_right_leaf = RECTOBJ_LIST_HANDLE(leaves); 
    }
    count++;
  }
  if ( count == 1 )
    the_right_leaf = NULL;
  count = 0;
  if ( ((int) xv_get(the_node, XV_KEY_DATA, TYPE) >= OPER)
       && (the_left_leaf != NULL &&
	   (((int) xv_get(the_left_leaf, XV_KEY_DATA, TYPE) < 100) 
	    || ((int) xv_get(the_left_leaf, XV_KEY_DATA, NAME_SET)))) ) { 
           
    left_type = strdup((char *) xv_get(the_left_leaf, XV_KEY_DATA, TYPENAME)); 
  } 
  else { 
    left_type = strdup("*");
    count++;
  }
  if ( ((int) xv_get(the_node, XV_KEY_DATA, TYPE) >= OPER) && 
       (the_right_leaf != NULL &&
	(((int) xv_get(the_right_leaf, XV_KEY_DATA, TYPE) < 100) || 
	 ((int) xv_get(the_right_leaf, XV_KEY_DATA, NAME_SET)))) ) { 
        
    right_type = strdup((char *) xv_get(the_right_leaf,
					XV_KEY_DATA, TYPENAME)); 
  } 
  else {
    right_type = strdup("*");
    count++;
  }
   
  if ( !count ) sprintf(queryp, 

"retrieve portal opers (o.oprname, f.typname) \
from o in pg_operator, l, r, f in pg_type \
where o.oprkind = \'b\'  and o.oprleft = l.oid \
      and l.typname = \"%s\" \
      and o.oprright = r.oid \
      and r.typname = \"%s\" \
      and o.oprresult = f.oid",

			left_type, right_type);

  else
    sprintf(queryp,

"retrieve portal opers unique (o.oprname, f.typname) \
from o in pg_operator, f in pg_type \
where o.oprkind = \'b\'  \
      and o.oprresult = f.oid"

	    );
 
      
  while ( (int) xv_get(operator_selector_popup->operators_list,
		       PANEL_LIST_NROWS) )  
    xv_set(operator_selector_popup->operators_list, 
	   PANEL_LIST_DELETE, 0,
	   NULL);   
  if ( Debugging )
    PQtracep = 0;

  alberi_PQexec("begin");
  alberi_PQexec(queryp);
                      
  alberi_PQexec("fetch all in opers");

  p = PQparray("opers");
  g = PQngroups(p);
  t = 0;

  for ( k = 0; k < g; k++ ) {
       
    n = PQntuplesGroup(p, k);
    m = PQnfieldsGroup(p, k);

    for ( i = 0; i < n; i++ ) {
      sprintf(entry, " \/* %s *\/ %s ",
	      PQgetvalue(p, t + i, 1),
	      PQgetvalue(p, t + i, 0));
      xv_set(operator_selector_popup->operators_list, 
	     PANEL_LIST_INSERT,
	       (int) xv_get(operator_selector_popup->operators_list,
			    PANEL_LIST_NROWS) ,
	     PANEL_LIST_STRING, 
	       (int) xv_get(operator_selector_popup->operators_list,
			    PANEL_LIST_NROWS) ,
	       (char *) entry,
	     PANEL_LIST_CLIENT_DATA,
	       (int) xv_get(operator_selector_popup->operators_list,
			    PANEL_LIST_NROWS),
	       (char *) PQgetvalue(p, t + i, 1),
	     NULL);
         
    }
    t += n;
  }
  alberi_PQexec("close opers");
  alberi_PQexec("end");

  if ( Debugging )
    PQtracep = 1;

  if ( count ) xv_set(operator_selector_popup->operator_selection_pop, 
                      FRAME_LEFT_FOOTER,
		        "No type indication, choose with care...",
                      NULL);
  else 
    xv_set(operator_selector_popup->operator_selection_pop, 
	   FRAME_LEFT_FOOTER, "",
	   NULL);
  xv_set(operator_selector_popup->operator_selection_pop,
	 XV_KEY_DATA, OPER, the_node, 
	 NULL); 
  xv_set(the_node, XV_KEY_DATA, TYPE, OPER, NULL);
  xv_set(operator_selector_popup->operator_selection_pop, XV_SHOW, TRUE, NULL);
}


void
name_change_fun_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  PortalBuffer *p;
  int i, j, k, g, n, m, t, x, ic,s, count;
  char queryp[8192];
  char entry[20];
  char type[2];
  char left_type[24], right_type[24]; 
  Rectobj the_node, the_left_leaf;
  Tree the_expression;
  Rectobj_list *leaves;

     
  the_node = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_expression = (Tree) xv_get(the_node, XV_OWNER);
  leaves = (Rectobj_list *) xv_get(the_expression, TREE_LINK_TO_LIST, the_node);
   
   
  sprintf(queryp, 

"retrieve portal funcs (p.proname, f.typname, p.pronargs) \
from p in pg_proc, f in pg_type \
where p.prorettype = f.oid", 

	  left_type);
    
 
      
    while ( (int) xv_get(unary_selector_popup->unary_operators_list,
			 PANEL_LIST_NROWS) )
      xv_set(funct_selector_popup->func_list, 
	     PANEL_LIST_DELETE, 0,
	     NULL);

  if ( Debugging )
    PQtracep = 0;

  alberi_PQexec("begin");
  alberi_PQexec(queryp);
                      
  alberi_PQexec("fetch all in funcs");

  p = PQparray("funcs");
  g = PQngroups(p);
  t = 0;

  for (k = 0; k < g; k++ ) {
       
    n = PQntuplesGroup(p, k);
    m = PQnfieldsGroup(p, k);

    for (i = 0; i < n; i++ ) {
      sprintf(entry, " \/* %s, %s *\/ %s ", 
	      PQgetvalue(p, t + i, 1), 
	      PQgetvalue(p, t + i, 2), 
	      PQgetvalue(p, t + i, 0));
      xv_set(funct_selector_popup->func_list, 
	     PANEL_LIST_INSERT, 
	       (int) xv_get(funct_selector_popup->func_list, PANEL_LIST_NROWS) ,
	     PANEL_LIST_STRING, 
	       (int) xv_get(funct_selector_popup->func_list, 
			    PANEL_LIST_NROWS) ,
	       (char *) entry,
	     PANEL_LIST_CLIENT_DATA, 
	       (int) xv_get(funct_selector_popup->func_list, PANEL_LIST_NROWS),
	       (char *) PQgetvalue(p, t + i, 1),
	     NULL);

    }
    t += n;
  }
  alberi_PQexec("close funcs");
  alberi_PQexec("end");

  if ( Debugging )
    PQtracep = 1;

  xv_set(funct_selector_popup->pop, 
	 FRAME_LEFT_FOOTER, "Type of arguments not known, check PG manual!",
	 NULL);
  xv_set(funct_selector_popup->pop, XV_KEY_DATA, OPER, the_node, NULL);
  xv_set(the_node, XV_KEY_DATA, TYPE, FUNC, NULL); 
  xv_set(funct_selector_popup->pop, XV_SHOW, TRUE, NULL);

}

void
delete_array_elem_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Array_tile the_array;
  Rectobj  the_element;
  Tree the_expression;
   

  the_element = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_array = (Array_tile) xv_get(the_element, XV_OWNER);
  the_expression = (Tree) xv_get(the_element, XV_KEY_DATA, EXPRESSION_TREE);
    
  xv_set(expression_frame, FRAME_BUSY, TRUE, NULL);
  xv_set((Frame) xv_get((Canvas_shell) xv_get(the_array, XV_OWNER), 
			XV_OWNER), 
	 FRAME_BUSY, TRUE, 
	 NULL);

  recursive_delete(the_expression, the_expression);  /* Kill the tree */
   
   
  xv_destroy(the_element);
  xv_destroy(menu);

  xv_set(expression_frame, FRAME_BUSY, FALSE, NULL);
   
  xv_set((Canvas_shell) xv_get(the_array, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(the_array, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(the_array, XV_HEIGHT) + 10,
         NULL);

  xv_set((Frame) xv_get((Canvas_shell) xv_get(the_array, XV_OWNER), 
			XV_OWNER), 
	 FRAME_BUSY, FALSE, 
	 NULL);
 
   
}

void
assign_constant_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  PortalBuffer *p;
  int i, j, k, g, n, m, t, x, ic,s, count;
  char queryp[8192];
  char entry[20];
  char type[2];
  char left_type[24], right_type[24]; 
  Rectobj the_node, the_left_leaf;
  Tree the_expression;
  Rectobj_list *leaves;

     
    the_node = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
    the_expression = (Tree) xv_get(the_node, XV_OWNER);
    leaves = (Rectobj_list *) xv_get(the_expression,
				     TREE_LINK_TO_LIST, the_node);
   
   
    sprintf(queryp, 

"retrieve portal tipos (pg_type.typname) \
where pg_type.typname !~ \"^_.*\" \
      and pg_type.typname !~ \"pg_.*\""

	    );
    
         
    while((int) xv_get(constant_selector_popup->type_list, PANEL_LIST_NROWS))  
          xv_set(constant_selector_popup->type_list, 
                 PANEL_LIST_DELETE, 0,
                 NULL);   

  if ( Debugging )
    PQtracep = 0;

  alberi_PQexec("begin");
  alberi_PQexec(queryp);
                      
  alberi_PQexec("fetch all in tipos");

  p = PQparray("tipos");
  g = PQngroups(p);
  t = 0;

  for (k = 0; k < g; k++ ) {
      
      n = PQntuplesGroup(p, k);
      m = PQnfieldsGroup(p, k);


      for ( i = 0; i < n; i++ ) {
	sprintf(entry, "%s", PQgetvalue(p, t + i, 0));
	xv_set(constant_selector_popup->type_list, 
	       PANEL_LIST_INSERT, 
	         (int) xv_get(constant_selector_popup->type_list, 
			      PANEL_LIST_NROWS) ,
	       PANEL_LIST_STRING, 
	         (int) xv_get(constant_selector_popup->type_list, 
			      PANEL_LIST_NROWS) ,
	         (char *) entry,
	       NULL);
         
      }
      t += n;
    }
  alberi_PQexec("close tipos");
  alberi_PQexec("end");

  if ( Debugging )
    PQtracep = 1;

  xv_set(constant_selector_popup->pop, 
	 FRAME_LEFT_FOOTER, "Type the constant and/or select a type",
	 NULL);
  xv_set(constant_selector_popup->pop, XV_KEY_DATA, OPER, the_node, NULL);
  xv_set(the_node, XV_KEY_DATA, TYPE, FUNC, NULL); 
  xv_set(constant_selector_popup->pop, XV_SHOW, TRUE, NULL);


}

void
name_retrieve_attr_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  xv_set(name_attribute_popup->pop, 
         XV_KEY_DATA, OPER, (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER), 
         NULL);
  xv_set(name_attribute_popup->pop, 
         XV_SHOW, TRUE, 
         NULL);
}

void 
name_change_unary_proc(menu, menu_item)
Menu menu;
Menu_item menu_item;
{
    PortalBuffer *p;
    int i, j, k, g, n, m, t, x, ic,s, count;
    char queryp[8192];
    char entry[20];
    char type[2];
    char *left_type, *right_type; 
    Rectobj the_node, the_left_leaf;
    Tree the_expression;
    Rectobj_list *leaves;

     
    the_node = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
    the_expression = (Tree) xv_get(the_node, XV_OWNER);
    leaves = (Rectobj_list *) xv_get(the_expression, 
				     TREE_LINK_TO_LIST, the_node);
   
    count = 0;
    list_for(leaves) { /* Assume only one leaf; 
			  ignore others and warn about it */
      if(!count) { the_left_leaf =  RECTOBJ_LIST_HANDLE(leaves); }
      
      count++;
    }

    count = 0;
    if ( ((int) xv_get(the_node, XV_KEY_DATA, TYPE) >= OPER) && 
	 (the_left_leaf &&
	  (((int) xv_get(the_left_leaf, XV_KEY_DATA, TYPE) < OPER) || 
	   ((int) xv_get(the_left_leaf, XV_KEY_DATA, NAME_SET)))) ) { 
           
      left_type =  strdup((char *) xv_get(the_left_leaf, 
					  XV_KEY_DATA, TYPENAME)); 
    } 
    else { 
      left_type = strdup("*");
      count++;
    }
    
   

    if ( !count ) 
      sprintf(queryp, 

"retrieve portal unaries (o.oprname, f.typname) \
from o in pg_operator, r, f in pg_type \
where o.oprkind = \'l\'  \
      and o.oprright = r.oid \
      and r.typname = \"%s\" \
      and o.oprresult = f.oid", 

	      left_type);
    else 
      sprintf(queryp, 

"retrieve portal unaries unique (o.oprname, f.typname) \
from o in pg_operator, f in pg_type \
where o.oprkind = \'l\'  \
      and o.oprresult = f.oid"

	      );
 
      
    while ( (int) xv_get(unary_selector_popup->unary_operators_list,
			 PANEL_LIST_NROWS) )
      xv_set(unary_selector_popup->unary_operators_list, 
	     PANEL_LIST_DELETE, 0,
	     NULL);   

    if(Debugging) 
      PQtracep = 0;

    alberi_PQexec("begin");
    alberi_PQexec(queryp);
                      
    alberi_PQexec("fetch all in unaries");

    p = PQparray("unaries");
    g = PQngroups(p);
    t = 0;

    for(k = 0; k < g; k++) {
       
      n = PQntuplesGroup(p, k);
      m = PQnfieldsGroup(p, k);
    

      for(i = 0; i < n; i++) {
          sprintf(entry, " \/* %s *\/ %s ",
		  PQgetvalue(p, t + i, 1), 
		  PQgetvalue(p, t + i, 0));
          xv_set(unary_selector_popup->unary_operators_list, 
                 PANEL_LIST_INSERT, 
		   (int) xv_get(unary_selector_popup->unary_operators_list, 
				PANEL_LIST_NROWS) ,
                 PANEL_LIST_STRING, 
		   (int) xv_get(unary_selector_popup->unary_operators_list, 
				PANEL_LIST_NROWS) , 
		   (char *) entry,
                 PANEL_LIST_CLIENT_DATA, 
		   (int) xv_get(unary_selector_popup->unary_operators_list, 
				PANEL_LIST_NROWS), 
		   (char *) PQgetvalue(p, t + i, 1),
                 NULL);
      
	}
      t += n;
    }
    alberi_PQexec("close unaries");
    alberi_PQexec("end");

    if (Debugging)
      PQtracep = 1;

    if(count) xv_set(unary_selector_popup->popup1, 
		     FRAME_LEFT_FOOTER, 
		       "No type indication, choose with care...",
		     NULL);
    else 
      xv_set(unary_selector_popup->popup1, 
	     FRAME_LEFT_FOOTER, "",
	     NULL);
    xv_set(unary_selector_popup->popup1, XV_KEY_DATA, OPER, the_node, NULL);
    xv_set(the_node, XV_KEY_DATA, TYPE, UNARY, NULL); 
    xv_set(unary_selector_popup->popup1, XV_SHOW, TRUE, NULL);
     
}

void
name_class_instance_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Rectobj the_leaf, the_parent, the_instance, current_one;
  Array_tile the_instances_array; /* use the global classes */
  Rectobj_list *the_class_list, *the_instances_list, *the_children_of_parent;
  char *the_parent_name, *the_instance_name, *current_name, *temp;

  the_leaf = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
 
  the_parent_name = strdup((char *) xv_get(the_leaf, XV_KEY_DATA, PARENT_NAME));
  while((int) xv_get(name_instance_popup->instances_list, PANEL_LIST_NROWS))  
          xv_set(name_instance_popup->instances_list, 
                 PANEL_LIST_DELETE, 0,
                 NULL);
  
  
  the_class_list = (Rectobj_list *) xv_get(classes, RECTOBJ_CHILDREN);
  list_for(the_class_list) {
       current_one = RECTOBJ_LIST_HANDLE(the_class_list);
       
       current_name = strdup((char *) xv_get(current_one, DRAWTEXT_STRING));
       if(!strcmp(current_name, the_parent_name)) { /* equal */
          the_parent = current_one; 
       }
       
  }
  the_children_of_parent = (Rectobj_list *) 
                               xv_get(the_parent, RECTOBJ_CHILDREN);
  
  if ( (Array_tile) xv_get(the_parent, XV_KEY_DATA, INSTANCES) == 0 ) { 
				 /* create the instances array */
    the_instances_array = (Array_tile) xv_create(the_parent, ARRAY_TILE, 
						 XV_SHOW, FALSE, 
						 NULL);
    xv_set(the_parent, XV_KEY_DATA, INSTANCES, the_instances_array, NULL);
  } 
  else 
    the_instances_array = (Array_tile) xv_get(the_parent,
					      XV_KEY_DATA, INSTANCES);
  
  current_name = (char *) malloc(35 + strlen(the_parent_name));
  sprintf(current_name, "Select instance name for <%s> class",
	                the_parent_name);
  
  the_instances_list = (Rectobj_list *) xv_get(the_instances_array,
					       RECTOBJ_CHILDREN);
  if ( (Rectobj_list *) the_instances_list != NULL ) {
    list_for( the_instances_list ) {
      current_one = RECTOBJ_LIST_HANDLE(the_instances_list);
       
      the_parent_name = strdup((char *) xv_get(current_one, DRAWTEXT_STRING));
      xv_set(name_instance_popup->instances_list, 
	     PANEL_LIST_INSERT, 
	       (int) xv_get(name_instance_popup->instances_list,
			    PANEL_LIST_NROWS) ,
	     PANEL_LIST_STRING, 
	       (int) xv_get(name_instance_popup->instances_list,
			    PANEL_LIST_NROWS) , 
                                 the_parent_name,
	     PANEL_LIST_CLIENT_DATA, 
	       (int) xv_get(name_instance_popup->instances_list,
			    PANEL_LIST_NROWS), 
	       (Rectobj) current_one,
	     NULL);
    }
  }
  xv_set(name_instance_popup->pop, XV_KEY_DATA, OPER, the_leaf, NULL);
  xv_set(name_instance_popup->pop, XV_KEY_DATA, FUNC, classes, NULL);
  xv_set(name_instance_popup->pop, XV_KEY_DATA, UNARY, the_parent, NULL);
  xv_set(name_instance_popup->new_instance_field,
	 PANEL_CLIENT_DATA, the_instances_array, 
	 NULL);
  xv_set(name_instance_popup->pop,
	 XV_SHOW, TRUE,
	 FRAME_LABEL, current_name,
	 NULL);
  
  /* Now that we have an array we can list instances in listbox and/or add a new one */
  
}

void 
start_where_tree(canvas_shell,
		 rectobj,
		 drop_canvas_shell,
		 drop_rectobj,
		 drop_event)

     Canvas_shell     canvas_shell;
     Rectobj          rectobj;
     Canvas_shell     drop_canvas_shell; /* where you add */
     Rectobj          drop_rectobj;   
     Event           *drop_event;

{

/* Here starts the construction of the where tree
 * of course, it is create here only once, and once
 * created this callback does nothing, so it starts,
 * checking there is no tree created in this canvas
 * the best way of checking this is to set a flag, 
 * with the handle of the tree as its value, on the
 * canvas (drop_canvas alias qual_shell) use 
 * THE_ARRAY data field.  
 * If the tree has not been created then proceed
 * to create it.  And set the THE_ARRAY flag to
 * the handle of the tree.
 * Create a node for the tree with label "Expression",
 * and set it to accept drop with a callback for 
 * building the tree, create a menu for the node.
 * Proceed to create a expression_tree on  
 * expression_canvas and initialize it (you know how to 
 * do it) Then return the damn thing.
 * Piece of cake...
 */

 Rectobj first_leaf, node1;
 Tree tree, atree;
 Menu where_leaf_menu, leaf_menu;
 char temp2[128], *parent, *typname, *label;
 

 if(!((Tree) xv_get(drop_canvas_shell, XV_KEY_DATA, THE_ARRAY)) && 
     ((int) xv_get(rectobj, XV_KEY_DATA, TYPE)))  { /* create the where_tree */
   
    atree = (Tree) xv_create(drop_canvas_shell /* qual_shell */, TREE, 
			     XV_X, 0, XV_Y, 10,
			     XV_KEY_DATA,
			       EXPRESSION_CANVAS, expression_shell,
			     XV_KEY_DATA, TYPE, 1,
			     XV_KEY_DATA, TREE_EMPTY, 1,
			     NULL);
    qual_tree = atree;
    xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, atree, NULL);

    first_leaf = (Drawicon) 
      xv_create(atree, DRAWICON, 
		DRAWIMAGE_SVRIMAGE, (Server_image) gray3,
		DRAWTEXT_STRING, "Expression",
		RECTOBJ_ACCEPTS_DROP, TRUE, 
		RECTOBJ_DROP_PROC, adding_stuff_to_the_where_tree,
		RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
		XV_KEY_DATA, EXPRESSION_TREE, 0,
		XV_KEY_DATA, EXPRESSION_HIDE, 0,
		XV_KEY_DATA, TYPE, 0, /* O means it is an expression, a leaf */
		NULL); 
    xv_set(atree, TREE_ADD_LINK, atree, first_leaf, NULL);
    
    tree =  (Tree)
      xv_create((Canvas_shell) xv_get(atree, XV_KEY_DATA, EXPRESSION_CANVAS),
		TREE,
		XV_SHOW, FALSE,                                      
		RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
		RECTOBJ_CHILD_DROP_PROC, adding_stuff_to_the_expression_tree,
		XV_KEY_DATA, ARRAY_ELEMENT, first_leaf, 
		XV_KEY_DATA, TREE_EMPTY, 1,
		XV_KEY_DATA, THE_ARRAY, atree, 
		NULL);
    sprintf(temp2, "%s.%s",
	    (char *) xv_get(rectobj, XV_KEY_DATA, CLASS),
	    (char *) xv_get(rectobj, DRAWTEXT_STRING));
    parent = strdup((char *) xv_get(rectobj, XV_KEY_DATA, PARENT_NAME));
    typname = strdup((char *) xv_get(rectobj, XV_KEY_DATA, TYPENAME));
    label = strdup(temp2);

    node1 = (Drawicon) 
      xv_create(tree, DRAWICON, 
		DRAWIMAGE_SVRIMAGE,
		  (Server_image) xv_get(rectobj, DRAWIMAGE_SVRIMAGE),
		DRAWTEXT_STRING, label, 
		RECTOBJ_ACCEPTS_DROP, TRUE, 
		RECTOBJ_DROP_PROC, adding_stuff_to_the_expression_tree,
		XV_KEY_DATA, PARENT_NAME, parent,
		XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
		XV_KEY_DATA, TYPENAME, typname,
		XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
		XV_KEY_DATA, TYPE, 
		   (((int) xv_get(rectobj, XV_KEY_DATA, TYPE))?1:0),
		NULL);

     leaf_menu = (Menu) 
       xv_create(XV_NULL, MENU,
		 MENU_TITLE_ITEM, "Attribute",
		 MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
		 MENU_ACTION_ITEM, 
		   "Name class instance...", name_class_instance_proc,
		 MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
		 XV_KEY_DATA, MENU_OWNER, node1,
		 NULL); 

     xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL); /* Menu node attached */

     xv_set(tree, TREE_ADD_LINK, tree, node1, NULL);
     where_leaf_menu = (Menu) 
       xv_create(XV_NULL, MENU,
		 MENU_TITLE_ITEM, "Qualifier Tree Leaf",
		 MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
		 MENU_ACTION_ITEM, "Delete", delete_where_tree_leaf_proc,
		 XV_KEY_DATA, MENU_OWNER, first_leaf,
		 NULL); 
 
     xv_set(first_leaf,
           RECTOBJ_MENU, where_leaf_menu, 
           XV_KEY_DATA, EXPRESSION_TREE, tree, 
           XV_KEY_DATA, EXPRESSION_HIDE, 0,
           NULL);
  }
}

void
adding_stuff_to_the_where_tree(canvas_shell,
			       rectobj,
			       drop_canvas_shell,
			       drop_rectobj, 
			       drop_event)

     Canvas_shell     canvas_shell;
     Rectobj          rectobj;
     Canvas_shell     drop_canvas_shell; /* where you add */
     Rectobj          drop_rectobj;   
     Event           *drop_event;

{

/* OK the tree exists, then the tree thinks...
 * Now down to business...
 * You are adding an entry in the where logical 
 * expression tree, there are no substitutions
 * just straight add of elements to the tree.
 * These are the possibilities:
 * 1) add an attribute to a leaf
 * 2) add an attribute to a node
 *    a) an OR/AND node
 *    b) NOT node
 * Classes are not accepted in this case.
 * Case 1:
 *   You want to create a new boolean expression
 *   connected to the target one via AND/OR node.
 *   Action: 
 *     Create the node and its correspondent expression
 *        tree, related menu, etc; 
 *     Decide which connector (logical) to link;
 *     Create the connector node and its menu, 
         set its link_counter to 2;
 *     Link the connector to the target leaf parent,
 *       unlink the target leaf, then link both
 *       leaves to the connector.
 *     Done.
 * Case 2:
 *    Case A:
 *     You want to create an expression connected with
 *     the current connector to an expression below.
 *     This present a couple of challenges, the bool
 *     nodes are binary so there is only space for
 *     two links, in the come and go of tree management
 *     it is possible to end up with a mutilated 
 *     connector.  Resume, if there is space add it,
 *     else just ignore the thing.
 *     Action:
 *       Check it is indeed an attribute;
 *       Check the links counter:  if less than 2
 *         add the guy, else 
 ************ create a new connector and add the attribute **********;
 *       Done.
 *    Case B:
 *     Lonely NOTs are not allowed and they are
 *     add through menus only.  In this case
 *     do nothing.
 *     Action:
 *       DO NOTHING;
 *       Done.
 * This is it folks!
 */


  int the_node_in_the_tree_type, links, the_boolean;
  Rectobj the_connector, the_new_leaf, node1, parent_node;
  Tree the_where_tree, the_expression_tree;
  Menu where_leaf_menu, leaf_menu, the_connector_menu;
  char temp2[80], *parent, *label, *typname;

  if ((int) xv_get(rectobj, XV_KEY_DATA, TYPE)) { /* it is an attribute */
    the_node_in_the_tree_type = (int) xv_get(drop_rectobj, XV_KEY_DATA, TYPE);
    switch(the_node_in_the_tree_type) {
       case 0: /* A leaf node */
         the_where_tree = (Tree) xv_get(drop_rectobj, XV_OWNER);
         the_new_leaf = (Drawicon)
	   xv_create(the_where_tree, DRAWICON,
		     DRAWIMAGE_SVRIMAGE, (Server_image) gray3,
		     DRAWTEXT_STRING, "Expression",
		     RECTOBJ_ACCEPTS_DROP, TRUE, 
		     RECTOBJ_DROP_PROC, adding_stuff_to_the_where_tree,
		     RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
		     XV_KEY_DATA, EXPRESSION_TREE, 0,
		     XV_KEY_DATA, EXPRESSION_HIDE, 1,
		     XV_KEY_DATA, TYPE, 0,
		     		/* O means it is an expression, a leaf */
		     NULL); 
         where_leaf_menu = (Menu) 
	   xv_create(XV_NULL, MENU,
		     MENU_TITLE_ITEM, "Qualifier Tree Leaf",
		     MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
		     MENU_ACTION_ITEM, "Delete", delete_where_tree_leaf_proc,
		     XV_KEY_DATA, MENU_OWNER, the_new_leaf,
		     NULL);

         the_expression_tree =  (Tree)
	   xv_create((Canvas_shell) xv_get(the_where_tree, 
					   XV_KEY_DATA, EXPRESSION_CANVAS), 
		     TREE,
		     XV_SHOW, FALSE,                                      
		     RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
		     RECTOBJ_CHILD_DROP_PROC,
		       adding_stuff_to_the_expression_tree,
		     XV_KEY_DATA, ARRAY_ELEMENT, the_new_leaf, 
		     XV_KEY_DATA, TREE_EMPTY, 1,
		     XV_KEY_DATA, THE_ARRAY, the_where_tree, 
		     NULL);
         sprintf(temp2, "%s.%s",
		 (char *) xv_get(rectobj, XV_KEY_DATA, CLASS), 
		 (char *) xv_get(rectobj, DRAWTEXT_STRING));
         parent = strdup((char *) xv_get(rectobj, XV_KEY_DATA, PARENT_NAME));
         typname = strdup((char *) xv_get(rectobj, XV_KEY_DATA, TYPENAME));
         label = strdup(temp2);

         node1 = (Drawicon) 
	   xv_create(the_expression_tree, DRAWICON, 
		     DRAWIMAGE_SVRIMAGE,
		       (Server_image) xv_get(rectobj, DRAWIMAGE_SVRIMAGE),
		     DRAWTEXT_STRING, label, 
		     RECTOBJ_ACCEPTS_DROP, TRUE, 
		     RECTOBJ_DROP_PROC, adding_stuff_to_the_expression_tree,
		     XV_KEY_DATA, PARENT_NAME, parent,
		     XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
		     XV_KEY_DATA, TYPENAME, typname,
		     XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
		     XV_KEY_DATA, TYPE, 
		        (((int) xv_get(rectobj, XV_KEY_DATA, TYPE))?1:0),
		     NULL);

         leaf_menu = (Menu) 
	   xv_create(XV_NULL, MENU,
		     MENU_TITLE_ITEM, "Attribute",
		     MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
		     MENU_ACTION_ITEM,
		       "Name class instance...", name_class_instance_proc,
		     MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
		     XV_KEY_DATA, MENU_OWNER, node1,
		     NULL); 

         xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL); /* Menu node attached */

         xv_set(the_expression_tree, 
		TREE_ADD_LINK, the_expression_tree, node1, 
		NULL);
         the_boolean =  
	   notice_prompt((Canvas_shell) xv_get(the_where_tree, XV_OWNER), 
			 NULL,
			 NOTICE_MESSAGE_STRINGS, 
		   "Choose a boolean connector for the logical expression",
			 NULL,
			 NOTICE_BUTTON, "and", ANDOP,
			 NOTICE_BUTTON, "or", OROP,
			 NULL);
         switch(the_boolean) {
             case ANDOP:
               the_connector = (Drawtext) xv_create(the_where_tree, DRAWTEXT,
                                                     DRAWTEXT_STRING, " and ",
                                                     XV_KEY_DATA, LINKS, 2,
                                                     XV_KEY_DATA, TYPE, ANDOP,
                                                     RECTOBJ_ACCEPTS_DROP, TRUE,
                                                     RECTOBJ_DROP_PROC, 
					      adding_stuff_to_the_where_tree,
                                                     NULL);
               break;
             case OROP:
                the_connector = (Drawtext) xv_create(the_where_tree, DRAWTEXT,
                                                     DRAWTEXT_STRING, " or ",
                                                     XV_KEY_DATA, LINKS, 2,
                                                     XV_KEY_DATA, TYPE, ANDOP,
                                                     RECTOBJ_ACCEPTS_DROP, TRUE,
                                                     RECTOBJ_DROP_PROC, 
					      adding_stuff_to_the_where_tree,
                                                     NULL);
               break;
           }
           the_connector_menu = (Menu)
	     xv_create(XV_NULL, MENU,
		       MENU_TITLE_ITEM, "Qualifier Tree Logical Node",
		       MENU_ACTION_ITEM, "Change boolean", switch_bool,
		       MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
		       MENU_ACTION_ITEM,
		         "Delete ...", delete_where_tree_binary_node,
		       XV_KEY_DATA, MENU_OWNER, the_connector,
		       NULL);
           xv_set(the_connector, RECTOBJ_MENU, the_connector_menu, NULL);
           
           parent_node = (Rectobj) xv_get(the_where_tree,
					  TREE_LINK_FROM, drop_rectobj);
        
           xv_set(the_where_tree, 
		  TREE_ADD_LINK, parent_node, the_connector, 
		  NULL);
           xv_set(the_where_tree, TREE_UNLINK, drop_rectobj, 
		  NULL);
           xv_set(the_where_tree, TREE_ADD_LINK, the_connector, drop_rectobj, 
		  NULL);
           xv_set(the_where_tree, TREE_ADD_LINK, the_connector, the_new_leaf,
		  NULL);
           xv_set(the_new_leaf,
              RECTOBJ_MENU, where_leaf_menu, 
              XV_KEY_DATA, EXPRESSION_TREE, the_expression_tree, 
              XV_KEY_DATA, EXPRESSION_HIDE, 0,
              NULL);
         break;
       case ANDOP:
       case OROP:
         links = (int) xv_get(drop_rectobj, XV_KEY_DATA, LINKS);
         if(links < 2)  { /* Job to do */
            the_connector = drop_rectobj;
            the_where_tree = qual_tree;
            the_new_leaf = (Drawicon)
	      xv_create(the_where_tree, DRAWICON,
			DRAWIMAGE_SVRIMAGE, (Server_image) gray3,
			DRAWTEXT_STRING, "Expression",
			RECTOBJ_ACCEPTS_DROP, TRUE, 
			RECTOBJ_DROP_PROC, adding_stuff_to_the_where_tree,
			RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
			XV_KEY_DATA, EXPRESSION_TREE, 0,
			XV_KEY_DATA, EXPRESSION_HIDE, 0,
			XV_KEY_DATA, TYPE, 0,
			         /* O means it is an expression, a leaf */
			NULL); 
            where_leaf_menu = (Menu)
	      xv_create(XV_NULL, MENU,
			MENU_TITLE_ITEM, "Qualifier Tree Leaf",
			MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
			MENU_ACTION_ITEM, "Delete", delete_where_tree_leaf_proc,
			XV_KEY_DATA, MENU_OWNER, the_new_leaf,
			NULL);

            the_expression_tree =  (Tree)
	      xv_create((Canvas_shell) xv_get(the_where_tree,
					      XV_KEY_DATA, EXPRESSION_CANVAS),
			TREE,
			XV_SHOW, FALSE,                                      
			RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
			RECTOBJ_CHILD_DROP_PROC,
			  adding_stuff_to_the_expression_tree,
			XV_KEY_DATA, ARRAY_ELEMENT, the_new_leaf, 
			XV_KEY_DATA, TREE_EMPTY, 1,
			XV_KEY_DATA, THE_ARRAY, the_where_tree, 
			NULL);
            sprintf(temp2, "%s.%s", 
		    (char *) xv_get(rectobj, XV_KEY_DATA, CLASS), 
		    (char *) xv_get(rectobj, DRAWTEXT_STRING));
            parent = strdup((char *) xv_get(rectobj, XV_KEY_DATA, PARENT_NAME));
            typname = strdup((char *) xv_get(rectobj, XV_KEY_DATA, TYPENAME));
            label = strdup(temp2);

            node1 = (Drawicon)
	      xv_create(the_expression_tree, DRAWICON, 
			DRAWIMAGE_SVRIMAGE,
			  (Server_image) xv_get(rectobj, DRAWIMAGE_SVRIMAGE),
			DRAWTEXT_STRING, label, 
			RECTOBJ_ACCEPTS_DROP, TRUE, 
			RECTOBJ_DROP_PROC, adding_stuff_to_the_expression_tree,
			XV_KEY_DATA, PARENT_NAME, parent,
			XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
			XV_KEY_DATA, TYPENAME, typname,
			XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
			XV_KEY_DATA, TYPE, 
			   (((int) xv_get(rectobj, XV_KEY_DATA, TYPE))?1:0),
			NULL);

            leaf_menu = (Menu)
	      xv_create(XV_NULL, MENU,
			MENU_TITLE_ITEM, "Attribute",
			MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
			MENU_ACTION_ITEM,
			  "Name class instance...", name_class_instance_proc,
			MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
			XV_KEY_DATA, MENU_OWNER, node1,
			NULL); 

           xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL);
					 /* Menu node attached */

           xv_set(the_expression_tree, 
		  TREE_ADD_LINK, the_expression_tree, node1,
		  NULL);
           links++;
           xv_set(the_connector, XV_KEY_DATA, LINKS, links, NULL);
           xv_set(the_where_tree,
		  TREE_ADD_LINK, the_connector, the_new_leaf, 
		  NULL);
         
           xv_set(the_new_leaf,
              RECTOBJ_MENU, where_leaf_menu, 
              XV_KEY_DATA, EXPRESSION_TREE, the_expression_tree, 
              XV_KEY_DATA, EXPRESSION_HIDE, 0,
              NULL); 
         }
	 else {
	   the_where_tree = (Tree) xv_get(drop_rectobj, XV_OWNER);
	   the_new_leaf = (Drawicon)
	     xv_create(the_where_tree, DRAWICON,
		       DRAWIMAGE_SVRIMAGE, (Server_image) gray3,
		       DRAWTEXT_STRING, "Expression",
		       RECTOBJ_ACCEPTS_DROP, TRUE, 
		       RECTOBJ_DROP_PROC, adding_stuff_to_the_where_tree,
		       RECTOBJ_DBL_CLICK_PROC, show_hide_expression_tree,
		       XV_KEY_DATA, EXPRESSION_TREE, 0,
		       XV_KEY_DATA, EXPRESSION_HIDE, 1,
		       XV_KEY_DATA, TYPE, 0,
				      /* O means it is an expression, a leaf */
		       NULL); 
         where_leaf_menu = (Menu)
	   xv_create(XV_NULL, MENU,
		     MENU_TITLE_ITEM, "Qualifier Tree Leaf",
		     MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
		     MENU_ACTION_ITEM, "Delete", delete_where_tree_leaf_proc,
		     XV_KEY_DATA, MENU_OWNER, the_new_leaf,
		     NULL);

         the_expression_tree =  (Tree)
	   xv_create((Canvas_shell) xv_get(the_where_tree,
					   XV_KEY_DATA, EXPRESSION_CANVAS),
		     TREE,
		     XV_SHOW, FALSE,                                      
		     RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
		     RECTOBJ_CHILD_DROP_PROC,
		       adding_stuff_to_the_expression_tree,
		     XV_KEY_DATA, ARRAY_ELEMENT, the_new_leaf, 
		     XV_KEY_DATA, TREE_EMPTY, 1,
		     XV_KEY_DATA, THE_ARRAY, the_where_tree, 
		     NULL);
         sprintf(temp2, "%s.%s",
		 (char *) xv_get(rectobj, XV_KEY_DATA, CLASS), 
		 (char *) xv_get(rectobj, DRAWTEXT_STRING));
         parent = strdup((char *) xv_get(rectobj, XV_KEY_DATA, PARENT_NAME));
         typname = strdup((char *) xv_get(rectobj, XV_KEY_DATA, TYPENAME));
         label = strdup(temp2);

         node1 = (Drawicon) 
	   xv_create(the_expression_tree, DRAWICON, 
		     DRAWIMAGE_SVRIMAGE,
		       (Server_image) xv_get(rectobj, DRAWIMAGE_SVRIMAGE),
		     DRAWTEXT_STRING, label, 
		     RECTOBJ_ACCEPTS_DROP, TRUE, 
		     RECTOBJ_DROP_PROC, adding_stuff_to_the_expression_tree,
		     XV_KEY_DATA, PARENT_NAME, parent,
		     XV_KEY_DATA_REMOVE_PROC, PARENT_NAME, free_string,
		     XV_KEY_DATA, TYPENAME, typname,
		     XV_KEY_DATA_REMOVE_PROC, TYPENAME, free_string,
		     XV_KEY_DATA, TYPE, 
		        (((int) xv_get(rectobj, XV_KEY_DATA, TYPE))?1:0),
		     NULL);

         leaf_menu = (Menu)
	   xv_create(XV_NULL, MENU,
		     MENU_TITLE_ITEM, "Attribute",
		     MENU_ACTION_ITEM, "Add operator...", add_unary_opr_proc,
		     MENU_ACTION_ITEM,
		       "Name class instance...", name_class_instance_proc,
		     MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
		     XV_KEY_DATA, MENU_OWNER, node1,
		     NULL); 

         xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL); /* Menu node attached */

         xv_set(the_expression_tree, 
		TREE_ADD_LINK, the_expression_tree, node1, 
		NULL);
         the_boolean = 
	   notice_prompt((Canvas_shell) xv_get(the_where_tree, XV_OWNER), NULL,
			 NOTICE_MESSAGE_STRINGS, 
		  "Choose a boolean connector for the logical expression",
			 NULL,
			 NOTICE_BUTTON, "and", ANDOP,
			 NOTICE_BUTTON, "or", OROP,
			 NULL);
         switch(the_boolean) {
             case ANDOP:
               the_connector = (Drawtext) xv_create(the_where_tree, DRAWTEXT,
                                                     DRAWTEXT_STRING, " and ",
                                                     XV_KEY_DATA, LINKS, 2,
                                                     XV_KEY_DATA, TYPE, ANDOP,
                                                     RECTOBJ_ACCEPTS_DROP, TRUE,
                                                     RECTOBJ_DROP_PROC,
					       adding_stuff_to_the_where_tree,
                                                     NULL);
               break;
             case OROP:
                the_connector = (Drawtext) xv_create(the_where_tree, DRAWTEXT,
                                                     DRAWTEXT_STRING, " or ",
                                                     XV_KEY_DATA, LINKS, 2,
                                                     XV_KEY_DATA, TYPE, ANDOP,
                                                     RECTOBJ_ACCEPTS_DROP, TRUE,
                                                     RECTOBJ_DROP_PROC, 
					       adding_stuff_to_the_where_tree,
                                                     NULL);
               break;
           }
           the_connector_menu = (Menu) 
	     xv_create(XV_NULL, MENU,
		       MENU_TITLE_ITEM, "Qualifier Tree Logical Node",
		       MENU_ACTION_ITEM, "Change boolean", switch_bool,
		       MENU_ACTION_ITEM, "Add not...", negate_the_branch_proc,
		       MENU_ACTION_ITEM, 
		         "Delete ...", delete_where_tree_binary_node,
		       XV_KEY_DATA, MENU_OWNER, the_connector,
		       NULL);
           xv_set(the_connector, RECTOBJ_MENU, the_connector_menu, NULL);
           
           parent_node = (Rectobj) xv_get(the_where_tree, 
					  TREE_LINK_FROM, drop_rectobj);
        
           xv_set(the_where_tree, 
		  TREE_ADD_LINK, parent_node, the_connector, 
		  NULL);
           xv_set(the_where_tree, TREE_UNLINK, drop_rectobj, NULL);
           xv_set(the_where_tree, 
		  TREE_ADD_LINK, the_connector, drop_rectobj, 
		  NULL);
           xv_set(the_where_tree, 
		  TREE_ADD_LINK, the_connector, the_new_leaf, 
		  NULL);
           xv_set(the_new_leaf,
              RECTOBJ_MENU, where_leaf_menu, 
              XV_KEY_DATA, EXPRESSION_TREE, the_expression_tree, 
              XV_KEY_DATA, EXPRESSION_HIDE, 0,
              NULL);
         } /* the case of adding an expression to a connector with 
	      a new connector */
         break;
       case NOTOP: /* DO NOTHING */
         break;
       }
   
  }
  xv_set(drop_canvas_shell, 
	 CANVAS_MIN_PAINT_WIDTH, xv_get(the_where_tree, XV_WIDTH) + 20,
	 CANVAS_MIN_PAINT_HEIGHT, xv_get(the_where_tree, XV_HEIGHT) + 10,
	 NULL);
  window_fit(the_where_tree);
  window_fit(drop_canvas_shell);
  window_fit((Frame) xv_get(drop_canvas_shell, XV_OWNER));
}

void
delete_where_tree_leaf_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{

/* This is very easy
 * Delete the leaf (it is just that)
 * But you have to check its parent to see
 * if it's a AND/OR decrement its link count
 * and it's NOT then unlink until a AND/OR
 * is encounter and decrement the link count.
 * Be careful not to eliminate the whole tree
 * or to have NOTs only.  
 * IF THE LEAF IS THE ONLY ONE,
 * ASK IF THAT IS DESIRED AND PROCEED TO 
 * DESTROY THE TREE.
 */

  Rectobj parent, you_gonna_die, temp, temp2, highest;
  Tree tree;
  Menu tempmenu;

  you_gonna_die = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  tree = (Tree) xv_get(you_gonna_die, XV_OWNER);
  parent = (Rectobj) xv_get(tree, TREE_LINK_FROM, you_gonna_die);

  /* check if the parent node is not 
     left alone and also that it is not the root */
  if ((Tree) parent == tree) { /* You are killing the tree, make it so! */
    recursive_delete((Tree) xv_get(you_gonna_die,
				   XV_KEY_DATA, EXPRESSION_TREE), 
		     (Rectobj) xv_get(you_gonna_die,
				      XV_KEY_DATA, EXPRESSION_TREE));
    xv_set(tree, TREE_UNLINK, you_gonna_die, NULL);
    xv_destroy(you_gonna_die);
    tempmenu = (Menu) xv_get(tree, RECTOBJ_MENU);
    xv_destroy(you_gonna_die);
    xv_destroy(menu);
    xv_destroy(tree);
    if (tempmenu)
      xv_destroy(tempmenu);
    qual_tree = 0;
     xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL);
  }
  else {
    switch((int) xv_get(parent, XV_KEY_DATA, TYPE)) {
       case ANDOP:
       case OROP:
         highest = 0;
         if ( (int) xv_get(parent, XV_KEY_DATA, LINKS) == 2) { 
				/* this is full so let's hurt parent only */
	   recursive_recursive_delete(tree, you_gonna_die);
	   xv_set(parent, XV_KEY_DATA, LINKS, 1, NULL);
	   /* recursively delete the branch starting in you_gonna_die */
         } 
	 else { /* this parent needs to die also
		   but check how high is the loneliness */
           temp = parent;
           while ((Rectobj) xv_get(tree, TREE_LINK_FROM, temp) != 
		  (Rectobj) tree) { /* don't reach the root */
             temp2 = (Rectobj) xv_get(tree, TREE_LINK_FROM, temp);
             if ( (((int) xv_get(temp2, XV_KEY_DATA, LINKS) == 1) && 
		   ((int) xv_get(temp2, XV_KEY_DATA, TYPE) != NOTOP)) ||
                  ((int) xv_get(temp2, XV_KEY_DATA, TYPE) == NOTOP)) {
	       temp = temp2;
             } 
	     else {
	       highest = temp; 
	       break;
	     }
           }
           if (highest) { /* kill recursively the branch starting on highest */
             xv_set((Rectobj) xv_get(tree, TREE_LINK_FROM, highest),
		    XV_KEY_DATA, LINKS, 1, 
		    NULL);
             recursive_recursive_delete(tree, highest);
           } 
	   else { /* kill the tree */
             recursive_recursive_delete(tree, tree);
             qual_tree = 0;
             xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL);
           }
         }     
         break;
       case NOTOP:
         temp = parent;
         while ( (Rectobj) xv_get(tree, TREE_LINK_FROM, temp) != tree) {
					 /* don't reach the root */
           temp2 = (Rectobj) xv_get(tree, TREE_LINK_FROM, temp);
           if ( (((int) xv_get(temp2, XV_KEY_DATA, LINKS) == 1) &&
		 ((int) xv_get(temp2, XV_KEY_DATA, TYPE) != NOTOP)) ||
	        ((int) xv_get(temp2, XV_KEY_DATA, TYPE) == NOTOP)) {
	     temp = temp2;
           } 
	   else {
	     highest = temp;
	     break;
	   }
         }
         if (highest) { /* kill recursively the branch starting on highest */
	   xv_set((Rectobj) xv_get(tree, TREE_LINK_FROM, highest), 
		  XV_KEY_DATA, LINKS, 1, 
		  NULL);
	   recursive_recursive_delete(tree, highest);                        
         } 
	 else { /* kill the tree */
           recursive_recursive_delete(tree, tree);
           qual_tree = 0;
           xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL); 
         }
         break;
       default:
         break;
       }
    
  }
}

void
negate_the_branch_proc(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{

/* This is so easy, add the NOT to the
   current node parent and then unlink
   the current node and attach it to
   the NOT
 */
  Tree the_tree;
  Rectobj the_node_to_negate, the_parent, the_negation;
  Menu the_negation_menu;


  the_node_to_negate = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_tree = (Tree) xv_get(the_node_to_negate, XV_OWNER);
  the_parent = (Rectobj) xv_get(the_tree, TREE_LINK_FROM, the_node_to_negate);
 
  the_negation = (Rectobj) xv_create(the_tree, DRAWTEXT, 
                                   DRAWTEXT_STRING, " not ",
                                   XV_KEY_DATA, TYPE, NOTOP, 
                                   XV_KEY_DATA, LINKS, 1, 
                                   NULL);
  the_negation_menu = (Menu) xv_create(XV_NULL, MENU,
                                 MENU_TITLE_ITEM, "Qualifier Not node",
                                 MENU_ACTION_ITEM, 
				       "Add not...", negate_the_branch_proc,
                                 MENU_ACTION_ITEM, 
				       "Delete", delete_where_tree_negate_node,
                                 XV_KEY_DATA, MENU_OWNER, the_negation,
                                 NULL);
  xv_set(the_negation, RECTOBJ_MENU, the_negation_menu, NULL);
  xv_set(the_tree, TREE_ADD_LINK, the_parent, the_negation, NULL);
  xv_set(the_tree, TREE_UNLINK, the_node_to_negate, NULL);
  xv_set(the_tree, TREE_ADD_LINK, the_negation, the_node_to_negate, NULL);

}

void
recursive_recursive_delete(tree, node)
     Tree tree;
     Rectobj node;
{
  Rectobj_list *all;
  Rectobj temp, child_tree;
  Menu menu;
  
  

  all = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, node);
  if(all) {
     list_for(all) {
        temp =  RECTOBJ_LIST_HANDLE(all);        
        recursive_recursive_delete(tree, temp);        
     }
  } 
  xv_set(tree, TREE_UNLINK, node, NULL);
  child_tree = (Tree) xv_get(node, XV_KEY_DATA, EXPRESSION_TREE);
  if(child_tree) recursive_delete(child_tree, child_tree);
  menu = (Menu) xv_get(node, RECTOBJ_MENU);
  xv_destroy(node);
  if(menu) xv_destroy(menu);
  
  
}

void
delete_where_tree_binary_node(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{

/* Well this only nuke out AND/OR connectors
 * so... check if the parent is not alone
 * or any of its ascendants neither then
 * nuke the whole branch under
 * connector's antecesor (maybe the the whole 
 * tree)
 */

 Rectobj parent, you_gonna_die, temp, temp2, highest;
 Tree tree;
 Menu tempmenu;

 you_gonna_die = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
 tree = (Tree) xv_get(you_gonna_die, XV_OWNER);
 parent = (Rectobj) xv_get(tree, TREE_LINK_FROM, you_gonna_die);

 /* check if the parent node is not 
    left alone and also that it is not the root */
  if ( (Tree) parent == tree) { /* You are killing the tree, make it so! */
     recursive_recursive_delete(tree, tree);
     qual_tree = 0;
     xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL);
  } 
  else {
    switch((int) xv_get(parent, XV_KEY_DATA, TYPE)) {
       case ANDOP:
       case OROP:
         highest = 0;
         if ((int) xv_get(parent, XV_KEY_DATA, LINKS) == 2) {
			 /* this is full so let's hurt parent only */
	   recursive_recursive_delete(tree, you_gonna_die);
	   xv_set(parent, XV_KEY_DATA, LINKS, 1, NULL);
	   /* recursively delete the branch starting in you_gonna_die */
         }
	 else { /* this parent needs to die also but
		   check how high is the loneliness */
           temp = parent;
           while ( (Rectobj) xv_get(tree, TREE_LINK_FROM, temp) != tree) { 
	     				/* don't reach the root */
             temp2 = (Rectobj) xv_get(tree, TREE_LINK_FROM, temp);
             if ( (((int) xv_get(temp2, XV_KEY_DATA, LINKS) == 1) &&
		   ((int) xv_get(temp2, XV_KEY_DATA, TYPE) != NOTOP)) ||
                  ((int) xv_get(temp2, XV_KEY_DATA, TYPE) == NOTOP)) {
	       temp = temp2;
             } 
	     else {
	       highest = temp;
	       break;
	     }
           }
           if (highest) { /* kill recursively the branch starting on highest */
             xv_set((Rectobj) xv_get(tree, TREE_LINK_FROM, highest), 
		    XV_KEY_DATA, LINKS, 1, 
		    NULL);
             recursive_recursive_delete(tree, highest);
           } 
	   else { /* kill the tree */
             recursive_recursive_delete(tree, tree);
             qual_tree = 0;
             xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL);
           }
         }     
         break;
       case NOTOP:
         temp = parent;
         while ((Rectobj) xv_get(tree, TREE_LINK_FROM, temp) != tree) {
	   			/* don't reach the root */
           temp2 = (Rectobj) xv_get(tree, TREE_LINK_FROM, temp);
           if ( (((int) xv_get(temp2, XV_KEY_DATA, LINKS) == 1) &&
		 ((int) xv_get(temp2, XV_KEY_DATA, TYPE) != NOTOP)) ||
	        ((int) xv_get(temp2, XV_KEY_DATA, TYPE) == NOTOP)) {
	     temp = temp2;
           } 
	   else {
	     highest = temp; 
	     break;
	   }
         }
         if (highest) { /* kill recursively the branch starting on highest */
	   xv_set((Rectobj) xv_get(qual_tree, TREE_LINK_FROM, highest), 
		  XV_KEY_DATA, LINKS, 1, 
		  NULL);
	   recursive_recursive_delete(tree, highest);                        
         } 
	 else { /* kill the tree */
           recursive_recursive_delete(tree, tree);
           qual_tree = 0;
           xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL); 
         }
         break;
       default:
         break;
       }
 
  }
} 

void
delete_where_tree_negate_node(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{

/* Piece of cake, move the branch under the negation
 * and attached it to the negation parent then kill 
 * negation 
 */

  Rectobj no_parent, no_child, no_itself; 
  Tree tree;
  Rectobj_list *no_list;

  no_itself = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  tree = (Tree) xv_get(no_itself, XV_OWNER);
  no_parent = (Rectobj) xv_get(tree, TREE_LINK_FROM, no_itself);

  no_list = (Rectobj_list *) xv_get(tree, TREE_LINK_TO_LIST, no_itself);
  list_for (no_list) {
    no_child = RECTOBJ_LIST_HANDLE(no_list);
  }
  xv_set(tree, TREE_UNLINK, no_child, NULL);
  xv_set(tree, TREE_ADD_LINK, no_parent, no_child, NULL);
  xv_set(tree, TREE_UNLINK, no_itself, NULL);
  xv_destroy(no_itself);
  xv_destroy(menu);
}

void
kill_this_tree(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
 
  if (qual_tree) 
    recursive_recursive_delete(qual_tree, qual_tree);
  qual_tree = 0;
  xv_set(qual_shell, XV_KEY_DATA, THE_ARRAY, 0, NULL);
}

char *
where_tree_constructor(expression, node)
     Tree expression;
     Rectobj node;
{

/* first, check if node has any child 
 * if not, it is a leaf and all you have
 * to do is to construct the expression;
 *
 * if have children then it is an internal node
 * and you do the following:
 *
 *  1) if it is an AND/OR
 *      a) "("
 *      b) obtain left_child = expression_constructor(expression, left_child_node)
 *      c) obtain the node label
 *      d) obtain right_child = expression_constructor(expression, right_child_node)
 *      e) ")"
 *      f) return all the things concatenated
 * 
 *  2) if it is NOT
 *     a) obtain label
 *     b) obtain child = expression_constructor(expression, child)
 *     c) return all the things concatenated
 *
 */
 int type, top, child_no;
 Rectobj_list *children;
 Rectobj left, right, dumb;
 Tree node_expression;
 char *the_answer;
 char *left_par = "(";
 char *right_par = ") ";
 char temp[8196], where[8196];


 
 children = (Rectobj_list *) xv_get(expression, TREE_LINK_TO_LIST, node);

 if (expression == node) 
   { top = 1; } 
 else 
   { top = 0; } /* to root or not to root */
 
 if (children != NULL) { /* cool this is not the end */
   if (!top) { /* this is not root so check what type is it */
     type = (int) xv_get(node, XV_KEY_DATA, TYPE);
     switch(type) {
       case ANDOP:
       case OROP:
         child_no = 0;
         (void) strcpy(temp, left_par);
         list_for(children) {
            if(child_no == 0) {
                dumb = RECTOBJ_LIST_HANDLE(children);
                strcat(temp, where_tree_constructor(expression, dumb));
            } else {
                strcat(temp, (char *) xv_get(node, DRAWTEXT_STRING));
                dumb = RECTOBJ_LIST_HANDLE(children);
                strcat(temp, where_tree_constructor(expression, dumb));
            }
            child_no++;
         }
         strcat(temp, right_par);
         break;
       case NOTOP:
         sprintf(temp, "%s(", (char *) xv_get(node, DRAWTEXT_STRING));
         dumb = RECTOBJ_LIST_HANDLE(children);
         strcat(temp, where_tree_constructor(expression, dumb));
         strcat(temp, ")");
        /* the_answer = strdup(temp); */
         break;
     }
   } 
   else { /* the root!!! */
     list_for(children) { /* one node under the tree */
       dumb = RECTOBJ_LIST_HANDLE(children);
       sprintf(temp, "%s", where_tree_constructor(expression, dumb));
     }
   }

 }
 else { /* a nice leaf */

   if (!top) { /* checking we don't have an empty tree, you never know */

     node_expression = (Tree) xv_get(node, XV_KEY_DATA, EXPRESSION_TREE);
     sprintf(temp, "%s",
	     expression_constructor(node_expression, node_expression));
   }

 }   
      
 
 return temp;
} 

void
switch_bool(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Rectobj the_connector;
  int the_bool;

  the_connector = (Rectobj) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  the_bool = (int) xv_get(the_connector, XV_KEY_DATA, TYPE);

  switch(the_bool) {
  case ANDOP:
   xv_set(the_connector,
          DRAWTEXT_STRING, " or ",
          XV_KEY_DATA, TYPE, OROP,
          NULL);
   break;
  case OROP:
   xv_set(the_connector, 
          DRAWTEXT_STRING, " and ",
          XV_KEY_DATA, TYPE, ANDOP,
          NULL);
   break;
 }
}


void
adding_a_constant_to_the_array(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{
  Canvas_shell the_shell;
  Array_tile array;
  Tree tree;
  Rectobj element, node1;
  Menu array_elem_menu, leaf_menu;

  the_shell = (Canvas_shell) xv_get(menu, XV_KEY_DATA, MENU_OWNER);
  array = (Array_tile) xv_get(the_shell, XV_KEY_DATA, THE_ARRAY);

  element = (Drawicon) xv_create(array, DRAWICON, 
				 DRAWIMAGE_SVRIMAGE, gray4,
				 DRAWTEXT_STRING,
				   " \/* attribute *\/ ",
				 RECTOBJ_DBL_CLICK_PROC, 
				   show_hide_expression_tree,
				 XV_KEY_DATA, EXPRESSION_HIDE, 0,
				 NULL);

  array_elem_menu = (Menu) xv_create(XV_NULL, MENU,
				     MENU_TITLE_ITEM, "Target List Element",
				     MENU_ACTION_ITEM,
				       "Name the attribute...", 
				       name_retrieve_attr_proc,
				     MENU_ACTION_ITEM,
				       "Delete", delete_array_elem_proc,
				     XV_KEY_DATA, MENU_OWNER, element,
				     NULL);

  tree = (Tree) 
    xv_create((Canvas_shell) xv_get(array, XV_KEY_DATA, EXPRESSION_CANVAS),
	      TREE,
	      XV_SHOW, FALSE,                                      
	      RECTOBJ_ACCEPTS_CHILD_DROP, TRUE,
	      RECTOBJ_CHILD_DROP_PROC, adding_stuff_to_the_expression_tree,
	      XV_KEY_DATA, ARRAY_ELEMENT, element, 
	      XV_KEY_DATA, TREE_EMPTY, 1,
	      XV_KEY_DATA, THE_ARRAY, array, 
	      NULL);

  node1 = (Drawicon) xv_create(tree, DRAWICON, 
			       DRAWIMAGE_SVRIMAGE, gray4,
			       DRAWTEXT_STRING, "Constant {Un-assigned}",
			       XV_KEY_DATA, TYPE, CONSTANT,
			       XV_KEY_DATA, NAME_SET, 0,
			       NULL);
  leaf_menu = (Menu) xv_create(XV_NULL, MENU, 
			       MENU_TITLE_ITEM, "Constant",
			       MENU_ACTION_ITEM, 
			         "Assign the constant...", assign_constant_proc,
			       MENU_ACTION_ITEM, 
			         "Add operator", add_unary_opr_proc,
			       MENU_ACTION_ITEM, "Delete", delete_leaf_proc,
			       XV_KEY_DATA, MENU_OWNER, node1,
			       NULL);


  xv_set(node1, RECTOBJ_MENU, leaf_menu, NULL); /* Menu node attached */

  xv_set(tree, TREE_ADD_LINK, tree, node1, NULL);
 
  xv_set(element,
	 RECTOBJ_MENU, array_elem_menu, 
	 XV_KEY_DATA, EXPRESSION_TREE, tree, 
	 XV_KEY_DATA, EXPRESSION_HIDE, 0,
	 NULL);

  xv_set((Canvas_shell) xv_get(tree, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(tree, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(tree, XV_HEIGHT) + 10,
         NULL);

  xv_set((Canvas_shell) xv_get(array, XV_OWNER),
         CANVAS_MIN_PAINT_WIDTH, xv_get(array, XV_WIDTH) + 10,
         CANVAS_MIN_PAINT_HEIGHT, xv_get(array, XV_HEIGHT) + 10,
         NULL);
}


void
dumbo(menu, menu_item)
     Menu menu;
     Menu_item menu_item;
{}
