Package org.olat.core.gui.components.form.flexible.impl

Source Code of org.olat.core.gui.components.form.flexible.impl.Form$EvaluatingFormComponentVisitor

/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS,
* <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.core.gui.components.form.flexible.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.MultipartStream.MalformedStreamException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.olat.core.gui.GUIInterna;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.Container;
import org.olat.core.gui.components.form.flexible.FormBaseComponentIdProvider;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.translator.Translator;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.LogDelegator;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.util.ArrayHelper;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.FileUtils;
import org.olat.core.util.ValidationStatus;
import org.olat.core.util.ValidationStatusHelper;
import org.olat.core.util.WebappHelper;
import org.olat.core.util.component.FormComponentTraverser;
import org.olat.core.util.component.FormComponentVisitor;


/**
* <h4>Description:<h4>
* This Form is responsible for creation of the form header and footer. It can
* not hold form elements. Instead one has to create a form container and put
* the form elements there. E.g. use FormLayoutContainer or
* FormVelocityContainer.
* <p>
* This Form is the Component which gets dispatched by the framework. It then
* dispatches further to the really clicked FormComponent. The Form implements
* the following phases:
* <ol>
* <li>let all Formelements evaluate the Formrequest</li>
* <li>dispatch to the correct FormComponent</li>
* <li>the dispatched FormComponent may decide to SUBMIT the form, e.g. let all
* FormComponents validate its input and report error, or taken other actions.</li>
* <li>during the validatition phase each FormComponent can register an action</li>
* <li>after the validation, all actions are applied</li>
* <li>an event is thrown if the form validated or not</li>
* </ol>
* <p>
* FormComponent and FormContainer form the same composite pattern as already
* used for the core.Component and core.Container, and take notice that the
* FormComponent itself is also a core.Component!<br>
* As a consequence of this, each element which want to live inside of a form
* must be a FormComponent but has also a Component side to the rendering
* framework.
* <p>
* The goals of the new form infrastructure are
* <ul>
* <li>to allow complete freedom for layouting forms.</li>
* <li>easy-migration path for existing forms</li>
* <li>easy-usage for developers</li>
* <li>easy-layouting for designers</li>
* <li>allow subworkflows in forms without loosing form input</li>
* <li>allow AJAX features for form elements (completion, on blur etc.)</li>
* </ul>
* Some extra care had to be taken to fullfill these requirements and still
* beeing compliant with the already existing AJAX component replacement.<br>
* It was decided that a FormComponent consist of
* <ul>
* <li>Formelement, e.g. input field, radio button, select box, a link!</li>
* <li>Label for the Formelement</li>
* <li>Error for the Formelement</li>
* <li>Example for the Formelement</li>
* </ul>
* <p>
* <h4>Multipart and file upload</h4>
* Since release 6.1 the form infrastructure does also support multipart form
* data (file uploads). The form switches to the multipart mode as soon as a
* form element of type FormMultipartItem is added. In this case, all file
* uploads and form parameters are parsed by the form class and added to the
* requestParams and requestMultipartFiles maps. If no multipart element is in the form, the
* normal non-multipart way is used (less overhead, stability).
* <p>
* Therefore it is important to always use the form.getParameter() methods and
* not the getParameter() methods from the user request directly. Normally you
* don't have to deal with this because the implemented form elements already
* take care of this issue.
* <p>
* All submitted files are saved to a temporary location in the userdata/tmp/
* directory. During the dispatch phase in evalFormRequest() this files can be
* access using the getMultipartFilesSet() and getMultipartFile() methods. The
* files must be moved to another location within the execution of the
* evalFormRequest() because at the end of the method call, the temporary files
* will be removed. The temporary files have a random file name, use the
* getMultipartFileName() to retrieve the original file name.
* <p>
* When using the FileElement this is all already encapsulated, see the
* documentation there.
* <p>
* Initial Date: 27.11.2006 <br>
*
* @author patrickb
*/
public class Form extends LogDelegator {
  //
  public final static String FORMCMD = "fid";
  public final static String FORMID = "ofo_";
  public final static String FORM_UNDEFINED="undefined";
 
  public final static int REQUEST_ERROR_NO_ERROR = -1;
  public final static int REQUEST_ERROR_GENERAL = 1;
  public final static int REQUEST_ERROR_FILE_EMPTY = 2;
  public final static int REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED = 3;
 
  private String formName;
  private String dispatchFieldId;
  private String eventFieldId;
  private Map actionListeners = new HashMap(5);

  // the real form
  private FormItemContainer formLayout = null;
  private FormWrapperContainer formWrapperComponent;
  private Integer action;
  private boolean hasAlreadyFired;
  private List<FormBasicController> formListeners;
  private boolean isValidAndSubmitted=true;
  private FormItem submitFormItem = null;
  private boolean isDirtyMarking=true;
  private boolean multipartEnabled = false;
  private int multipartUploadMaxSizeKB = 0;
  // temporary form data, only valid within execution of evalFormRequest()
  private Map<String,String[]> requestParams = new HashMap<String,String[]>();
  private Map<String, File> requestMultipartFiles = new HashMap<String,File>();
  private Map<String, String> requestMultipartFileNames = new HashMap<String,String>();
  private Map<String, String> requestMultipartFileMimeTypes = new HashMap<String,String>();
  private int requestError = REQUEST_ERROR_NO_ERROR;
 
  private Form() {
  // internal use only
  }

  /**
   * create a new form, where the caller is attached as component listener.
   * Caller receives form validation success or failure events.
   *
   * @param name
   * @param translator
   * @param rootFormContainer if null the default layout is choosen, otherwise
   *          the given layouting container is taken.
   * @param listener the component listener of this form, typically the caller
   * @return
   */
  public static Form create(String name, FormItemContainer formLayout, Controller listener) {
    Form form = new Form();
    // this is where the formitems go to
    form.formLayout = formLayout;
    form.formLayout.setRootForm(form);
    form.formListeners = new ArrayList<FormBasicController>();
    if(listener instanceof FormBasicController){
      form.formListeners.add((FormBasicController)listener);
    }
    Translator translator = formLayout.getTranslator();
    if (translator == null) { throw new AssertException("please provide a translator in the FormItemContainer <" + formLayout.getName()
        + ">"); }
    // renders header + <formLayout> + footer of html form
    form.formWrapperComponent = new FormWrapperContainer(name, translator, form);
    form.formWrapperComponent.addListener(listener);
    form.formWrapperComponent.put(formLayout.getComponent().getComponentName(), formLayout.getComponent());
    // generate name for form and dispatch uri hidden field

    form.formName = Form.FORMID + form.formWrapperComponent.getDispatchID();
    form.dispatchFieldId = form.formName + "_dispatchuri";
    form.eventFieldId = form.formName +"_eventval";
   
    if (GUIInterna.isLoadPerformanceMode()) {
      initReplayIdCounter(form);
    }
   
    return form;
  }
 
  /**
   * @param ureq
   */
  public void evalFormRequest(UserRequest ureq) {
    // Initialize temporary request parameters
    doInitRequestParameterAndMulipartData(ureq);
   
    String dispatchUri = getRequestParameter("dispatchuri");
    String dispatchAction = getRequestParameter("dispatchevent");
    boolean invalidDispatchUri = dispatchUri == null || dispatchUri.equals(FORM_UNDEFINED);
    boolean invalidDispatchAct = dispatchAction == null || dispatchAction.equals(FORM_UNDEFINED);
    boolean implicitFormSubmit = false;//see also OLAT-3141
    if(invalidDispatchAct && invalidDispatchUri){
      //case if:
      //enter was pressed in Safari / IE
      //crawler tries form links
      if(submitFormItem != null){
        //if we have submit form item
        //assume a click on this item
        dispatchUri = FormBaseComponentIdProvider.DISPPREFIX + submitFormItem.getComponent().getDispatchID();
        action = FormEvent.ONCLICK;
      }else{
        // instead of
        // throw new AssertException("You have an input field but no submit item defined! this is no good if enter is pressed.");
        // assume a desired implicit form submit
        // see also OLAT-3141
        implicitFormSubmit = true;
      }
    }else{
      action = Integer.valueOf(dispatchAction);
    }
    hasAlreadyFired = false;
    isValidAndSubmitted = false;
    //
    // step 1: call evalFormRequest(ureq) on each FormComponent this gives
    // ....... for each element the possibility to intermediate save a value.
    // ....... As a sideeffect the formcomponent to be dispatched is found.
    EvaluatingFormComponentVisitor efcv = new EvaluatingFormComponentVisitor(dispatchUri);
    FormComponentTraverser ct = new FormComponentTraverser(efcv, formLayout, false);
    ct.visitAll(ureq);
    // step 2: dispatch to the form component
    // ......... only one component to be dispatched can be found, e.g. clicked
    // ......... element....................................................
    // ......... dispatch changes server model -> rerendered
    // ......... dispatch may also request a form validation by
    // ......... calling the submit
    FormItem dispatchFormItem = efcv.getDispatchToComponent();
    //.......... doDispatchFormRequest is called on the found item
    //.......... which in turn may call submit(UserRequest ureq).
    //.......... After submitting, which fires a ok/nok event
    //.......... the code goes further with step 3.........................
    if (implicitFormSubmit) {
      //implicit Submit (Press Enter without on a Field without submit item.)
      // see also OLAT-3141
      submit(ureq);
    }else{
      if (dispatchFormItem == null) {
        // source not found. This "never happens". Try to produce some hints.
        String fbc = new String();
        for (FormBasicController i: formListeners) {
          if (fbc.length()>0) {
            fbc += ",";
          }
          fbc+=(i.getClass().getName());
        }
        logWarn("OLAT-5061: Could not determine request source in FlexiForm >"+formName+"<. Check >"+fbc+"<", null);
       
        // TODO: what now?
        // Assuming the same as "implicitFormSubmit" for now.
        submit(ureq);
       
      } else {
        // ****************************************
        // explicit Submit or valid form dispatch *
        // ****************************************
        dispatchFormItem.doDispatchFormRequest(ureq);
        // step 3: find parent container of dispatched component
        // .......... check dependency rules
        // .......... apply dependency rules
        FindParentFormComponentVisitor fpfcv = new FindParentFormComponentVisitor(
            dispatchFormItem);
        ct = new FormComponentTraverser(fpfcv, formLayout, false);
        ct.visitAll(ureq);
        fpfcv.getParent().evalDependencyRuleSetFor(ureq, dispatchFormItem);
      }
    }
    //
    action = -1;
   
    // End of request dispatch: cleanup temp files: ureq requestParams and multipart files
    doClearRequestParameterAndMultipartData();
  }

  /**
   * Internal helper to initialize the request parameter map an to temporary
   * store the uploaded files when a multipart request is used. The files are
   * stored to a temporary location and a filehandle is added to the
   * requestMultipartFiles map for later retrieval by the responsible FormItem.
   *
   * @param ureq
   */
  private void doInitRequestParameterAndMulipartData(UserRequest ureq) {
    // First fill parameter map either from multipart data or standard http request
    if (isMultipartEnabled() && ServletFileUpload.isMultipartContent(ureq.getHttpReq())) {
      long uploadSize = -1; // default unlimited
      // Limit size of complete upload form: upload size limit + 500k for
      // other input fields
      if (multipartUploadMaxSizeKB > -1) {
        uploadSize = (multipartUploadMaxSizeKB * 1024l * 1024l) + 512000l;
      }

      // Create a new file upload handler, use commons fileupload streaming
      // API to save files right to the tmp location
      ServletFileUpload uploadParser = new ServletFileUpload();
      uploadParser.setSizeMax(uploadSize);
      // Parse the request
      try {
        FileItemIterator iter = uploadParser.getItemIterator(ureq.getHttpReq());
        while (iter.hasNext()) {
          FileItemStream item = iter.next();
          String itemName = item.getFieldName();
          InputStream itemStream = item.openStream();
          if (item.isFormField()) {
            // Normal form item
            // analog to ureq.getParameter in non-multipart mode
            String value = Streams.asString(itemStream, "UTF-8");
            addRequestParameter(itemName, value);
          } else {
            // File item, store it to temp location
            String fileName = item.getName();
            // Cleanup IE filenames that are absolute
            int slashpos = fileName.lastIndexOf("/");
            if (slashpos != -1) fileName = fileName.substring(slashpos + 1);
            slashpos = fileName.lastIndexOf("\\");
            if (slashpos != -1) fileName = fileName.substring(slashpos + 1);

            File tmpFile = new File(WebappHelper.getUserDataRoot() + "/tmp/" + CodeHelper.getGlobalForeverUniqueID());
            try {
              FileUtils.save(itemStream, tmpFile);
              // Only save non-empty file transfers, ignore empty transfers
              // (e.g. already submitted in a previous form submit, not an error!)
              if (tmpFile.length() > 0) {
                // Save file and also original file name
                requestMultipartFiles.put(itemName, tmpFile);
                requestMultipartFileNames.put(itemName, fileName);
                requestMultipartFileMimeTypes.put(itemName, item.getContentType());
              } else {
                if (tmpFile.exists()) tmpFile.delete();
              }
            } catch (OLATRuntimeException e) {
              // Could not save stream for whatever reason, cleanup temp file and delegate exception
              if (tmpFile.exists()) tmpFile.delete();
             
              if (e.getCause() instanceof MalformedStreamException){
                logWarn("Could not read uploaded file >"+fileName+"< from stream. Possibly an attempt to upload a directory instead of a file (happens on Mac)",e);
                if (tmpFile.exists()) tmpFile.delete();
                return;
              }
             
              throw new OLATRuntimeException("Could not save uploaded file",e);             
            }
          }
        }
      } catch (SizeLimitExceededException sizeLimitExceededException) {
        logError("Error while dispatching multipart form: file limit (" + uploadSize + ") exceeded", sizeLimitExceededException);
        requestError = REQUEST_ERROR_UPLOAD_LIMIT_EXCEEDED;
      } catch (IOException e) {
        logWarn("Error while dispatching multipart form: ioexception", e);
        requestError = REQUEST_ERROR_GENERAL;
      } catch (Exception e) {
        logError("Error while dispatching multipart form: general exception", e);
        requestError = REQUEST_ERROR_GENERAL;
      }
    } else {
      // Get parameters the standard way
      logDebug("Dispatching non-multipart form", null);
      Set<String> keys = ureq.getParameterSet();
      for (String key : keys) {
        String[] values = ureq.getHttpReq().getParameterValues(key);
        if (values != null) {
          requestParams.put(key, values)
        } else {
          addRequestParameter(key, ureq.getParameter(key));         
        }
      }
    }
  }

  /**
   * Internal helper to add the request parameters to the request param map.
   * Takes care of multi value parameters
   *
   * @param key
   * @param value
   */
  private void addRequestParameter(String key, String value) {
    String[] values = requestParams.get(key);
    if (values == null) {
      // First element for this key
      values = new String[]{value};
      //use log.debug instead of System.out.println("PARAMS:"+key+" :: "+value);
    }
    else {
      // A multi-key element (e.g. radio button)
      values = ArrayHelper.addToArray(values, value, true);
    //use log.debug instead of System.out.println("PARAMS:"+key+" ::[array of values]");
    }
   
    requestParams.put(key, values);   
  }
 
  /**
   * Internal helper to clear the temporary request parameter and file maps.
   * Will delete all uploaded files if they have not been removed by the
   * responsible FormItem.
   */
  private void doClearRequestParameterAndMultipartData() {
    for (Entry<String, File> entry : requestMultipartFiles.entrySet()) {
      File tmpFile = entry.getValue();
      if (tmpFile.exists()) tmpFile.delete();
    }
    requestMultipartFiles.clear();
    requestMultipartFileNames.clear();
    requestMultipartFileMimeTypes.clear();
    requestParams.clear();
    requestError = REQUEST_ERROR_NO_ERROR;
  }

  /**
   * Check if there was an error while parsing this request. See REQUEST_ERROR_*
   * constants
   *
   * @return the last error code
   */
  public int getLastRequestError() {
    return requestError;
  }

  /**
   * @param ureq
   */
  public void submit(UserRequest ureq) {
    ValidatingFormComponentVisitor vfcv = new ValidatingFormComponentVisitor();
    FormComponentTraverser ct = new FormComponentTraverser(vfcv, formLayout, false);
    ct.visitAll(ureq);
    // validate all form elements and gather validation status
    ValidationStatus[] status = vfcv.getStatus();
    //
    boolean isValid = status == null || status.length == 0;
    // let the businesslogic validate this is implemented by the outside listener
   
    for (Iterator<FormBasicController> iterator = formListeners.iterator(); iterator.hasNext();) {
      FormBasicController fbc = iterator.next();
      //let all listeners validate and calc the total isValid
      //let further validate even if one fails. TODO:pb discuss with cg
      isValid = fbc.validateFormLogic(ureq) && isValid;
    }
   
    //
    formWrapperComponent.fireValidation(ureq, isValid);
    isValidAndSubmitted = isValid;
    hasAlreadyFired = true;
  }
 
  /**
   * @param ureq
   */
  public void reset(UserRequest ureq) {
    ResettingFormComponentVisitor rfcv = new ResettingFormComponentVisitor();
    FormComponentTraverser ct = new FormComponentTraverser(rfcv, formLayout, false);
    ct.visitAll(ureq);//calls reset on all elements!
    //
    evalAllFormDependencyRules(ureq);
    //
    formWrapperComponent.fireFormEvent(ureq, FormEvent.RESET);
    hasAlreadyFired = true;
  }

  /**
   * @return
   */
  Container getFormLayout() {
    return (Container) formLayout.getComponent();
  }

  public Container getInitialComponent() {
    return formWrapperComponent;
  }

  /**
   * add another listener then the default listener, which is added at construction
   * time.
   * @param listener
   */
  public void addListener(Controller listener){
    formWrapperComponent.addListener(listener);
  }

  /**
   * Return the form parameter for a certain key. This takes care if a multipart
   * form has been used or a normal form.
   * <p>
   * LiveCycle scope: only within one call of evalFormRequest() !
   *
   * @param key
   * @return the value of the parameter with key 'key'
   */
  public String getRequestParameter(String key) {
    String[] values = requestParams.get(key);
    if (values != null) return values[0];
    else return null;
  }

  /**
   * Return the form parameter values for a certain key. This takes care if a
   * multipart form has been used or a normal form. <br />
   * This method is used to retrieve multi-value elements, e.g. radio buttons.<br />
   * Use the getRequestParameter() to retrieve single value elements, e.g. input
   * type=text elements
   *
   * @param key
   * @return Array of values for this key
   */
  public String[] getRequestParameterValues(String key) {
    return requestParams.get(key);
  }
 
  /**
   * Return the form parameter set. This takes care if a multipart form has been
   * used or a normal form.
   * <p>
   * LiveCycle scope: only within one call of evalFormRequest() !
   *
   * @return the Set of parameters
   */
  public Set<String> getRequestParameterSet() {
    return requestParams.keySet();
  }

  /**
   * Return the multipart file for this key
   * <p>LiveCycle scope: only within one call of evalFormRequest() !
   * @param key
   * @return
   */
  public File getRequestMultipartFile(String key) {
    return requestMultipartFiles.get(key);
  }

  /**
   * Return the multipart file name for this key:
   * <p>LiveCycle scope: only within one call of evalFormRequest() !
   * @param key
   * @return
   */
  public String getRequestMultipartFileName(String key) {
    return requestMultipartFileNames.get(key);
  }

  /**
   * Return the multipart file mime type (content type) for this key:
   * <p>LiveCycle scope: only within one call of evalFormRequest() !
   * @param key
   * @return
   */
  public String getRequestMultipartFileMimeType(String key) {
    return requestMultipartFileMimeTypes.get(key);
  }

  /**
   * @return The set of multipart file identifyers
   */
  public Set<String> getRequestMultipartFilesSet() {
    return requestMultipartFiles.keySet();
  }
 
 
  /**
   * Description:<br>
   * TODO: patrickb Class Description for EvaluatingFormComponentVisitor
   * <P>
   * Initial Date: 04.12.2006 <br>
   *
   * @author patrickb
   */
  private class EvaluatingFormComponentVisitor implements FormComponentVisitor {

    private boolean foundDispatchItem = false;
    private FormItem dispatchFormItem = null;
    private String dispatchId;

    public EvaluatingFormComponentVisitor(String dispatchUri) {
      this.dispatchId = dispatchUri;
    }

    public FormItem getDispatchToComponent() {
      return dispatchFormItem;
    }

    public boolean visit(FormItem fi, UserRequest ureq) {
      /*
       * check if this is the FormItem to be dispatched
       */
      Component tmp = fi.getComponent();
     
      String tmpD;
      if (GUIInterna.isLoadPerformanceMode()) {
        tmpD = FormBaseComponentIdProvider.DISPPREFIX+Long.toString(getReplayableDispatchID(fi.getComponent()));
      } else {
        tmpD = FormBaseComponentIdProvider.DISPPREFIX + tmp.getDispatchID();
      }
     
      if (!foundDispatchItem && tmpD.equals(dispatchId)) {
        dispatchFormItem = fi;
        foundDispatchItem = true; //
      }
     
      /*
       * let the form item evaluate the form request, e.g. get out its data
       */
      fi.evalFormRequest(ureq);
      return true;// visit further
    }

  }

  private class FindParentFormComponentVisitor implements FormComponentVisitor {

    private FormItem child;
    private FormItemContainer parentContainer = formLayout;

    public FindParentFormComponentVisitor(FormItem child){
      this.child = child;
    }
   
    public FormItemContainer getParent(){
      return parentContainer;
    }
   
    public boolean visit(FormItem comp, UserRequest ureq) {
      if (comp instanceof FormItemContainer) {
        FormItemContainer new_name = (FormItemContainer) comp;
        if(new_name.getFormComponents().containsValue(child)){
          parentContainer = (FormItemContainer)comp;
          return false;
        }
      }
      return true;
    }
   
  }
 

  private class FormDependencyRulesInitComponentVisitor implements FormComponentVisitor {

    public boolean visit(FormItem comp, UserRequest ureq) {
      if (comp instanceof FormItemContainer) {
        FormItemContainer fic = (FormItemContainer)comp;
        Map<String, FormItem> pairs = fic.getFormComponents();
        //go to next container if no elements inside
        if(pairs == null || pairs.size()==0) return true;
        //otherwise iterate overall elements and evaluate dependency rules
        Iterable<FormItem> elms= pairs.values();
        for (FormItem item : elms) {
          fic.evalDependencyRuleSetFor(ureq, item);
        }
      }
      return true;
    }
   
  }
 
 
  /**
   * Description:<br>
   * TODO: patrickb Class Description for ValidatingFormComponentVisitor
   * <P>
   * Initial Date: 07.12.2006 <br>
   *
   * @author patrickb
   */
  private class ValidatingFormComponentVisitor implements FormComponentVisitor {

    List tmp = new ArrayList();

    public ValidationStatus[] getStatus() {
      return ValidationStatusHelper.sort(tmp);
    }

    public boolean visit(FormItem comp, UserRequest ureq) {
      if(comp.isVisible() && comp.isEnabled()){
        //validate only if form item is visible and enabled
        comp.validate(tmp);
      }
      return true;
    }
  }
  /**
   * Description:<br>
   * TODO: patrickb Class Description for ValidatingFormComponentVisitor
   * <P>
   * Initial Date: 07.12.2006 <br>
   *
   * @author patrickb
   */
  private class ResettingFormComponentVisitor implements FormComponentVisitor {

    public boolean visit(FormItem comp, UserRequest ureq) {
      //reset all fields including also non visible and disabled form items!
      comp.reset();
      return true;
    }
  }

  public String getDispatchFieldId() {
    return dispatchFieldId;
  }

  public String getFormName() {
    return formName;
  }

  public void fireFormEvent(UserRequest ureq, FormEvent event) {
    formWrapperComponent.fireFormEvent(ureq, event);
    hasAlreadyFired = true;
  }

  boolean hasAlreadyFired(){
    return hasAlreadyFired;
  }
  /**
   * @return Returns the eventFieldId.
   */
  public String getEventFieldId() {
    return eventFieldId;
  }

  public int getAction() {
    return action;
  }

  /**
   * @param ureq
   */
  void evalAllFormDependencyRules(UserRequest ureq) {
    FormDependencyRulesInitComponentVisitor fdrocv = new FormDependencyRulesInitComponentVisitor();
    FormComponentTraverser ct = new FormComponentTraverser(fdrocv, formLayout, false);
    ct.visitAll(ureq);//visit all container and eval container with its elements!
  }

  public boolean isSubmittedAndValid(){
    return isValidAndSubmitted;
  }

  void registerSubmit(FormItem submFormItem) {
    this.submitFormItem = submFormItem;
  }

  /**
   * true if the form should not loose unsubmitted changes, if another link
   * is clicked which throws away the changes.
   * @return
   */
  public boolean isDirtyMarking() {
    return isDirtyMarking;
  }
  public void setDirtyMarking(boolean isDirtyMarking){
    this.isDirtyMarking = isDirtyMarking;
  }

  public void addSubFormListener(FormBasicController formBasicController) {
    this.formListeners.add(formBasicController);
    addListener(formBasicController);
  }

  public void setMultipartEnabled(boolean multipartEnabled, int multipartUploadMaxSizeKB) {
    this.multipartEnabled = multipartEnabled;
    // Add upload size to already existing upload limit (two uploads are summed up)
    this.multipartUploadMaxSizeKB += multipartUploadMaxSizeKB;
  }
 
  public boolean isMultipartEnabled() {
    return multipartEnabled;
  }
 
 
  // replayableID Counter
  private long replayIdCount;
 
  /**
   * Make replayID distinct for distinct forms by inserting the
   * number of Form Objects created during the current session at
   * the 10000 position.
   * So the replayID will look like o_fi900060004 for the
   * fourth FormItem of the sixth Form. The last four digits
   * represent the running number of Items in the current Form.
   * @param form
   * @param name
   */
 
  @SuppressWarnings("unchecked")
  private static void initReplayIdCounter(Form form) {
   
    Integer formNum;
   
    Object o = GUIInterna.getReplayModeData().get("formNum");
   
    if (o == null) {
      formNum = 1;
    } else {
      formNum = (Integer) o + 1;
    }
   
    GUIInterna.getReplayModeData().put("formNum", formNum);
    form.replayIdCount = 900000000L + formNum * 10000L;
    // max 10000 items can be in a form
    // max 10000 forms can appear in a  load test run
  }
 
  // Map to replayableID real dispatchID
  private  HashMap<Long,Long> replayIdMap = new HashMap<Long,Long>();
 
  /**
   * Get the replayableID for a component, for use only in urlReplay mode.
   * The replayableID is set the first time this method is called
   * for a particular component.
   * @param component
   * @return replayableID
   */
 
  public long getReplayableDispatchID (Component comp) {
    Long oid = comp.getDispatchID();
    Long id = replayIdMap.get(oid);
    if (id != null) return id.longValue();
    id = new Long(++replayIdCount);
   
    if (id >= 999900000L) {
      throw new AssertException ("Form count limit for a loadtest reached");
    }
    if (id%999990000L==9999) {
      throw new AssertException ("Form item count limit for a form reached");
    }
   
    replayIdMap.put(oid, id);
    if (comp instanceof FormBaseComponentImpl) {
      // set the replayID which was just determined because it is convenient
      ((FormBaseComponentImpl)comp).setReplayableDispatchID(id);
    } // else it is a VelocityContainer
    return id.longValue();
  }
}
TOP

Related Classes of org.olat.core.gui.components.form.flexible.impl.Form$EvaluatingFormComponentVisitor

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.