/*
* Gtk/XmHTML form support. Koen/Miguel.
*
* FIXME:
* - Add support for configuring the background colors (allow_form_coloring)
* - Add support for setting the sizes of the listboxes (gtk_list) and the
* input lines (gtk_entry).
* - Some reset routines are not finished
* - The Text entry is not editable, do not know why.
*/
#include
#include
#include
#include "XmHTMLP.h"
#include "XmHTMLfuncs.h"
/* scratch stuff */
static XmHTMLFormData *current_form;
static XmHTMLForm *current_entry;
static void
finalizeEntry(XmHTMLWidget html, XmHTMLForm *entry, Boolean insert)
{
if(entry->w)
{
GtkRequisition req;
gtk_widget_size_request (entry->w, &req);
entry->width = req.width;
entry->height = req.height;
}
else
{
entry->width = 0;
entry->height = 0;
}
/* add to parent form when requested */
if(insert)
{
if(current_entry)
{
entry->prev = current_entry;
current_entry->next = entry;
current_entry = entry;
}
else
{
current_form->components = current_entry = entry;
}
/* and keep up component counter */
current_form->ncomponents++;
}
_XmHTMLDebug(12, ("forms.c: finalizeEntry, added form entry, "
"type = %i, name = %s\n", entry->type, entry->name));
}
/*****
* Name: getInputType
* Return Type: componentType
* Description: retrieves the type of an HTML form member.
* In:
* attrib..: attributes to check
* Returns:
* componenttype if ``type'' is present in attributes. FORM_TEXT is
* returned if type is not present or type is invalid/misspelled.
*****/
static componentType
getInputType(String attributes)
{
String chPtr;
componentType ret_val = FORM_TEXT;
/* if type isn't specified we default to a textfield */
if((chPtr = _XmHTMLTagGetValue(attributes, "type")) == NULL)
return(ret_val);
if(!(strcasecmp(chPtr, "text")))
ret_val = FORM_TEXT;
else if(!(strcasecmp(chPtr, "password")))
ret_val = FORM_PASSWD;
else if(!(strcasecmp(chPtr, "checkbox")))
ret_val = FORM_CHECK;
else if(!(strcasecmp(chPtr, "radio")))
ret_val = FORM_RADIO;
else if(!(strcasecmp(chPtr, "submit")))
ret_val = FORM_SUBMIT;
else if(!(strcasecmp(chPtr, "reset")))
ret_val = FORM_RESET;
else if(!(strcasecmp(chPtr, "file")))
ret_val = FORM_FILE;
else if(!(strcasecmp(chPtr, "hidden")))
ret_val = FORM_HIDDEN;
else if(!(strcasecmp(chPtr, "image")))
ret_val = FORM_IMAGE;
free(chPtr);
return(ret_val);
}
void _XmHTMLFormReset(XmHTMLWidget html, XmHTMLForm *entry)
{
XmHTMLFormData *form = entry->parent;
XmHTMLForm *tmp, *option;
int i;
_XmHTMLDebug(12, ("forms.c: _XmHTMLFormReset start\n"));
for(tmp = form->components; tmp != NULL; tmp = tmp->next)
{
_XmHTMLDebug(12, ("\tchecking %s\n", tmp->name));
switch(tmp->type)
{
/* passwd doesn't have a default value, clear it */
case FORM_PASSWD:
_XmHTMLDebug(12, ("\t\temptying current password\n"));
gtk_entry_set_text (GTK_ENTRY (tmp->child), "");
if(tmp->content)
{
free(tmp->content);
tmp->content = NULL;
}
break;
case FORM_TEXT:
_XmHTMLDebug(12, ("\t\tsetting XmNvalue to: %s\n", tmp->value));
gtk_entry_set_text (GTK_ENTRY (tmp->child), tmp->value);
break;
case FORM_TEXTAREA:
_XmHTMLDebug(12, ("\t\tsetting XmNvalue to: %s\n", tmp->value));
fprintf (stderr, "FIXME: form reset: we need to reset gtk_text\n");
break;
case FORM_CHECK:
case FORM_RADIO:
/* checkbuttons, set default state */
_XmHTMLDebug(12, ("\t\tsetting state to %s\n",
tmp->selected ? "on" : "off"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tmp->w), tmp->selected);
/* store default selection state */
tmp->checked = (Boolean)tmp->selected;
break;
/* clear selection */
case FORM_FILE:
_XmHTMLDebug(12, ("\t\temptying current selection\n"));
gtk_entry_set_text (GTK_ENTRY (tmp->child), "");
break;
case FORM_SELECT:
if(tmp->multiple || tmp->size > 1)
{
GList *children;
GtkList *list = GTK_LIST (tmp->child);
children = list->children;
for (i = 0; children; children = children->next)
gtk_list_unselect_item (list, i++);
/* now see what options should be selected */
for(i = 0, option = tmp->options; option != NULL; option = option->next, i++)
{
if(option->selected)
gtk_list_select_item (list, i+1);
}
}
else
{
/* FIXME: reset option menu default settng */
fprintf (stderr, "FIXME: form-reset: should reset option menu\n");
}
break;
default:
break;
}
}
_XmHTMLDebug(12, ("forms.c: _XmHTMLFormReset end.\n"));
}
/*****
* Name: formCountComponents
* Return Type: int
* Description: count the number of client side components in a form
* (called from _XmHTMLFormActivate).
* In:
* parent: parent component of the the component that activated the
* callback.
* comp: component that activated the callback.
*
* Returns:
* the number of client side components.
* Note:
* written by: offer@sgi.com
*****/
static int
formCountComponents(XmHTMLForm *parent, XmHTMLForm *comp)
{
int count=1;
current_entry = NULL;
/* walk all components for this form and see which ones are selected */
for(current_entry = parent; current_entry != NULL;
current_entry = current_entry->next)
{
switch((componentType)current_entry->type)
{
case FORM_SELECT:
if(current_entry->multiple || current_entry->size > 1)
{
/* list. Get count of all selected items */
#if 0
int *pos_list, pos_cnt = 0;
/* must take it from child, parent is a scrolledWindow */
if((XmListGetSelectedPos(current_entry->child, &pos_list,
&pos_cnt)))
{
count += pos_cnt;
free(pos_list); /* don't forget! */
}
#else
count++;
fprintf (stderr, "FIXME: CountComponets: Missing code\n");
#endif
}
else
{
/* option menu, add entry when an item has been selected */
XmHTMLForm *opt = NULL;
for(opt = current_entry->options; opt != NULL;
opt = opt->next)
{
if(opt->checked)
count++;
}
}
break;
case FORM_CHECK:
case FORM_RADIO:
if(current_entry->checked)
count++;
break;
case FORM_IMAGE:
if(comp == current_entry)
count+=2; /* name.x=... and name.y=... */
break;
case FORM_RESET:
case FORM_SUBMIT:
if(comp == current_entry)
count++;
case FORM_PASSWD:
if(current_entry->content != NULL)
count++;
break;
/* only return text fields if these actually contain text */
case FORM_TEXT:
/* FIXME: check forms.c: check for text contents here */
count++;
break;
case FORM_FILE:
/* FIXME: check forms.c: check for text contents here */
count++;
break;
case FORM_TEXTAREA:
count++;
/* FIXME: check forms.c: check for text contents here */
break;
/* hidden fiels are always returned */
case FORM_HIDDEN:
count++;
break;
case FORM_OPTION:
/* is a wrapper, so doesn't do anything */
break;
/* no default */
}
}
return(count);
}
void
_XmHTMLFormActivate(XmHTMLWidget html, TEvent *event, XmHTMLForm *entry)
{
XmHTMLFormCallbackStruct cbs;
XmHTMLFormDataPtr components;
int nComponents;
int i, j;
String chPtr;
_XmHTMLDebug(12, ("forms.c: _XmHTMLFormActivate, activated by component "
"%s\n", entry->name));
/* only do something when a form callback has been installed */
if (CHECK_CALLBACK (html, form_callback, FORM) == 0)
return;
/*****
* Check which components of the current form should be returned.
*
* Seems time consuming stepping through the link list twice, but this way
* we can guarantee that we malloc the right ammount of memory (there isn't
* a one-to-one mapping for internal and application views of the
* components, _and_ we won't frag memory unlike repeated calls to realloc
* -- rmo
*****/
nComponents = formCountComponents(entry->parent->components, entry);
components = (XmHTMLFormDataPtr)calloc(nComponents,
sizeof(XmHTMLFormDataRec));
current_entry = NULL;
for(current_entry = entry->parent->components, j=0;
current_entry != NULL && j < nComponents;
current_entry = current_entry->next)
{
/* default settings for this entry. Overridden when required below */
components[j].type = current_entry->type;
components[j].name = current_entry->name;
switch((componentType)current_entry->type)
{
case FORM_SELECT:
/*****
* Option menu, get value of selected item (size check required
* as multiple is false for list boxes offering a single
* entry).
*****/
if(!current_entry->multiple && current_entry->size == 1)
{
XmHTMLForm *opt = NULL;
/*****
* Get selected item (if any). Only one item can be
* selected at a time as this is an option menu.
*****/
for(opt = current_entry->options; opt != NULL &&
!opt->checked; opt = opt->next);
if(opt)
{
components[j].name = current_entry->name;
components[j].type = FORM_OPTION; /* override */
components[j].value = opt->value;
j++;
}
}
else
{
/* list. Get all selected items and store them */
fprintf (stderr, "FormActivate: Missing chunk of code #1\n");
}
break;
/* password entry has really entered text stored */
case FORM_PASSWD:
if(current_entry->content != NULL)
components[j++].value = current_entry->content;
break;
/* textfield contents aren't stored by us */
case FORM_TEXT:
chPtr = gtk_entry_get_text (GTK_ENTRY (current_entry->child));
components[j++].value = chPtr;
break;
/*****
* File contents aren't stored by us and must be taken from the
* textfield child.
*****/
case FORM_FILE:
chPtr = gtk_entry_get_text (GTK_ENTRY (current_entry->child));
components[j++].value = chPtr;
break;
/*****
* Textarea contents aren't stored by us and must be taken from
* the child (current_entry->w is the id of the scrolled window
* parent for this textarea)
*****/
case FORM_TEXTAREA:
chPtr = gtk_entry_get_text (GTK_ENTRY (current_entry->child));
components[j++].value = chPtr;
break;
/* check/radio boxes are equal in here */
case FORM_CHECK:
case FORM_RADIO:
if(current_entry->checked)
components[j++].value = current_entry->value;
break;
case FORM_IMAGE:
if(entry == current_entry)
{
char *xname, *yname;
char *x, *y;
xname = calloc(strlen(current_entry->name)+3, sizeof(char));
yname = calloc(strlen(current_entry->name)+3, sizeof(char));
x= calloc(16, sizeof(char));
y= calloc(16, sizeof(char));
memcpy(xname, current_entry->name,
strlen(current_entry->name));
memcpy(yname, current_entry->name,
strlen(current_entry->name));
strcat(xname,".x");
strcat(yname,".y");
#if 0
fprintf (stderr, "FIXME: ButtonXY positionsc should be computed\n");
sprintf(x,"%d", event->xbutton.x - entry->data->x);
sprintf(y,"%d", event->xbutton.y - entry->data->y);
#endif
components[j].name = xname; /* override */
components[j].value = x;
j++;
components[j].name = yname; /* override */
components[j].value = y;
j++;
}
break;
/* always return these */
case FORM_HIDDEN:
components[j++].value = current_entry->value;
break;
/* reset and submit are equal in here */
case FORM_RESET:
case FORM_SUBMIT:
if(entry == current_entry)
components[j++].value = current_entry->value;
break;
case FORM_OPTION:
/* is a wrapper, so doesn't do anything */
break;
/* no default */
}
}
(void)memset(&cbs, 0, sizeof(XmHTMLFormCallbackStruct));
cbs.reason = XmCR_HTML_FORM;
cbs.event = event;
cbs.action = strdup(entry->parent->action);
cbs.method = entry->parent->method;
cbs.enctype = strdup(entry->parent->enctype);
cbs.ncomponents = nComponents;
cbs.components = components;
Toolkit_Call_Callback((TWidget)html, html->html.form_callback, FORM, &cbs);
/* free all */
for(i = 0; i < j; i++)
{
/* use free to avoid FMM errors in purify */
if(components[i].type == FORM_IMAGE)
{
if(components[i].value)
free(components[i].value);
if(components[i].name)
free(components[i].name);
}
}
free(components);
free(cbs.action);
free(cbs.enctype);
}
/*****
* Name: freeForm
* Return Type: void
* Description: releases all memory occupied by the given form component.
* In:
* entry: form component to be released;
* being_de..: True if the parent HTML widget is being destroyed, in
* which case don't destroy the widgets as they've already been
* destroyed by the time this is called via the
* DestroyCallback -- fix 15/12/97-01, offer
* Returns:
* nothing.
* Background:
* when the parent HTML widget is being destroyed, the call to XtMoveWidget
* triggers a call to XtConfigureWidget which in turn triggers a call to
* XConfigureWindow resulting in a BadWindow as the Window ID already
* has become invalid.
*****/
static void
freeForm(XmHTMLForm *entry)
{
XmHTMLForm *tmp;
fprintf (stderr, "FIXME: freeForm is not releasing created widgets\n");
return;
while(entry != NULL)
{
tmp = entry->next;
if(entry->w)
{
/* destroy */
gtk_container_remove (GTK_CONTAINER (entry->w->parent), entry->w);
entry->w = NULL;
}
if(entry->name)
free(entry->name);
if(entry->value)
free(entry->value);
if(entry->content)
free(entry->content);
/* call ourselves recursively to destroy all option members */
if(entry->options)
freeForm(entry->options);
free(entry);
entry = tmp;
}
}
void
_XmHTMLFreeForm(XmHTMLWidget html, XmHTMLFormData *form)
{
XmHTMLFormData *tmp;
while(form != NULL)
{
tmp = form->next;
freeForm(form->components);
if(form->action)
free(form->action);
if(form->enctype)
free(form->enctype);
free(form);
form = tmp;
}
}
/*****
* Name: _XmHTMLFormAddTextArea
* Return Type: XmHTMLForm*
* Description: creates a form