$r.render("sourceview")
public class GuiDemoFlexiFormSubworkflow extends FormBasicController implements Controller {

  private GuiDemoFlexiFormPersonData personData;
  private TextElement firstName;
  private TextElement lastName;
  private FormLayoutContainer horizontalLayout;
  private TextElement institution;
  private FormLink choose;
  private FormSubmit submit;
  private String[] values;
  private GuiDemoFlexiFormSubworkflowTheChooser subworkflowTheChooser;
  private CloseableModalController cmc;
    
  public GuiDemoFlexiFormSubworkflow(UserRequest ureq, WindowControl wControl, GuiDemoFlexiFormPersonData data) {
    super(ureq, wControl);
    // first you may preprocess data to fit into the form items
    // if all preprocessing is done, create the form items
    //
    // example for simple preprocessing - check for NULL
    if (data != null) {
      personData = data;
    else {
      personData = new GuiDemoFlexiFormPersonData();
    }
    //
    values = new String[]{"Faculty of Medicine","Vetsuisse Faculty","Faculty of Arts","Faculty of Science","All institutes and clinics of UZH"};
    //
    // calls our initForm(formlayout,listener,ureq) with default values.
    initForm(ureq);
    //
    // after initialisation you may need to do some stuff
    // but typically initForm(..) is the last call in the constructor.
  }

  /**
   @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose(boolean)
   */
  @Override
  protected void doDispose(boolean asynchronous) {
  // TODO Auto-generated method stub

  }

  /**
   @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest)
   */
  @Override
  protected void formOK(UserRequest ureq) {
    //this is a work-around for the current flexi form infrastructure to render
    //errormessages in  the case of # if constructs in the velocity page
    this.flc.setDirty(true);
  }

  @Override
  protected void formNOK(UserRequest ureq) {
    //this is a work-around for the current flexi form infrastructure to render
    //errormessages in the case of # if constructs in the velocity page
    this.flc.setDirty(true);
  }

  @Override
  protected void  formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
    if(source == choose){
      //choose link clicked
      //show a subworkflow in a modal dialog without loosing fromdata
      //
      // work around to disable orange button and alert box of "unsubmitted form onscreen"
      // this will change within the next release.
      this.flc.getRootForm().setDirtyMarking(false);
      //
      //
      subworkflowTheChooser = new GuiDemoFlexiFormSubworkflowTheChooser(ureq, getWindowControl(), values, institution.getValue());
      // get informed if subworkflow has submitted =>
      subworkflowTheChooser.addControllerListener(this);
      cmc = new CloseableModalController(getWindowControl()"close", subworkflowTheChooser.getInitialComponent());
      // get informed if modal dialog is closed => this means canceling the workflow 
      cmc.addControllerListener(this)
      cmc.activate();
      return;
    }
  }
  
  @Override
  protected void event(UserRequest ureq, Controller source, org.olat.core.gui.control.Event event) {
    if(source == cmc){
      if(event == CloseableModalController.CLOSE_MODAL_EVENT){
        // work around to re-enable orange button and alert box of "unsubmitted form onscreen"
        // this will change within the next release.
        this.flc.getRootForm().setDirtyMarking(true);
        // modal dialog is closed
        // modal dialog has already deactivated itself (you would get a redscreen otherwise)
        subworkflowTheChooser.dispose(false);
      }
    }else if(source == subworkflowTheChooser){
      //some value is choosen
      //set the value and close dialog
      institution.setValue(subworkflowTheChooser.getSelected());
      cmc.deactivate();
      subworkflowTheChooser.dispose(false);
      
      // work around to re-enable orange button and alert box of "unsubmitted form onscreen"
      // this will change within the next release.
      this.flc.getRootForm().setDirtyMarking(true);
    }
  }
  
  /**
   @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#initForm(org.olat.core.gui.components.form.flexible.FormItemContainer,
   *      org.olat.core.gui.control.Controller, org.olat.core.gui.UserRequest)
   */
  @Override
  protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
    /*
     * create a form with a title and 4 input fields to enter some persons data
     */
    setFormTitle("guidemo_flexi_form_withchooser");
    final int defaultDisplaySize = 32;
    final boolean inputMode = !personData.isReadOnly();
    firstName = new TextElementImpl("firstname", personData.getFirstName()) {
      {
        this.displaySize = defaultDisplaySize;
        setNotLongerThanCheck(256"notlongerthan");
        setLabel("guidemo.flexi.form.firstname"null);
        setNotEmptyCheck("guidemo.flexi.form.mustbefilled");
        setMandatory(true);
        setEnabled(inputMode);
      }
    };
    formLayout.add(firstName);

    lastName = new TextElementImpl("guidemo.flexi.form.lastname", personData.getLastName()) {
      {
        this.displaySize = defaultDisplaySize;
        setNotLongerThanCheck(256"guidemo.flexi.form.notlongerthan");
        setLabel("guidemo.flexi.form.lastname"null);
        setNotEmptyCheck("guidemo.flexi.form.mustbefilled");
        setMandatory(true);
        setEnabled(inputMode);
      }
    };
    formLayout.add(lastName);

    /*
     * - create a composite element
     * - text element and to the left a choose link
     * - the label of the textelement is set as the label of the layouting 
     * container. 
     */
    horizontalLayout = (FormLayoutContainer)FormLayoutContainer.createHorizontalFormLayout("chooser", getTranslator());
    horizontalLayout.  setLabel("guidemo.flexi.form.institution"null);;
    formLayout.add(horizontalLayout);    
    institution = new TextElementImpl("institution", personData.getInstitution()) {
      {
        this.displaySize = defaultDisplaySize;
        setNotLongerThanCheck(256"guidemo.flexi.form.notlongerthan");
        setEnabled(false);
      }
    };
    
    horizontalLayout.add(institution);
    choose = new FormLinkImpl("choose");
    horizontalLayout.add(choose);

    
    if (inputMode) {
      // submit only if in input mode
      submit = new FormSubmit("submit""submit");
      formLayout.add(submit);
    }
  }

  
  
  //this innerclass represents the subworkflow
  //but it could be any top level controller
  private class GuiDemoFlexiFormSubworkflowTheChooser extends FormBasicController {

    String[] entries;
    private SingleSelection entrySelector;
    private String selection;

    public GuiDemoFlexiFormSubworkflowTheChooser(UserRequest ureq, WindowControl wControl, String[] values, String selection) {
      super(ureq, wControl);
      this.entries = values;
      this.selection = selection;
      initForm(ureq);
    }

    @Override
    protected void doDispose(boolean asynchronous) {
      // TODO Auto-generated method stub
      
    }

    @Override
    protected void formOK(UserRequest ureq) {
      // TODO Auto-generated method stub  
    }
    
    @Override
    protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
      fireEvent(ureq, Event.DONE_EVENT);
    }

    @Override
    protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
      entrySelector = new SingleSelectionImpl("entries", SingleSelectionImpl.createVerticalLayout("entries")) {
        {
          keys = entries;
          values = entries;
          if(selection != null && !selection.equals("")){
            select(selection,true);
          }
        }
      };
      entrySelector.addActionListener(this, FormEvent.ONCLICK);
      formLayout.add(entrySelector);
      
    }
    
    
    String getSelected(){
      return entrySelector.getSelectedKey();
    }
  }
  
  
  
  
}