Package javango.forms

Source Code of javango.forms.FormSet

package javango.forms;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javango.forms.fields.BooleanField;
import javango.forms.fields.BoundField;
import javango.forms.fields.FieldFactory;
import javango.forms.fields.IntegerField;
import javango.forms.widgets.HiddenInputWidget;

public class FormSet<T extends Form> implements Collection<T> {

  // TODO make this changable.
  private final String formCountFieldName = "TOTAL_FORMS";
  private final String initialFormCountFieldName = "INITIAL_FORMS";
  private final String deletionFieldName = "DELETE";
 
  protected final Forms forms;
  protected final FieldFactory fieldFactory;
  protected final Class<? extends T> formClass;
  protected final String prefix;
  protected final Integer extra;
 
  protected final List<T> formList = new ArrayList<T>();
  protected final Form controlForm;

  protected final List<?> initial;
  protected final Map<String, String[]> data;
 
  protected final boolean canDelete;
 
  private int getTotalFormCount() throws ValidationException {
    if (this.data != null) {
      Integer count = (Integer)controlForm.getCleanedData().get(formCountFieldName);
      if (count == null) {
        throw new ValidationException("ManagementForm data is missing or has been tampered with" );
      }
      return count;
    } else {
      return getInitialFormCount() + extra;
    }
  }
 
  private int getInitialFormCount() throws ValidationException {
    if (this.data != null) {
      Integer count = (Integer)controlForm.getCleanedData().get(initialFormCountFieldName);
      if (count == null) {
        throw new ValidationException("ManagementForm data is missing or has been tampered with" );
      }
      return count;
    } else {
      return initial == null ? 0 : initial.size();
    }
  }
 
  public FormSet(
      Forms forms,
      FieldFactory fieldFactory,
      Class<? extends T> formClass,
      boolean canDelete,
      List<?> initial,
      Map<String, String[]> data,
      String prefix,
      Integer extra) throws ValidationException {
    this.forms = forms;
    this.fieldFactory = fieldFactory;
    this.formClass = formClass;
    this.canDelete = canDelete;
   
    this.prefix = prefix == null ? "form" : prefix;
    this.extra = extra == null ? 1 : extra;
    this.initial = initial;
    this.data = data;
   
    controlForm = createControlForm();
   
    for(int i=0; i<getTotalFormCount(); i++) {
      formList.add(constructForm(i));
    }
  }
 
  /**
   * Experimental method which clones this formset into a new formset,  the new formset can optionally have deleted forms removed.
   *
   * The resulting formset's forms initial data are set to the values of their cleanedData and are not bound.  The new formset is
   * really only useful for displaying in a template.   
   *
   * @param includeDeleted Should deleted forms be included in the new FormSet
   * @return
   * @throws ValidationException
   */
  public FormSet<T> clone(boolean includeDeleted) throws ValidationException {
    List<Map<String, Object>> newData = new ArrayList<Map<String,Object>>();
    for(T form : formList) {
      if (includeDeleted || !shouldDeleteForm(form)) {
        newData.add(form.getCleanedData());
      }
    }
   
    return new FormSet<T>(forms, fieldFactory, formClass, canDelete, newData, null, prefix, 0);
  }
 
  /**
   * Add any exta fields that are needed (ie delete)
   * @param form
   */
  private void addExtraFields(T form) {
    if (canDelete) {
      final BooleanField deleteField = fieldFactory.newField(BooleanField.class);
      deleteField.setName(deletionFieldName)
        .setRequired(false)     
        .setAllowNull(false);
      form.getFields().put(deletionFieldName, deleteField);
    }
  }
 
  private T constructForm(int i) {
    Object initialValues = initial == null ? null : i < initial.size() ? initial.get(i) : null;
    T form = forms.newForm(formClass);
    String formPrefix = String.format("%s-%d", this.prefix, i++);
    form.setPrefix(formPrefix);
    form.setInitial(initialValues);
    form.bind(data);
   
    addExtraFields(form);
   
    return form;
  }

  private Form createControlForm() throws ValidationException {
    Form controlForm = forms.newForm(AbstractForm.class);
    controlForm.setPrefix(String.format("%s_CTRL", prefix));
    final IntegerField countField = fieldFactory.newField(IntegerField.class);
    countField.setName(formCountFieldName)
      .setWidget(HiddenInputWidget.class)
      .setRequired(true)     
      .setAllowNull(false);
    controlForm.getFields().put(formCountFieldName, countField);
   
    final IntegerField initialFormCount = fieldFactory.newField(IntegerField.class);
    initialFormCount.setName(initialFormCountFieldName)
      .setWidget(HiddenInputWidget.class)
      .setRequired(true)     
      .setAllowNull(false);
    controlForm.getFields().put(initialFormCountFieldName, initialFormCount);
   
    if (data != null) {
      controlForm.bind(data);
      if (!controlForm.isValid()) {
        throw new UnsupportedOperationException("Missing control fields");
      }
    } else {
      controlForm.getInitial().put(formCountFieldName, getTotalFormCount());
      controlForm.getInitial().put(initialFormCountFieldName, getInitialFormCount());
    }
    return controlForm;
  }

  private boolean shouldDeleteForm(T form) {
    if (!form.isBound()) {
      return false;
    }
    BooleanField field = (BooleanField) form.getFields().get(deletionFieldName);
    String[] value = form.getData().get(String.format("%s-%s", form.getPrefix(), deletionFieldName));
    if (value == null || value.length == 0) {
      return false;
    }
    try {
      return field.clean(value, new HashMap<String, String>());
    } catch (ValidationException e) {
      return false;
    }
  }
 
  /**
   * Returns true is all forms are valid,  does not short circuit, isValid will be called on all forms.
   * @return
   */
  public boolean isValid() {
    boolean isvalid = true;
    for (T form : formList) {
      if (!shouldDeleteForm(form)) {
        if (!form.isValid()) isvalid = false;
      }
    }
    return isvalid;
  }
 
  /**
   * Returns the HTML for the management form fields.
   * @return
   */
  public String getManagementForm() {
    StringBuilder builder = new StringBuilder();
    for(BoundField bf: controlForm) {
      builder.append(bf.toString());
    }
    return builder.toString();
  }
   

  List<T> nonDeletedForms;
  public List<T> getNonDeletedForms() {
    if (nonDeletedForms == null) {
      nonDeletedForms = new ArrayList<T>();
      for(T form : formList) {
        if (!shouldDeleteForm(form)) {
          nonDeletedForms.add(form);
        }
      }
    }
    return nonDeletedForms;

  }
 
  List<T> deletedForms;
  public List<T> getDeletedForms() {
    if (deletedForms == null) {
      deletedForms = new ArrayList<T>();
      for(T form : formList) {
        if (shouldDeleteForm(form)) {
          deletedForms.add(form);
        }
      }
    }
    return deletedForms;
  }
 
  public Iterator<T> iterator() {
    return formList.iterator();
  }

  /**
   * Return an empty form with a custom prefix for use in javascript
   */
  public T getEmptyForm(String prefix) {
    T form = forms.newForm(formClass);
    String formPrefix = String.format("%s-%s", this.prefix, prefix);
    form.setPrefix(formPrefix);
    addExtraFields(form);
    return form;
  }
 
  /**
   * Return an empty form with a prefix of "__prefix__" for use in javascript
   */
  public T getEmptyForm() {
    return getEmptyForm("__prefix__");
  }

 
  // collectin interface crap...
  public boolean add(T arg0) {
    throw new UnsupportedOperationException();
  }

  public boolean addAll(Collection<? extends T> arg0) {
    throw new UnsupportedOperationException();
  }

  public void clear() {
    throw new UnsupportedOperationException();
  }

  public boolean contains(Object arg0) {
    return formList.contains(arg0);
  }

  public boolean containsAll(Collection<?> arg0) {
    return formList.containsAll(arg0);
  }

  public boolean isEmpty() {
    return formList.isEmpty();
  }

  public boolean remove(Object arg0) {
    throw new UnsupportedOperationException();

  }

  public boolean removeAll(Collection<?> arg0) {
    throw new UnsupportedOperationException();

  }

  public boolean retainAll(Collection<?> arg0) {
    throw new UnsupportedOperationException();
  }

  public int size() {
    return formList.size();
  }

  public Object[] toArray() {
    return formList.toArray();
  }

  public <T> T[] toArray(T[] arg0) {
    return formList.toArray(arg0);
  }

}
TOP

Related Classes of javango.forms.FormSet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.