/*** DTB_USER_CODE_START vvv Add file header below vvv ***/
/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/*** DTB_USER_CODE_END   ^^^ Add file header above ^^^ ***/

/*
 * File: dnd_ed_stubs.c
 * Contains: Module callbacks and connection functions
 *
 * This file was generated by dtcodegen, from module dnd_ed
 *
 * Any text may be added between the DTB_USER_CODE_START and
 * DTB_USER_CODE_END comments (even non-C code). Descriptive comments
 * are provided only as an aid.
 *
 *  ** EDIT ONLY WITHIN SECTIONS MARKED WITH DTB_USER_CODE COMMENTS.  **
 *  ** ALL OTHER MODIFICATIONS WILL BE OVERWRITTEN. DO NOT MODIFY OR  **
 *  ** DELETE THE GENERATED COMMENTS!                                 **
 */

#include <stdint.h>
#include <stdio.h>
#include <Xm/Xm.h>
#include "dtb_utils.h"
#include "dtbuilder.h"
#include "dnd_ed_ui.h"


/**************************************************************************
 *** DTB_USER_CODE_START
 ***
 *** All necessary header files have been included.
 ***
 *** Add include files, types, macros, externs, and user functions here.
 ***/

#include <Xm/List.h>
#include <Xm/RowColumn.h>

#include <ab_private/ui_util.h>
#include "dtbuilder.h"
#include "dnd_ed_ui.h"
#include "abobj_set.h"
#include "conn.h"

#include <ab_private/ab.h>
#include <ab_private/trav.h>
#include <ab_private/prop.h>
#include "abobj_list.h"

/* REMIND: nuke this! */
#include "help_ed_ui.h"


#define NO_DISMISS      0
#define DISMISS         1
#include "dtb_utils.h"

/*
 * Drag and Drop Editor Settings
 */
typedef struct  DND_EDITOR_SETTINGS
{
    ABObj                       curObj;
    AB_OBJECT_TYPE		objType;
    int				objSubtype;
    Widget                      propSheet;
    Widget			objTypeMenu;
    Widget                      objList;
    PropCheckboxSettingRec	drag_ops_checkbox;
    PropFieldSettingRec		drag_icon_text;
    PropFieldSettingRec		drag_icon_mask_text;
    PropRadioSettingRec		drag_types_radiobox;
    PropCheckboxSettingRec	drop_ops_checkbox;
    PropCheckboxSettingRec	drop_types_checkbox;
    PropCheckboxSettingRec	drop_child_checkbox;
} DndEditorSettingsRec, *DndEditorSettings;

static void	dnd_change_objecttype_palCB(
    			Widget	widget,
    			XtPointer   client_data,
    			XtPointer   call_data
		);
static void	change_objtype(
    			Widget		widget,
    			AB_OBJECT_TYPE	newtype,
    			int			newsubtype
		);
static void	update_objecttype_menu_from_obj(
    			Widget	menu,
    			ABObj	obj
		);
static Widget   dnd_ed_editor_init(
                    DtbDndEdDialogInfo  dnd_ed,
                    Widget              parent
                );
static DTB_MODAL_ANSWER	do_auto_apply(
			Widget list,
			ABObj old_obj,
			ABObj new_obj
		);
static void	clear_editor_fields(void);

static BOOL	dnd_editable_obj_test(
    			PalEditableObjInfo  *ed_obj_info
		);
static int      dnd_ed_editor_load(
                    ABObj   project
                );
static int      dnd_ed_editor_apply(void);

static void     dnd_turnoff_changebars(void);

static int	check_active(void);

static int	dnd_ed_update_objecttype_menu(
    			Widget	menu_pane
		);

static BOOL	dnd_list_test(
			ABObj test_obj
		);

static int	dnd_store_attrs(
			ABObj	obj
		);
static void	dnd_fetch_attrs(
    			ABObj obj
		);

static BOOL	dnd_obj_is_target_type(
			ABObj obj
		);

static int	dnd_obj_was_deleted(
    			ObjEvDestroyInfo info
		);
static int	dnd_obj_was_renamed(
    			ObjEvAttChangeInfo	info
		);
static int	dnd_obj_was_updated(
    			ObjEvUpdateInfo	info
		);

static void	dnd_select_instanceCB(
    			Widget widget,
    			XtPointer client_data,
    			XmListCallbackStruct *listdata
		);

static void	dnd_prevent_closeCB(
    			Widget	widget,
    			XtPointer   client_data,
    			XtPointer   call_data
		);

/*
 * Declarations of global widgets used by callbacks.
 */

static DndEditorSettingsRec	dndEdInfo;


/*
 * End declarations of global widgets
 */

void
dnd_ed_show_dialog(void)
{
    /* If there is no DragAndDrop Editor, create it */
    if (AB_dnd_dialog == (Widget)NULL)
    {
        AB_dnd_dialog = dnd_ed_editor_init(&dtb_dnd_ed_dialog, AB_toplevel);
    }
    if (AB_dnd_dialog != NULL)
	ab_show_window(AB_dnd_dialog);

}


/*
 * Returns the topmost form widget
 */
static Widget 
dnd_ed_editor_init(
    DtbDndEdDialogInfo  dnd_ed,
    Widget              parent
)
{
    DndEditorSettings	dds = &dndEdInfo;
    Widget		item[10];
    int			item_val[10];
    int			n = 0;

    /*
     * Create Dialog widgets...
     */

    if (dnd_ed->dialog_shellform != NULL)
    {
        return dnd_ed->dialog_shellform;
    }
    if (dtb_dnd_ed_dialog_initialize(dnd_ed, parent) != 0)
    {
#ifdef DEBUG
        util_dprintf(1,
	    "dnd_ed_show_dialog: could not initialize Drag and Drop Editor\n"); 
        return NULL;
#endif /* DEBUG */
    }


    /* 
     * Hook widgets up to DragAndDrop Editor
     */
    dds->curObj = NULL;
    dds->objType = AB_TYPE_UNDEF;
    dds->objSubtype = 0;
    dds->propSheet = dnd_ed->attrs_ctrlpanel;
    dds->objList = dnd_ed->objlist;
    dds->objTypeMenu = dnd_ed->objtype_opmenu;

    /*
     * Initialization of Editor Settings...
     */

    /* drag operation checkbox */
    n = 0;
    item[n] = dnd_ed->drag_op_checkbox_items.Copy_item;
    item_val[n++] = (int)ABDndOpCopy;
    item[n] = dnd_ed->drag_op_checkbox_items.Move_item;
    item_val[n++] = (int)ABDndOpMove;
    item[n] = dnd_ed->drag_op_checkbox_items.Link_item;
    item_val[n++] = (int)ABDndOpLink;
    prop_checkbox_init(&(dds->drag_ops_checkbox),
	dnd_ed->drag_op_checkbox_label, dnd_ed->drag_op_checkbox,
	n, item, item_val,
	dnd_ed->drag_op_cb);

    /* drag icon text */
    prop_field_init(&(dds->drag_icon_text),
	dnd_ed->drag_icon_field_label, dnd_ed->drag_icon_field,
	dnd_ed->drag_icon_cb);
    prop_field_init(&(dds->drag_icon_mask_text),
	dnd_ed->drag_icon_mask_field_label, dnd_ed->drag_icon_mask_field,
	dnd_ed->drag_icon_mask_cb);

    /* drag data types checkbox */
    n = 0;
    item[n] = dnd_ed->drag_data_checkbox_items.Text_item;
    item_val[n++] = (int)ABDndTypeText;
    item[n] = dnd_ed->drag_data_checkbox_items.Filename_item;
    item_val[n++] = (int)ABDndTypeFilename;
    item[n] = dnd_ed->drag_data_checkbox_items.Buffer_item;
    item_val[n++] = (int)ABDndTypeUserDef;
    prop_radiobox_init(&(dds->drag_types_radiobox),
	dnd_ed->drag_data_checkbox_label, dnd_ed->drag_data_checkbox,
	n, item, (XtPointer*)item_val,
	dnd_ed->drag_data_cb);

    /* drop ops checkbox */
    n = 0;
    item[n] = dnd_ed->drop_op_checkbox_items.Copy_item;
    item_val[n++] = (int)ABDndOpCopy;
    item[n] = dnd_ed->drop_op_checkbox_items.Move_item;
    item_val[n++] = (int)ABDndOpMove;
    item[n] = dnd_ed->drop_op_checkbox_items.Link_item;
    item_val[n++] = (int)ABDndOpLink;
    prop_checkbox_init(&(dds->drop_ops_checkbox),
	dnd_ed->drop_op_checkbox_label, dnd_ed->drop_op_checkbox,
	n, item, item_val,
	dnd_ed->drop_op_cb);

    /* drop data types checkbox */
    n = 0;
    item[n] = dnd_ed->drop_data_checkbox_items.Text_item;
    item_val[n++] = (int)ABDndTypeText;
    item[n] = dnd_ed->drop_data_checkbox_items.Filename_item;
    item_val[n++] = (int)ABDndTypeFilename;
    item[n] = dnd_ed->drop_data_checkbox_items.Buffer_item;
    item_val[n++] = (int)ABDndTypeUserDef;
    prop_checkbox_init(&(dds->drop_types_checkbox),
	dnd_ed->drop_data_checkbox_label, dnd_ed->drop_data_checkbox,
	n, item, item_val,
	dnd_ed->drop_data_cb);

    /* allow drops on children checkbox */
    n = 0;
    item[n] = dnd_ed->drop_child_checkbox_items.nolabel_item;
    item_val[n++] = 0;
    prop_checkbox_init(&(dds->drop_child_checkbox),
	dnd_ed->drop_child_checkbox_label, dnd_ed->drop_child_checkbox,
	n, item, item_val,
	dnd_ed->drop_child_cb);

    /* 
     * Build object type menu and select the first item (but first must 
     * destroy dummy option item) 
     */
    dndEdInfo.objType = AB_TYPE_UNDEF;
    dndEdInfo.objSubtype = 0;
    XtDestroyWidget(dnd_ed->objtype_opmenu_items.object_type_item);
    pal_add_editable_obj_menu_items(dnd_ed->objtype_opmenu_menu,
            dnd_change_objecttype_palCB, dnd_editable_obj_test);
    XtVaGetValues(dds->objList, XmNitemCount,&n, NULL);
    if(n > 0) 
    {
    	XmListSelectPos(dds->objList,1,True);	/* invokes callbacks */
    }

    /* Register Dnd Editor callbacks */
    XtAddCallback(dds->objList, XmNsingleSelectionCallback,
            (XtCallbackProc)dnd_select_instanceCB, (XtPointer)NULL);

    /*
     * Setup dialog to participate in dtbuilder window protocol
     */
    ab_register_window(dnd_ed->dialog_shellform, AB_WIN_DIALOG, 
		WindowHidden, AB_toplevel, AB_WPOS_TILE_HORIZONTAL,
		dnd_prevent_closeCB, NULL);

    dnd_turnoff_changebars();

    /*
     * Make necessary fields active
     */
    check_active();

    /*
    ** Hook up callbacks so we're notified when an object is modified.
    ** an update callback occurs when the object has been completely
    ** modified (e.g., when an object is loaded from a file).
    **
    ** The second parameter is our "name" for debugging messages. We'll Just
    ** use the file name.
    **
    ** We don't use the create_callback() to detect the creation of objects
    ** because at the time they are created their name is "(nil)".  However,
    ** a later part of the creation process is to change their name from
    ** "(nil)" to their proper name, and at that time the rename callback is
    ** called.  We therefore use the rename callback to handle both object
    ** creation and renaming.
    */
    obj_add_destroy_callback(dnd_obj_was_deleted, __FILE__);
    obj_add_rename_callback(dnd_obj_was_renamed, __FILE__);
    obj_add_update_callback(dnd_obj_was_updated, __FILE__);

    return dnd_ed->dialog_shellform;
}


static int
dnd_ed_update_objecttype_menu(
    Widget	menu_pane
)
{
return 0;
}


static void
dnd_change_objecttype_palCB(
    Widget	widget,
    XtPointer   client_data,
    XtPointer   call_data
)
{
    PalEditableObjInfo *item = (PalEditableObjInfo*)client_data;

    change_objtype(widget,item->type,item->subtype);
}


static void
change_objtype(
    Widget		widget,
    AB_OBJECT_TYPE	newtype,
    int			newsubtype
)
{
    DTB_MODAL_ANSWER		answer;
    int				i;
    DndEditorSettings		dds = &dndEdInfo;

    /*
    ** If there are pending changes, process the requested
    ** load in a special way that allows the user to abort it
    ** if they so choose.  
    */
    if((dds->curObj != NULL) && prop_changebars_pending(dds->propSheet))
    {
	answer = do_auto_apply(widget, dds->curObj, (ABObj)NULL);
	if (answer == DTB_ANSWER_CANCEL) 
	{
	    update_objecttype_menu_from_obj(dds->objTypeMenu, dds->curObj);
	    return;
	}
    }

    /*
    ** Either nothing to auto-apply, or the user said "Sure, go ahead".
    ** Because the do_auto_apply() function didn't have a new object to
    ** change to (automatically) we have to do it manually
    */

    /* First, clear out fields in Dnd Editor */
    clear_editor_fields();

    /* Update current-objecttype (from menu selection) & clear current object */
    dds->curObj = (ABObj)NULL;
    dds->objType = newtype;
    dds->objSubtype = newsubtype;

    /* Load object list with new type */
    (void) abobj_list_load(dds->objList,proj_get_project(),dnd_list_test);

    /* Select 1st item in the list (if there is one) and load its attributes */
    XtVaGetValues(dds->objList, XmNitemCount,&i, NULL);
    if(i > 0) {
    	/* 
    	** This will call the item_selected callback for the list,
    	** which will update the Dnd Editor's fields.
    	*/
    	XmListSelectPos(dds->objList,1,True);
    }
    else
    {
	check_active(); 	/* gray out fields */
    }
    
    return;
}

/* Update the object type menu to match the type of a given object */
static void
update_objecttype_menu_from_obj(
    Widget	menu,
    ABObj	obj
)
{
    PalItemInfo*	palitem = (PalItemInfo*)NULL;
    XmString		xmlabel = NULL;
    Widget		menu_selection = NULL;

    if(obj == (ABObj)NULL) return;

    /* Get palette item info for target object */
    if( (palitem = pal_get_item_info(obj)) == (PalItemInfo*)NULL) return;

    /* Get selection button gadget for specified option menu */
    if((menu_selection = XmOptionButtonGadget(menu)) == NULL) return;

    xmlabel = XmStringCreateLocalized(palitem->name);
    XtVaSetValues(menu_selection,
	XmNlabelString, xmlabel,
	NULL);
    XmStringFree(xmlabel);
}


static BOOL
dnd_editable_obj_test(
    PalEditableObjInfo  *ed_obj_info
)
{
    BOOL        needed = FALSE;

    switch(ed_obj_info->type)
    {
	case AB_TYPE_BASE_WINDOW:
	case AB_TYPE_DIALOG:
	case AB_TYPE_DRAWING_AREA:
	case AB_TYPE_LABEL:
	    needed = TRUE;
	break;

	case AB_TYPE_CONTAINER:
	    needed = (ed_obj_info->subtype == (int)AB_CONT_RELATIVE);
	break;
    }

    return needed;
}


static int
dnd_ed_editor_load(
    ABObj       obj
)
{
    DndEditorSettings	dds = &dndEdInfo;
 
    if (obj == NULL)
    {
        if (dds->curObj != NULL)
            obj = dds->curObj;
        else
            return ERROR;
    }
    else
        dds->curObj = obj;

    /* REMIND: LOAD ALL EDITOR SETTINGS WITH OBJ VALUES HERE */

    dnd_turnoff_changebars();

    return OK;

}

static int
dnd_ed_editor_apply(void)
{
    return dnd_store_attrs(dndEdInfo.curObj);
}




static void
dnd_turnoff_changebars(void)
{
    DndEditorSettings	dds = &dndEdInfo;
    prop_set_changebar(dds->drag_ops_checkbox.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drag_icon_text.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drag_icon_mask_text.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drag_types_radiobox.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drop_ops_checkbox.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drop_types_checkbox.changebar,PROP_CB_OFF);
    prop_set_changebar(dds->drop_child_checkbox.changebar,PROP_CB_OFF);
    prop_changebars_cleared(dds->propSheet);
}


/*
** Callback: object has been selected from list of objects
*/
static void
dnd_select_instanceCB(
    Widget widget,
    XtPointer client_data,
    XmListCallbackStruct *listdata
)
{
    ABObj        		module = NULL;
    ABObj        		selected_obj = NULL;
    STRING       		name = NULL;
    DndEditorSettings		dds = &dndEdInfo;

    name = objxm_xmstr_to_str(listdata->item);

    if (   (listdata->selected_item_count == 0)
	|| (name == NULL) )
    {
	dndEdInfo.curObj = NULL;
	check_active();
	return;
    }

    if (name != NULL)
    {
	util_dprintf(2,"You selected <%s>\n",name);
        abobj_moduled_name_extract(name, &module, &selected_obj);
        XtFree(name);
        if (selected_obj)
        {
	    /*
	    ** If there are pending changes, process the requested
	    ** load in a special way that allows the user to abort it
	    ** if they so choose.  
	    */
	    if((dds->curObj != NULL) && 
		prop_changebars_pending(dds->propSheet) == True) {
		(void) do_auto_apply(widget, dds->curObj, selected_obj);
	    }
	    /* No pending changes, so just load the new object */
	    else {
		dds->curObj = selected_obj;
		dds->objType    = obj_get_type(dds->curObj);
		dds->objSubtype = obj_get_subtype(dds->curObj);
		dnd_fetch_attrs(dds->curObj);
	    }
            return;
        }
    }
    if (util_get_verbosity() > 0)
        fprintf(stderr,"Dnd Editor::dnd_select_instanceCB: could not get object in list\n");
}

/*
** Handle auto apply.  This condition can occur in any of the following ways:
**  - The user selects another object to be edited and hasn't yet saved changes 
**     made to the current object  (old_obj = current object, new_obj = new
**     object they've chosen from the list)
**  - The user selects "Close" from the Motif window menu and hasn't yet saved
**     changes made to the current object (old_obj and new_obj are both = 
**     current object)
**  - The user selects another object type from the object type menu and hasn't
**     yet saved changes made to the current object  (old_obj = current object,
**     new_obj = NULL)
** The assumption here is that the user wants to be given the opportunity
** to save the changes or discard them, and a modal dialog is an o.k.
** way to handle the situation.
*/
static DTB_MODAL_ANSWER
do_auto_apply(
	Widget list,
	ABObj old_obj,
	ABObj new_obj
)
{
    DTB_MODAL_ANSWER	answer;
    char		buffer[256];
    char		*old_name, *new_name;
    BOOL		changing_objects = FALSE;
    XmString		xm_buf = (XmString) NULL;

    if(old_obj == (ABObj) NULL)
	return(DTB_ANSWER_CANCEL);
    else
	old_name = abobj_get_moduled_name(old_obj);

    if (new_obj == (ABObj) NULL)
	new_name = "";
    else
	new_name = abobj_get_moduled_name(new_obj);

    /* Check for object change auto-apply vs. same object auto-apply */
    if( (new_obj != (ABObj) NULL) && (new_obj != old_obj) ) 
	changing_objects = TRUE;

    if (dtb_app_resource_rec.implied_apply == True)
        answer = DTB_ANSWER_ACTION1;
    else
    {   
    	if (changing_objects) 
    	{
	    sprintf(buffer, CATGETS(Dtb_project_catd, 100, 31,
		"Drag and drop properties for \"%s\"\n\
		have been modified but not Applied.\n\n\
		You can Apply the Changes or Cancel the\n\
		Load operation for \"%s\"."),old_name, new_name);
    	}
    	else 
    	{
	    if(new_obj != (ABObj) NULL) 
	    {
		sprintf(buffer, CATGETS(Dtb_project_catd, 100, 32,
		"Drag and drop properties for \"%s\"\n\
		have been modified but not Applied.\n\n\
		You can Apply the Changes or Cancel the\n\
		Close operation."), old_name);
	    }
	    else 
	    {
		sprintf(buffer,CATGETS(Dtb_project_catd, 100, 33,
		"Drag and drop properties for \"%s\"\n\
		have been modified but not Applied.\n\n\
		You can Apply the Changes or Cancel the\n\
		'Change Object-Type' operation."), old_name);
	    }
    	}

    	/* Popup modal message and wait for answer */
    
	/* REMIND: make new dnd_ed_warn_msg.. */
    	xm_buf = XmStringCreateLocalized(buffer);
    	dtb_help_ed_wrn_msg_initialize(&dtb_help_ed_wrn_msg);
    	answer = dtb_show_modal_message(list, &dtb_help_ed_wrn_msg,
		xm_buf, NULL, NULL);
    	XmStringFree(xm_buf);
    }

    /* Process answer */
    switch(answer) 
    {
	case DTB_ANSWER_ACTION1: /* Apply Changes */
		dnd_store_attrs(old_obj);
		if (changing_objects) 
		    dnd_fetch_attrs(new_obj);
		break;
	case DTB_ANSWER_CANCEL: /* Cancel */
		if(changing_objects) {
		    util_dprintf(2,"Resetting <%s> as the current item\n",
			old_name);
		    ui_list_select_item(list,old_name,FALSE);
		}
		break;
    }

    if (old_obj != (ABObj)NULL) XtFree(old_name);
    if (new_obj != (ABObj)NULL) XtFree(new_name);

    /* Pass along the answer in case the caller needs it */
    return (answer);
}
	

static void
clear_editor_fields(void)
{
    DndEditorSettingsRec	*dds = &dndEdInfo;

    prop_checkbox_set_value(&(dds->drag_ops_checkbox), 
	ABDndOpCopy, False, False);
    prop_checkbox_set_value(&(dds->drag_ops_checkbox), 
	ABDndOpLink, False, False);
    prop_checkbox_set_value(&(dds->drag_ops_checkbox), 
	ABDndOpMove, False, False);
    prop_field_set_value(&(dds->drag_icon_text), Util_empty_string, False);
    prop_field_set_value(&(dds->drag_icon_mask_text), Util_empty_string, False);
    prop_radiobox_set_value(&(dds->drag_types_radiobox), 
	(XtPointer)ABDndTypeText, False);
    
    prop_checkbox_set_value(&(dds->drop_ops_checkbox), 
	ABDndOpCopy, False, False);
    prop_checkbox_set_value(&(dds->drop_ops_checkbox),
	ABDndOpLink, False, False);
    prop_checkbox_set_value(&(dds->drop_ops_checkbox),
	ABDndOpMove, False, False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeText, False, False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeFilename, False, False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeUserDef, False, False);
    prop_checkbox_set_value(&(dds->drop_child_checkbox),
	0, False, False);

    /* Reset changebars */
    dnd_turnoff_changebars();
}

/*
** Test function to determine whether an object should appear in the Dnd
** Editor's list.
*/
static BOOL
dnd_list_test(
	ABObj test_obj
)
{
    /* Is this an object we'd want to display? */
    if (obj_is_salient_ui(test_obj) && 
	obj_is_defined(test_obj) &&
	(!obj_is_list_item(test_obj)) &&	/* no List Items */
	/* (!obj_is_popup_win(test_obj)) &&	    no CustomDialogs */
	(obj_get_module(test_obj) != NULL) && 
	(obj_has_flag(test_obj, MappedFlag) || (obj_is_message(test_obj)))
       )
    {
	/* Yes it is.  If we're looking for a current type, do they match ? */
	return(dnd_obj_is_target_type(test_obj));
    }
    return(False);
}

/*
** Get the dnd attributes from an object and update the Dnd Editor's
** fields accordingly.
*/
static void
dnd_fetch_attrs(
    ABObj obj
)
{
    DndEditorSettingsRec	*dds = &dndEdInfo;
    ABDndOpFlags		dragOps = 0;
    ABDndTypeFlags		dragType = 0;
    ABDndOpFlags		dropOps = 0;
    ABDndTypeFlags		dropTypes = 0;
    BOOL			dropOnChildren = FALSE;

    util_dprintf(2,"Load object dnd attributes into editor display fields\n");

    if (obj == NULL)
    {
	clear_editor_fields();
	dds->curObj = NULL;
	return;
    }

    /* get some data */
    dragOps = obj_get_drag_ops(obj);
    dragType = obj_get_drag_types(obj);
    dropOps = obj_get_drop_ops(obj);
    dropTypes = obj_get_drop_types(obj);
    dropOnChildren = obj_drop_on_children_is_allowed(obj);

    if ((dragOps != 0) && (dragType == 0))
    {
	dragType = ABDndTypeText;
    }
    if ((dropOps != 0) && (dropTypes == 0))
    {
	dropTypes |= ABDndTypeText;
    }

    /* Fill the editor's fields with the object's data */
    prop_checkbox_set_value(&(dds->drag_ops_checkbox),
	ABDndOpCopy, ((dragOps & ABDndOpCopy) != 0), False);
    prop_checkbox_set_value(&(dds->drag_ops_checkbox),
    	ABDndOpLink, ((dragOps & ABDndOpLink) !=0), False);
    prop_checkbox_set_value(&(dds->drag_ops_checkbox),
	ABDndOpMove, ((dragOps & ABDndOpMove) != 0), False);
    prop_field_set_value(&(dds->drag_icon_text), 
	obj_get_drag_cursor(obj), False);
    prop_field_set_value(&(dds->drag_icon_mask_text), 
	obj_get_drag_cursor_mask(obj), False);
    if (dragOps != 0)
    	prop_radiobox_set_value(&(dds->drag_types_radiobox),
		(XtPointer)(uintptr_t) dragType, False);
    
    prop_checkbox_set_value(&(dds->drop_ops_checkbox),
	ABDndOpCopy, ((dropOps & ABDndOpCopy) != 0), False);
    prop_checkbox_set_value(&(dds->drop_ops_checkbox),
	ABDndOpLink, ((dropOps & ABDndOpLink) != 0), False);
    prop_checkbox_set_value(&(dds->drop_ops_checkbox),
	ABDndOpMove, ((dropOps & ABDndOpMove) != 0), False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeText, ((dropTypes & ABDndTypeText) != 0), False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeFilename, ((dropTypes & ABDndTypeFilename) != 0), False);
    prop_checkbox_set_value(&(dds->drop_types_checkbox),
	ABDndTypeUserDef, ((dropTypes & ABDndTypeUserDef) != 0), False);

    prop_checkbox_set_value(&(dds->drop_child_checkbox),
	0, dropOnChildren, False);

    /* Reset changebars */
    dnd_turnoff_changebars();

    /* Update current object */
    dds->curObj = obj;
    dds->objType    = obj_get_type(dds->curObj);
    dds->objSubtype = obj_get_subtype(dds->curObj);

    check_active();
}


/* 
** Get the new dnd info out of the Dnd Editor and update the
** object's dnd  attributes accordingly.
*/
static int 
dnd_store_attrs(
	ABObj	obj
)
{
    DndEditorSettings 		dds = &dndEdInfo;
    BOOL			changesPending = FALSE;
    STRING			dragIcon = NULL;
    STRING			dragIconMask = NULL;
    ABDndOpFlags		dragOps = 0;
    ABDndTypeFlags		dragType = 0;
    ABDndOpFlags		dropOps = 0;
    ABDndTypeFlags		dropTypes = 0;
    BOOL			dropOnChildren = FALSE;

    if (obj == NULL)
    {
	return ERR;
    }

    util_dprintf(2,"Store prop dnd attributes into obj fields\n");
    changesPending = prop_changebars_pending(dds->propSheet);

    /* 
     * Get data from fields
     */
    if (prop_checkbox_get_value(&(dds->drag_ops_checkbox), ABDndOpCopy))
    {
	dragOps |= ABDndOpCopy;
    }
    if (prop_checkbox_get_value(&(dds->drag_ops_checkbox), ABDndOpLink))
    {
	dragOps |= ABDndOpLink;
    }
    if (prop_checkbox_get_value(&(dds->drag_ops_checkbox), ABDndOpMove))
    {
	dragOps |= ABDndOpMove;
    }
    dragIcon = prop_field_get_value(&(dds->drag_icon_text));
    dragIconMask = prop_field_get_value(&(dds->drag_icon_mask_text));
    dragType = prop_radiobox_get_value(&(dds->drag_types_radiobox));

    if (prop_checkbox_get_value(&(dds->drop_ops_checkbox), ABDndOpCopy))
    {
	dropOps |= ABDndOpCopy;
    }
    if (prop_checkbox_get_value(&(dds->drop_ops_checkbox), ABDndOpLink))
    {
	dropOps |= ABDndOpLink;
    }
    if (prop_checkbox_get_value(&(dds->drop_ops_checkbox), ABDndOpMove))
    {
	dropOps |= ABDndOpMove;
    }
    if (prop_checkbox_get_value(&(dds->drop_types_checkbox), ABDndTypeText))
    {
	dropTypes |= ABDndTypeText;
    }
    if (prop_checkbox_get_value(&(dds->drop_types_checkbox), ABDndTypeFilename))
    {
	dropTypes |= ABDndTypeFilename;
    }
    if (prop_checkbox_get_value(&(dds->drop_types_checkbox), ABDndTypeUserDef))
    {
	dropTypes |= ABDndTypeUserDef;
    }

    dropOnChildren = prop_checkbox_get_value(&(dds->drop_child_checkbox), 0);

    /*
     * Fiddle with the data a little bit
     */
    if ((dragOps != 0) && (dragType == 0))
    {
	dragType = ABDndTypeText;
    }
    if ((dropOps != 0) && (dropTypes == 0))
    {
	dropTypes |= ABDndTypeText;
    }


    /*
     * Put the data into the object
     */
    obj_set_drag_initially_enabled(obj, (dragOps != 0));
    obj_set_drag_cursor(obj, dragIcon);
    obj_set_drag_cursor_mask(obj, dragIconMask);
    obj_set_drag_ops(obj, dragOps);
    obj_set_drag_types(obj, dragType);
    obj_set_drop_initially_enabled(obj, (dropOps != 0));
    obj_set_drop_ops(obj, dropOps);
    obj_set_drop_types(obj, dropTypes);
    obj_set_drop_on_children_is_allowed(obj, dropOnChildren);

    /* Reset changebars */
    dnd_turnoff_changebars();

    /* Update current object */
    dds->curObj = obj;
    dds->objType    = obj_get_type(dds->curObj);
    dds->objSubtype = obj_get_subtype(dds->curObj);

    /*
     * Redisplay any modified data.
     */
    dnd_fetch_attrs(obj);

    if (changesPending)
    {
	abobj_set_save_needed(obj, True);
    }
    check_active();
    return 0;
}


/*
** Called when the user attempts to dismiss the Dnd Editor via the Motif
** window menu.
*/
static void
dnd_prevent_closeCB(
    Widget	widget,
    XtPointer   client_data,
    XtPointer   call_data
)
{
    DTB_MODAL_ANSWER		answer;
    DndEditorSettingsRec	*dds = &dndEdInfo;

    /* 
    ** If there are pending changes for the current object, handle the
    ** implied auto-apply.
    */
    if((dds->curObj != NULL) && prop_changebars_pending(dds->propSheet))
    {
	answer = do_auto_apply(widget, dds->curObj, dds->curObj);
	if (answer == DTB_ANSWER_ACTION1) 
	    ui_win_show(AB_dnd_dialog, False, XtGrabNone);
    }
    else 
    {
	/* Nope, no pending changes, so just dismiss the Dnd Editor */
	ui_win_show(AB_dnd_dialog, False, XtGrabNone); 
    }
}


/*
 * Activates or greys out fields, as necessary.
 */
static int
check_active(void)
{
    DndEditorSettings	dds = &dndEdInfo;
    DtbDndEdDialogInfo	dnd_ed = &dtb_dnd_ed_dialog;
    BOOL		sensitive = False;

    if (dds->curObj != NULL)
    {
	XtSetSensitive(dnd_ed->drag_op_checkbox_rowcolumn, True);
	sensitive = False;
	if (   prop_checkbox_get_value(&(dds->drag_ops_checkbox),
			ABDndOpCopy)
	    || prop_checkbox_get_value(&(dds->drag_ops_checkbox),
			ABDndOpLink)
	    || prop_checkbox_get_value(&(dds->drag_ops_checkbox),
			ABDndOpMove) )
	{
	    /* at least one operation is valid - enable fields */
	    sensitive = True;
	}
	XtSetSensitive(dnd_ed->drag_icon_field_rowcolumn, sensitive);
	XtSetSensitive(dnd_ed->drag_icon_mask_field_rowcolumn, sensitive);
	XtSetSensitive(dnd_ed->drag_data_checkbox_rowcolumn, sensitive);
	XtSetSensitive(dnd_ed->drag_conn_button, sensitive);

	XtSetSensitive(dnd_ed->drop_op_checkbox_rowcolumn, True);
	sensitive = False;
	if (   prop_checkbox_get_value(&(dds->drop_ops_checkbox),
			ABDndOpCopy)
	    || prop_checkbox_get_value(&(dds->drop_ops_checkbox),
			ABDndOpLink)
	    || prop_checkbox_get_value(&(dds->drop_ops_checkbox),
			ABDndOpMove) )
	{
	    sensitive = True;
	}
	XtSetSensitive(dnd_ed->drop_data_checkbox_rowcolumn, sensitive);
	XtSetSensitive(dnd_ed->drop_child_checkbox_rowcolumn, sensitive);
	XtSetSensitive(dnd_ed->drop_conn_button, sensitive);
    }
    else
    {
	XtSetSensitive(dnd_ed->drag_op_checkbox_rowcolumn, False);
	XtSetSensitive(dnd_ed->drag_icon_field_rowcolumn, False);
	XtSetSensitive(dnd_ed->drag_icon_mask_field_rowcolumn, False);
	XtSetSensitive(dnd_ed->drag_data_checkbox_rowcolumn, False);
	XtSetSensitive(dnd_ed->drag_conn_button, False);
	XtSetSensitive(dnd_ed->drop_op_checkbox_rowcolumn, False);
	XtSetSensitive(dnd_ed->drop_data_checkbox_rowcolumn, False);
	XtSetSensitive(dnd_ed->drop_child_checkbox_rowcolumn, False);
	XtSetSensitive(dnd_ed->drop_conn_button, False);
    }

    return 0;
}


static BOOL
dnd_obj_is_target_type(
	ABObj obj
)
{

    DndEditorSettingsRec	*dds = &dndEdInfo;
    AB_OBJECT_TYPE		type = obj_get_type(obj);
    int				subtype = obj_get_subtype(obj);

    /* In some cases we care about both type & subtype and must check both */
    if( (dds->objType == AB_TYPE_ITEM) ||
	(dds->objType == AB_TYPE_CONTAINER) ) {
	if((type == dds->objType) &&
	   (subtype == dds->objSubtype) ) {
		return(True);
	}
	else return(False);
    }
    /* 
    ** Otherwise we only need to check object type, and in fact don't want to
    ** check subtype because it might confuse things (e.g. we're looking for
    ** any Button palette item, which includes several subtypes of type 
    ** AB_TYPE_BUTTON).
    */
    else {
	if(type == dds->objType) return(True);
	else return(False);
    }

    /* Should never get here - every test above returns True or False */
}


static int
dnd_obj_was_deleted(
    ObjEvDestroyInfo info
)
{
    DndEditorSettings	dds = &dndEdInfo;

    /* 
    ** If this happens to be the object currently being displayed,
    ** clear out the editor's fields, remove it from the object list
    ** and leave the list & editor without a selected object.  Don't change
    ** the current object type, though.
    **
    ** Otherwise, just delete it from the list.
    */
    if((dds->curObj != NULL) && (info->obj == dds->curObj)) {
	clear_editor_fields();
	dds->curObj = (ABObj) NULL;
    }

    abobj_list_obj_destroyed(dds->objList, info->obj, dnd_list_test);

    return 0;
}

static int
dnd_obj_was_renamed(
    ObjEvAttChangeInfo	info
)
{
    return abobj_list_obj_renamed(
		dndEdInfo.objList,
		info->obj, 
		istr_string(info->old_name),
		dnd_list_test);
}

static int
dnd_obj_was_updated(
    ObjEvUpdateInfo	info
)
{
    return abobj_list_obj_updated(dndEdInfo.objList, info, dnd_list_test);
}


/*** DTB_USER_CODE_END
 ***
 *** End of user code section
 ***
 **************************************************************************/



void 
dnd_okCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    dnd_applyCB(widget, clientData, callData);
    ui_win_show(dtb_dnd_ed_dialog.dialog, False, XtGrabNone);
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
dnd_applyCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    dnd_ed_editor_apply();
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
dnd_resetCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    if (dndEdInfo.curObj != NULL)
    {
        dnd_fetch_attrs(dndEdInfo.curObj);
    }
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
dnd_cancelCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    dnd_resetCB(widget, clientData, callData);
    ui_win_show(dtb_dnd_ed_dialog.dialog, False, XtGrabNone);
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
dnd_drag_connCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    if (dndEdInfo.curObj != NULL)
    {
        conn_set_source(dndEdInfo.curObj);
	conn_set_target(NULL);

        conn_override_default_when(AB_WHEN_DRAGGED_FROM); 
        conn_override_default_action_type(AB_FUNC_USER_DEF); 
	conn_popup_dialog(dtb_get_toplevel_widget(), (XtPointer)0, NULL);
        conn_reset_default_when();
        conn_reset_default_action_type();
    }
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
dnd_drop_connCB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/
    if (dndEdInfo.curObj != NULL) 
    {
        conn_set_source(dndEdInfo.curObj);
	conn_set_target(NULL);

	conn_override_default_when(AB_WHEN_DROPPED_ON);
        conn_override_default_action_type(AB_FUNC_USER_DEF); 
	conn_popup_dialog(dtb_get_toplevel_widget(), (XtPointer)0, NULL);
	conn_reset_default_when();
        conn_reset_default_action_type();
    }
    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
drag_op_CB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/

    check_active();

    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}


void 
drop_op_CB(
    Widget widget,
    XtPointer clientData,
    XtPointer callData
)
{
    /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/
    /*** DTB_USER_CODE_END   ^^^ Add C variables and code above ^^^ ***/
    
    /*** DTB_USER_CODE_START vvv Add C code below vvv ***/

    check_active();

    /*** DTB_USER_CODE_END   ^^^ Add C code above ^^^ ***/
}



/**************************************************************************
 *** DTB_USER_CODE_START
 ***
 *** All automatically-generated data and functions have been defined.
 ***
 *** Add new functions here, or at the top of the file.
 ***/
/*** DTB_USER_CODE_END
 ***
 *** End of user code section
 ***
 **************************************************************************/


