Package org.olat.ims.qti.editor

Source Code of org.olat.ims.qti.editor.FeedbackFormController

/**
* 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) frentix GmbH<br>
* http://www.frentix.com<br>
* <p>
*/
package org.olat.ims.qti.editor;

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

import org.olat.core.gui.UserRequest;
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.elements.RichTextElement;
import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.form.flexible.impl.FormEvent;
import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
import org.olat.core.gui.components.form.flexible.impl.elements.richText.RichTextConfiguration;
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.generic.closablewrapper.CloseableModalController;
import org.olat.core.util.Util;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.ims.qti.editor.beecom.objects.ChoiceResponse;
import org.olat.ims.qti.editor.beecom.objects.Control;
import org.olat.ims.qti.editor.beecom.objects.Item;
import org.olat.ims.qti.editor.beecom.objects.Material;
import org.olat.ims.qti.editor.beecom.objects.Question;

/**
* This is the form controller responsible for setting user feedback (i.e. is
* the answer right, explanations etc.)
*
* <P>
* Initial Date: Jul 16, 2009 <br>
*
* @author gwassmann
*/
public class FeedbackFormController extends FormBasicController {

  private static final String NO = "no";
  private static final String YES = "yes";
  private final Item item;
  private final QTIEditorPackage qtiPackage;
  private final boolean isRestrictedEditMode;
  private CloseableModalController dialogCtr;
  private MaterialFormController materialCtr;
  private SingleSelection feedbackSwitch;
  private Control control;
  private HashMap<Material, RichTextElement> textElements = new HashMap<Material, RichTextElement>();
  private HashMap<Material, String> identities = new HashMap<Material, String>();
  private HashMap<RichTextElement, Material> materialsByText = new HashMap<RichTextElement, Material>();
  private HashMap<FormLink, Material> materialsByLink = new HashMap<FormLink, Material>();
  private FormLayoutContainer overallFeedbackLayout, responseLevelHintsLayout;
  private String mediaBaseUrl;
  private Material masteryMat, failureMat;

  public FeedbackFormController(UserRequest ureq, WindowControl wControl, QTIEditorPackage qtiPackage, Item item,
      boolean isRestrictedEditMode) {
    super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL);
    this.qtiPackage = qtiPackage;
    this.item = item;
    this.mediaBaseUrl = qtiPackage.getMediaBaseURL();

    control = QTIEditHelper.getControl(item);
    this.isRestrictedEditMode = isRestrictedEditMode;
    initForm(ureq);
  }

  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose()
   */
  protected void doDispose() {
  // nothing so far
  }

  /**
   * @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(UserRequest ureq, Controller source, Event event) {
    if (source == materialCtr) {
      if (event instanceof QTIObjectBeforeChangeEvent) {
        NodeBeforeChangeEvent nce = new NodeBeforeChangeEvent();
        nce.setItemIdent(item.getIdent());
        nce.setQuestionIdent(item.getQuestion().getQuestion().getId());
        fireEvent(ureq, nce);
      } else if (event == Event.DONE_EVENT || event == Event.CANCELLED_EVENT) {
        if (event == Event.DONE_EVENT) {
          Material mat = materialCtr.getMaterial();
          String html = mat.renderAsHtmlForEditor();
          if (mat == masteryMat) {
            QTIEditHelper.setFeedbackMastery(item, html);
          } else if (mat == failureMat) {
            QTIEditHelper.setFeedbackFail(item, html);
          } else {
            QTIEditHelper.setFeedbackOlatResp(item, html, identities.get(mat));
          }

          // update view
          RichTextElement text = textElements.get(mat);
          //the html code is embbeded in the panel and as not a proper baseurl
          text.setValue(mat.renderAsHtml(mediaBaseUrl));
          // serialize document
          qtiPackage.serializeQTIDocument();
        }
        // dispose controllers
        dialogCtr.deactivate();
        removeAsListenerAndDispose(dialogCtr);
        dialogCtr = null;
        removeAsListenerAndDispose(materialCtr);
        materialCtr = null;
      }
    } else if (source == dialogCtr) {
      if (event == Event.CANCELLED_EVENT) {
        removeAsListenerAndDispose(dialogCtr);
        dialogCtr = null;
        removeAsListenerAndDispose(materialCtr);
        materialCtr = null;
      }
    }
  }

  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest)
   */
  protected void formOK(UserRequest ureq) {
  // there's no submit button in this form
  }

  /**
   * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formInnerEvent(org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.components.form.flexible.FormItem,
   *      org.olat.core.gui.components.form.flexible.impl.FormEvent)
   */
  protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
    if (source instanceof RichTextElement) {
      displayMaterialFormController(ureq, materialsByText.get(source), isRestrictedEditMode);
    } else if (source instanceof FormLink) {
      displayMaterialFormController(ureq, materialsByLink.get(source), isRestrictedEditMode);
    } else if (source == feedbackSwitch) {
      // feedbackSwitch takes values in {0 = on/yes, 1 = off/no}
      // control.feedback takes values in {0 = undef, 1 = on, 2 = off}
      control.setFeedback(feedbackSwitch.getSelected() + 1);
      qtiPackage.serializeQTIDocument();
      showHideFeedbackFields();
    }
  }

  /**
   * shows or hides the feedback input fields depending on if feedback is
   * enabled
   */
  private void showHideFeedbackFields() {
    boolean feedbackEnabled = control.isFeedback();
    overallFeedbackLayout.setVisible(feedbackEnabled);
    responseLevelHintsLayout.setVisible(feedbackEnabled);
    this.flc.setDirty(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)
   */
  protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
    setFormTitle("fieldset.legend.feedback");
    setFormContextHelp("org.olat.ims.qti.editor", "qed-feedback.html", "help.hover.qti-feedback");

    FormLayoutContainer switchLayout = FormLayoutContainer.createDefaultFormLayout("switchLayout", getTranslator());
    overallFeedbackLayout = FormLayoutContainer.createDefaultFormLayout("overallFeedbackLayout", getTranslator());
    responseLevelHintsLayout = FormLayoutContainer.createCustomFormLayout("responseLevelHintsLayout", getTranslator(), Util
        .getPackageVelocityRoot(this.getClass())
        + "/response_level_feedback.html");
    // add the layouts to the custom layout
    formLayout.add(switchLayout);
    formLayout.add(overallFeedbackLayout);
    formLayout.add(responseLevelHintsLayout);

    String[] yesNoKeys, yesNoValues;
    yesNoKeys = new String[] { YES, NO };
    yesNoValues = new String[] { translate(YES), translate(NO) };

    feedbackSwitch = uifactory.addRadiosHorizontal("feedbackswitch", switchLayout, yesNoKeys, yesNoValues);
    feedbackSwitch.addActionListener(this, FormEvent.ONCLICK);
    if (control.isFeedback()) {
      feedbackSwitch.select(yesNoKeys[0], true);
    } else {
      // defaults to 'not showing feedback'
      feedbackSwitch.select(yesNoKeys[1], true);
    }

    responseLevelHintsLayout.contextPut("mediaBaseUrl", mediaBaseUrl);

    masteryMat = QTIEditHelper.getFeedbackMasteryMaterial(item);
    masteryMat = masteryMat == null ? new Material() : masteryMat;
    failureMat = QTIEditHelper.getFeedbackFailMaterial(item);
    failureMat = failureMat == null ? new Material() : failureMat;

    VFSContainer baseContainer = qtiPackage.getBaseDir();

    // Mastery Layout
    FormLayoutContainer masteryEditLayout = FormLayoutContainer.createCustomFormLayout("masteryEditLayout", getTranslator(), Util
        .getPackageVelocityRoot(this.getClass())
        + "/rich_text_and_edit_link.html");
    masteryEditLayout.setLabel("item_feedback_mastery", null);
    overallFeedbackLayout.add(masteryEditLayout);
    RichTextElement masteryFeedback = uifactory.addRichTextElementForStringData("richTextElement", "item_feedback_mastery", masteryMat
        .renderAsHtml(mediaBaseUrl), 4, -1, true, true, baseContainer, null, masteryEditLayout, ureq.getUserSession(), getWindowControl());
    FormLink editLink = uifactory.addFormLink("editLink", masteryEditLayout, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS);
    ((Link) editLink.getComponent()).setCustomDisplayText("");
    ((Link) editLink.getComponent()).setCustomEnabledLinkCSS("b_small_icon b_edit_icon qti_edit_link");
    registerFeedbackElement(masteryMat, masteryFeedback, editLink);

    // One Failure Layout
    FormLayoutContainer failureEditLayout = FormLayoutContainer.createCustomFormLayout("failureEditLayout", getTranslator(), Util
        .getPackageVelocityRoot(this.getClass())
        + "/rich_text_and_edit_link.html");
    failureEditLayout.setLabel("item_feedback_fail", null);
    overallFeedbackLayout.add(failureEditLayout);
    RichTextElement failureFeedback = uifactory.addRichTextElementForStringData("richTextElement", "item_feedback_fail", failureMat
        .renderAsHtml(mediaBaseUrl), 4, -1, true, true, baseContainer, null, failureEditLayout, ureq.getUserSession(), getWindowControl());
    failureFeedback.setLabel("item_feedback_fail", null);
    FormLink failureLink = uifactory.addFormLink("editLink", failureEditLayout, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS);
    ((Link) failureLink.getComponent()).setCustomDisplayText("");
    ((Link) failureLink.getComponent()).setCustomEnabledLinkCSS("b_small_icon b_edit_icon");
    registerFeedbackElement(failureMat, failureFeedback, failureLink);

    // Feedback for each response when single or multiple choice question
    List<Material> responses = new ArrayList<Material>();
    boolean hasResponseLevelHints = false;
    if (item.getQuestion().getType() <= Question.TYPE_MC) {
      int i = 1;
      for (Object obj : item.getQuestion().getResponses()) {
        ChoiceResponse response = (ChoiceResponse) obj;
        // response-level feedback
        Material responseFeedbackMat = QTIEditHelper.getFeedbackOlatRespMaterial(item, response.getIdent());
        responseFeedbackMat = responseFeedbackMat == null ? new Material() : responseFeedbackMat;
        identities.put(responseFeedbackMat, response.getIdent());
        RichTextElement responseHintText = uifactory.addRichTextElementForStringData("feedback_" + i, null, responseFeedbackMat
            .renderAsHtml(mediaBaseUrl), 4, -1, true, true, baseContainer, null, responseLevelHintsLayout, ureq.getUserSession(),
            getWindowControl());
        FormLink link = uifactory.addFormLink("link_" + i, responseLevelHintsLayout, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS);
        ((Link) link.getComponent()).setCustomDisplayText("");
        ((Link) link.getComponent()).setCustomEnabledLinkCSS("b_small_icon b_edit_icon");
        registerFeedbackElement(responseFeedbackMat, responseHintText, link);
        // get response for displaying
        Material responseMat = response.getContent();
        responses.add(responseMat);
        i++;
      }
      // If 'i' is strictly greater than the initial value, there's at least one
      // response.
      hasResponseLevelHints = i > 1;
    }

    this.flc.contextPut("hasResponseLevelHints", hasResponseLevelHints);
    responseLevelHintsLayout.contextPut("responses", responses);
    showHideFeedbackFields();
  }

  /**
   * @param masteryMat
   * @param masteryFeedback
   */
  private void registerFeedbackElement(Material mat, RichTextElement textElement, FormLink link) {
    textElement.setEnabled(false);
    textElement.addActionListener(this, FormEvent.ONCLICK);
    link.addActionListener(this, FormEvent.ONCLICK);
    textElements.put(mat, textElement);
    //allow scripts...
    textElement.getEditorConfiguration().setQuotedConfigValue(RichTextConfiguration.INVALID_ELEMENTS, RichTextConfiguration.INVALID_ELEMENTS_FORM_FULL_VALUE_UNSAVE_WITH_SCRIPT);
    textElement.getEditorConfiguration().setQuotedConfigValue(RichTextConfiguration.EXTENDED_VALID_ELEMENTS, "script[src,type,defer]");
   
    materialsByText.put(textElement, mat);
    materialsByLink.put(link, mat);
  }

  /**
   * Displays the MaterialFormController in a closable box.
   *
   * @param ureq
   * @param mat
   * @param isRestrictedEditMode
   */
  private void displayMaterialFormController(UserRequest ureq, Material mat, boolean isRestrictedEditMode) {
    materialCtr = new MaterialFormController(ureq, getWindowControl(), mat, qtiPackage, isRestrictedEditMode);
    listenTo(materialCtr);
    dialogCtr = new CloseableModalController(getWindowControl(), "close", materialCtr.getInitialComponent());
    listenTo(dialogCtr);
    dialogCtr.activate();
  }
}
TOP

Related Classes of org.olat.ims.qti.editor.FeedbackFormController

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.