Package org.olat.core.gui.control.generic.wizard

Source Code of org.olat.core.gui.control.generic.wizard.StepsMainRunController

/**
*
*/
package org.olat.core.gui.control.generic.wizard;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Window;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.FormLink;
import org.olat.core.gui.components.form.flexible.impl.Form;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.form.flexible.impl.elements.FormLinkImpl;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.creator.ControllerCreator;
import org.olat.core.logging.AssertException;
import org.olat.core.util.event.GenericEventListener;

/**
* @author patrickb
*
*/
public class StepsMainRunController extends FormBasicController implements GenericEventListener {

  public final static Step DONE_UNCHANGED = new Step(){
 

    public Step nextStep() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
    public PrevNextFinishConfig getInitialPrevNextFinishConfig(){
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
   
    public FormItem getStepTitle() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
    public FormItem getStepShortDescription() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
    @SuppressWarnings("unused")
    public StepFormController getStepController(UserRequest ureq, WindowControl windowControl,StepsRunContext stepsRunContext, Form form) {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
  };
  public final static Step DONE_MODIFIED = new Step(){
   

    public Step nextStep() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
    public PrevNextFinishConfig getInitialPrevNextFinishConfig(){
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
   
    public FormItem getStepTitle() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
    public FormItem getStepShortDescription() {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
   
    @SuppressWarnings("unused"
    public StepFormController getStepController(UserRequest ureq, WindowControl windowControl,StepsRunContext stepsRunContext, Form form) {
      throw new IllegalAccessError("not to be called on NOSTEP");
    }
 
  };
 
 
  private FormLink prevButton;
  private FormLink nextButton;
  private FormLink finishButton;
  private FormLink cancelButton;
  private FormLink closeLink;
  private Step startStep;
  // private Stack<FormItem> stepTitleLinks;
  private List<FormItem> stepTitleLinks;
  private int currentStepIndex = 0;
  private Stack<FormItem> stepPages;
  private StepsRunContext stepsContext;
  private Stack<StepFormController> stepPagesController;
  private Stack<Step> steps;
  private Event lastEvent;
  private boolean doAfterDispatch;
  Step nextStep;
  private ControllerCreator nextChildCreator;
  private int maxSteps;
  private StepRunnerCallback cancel;
  private StepRunnerCallback finish;
  private boolean finishCycle = false;

  /**
   * @param ureq
   * @param control
   */
  public StepsMainRunController(UserRequest ureq, WindowControl control, Step startStep, StepRunnerCallback finish,
      StepRunnerCallback cancel, String wizardTitle) {
    super(ureq, control, "stepslayout");

    this.finish = finish;
    this.cancel = cancel;
    flc.contextPut("wizardTitle", wizardTitle);

    this.startStep = startStep;
    steps = new Stack<Step>();
    stepTitleLinks = new ArrayList<FormItem>();
    stepPages = new Stack<FormItem>();
    stepPagesController = new Stack<StepFormController>();
    stepsContext = new StepsRunContext() {
      Map<String, Object> context = new HashMap<String, Object>();

      public void put(String key, Object value) {
        context.put(key, value);
      }

      public Object get(String key) {
        return context.get(key);
      }

      public boolean containsKey(String key) {
        return context.containsKey(key);
      }

    };
    initForm(ureq);
    // add current step index to velocity
    flc.contextPut("currentStepPos", currentStepIndex + 1);
   
    getWindowControl().getWindowBackOffice().addCycleListener(this);
  }

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

  }

  /*
   * (non-Javadoc)
   *
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest)
   */
  @Override
  @SuppressWarnings("unused")
  protected void formOK(UserRequest ureq) {
  // unused
  }

  @Override
  @SuppressWarnings("unused")
  protected void formInnerEvent(UserRequest ureq, FormItem source, org.olat.core.gui.components.form.flexible.impl.FormEvent event) {
    int whichTitleClickedIndex = stepTitleLinks.indexOf(source);
    if (source == cancelButton || source == closeLink) {
      if (cancel != null) {
        // execute some cancel / rollback code
        // a wizard is expected not to touch / change data in the cancel
        // case undo your work here.
        Step returnStep = cancel.execute(ureq, getWindowControl(), stepsContext);
        if (returnStep != Step.NOSTEP) {
          // error case FIXME:pb finish wizard for this case
        } else {
          // fireEvent(ureq, Event.CANCELLED_EVENT);
        }
      }
      fireEvent(ureq, Event.CANCELLED_EVENT);
    } else if (source == nextButton) {
      // submit and let current unsaved step do its work
      flc.getRootForm().submit(ureq);
      // the current step decides whether to proceed to the next step or
      // not.
    } else if (source == finishButton) {
      // submit and let last unsaved step do its work
      finishCycle = true;
      flc.getRootForm().submit(ureq);
      // the current step decides whether to proceed or not
      // an end step will fire FINISH
      // a intermediate step will fire NEXT .. but NEXT && FINISHCYCLE
      // means also finish
    } else if (source == prevButton) {
      lastEvent = StepsEvent.ACTIVATE_PREVIOUS;
      doAfterDispatch = true;
    } else if (whichTitleClickedIndex >= 0) {
      // handle a step title link
      // remove all steps until the clicked one
      for (int from = currentStepIndex; from > whichTitleClickedIndex; from--) {
        stepPages.pop();
        steps.pop();
        currentStepIndex--;
        stepTitleLinks.get(currentStepIndex).setEnabled(false);// disable
        // "previous"
        // step.
        removeAsListenerAndDispose(stepPagesController.pop());
        // update current step index to velocity
        flc.contextPut("currentStepPos", currentStepIndex + 1);
      }
      flc.add("FFO_CURRENTSTEPPAGE", stepPages.peek());
      PrevNextFinishConfig pnfConf = steps.peek().getInitialPrevNextFinishConfig();
      prevButton.setEnabled(pnfConf.isBackIsEnabled());
      nextButton.setEnabled(pnfConf.isNextIsEnabled());
      finishButton.setEnabled(pnfConf.isFinishIsEnabled());
    }
  }

  /*
   * (non-Javadoc)
   *
   * @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
  @SuppressWarnings("unused")
  protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
    formLayout.add("stepLinks", stepTitleLinks);
    // steps/wizard navigation .. as start most of buttons are disabled
    // they must be enabled by the first step according to its rules
    // cancel button is not possible to disable
    prevButton = new FormLinkImpl("back");
    prevButton.setCustomEnabledLinkCSS("b_button b_wizard_button_prev");
    prevButton.setCustomDisabledLinkCSS("b_button b_wizard_button_prev");
    nextButton = new FormLinkImpl("next");
    nextButton.setCustomEnabledLinkCSS("b_button b_wizard_button_next");
    nextButton.setCustomDisabledLinkCSS("b_button b_wizard_button_next");
    finishButton = new FormLinkImpl("finish");
    finishButton.setCustomEnabledLinkCSS("b_button b_wizard_button_finish");
    finishButton.setCustomDisabledLinkCSS("b_button b_wizard_button_finish");
    cancelButton = new FormLinkImpl("cancel");
    cancelButton.setCustomEnabledLinkCSS("b_button b_wizard_button_cancel");
    cancelButton.setCustomDisabledLinkCSS("b_button b_wizard_button_cancel");
    closeLink = new FormLinkImpl("closeIcon", "close", "", Link.NONTRANSLATED);
    closeLink.setCustomEnabledLinkCSS("b_link_close");
    formLayout.add(prevButton);
    formLayout.add(nextButton);
    formLayout.add(finishButton);
    formLayout.add(cancelButton);
    formLayout.add(closeLink);
    // add all step titles, but disabled.
    Step tmp = startStep;
    maxSteps = 0;
    do {
      FormItem title = tmp.getStepTitle();
      title.setEnabled(false);
      stepTitleLinks.add(title);
      maxSteps++;
      tmp = tmp.nextStep();
    } while (tmp != Step.NOSTEP);
    // init buttons and the like
    currentStepIndex = -1;// start with -1 to be on zero after calling
    // update current step index to velocity
    flc.contextPut("currentStep", currentStepIndex + 1);
    // next step the first time
    addNextStep(startStep.getStepController(ureq, getWindowControl(), this.stepsContext, this.mainForm), startStep);
  }

  @SuppressWarnings("unused")
  private void addNextStep(StepFormController child, Step nextStep) {

    currentStepIndex++;

    if (!stepTitleLinks.isEmpty() && currentStepIndex > 0) {
      // enable previous step
      stepTitleLinks.get(currentStepIndex - 1).setEnabled(true);
    }
    // update current step index to velocity
    flc.contextPut("currentStepPos", currentStepIndex + 1);

    flc.add("stepLinks", stepTitleLinks);

    listenTo(child);
    steps.push(nextStep);
    stepPages.push(child.getStepFormItem());
    stepPagesController.push(child);
    flc.add("FFO_CURRENTSTEPPAGE", stepPages.peek());

    PrevNextFinishConfig pnfConf = nextStep.getInitialPrevNextFinishConfig();
    prevButton.setEnabled(pnfConf.isBackIsEnabled());
    nextButton.setEnabled(pnfConf.isNextIsEnabled());//
    finishButton.setEnabled(pnfConf.isFinishIsEnabled());
  }

  @Override
  /*
   * (non-Javadoc)
   *
   * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
   */
  protected void event(final UserRequest ureq, Controller source, Event event) {
    /*
     * FIXME:pb:
     */
    if (source == stepPagesController.peek()) {

      if (event == StepsEvent.ACTIVATE_NEXT && !finishCycle) {
        // intermediate steps wants to proceed - and next link was clicked
        lastEvent = event;
        doAfterDispatch = true;
        // activate next event on source
        Step current = steps.peek();
        // TODO:pb detach previous from "submit" cycle
        nextStep = current.nextStep();
        nextChildCreator = new ControllerCreator() {
          private final UserRequest ureqForAfterDispatch = ureq;

          @SuppressWarnings("unused")
          public Controller createController(UserRequest lureq, WindowControl lwControl) {
            // lureq unused as the remembered ureqForAfterDispatch is
            // taken
            return nextStep.getStepController(ureqForAfterDispatch, lwControl, stepsContext, mainForm);
          }
        };
        // creation of controller and setting the controller is deferred to
        // the afterDispatch Cycle
        //
      } else if (event == StepsEvent.ACTIVATE_NEXT && finishCycle) {
        // intermediate step wants to proceed - but finish link was clicked
        // this means current step validated and we are ready to terminate
        // the wizard.
        finishWizard(ureq);
      } else if (event == StepsEvent.INFORM_FINISHED) {
        // finish link was clicked -> step form controller has valid data ->
        // fires
        // FINISH EVENT
        // all relevant data for finishing the wizards work must now be
        // present in the stepsContext
        finishWizard(ureq);
      }

    }

  }

  private void finishWizard(final UserRequest ureq) {
    if (finish == null) { throw new AssertException(
        "You must provide a finish callback - a wizard only makes sense to commit work at the end. Do not change data allong the steps."); }
    Step returnStep = finish.execute(ureq, getWindowControl(), stepsContext);
    if(returnStep == DONE_MODIFIED){
      //finish tells that really some data was changed in this wizard
      fireEvent(ureq, Event.CHANGED_EVENT);
    }else if(returnStep == DONE_UNCHANGED){
      //finish called but nothing was modified
      fireEvent(ureq, Event.DONE_EVENT);
    }else{
      //special step comes back
      throw new AssertException("FIXME:pb treat special error steps");
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
   */
  public void event(Event event) {
    /*
     * activate a new step immediate after dispatch - a new step form controller
     * can only be added to surrounding steps runner after dispatching -
     * otherwise a concurrent modification exception within the form container
     * occurs.
     */
    if (event == Window.END_OF_DISPATCH_CYCLE && doAfterDispatch) {
      doAfterDispatch = false;
      if (lastEvent == StepsEvent.ACTIVATE_NEXT) {
        // create with null as UserRequest, the controller creator was
        // created
        // during dispatching and controller creation was deferred to
        // the end of
        // dispatch cycle.
        addNextStep((StepFormController) nextChildCreator.createController(null, getWindowControl()), nextStep);
      } else if (lastEvent == StepsEvent.ACTIVATE_PREVIOUS) {
        stepPages.pop();
        steps.pop();
        currentStepIndex--;
        // update current step index to velocity
        flc.contextPut("currentStepPos", currentStepIndex + 1);
        // disable "previous" step.
        stepTitleLinks.get(currentStepIndex).setEnabled(false);
        removeAsListenerAndDispose(stepPagesController.pop());
        flc.add("FFO_CURRENTSTEPPAGE", stepPages.peek());
        PrevNextFinishConfig pnfConf = steps.peek().getInitialPrevNextFinishConfig();
        prevButton.setEnabled(pnfConf.isBackIsEnabled());
        nextButton.setEnabled(pnfConf.isNextIsEnabled());
        finishButton.setEnabled(pnfConf.isFinishIsEnabled());
      }
    }
  }
}
TOP

Related Classes of org.olat.core.gui.control.generic.wizard.StepsMainRunController

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.