/* * 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