Package org.olat.ims.qti.editor

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

/**
* 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) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/

package org.olat.ims.qti.editor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.dom4j.Element;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.vfs.VFSItem;
import org.olat.ims.qti.editor.beecom.objects.Assessment;
import org.olat.ims.qti.editor.beecom.objects.ChoiceQuestion;
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.EssayQuestion;
import org.olat.ims.qti.editor.beecom.objects.EssayResponse;
import org.olat.ims.qti.editor.beecom.objects.FIBQuestion;
import org.olat.ims.qti.editor.beecom.objects.FIBResponse;
import org.olat.ims.qti.editor.beecom.objects.Feedback;
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.Mattext;
import org.olat.ims.qti.editor.beecom.objects.Metadata;
import org.olat.ims.qti.editor.beecom.objects.QTIDocument;
import org.olat.ims.qti.editor.beecom.objects.QTIObject;
import org.olat.ims.qti.editor.beecom.objects.Question;
import org.olat.ims.qti.editor.beecom.objects.Response;
import org.olat.ims.qti.editor.beecom.objects.Section;
import org.olat.ims.qti.editor.beecom.parser.ParserManager;
import org.olat.ims.qti.process.AssessmentInstance;

/**
* @author rkulow
*/
public class QTIEditHelper {

  private static String EDITOR_IDENT = "QTIEDIT";
  private static String ITEM_TYPE_SC = "SCQ";
  private static String ITEM_TYPE_MC = "MCQ";
  private static String ITEM_TYPE_FIB = "FIB";
  private static String ITEM_TYPE_ESSAY = "ESSAY";
  private static String ITEM_TYPE_KPRIM = "KPRIM";

  private static ParserManager parserManager = new ParserManager();

  /**
   * Counts the number of sections in this assessment.
   * @param assessment
   * @return Number of sections in this assessment.
   */
  public static int countSections(Assessment assessment) {
    return assessment.getSections().size();
  }
 
  /**
   * Counts the number of items in this assessment.
   * @param assessment
   * @return Number of items in this assessment.
   */
  public static int countItems(Assessment assessment) {
    int itemCount = 0;
    Iterator sectionIter = assessment.getSections().iterator();
    while (sectionIter.hasNext()) {
      itemCount += ((Section)sectionIter.next()).getItems().size();
    }
    return itemCount;
  }
 
  /**
   * Creates an empty assessment
   * @param title
   * @param type
   * @return Assessment
   */
  public static Assessment createAssessment(String title, String type) {
    Assessment assessment = new Assessment();
    assessment.setIdent(CodeHelper.getGlobalForeverUniqueID());
    assessment.setTitle(title);
    Metadata meta = new Metadata();
    meta.setField(AssessmentInstance.QMD_LABEL_TYPE, type);
    assessment.setMetadata(meta);
    return assessment;
  }
 
  /**
   * Creates an empty section
   * @param trans
   * @return Section
   */
  public static Section createSection(Translator trans) {
    Section section = new Section();
    section.setIdent(CodeHelper.getGlobalForeverUniqueID());
    section.setTitle(trans.translate("editor.newsection"));
    return section;
  }
 
  /**
   * Creates a new Single Choice item
   * @param trans
   * @return New Singe Choice item.
   */
  public static Item createSCItem(Translator trans) {
    Item newItem = new Item();
    newItem.setIdent(EDITOR_IDENT+":"+ITEM_TYPE_SC+":"+String.valueOf(CodeHelper.getRAMUniqueID()));
    newItem.setTitle(trans.translate("editor.newquestion"));
    newItem.setLabel("");
    // conrols
    Control control = new Control();
    ArrayList controls = new ArrayList();
    controls.add(control);
    newItem.setItemcontrols(controls);

    // pepare question
    ChoiceQuestion question = new ChoiceQuestion();
    question.setLable(trans.translate("editor.newquestion"));
    question.getQuestion().getElements().add(new Mattext(
        trans.translate("editor.newquestiontext")));
    question.setType(Question.TYPE_SC);
    question.setSingleCorrect(true);
    question.setSingleCorrectScore(1);

    ChoiceResponse newChoice = new ChoiceResponse();
    newChoice.setCorrect(true);
    newChoice.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    question.getResponses().add(newChoice);

    QTIEditHelper.setFeedbackMastery(newItem, "");
    QTIEditHelper.setFeedbackFail(newItem, "");

    newItem.setQuestion(question);
    return newItem;
  }

  /**
   * Creates a new Multiple Choice item.
   * @param trans
   * @return New Multiple Choice item.
   */
  public static Item createMCItem(Translator trans) {
    // create item
    Item newItem = new Item();
    newItem.setIdent(EDITOR_IDENT+":"+ITEM_TYPE_MC+":"+String.valueOf(CodeHelper.getRAMUniqueID()));
    newItem.setTitle(trans.translate("editor.newquestion"));
    newItem.setLabel("");

    // conrols
    Control control = new Control();
    ArrayList controls = new ArrayList();
    controls.add(control);
    newItem.setItemcontrols(controls);
   
    // pepare question
    ChoiceQuestion question = new ChoiceQuestion();
    question.setLable(trans.translate("editor.newquestion"));
    question.getQuestion().getElements().add(new Mattext(trans.translate("editor.newquestiontext")));
    question.setType(Question.TYPE_MC);
    question.setSingleCorrect(true);
    question.setSingleCorrectScore(1);
   
    ChoiceResponse newChoice = new ChoiceResponse();
    newChoice.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    newChoice.setCorrect(true);
    newChoice.setPoints(1);
    question.getResponses().add(newChoice);
    newItem.setQuestion(question);
   
    QTIEditHelper.setFeedbackMastery(newItem, "");
    QTIEditHelper.setFeedbackFail(newItem, "")

    return newItem;
  }
 
  /**
   * Creates a new Kprim item
   * @param trans
   * @return New Kprim item.
   */
  public static Item createKPRIMItem(Translator trans) {
    // create item
    Item newItem = new Item();
    newItem.setIdent(EDITOR_IDENT+":"+ITEM_TYPE_KPRIM+":"+String.valueOf(CodeHelper.getRAMUniqueID()));
    newItem.setTitle(trans.translate("editor.newquestion"));
    newItem.setLabel("");

    // controls
    Control control = new Control();
    ArrayList controls = new ArrayList();
    controls.add(control);
    newItem.setItemcontrols(controls);
   
    // prepare question
    float maxValue = 1;
    ChoiceQuestion question = new ChoiceQuestion();
    question.setLable(trans.translate("editor.newquestion"));
    question.getQuestion().getElements().add(new Mattext(trans.translate("editor.newquestiontext")));
    question.setType(Question.TYPE_KPRIM);
    question.setSingleCorrect(false);
   
    // Kprim has always 4 answers, each of them score 1/4 of the maximum value
    ChoiceResponse newChoice = new ChoiceResponse();
    newChoice.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    newChoice.setCorrect(false);
    newChoice.setPoints(maxValue/4);
    question.getResponses().add(newChoice);
    ChoiceResponse newChoice2 = new ChoiceResponse();
    newChoice2.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    newChoice2.setCorrect(false);
    newChoice2.setPoints(maxValue/4);
    question.getResponses().add(newChoice2);
    ChoiceResponse newChoice3 = new ChoiceResponse();
    newChoice3.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    newChoice3.setCorrect(false);
    newChoice3.setPoints(maxValue/4);
    question.getResponses().add(newChoice3);
    ChoiceResponse newChoice4 = new ChoiceResponse();
    newChoice4.getContent().add(new Mattext(trans.translate("editor.newresponsetext")));
    newChoice4.setCorrect(false);
    newChoice4.setPoints(maxValue/4);
    question.getResponses().add(newChoice4);
    question.setMaxValue(maxValue);
    newItem.setQuestion(question);
   
    QTIEditHelper.setFeedbackMastery(newItem, "");
    QTIEditHelper.setFeedbackFail(newItem, "")

    return newItem;
  }
 
  /**
   * Creates a new FIB item
   * @param trans
   * @return New fib item.
   */
  public static Item createFIBItem(Translator trans) {
    // create item
    Item newItem = new Item();
    newItem.setIdent(EDITOR_IDENT+":"+ITEM_TYPE_FIB+":"+String.valueOf(CodeHelper.getRAMUniqueID()));
    newItem.setTitle(trans.translate("editor.newquestion"));
    newItem.setLabel("");

    // conrols
    Control control = new Control();
    ArrayList controls = new ArrayList();
    controls.add(control);
    newItem.setItemcontrols(controls);
   
    QTIEditHelper.setFeedbackMastery(newItem, "");
    QTIEditHelper.setFeedbackFail(newItem, "")
   
    FIBQuestion fibquestion = new FIBQuestion();
    fibquestion.getQuestion().getElements().add(new Mattext(trans.translate("editor.newquestiontext")));
    fibquestion.setSingleCorrect(true);
    fibquestion.setSingleCorrectScore(1);

    FIBResponse response = new FIBResponse();
    response.setType(FIBResponse.TYPE_CONTENT);
    Material mat = new Material();
    mat.add(new Mattext(trans.translate("editor.newtextelement")));
    response.setContent(mat);
    fibquestion.getResponses().add(response);
    newItem.setQuestion(fibquestion);

    return newItem;
  }

  /**
   * Creates a new essay item
   * @param trans
   * @return New essay item.
   */
  public static Item createEssayItem(Translator trans) {
    // create item
    Item newItem = new Item();
    newItem.setIdent(EDITOR_IDENT+":"+ITEM_TYPE_ESSAY+":"+String.valueOf(CodeHelper.getRAMUniqueID()));
    newItem.setTitle(trans.translate("editor.newquestion"));
    newItem.setLabel("");

    // conrols
    Control control = new Control();
    ArrayList controls = new ArrayList();
    controls.add(control);
    newItem.setItemcontrols(controls);
   
    QTIEditHelper.setFeedbackMastery(newItem, "");
    QTIEditHelper.setFeedbackFail(newItem, "")
   
    EssayQuestion essayquestion = new EssayQuestion();
    essayquestion.getQuestion().getElements().add(new Mattext(trans.translate("editor.newquestiontext")));
    essayquestion.setSingleCorrect(true);
    essayquestion.setSingleCorrectScore(1);

    EssayResponse response = new EssayResponse();
    Material mat = new Material();
    mat.add(new Mattext(trans.translate("editor.newtextelement")));
    response.setContent(mat);
    essayquestion.getResponses().add(response);
    newItem.setQuestion(essayquestion);

    return newItem;
  }

  /**
   * Configure max score for a question.
   * @param question
   * @param decvar
   */
  public static void configureMinMaxScore(Question question, Element decvar) {
    // set min/max score
    boolean doCalculate = true;
    if (decvar != null) {
      String min = decvar.attributeValue("minvalue");
      if (min != null) question.setMinValue(min);
      String max = decvar.attributeValue("maxvalue");
      if (max != null) {
        question.setMaxValue(max);
        doCalculate = false;
      }
    }
    if (doCalculate) question.setMaxValue(QTIEditHelper.calculateMaxScore(question));
  }

  /**
   * Get controls.
   * @param object
   * @return Controls.
   */
  public static Control getControl(QTIObject object) {
    Control control = null;
    List controls = null;
    if (Item.class.isAssignableFrom(object.getClass())) {
      Item item = (Item) object;
      controls = item.getItemcontrols();
    } else if (Section.class.isAssignableFrom(object.getClass())) {
      Section section = (Section) object;
      controls = section.getSectioncontrols();
    } else if (Assessment.class.isAssignableFrom(object.getClass())) {
      Assessment assessment = (Assessment) object;
      controls = assessment.getAssessmentcontrols();
    }
    for (Iterator i = controls.iterator(); i.hasNext();) {
      Control tmp = (Control) i.next();
      if (tmp.getView() != null) {
        if (tmp.getView().equalsIgnoreCase("all")) {
          control = tmp;
          break;
        }
      } else {
        control = tmp;
      }
    }
    return control;
  }

  /**
   * Calculates the max score for a question (sum of scores)
   * @param question
   * @return max score.
   */
  public static float calculateMaxScore(Question question) {
    float tmpScore = 0;
    if (question.isSingleCorrect()) return question.getSingleCorrectScore();
    for (Iterator iter = question.getResponses().iterator(); iter.hasNext();) {
      Response resp = (Response) iter.next();
      float points = resp.getPoints();
      if (points > 0) tmpScore = tmpScore + points;
    }
    return tmpScore;
  }

  /**
   * Returns a hasmap with responselabel_idents as keys and points as values.
   *
   * @param respconditions
   * @param type
   * @return hasmap with responselabel_idents as keys and points as values.
   */
  public static HashMap fetchPoints(List respconditions, int type) {
    HashMap points = new HashMap();
    for (Iterator i = respconditions.iterator(); i.hasNext();) {
      Element el_resp_condition = (Element) i.next();
      ///todo
      float fPoints = 0;
      try {
        Element el_setvar = el_resp_condition.element("setvar");
        if (el_setvar == null) continue;
        if (!el_setvar.attributeValue("action").equals("Add") && !el_setvar.attributeValue("action").equals("Subtract")
            && !el_setvar.attributeValue("action").equals("Set")) continue;
        fPoints = new Float(el_setvar.getTextTrim()).floatValue();
        if (el_setvar.attributeValue("action").equals("Subtract")) fPoints = fPoints * -1;
      } catch (NumberFormatException nfe) {
        continue;
      }
      if (fPoints != 0) {
        Element conditionvar = el_resp_condition.element("conditionvar");
        Element and = conditionvar.element("and");
        // in and are all choices that are true

        List tmp_points = (and == null) ? conditionvar.selectNodes(".//varequal") : and.selectNodes(".//varequal");
        for (Iterator iter = tmp_points.iterator(); iter.hasNext();) {
          Element el_varequal = (Element) iter.next();
          if (type == Question.TYPE_SC || type == Question.TYPE_MC || type == Question.TYPE_KPRIM) points.put(el_varequal.getTextTrim(), new Float(fPoints));
          else if (type == Question.TYPE_FIB) points.put(el_varequal.attributeValue("respident"), new Float(fPoints));
        }
      }
    }
    return points;
  }

  /**
   * Fetch choices.
   * @param response_labels
   * @return Map of choices.
   */
  public static List fetchChoices(List response_labels) {
    List choices = new ArrayList();
    for (Iterator i = response_labels.iterator(); i.hasNext();) {
      ChoiceResponse choice = new ChoiceResponse();
      Element response_label = (Element) i.next();
      choice.setIdent(response_label.attributeValue("ident"));

      List materials = response_label.selectNodes(".//material");
      Material content = new Material();
      for (Iterator iter = materials.iterator(); iter.hasNext();) {
        Element el_material = (Element) iter.next();
        Material mat = (Material) parserManager.parse(el_material);
        content.getElements().addAll(mat.getElements());
      }
      // assure material always has some content
      if (content.getElements().size() == 0) content.getElements().add(new Mattext("[blank]"));
      choice.setContent(content);
      choices.add(choice);
    }
    return choices;
  }

  /**
   * Get olat response feddback
   * @param object
   * @param respident
   * @return feedback
   */
  public static String getFeedbackOlatRespText(QTIObject object, String respident) {
    return getFeedbackText(object, respident);
  }

  /**
   * Get olat response feddback
   * @param object
   * @param respident
   * @return feedback
   */
  public static Material getFeedbackOlatRespMaterial(QTIObject object, String respident) {
    return getFeedbackMaterial(object, respident);
  }

  /**
   * Get mastery feedback
   * @param object
   * @return mastery feedback
   */
  public static String getFeedbackMasteryText(QTIObject object) {
    return getFeedbackText(object, "Mastery");
  }

  /**
   * Get mastery feedback
   * @param object
   * @return mastery feedback
   */
  public static Material getFeedbackMasteryMaterial(QTIObject object) {
    return getFeedbackMaterial(object, "Mastery");
  }

  /**
   * Get fail feedback
   * @param object
   * @return fail feedback
   */
  public static String getFeedbackFailText(QTIObject object) {
    return getFeedbackText(object, "Fail");
  }

  /**
   * Get fail feedback
   * @param object
   * @return fail feedback
   */
  public static Material getFeedbackFailMaterial(QTIObject object) {
    return getFeedbackMaterial(object, "Fail");
  }

  /**
   * Get feedback
   * @param object
   * @param sIdent
   * @return feedback
   */
  public static String getFeedbackText(QTIObject object, String sIdent) {
    Feedback feedback = getFeedback(object, sIdent);
    try {
      Material mat = (Material) feedback.getMaterials().get(0);
      return mat.renderAsText();
    } catch (Exception e) {
      // 
    }
    return "";
  }

  /**
   * @param object
   * @param sIdent
   * @return
   */
  public static Feedback getFeedback(QTIObject object, String sIdent) {
    List<Feedback> feedbacks = getFeedbacks(object);
    return getFeedback(sIdent, feedbacks);
  }

  /**
   * @param object
   * @param sIdent
   * @return
   */
  public static Material getFeedbackMaterial(QTIObject object, String sIdent) {
    Feedback feedback = getFeedback(object, sIdent);
    Material mat = null;
    try {
      mat = (Material) feedback.getMaterials().get(0);
    } catch (NullPointerException e) {
      // feedback is null
    }
    return mat;
  }
 
  /**
   * @param sIdent
   * @param feedback
   * @param feedbacks
   * @return
   */
  private static Feedback getFeedback(String sIdent, List<Feedback> feedbacks) {
    Feedback feedback = null;
    for (Feedback tmp :feedbacks) {
      if (tmp.getIdent().equalsIgnoreCase(sIdent)) {
        if (tmp.getView() != null) {
          if (tmp.getView().equalsIgnoreCase("all")) {
            feedback = tmp;
            break;
          }
        } else {
          feedback = tmp;
        }
      }
    }
    return feedback;
  }
 
 

  /**
   * @param object
   * @return
   */
  private static List<Feedback> getFeedbacks(QTIObject object) {
    List<Feedback> feedbacks = null;
    if (Item.class.isAssignableFrom(object.getClass())) {
      Item item = (Item) object;
      feedbacks = item.getItemfeedbacks();
    } else if (Section.class.isAssignableFrom(object.getClass())) {
      Section section = (Section) object;
      feedbacks = section.getSectionfeedbacks();
    } else if (Assessment.class.isAssignableFrom(object.getClass())) {
      Assessment assessment = (Assessment) object;
      feedbacks = assessment.getAssessfeedbacks();
    }
    return feedbacks;
  }

  /**
   * Set response feedback
   * @param object
   * @param feedbackString
   * @param respident
   */
  public static void setFeedbackOlatResp(QTIObject object, String feedbackString, String respident) {
    setFeedback(object, feedbackString, respident);
  }

  /**
   * Set mastery feedback.
   * @param object
   * @param feedbackString
   */
  public static void setFeedbackMastery(QTIObject object, String feedbackString) {
    setFeedback(object, feedbackString, "Mastery");
  }

  /**
   * Set fail feedback.
   * @param object
   * @param feedbackString
   */
  public static void setFeedbackFail(QTIObject object, String feedbackString) {
    setFeedback(object, feedbackString, "Fail");
  }

  /**
   * Set feedback
   * @param object
   * @param feedbackString
   * @param sIdent
   */
  public static void setFeedback(QTIObject object, String feedbackString, String sIdent) {
    List feedbacks = getFeedbacks(object);
    Feedback feedback = getFeedback(sIdent, feedbacks);

    if (feedbackString == null || feedbackString.trim().length() == 0) {
      feedbacks.remove(feedback);
      return;
    }

    if (feedback != null) {
      feedbackString = feedbackString.trim();
      List matList = feedback.getMaterials();
      if (matList.size() > 0) {
        Material mat = (Material) feedback.getMaterials().get(0);
        if (mat == null) {
          mat = new Material();
          mat.getElements().add(new Mattext(feedbackString));
          feedback.getMaterials().add(mat);
        } else if (mat.getElements().size() > 0) {
          mat.getElements().set(0, new Mattext(feedbackString));
        } else {
          mat.getElements().add(new Mattext(feedbackString));
        }
      } else {
        Material mat = new Material();
        mat.getElements().add(new Mattext(feedbackString));
        feedback.getMaterials().add(mat);
      }
    } else {
      Feedback newFeedback = new Feedback();
      newFeedback.setIdent(sIdent);
      newFeedback.setView("All");
      Mattext newMattext = new Mattext(feedbackString);

      ArrayList newMattextL = new ArrayList();
      newMattextL.add(newMattext);

      Material material = new Material();
      material.setElements(newMattextL);

      ArrayList newMaterialL = new ArrayList();
      newMaterialL.add(material);
      newFeedback.setMaterials(newMaterialL);
      feedbacks.add(newFeedback);
    }

  }

  /**
   * Add objectives.
   * @param root
   * @param objectives
   */
  public static void addObjectives(Element root, String objectives) {
    if (objectives != null && objectives.length() > 0) {
      Element mattext = root.addElement("objectives").addElement("material").addElement("mattext");
      mattext.addCDATA(objectives);
    }
  }

  /**
   * Add response feedback.
   * @param root
   * @param respident
   */
  public static void addFeedbackOlatResp(Element root, String respident) {
    addFeedback(root, "Response", respident);
  }

  /**
   * Add mastery feedback
   * @param root
   */
  public static void addFeedbackMastery(Element root) {
    addFeedback(root, "Response", "Mastery");
  }

  /**
   * Add fail feedback
   * @param root
   */
  public static void addFeedbackFail(Element root) {
    addFeedback(root, "Response", "Fail");
  }

  /**
   * Add hint
   * @param root
   */
  public static void addFeedbackHint(Element root) {
    addFeedback(root, "Solution", "Solution");
  }

  /**
   * Add solution
   * @param root
   */
  public static void addFeedbackSolution(Element root) {
    addFeedback(root, "Hint", "Hint");
  }

  private static void addFeedback(Element root, String feedbacktype, String linkrefid) {
    Element displayfeedback = root.addElement("displayfeedback");
    displayfeedback.addAttribute("feedbacktype", feedbacktype);
    displayfeedback.addAttribute("linkrefid", linkrefid);
  }

  /**
   * Add solution
   * @param root
   * @param solutionText
   */
  public static void addSolutionElement(Element root, String solutionText) {
    Element el_solution = root.addElement("itemfeedback");
    el_solution.addAttribute("ident", "Solution");
    el_solution.addAttribute("view", "All");
    el_solution.addElement("solution").addElement("solutionmaterial").addElement("material").addElement("mattext").addCDATA(solutionText);
  }

  /**
   * Add hint
   * @param root
   * @param hintText
   */
  public static void addHintElement(Element root, String hintText) {
    Element el_feedback = root.addElement("itemfeedback");
    el_feedback.addAttribute("ident", "Hint");
    el_feedback.addAttribute("view", "All");
    Element el_hint = el_feedback.addElement("hint");
    el_hint.addAttribute("feedbackstyle", "Incremental");
    el_hint.addElement("hintmaterial").addElement("material").addElement("mattext").addCDATA(hintText);
  }
 
 
  /**
   * Retrieves all deleteable media files, that is the media files that are referenced by thisItem only.
   * Note: doesn't retrieve the media from the question description because of OLAT-4647
   * @param qtiDocument
   * @param thisItem
   * @return
   */
  public static Set<String> getDeletableMedia(QTIDocument qtiDocument, Item thisItem) {     
    Set<String> deletableMediaFiles = QTIEditHelper.getMediaReferencesForItem(qtiDocument, thisItem);
    if(deletableMediaFiles.size()>0) {
      Set<String> referencedMediaFiles = QTIEditHelper.getMediaReferencesExceptForItem(qtiDocument, thisItem);       
      deletableMediaFiles.removeAll(referencedMediaFiles);
    }
    return deletableMediaFiles;
  }
 
  /**
   * Retrieves all referenced media by thisItem if filterOut is false,
   * or all referenced media by other items if filterOut is true.
   * <p>
   * Iterates over all sections, items, etc. </br>
   * -> if filterOut is true gets all references except those for thisItem.
   * -> if filterOut is false gets all references for thisItem.
   *
   * @param qtiDocument
   * @param thisItem
   * @param filterOut
   * @return Returns empty set if no reference found.
   */
  private static Set<String> getMediaReferences(QTIDocument qtiDocument, Item thisItem, boolean filterOut) {
    HashSet<String> returnSet = new HashSet<String>();
    //sections
    List sectionList = qtiDocument.getAssessment().getSections();
    Iterator sectionIterator = sectionList.iterator();
    while(sectionIterator.hasNext()) {
      //section
      Section section = (Section)sectionIterator.next();
      List itemList = section.getItems();
      Iterator listIterator = itemList.iterator();
      while(listIterator.hasNext()) {
        //item
        Item item = (Item)listIterator.next();       
        if((filterOut && thisItem.getIdent().equals(item.getIdent())) || (!filterOut && !thisItem.getIdent().equals(item.getIdent()))) {
          continue;
        }
        //question       
        Material material = item.getQuestion().getQuestion();
        if(material!=null) {
          String htmlContent = material.renderAsHtmlForEditor();
          //parse filenames
          returnSet.addAll(getMediaFileNames(htmlContent));
        }     
        //responses
        List responseList = item.getQuestion().getResponses();
        Iterator responseIterator = responseList.iterator();
        while(responseIterator.hasNext()) {
          Response response = (Response)responseIterator.next();
          Material responseMat = response.getContent();
          //parse filenames
          if(responseMat!=null) {
            returnSet.addAll(getMediaFileNames(responseMat.renderAsHtmlForEditor()));
          }
          // response-level feedback
          Material responseFeedbackMat = QTIEditHelper.getFeedbackOlatRespMaterial(item, response.getIdent());
          if(responseFeedbackMat!=null) {
            returnSet.addAll(getMediaFileNames(responseFeedbackMat.renderAsHtmlForEditor()));
          }
        } 
        //feedback
        Material masteryMat = QTIEditHelper.getFeedbackMasteryMaterial(item);
        if(masteryMat!=null) {
          returnSet.addAll(getMediaFileNames(masteryMat.renderAsHtmlForEditor()));
        }
        Material failureMat = QTIEditHelper.getFeedbackFailMaterial(item);
        if(failureMat!=null) {
          returnSet.addAll(getMediaFileNames(failureMat.renderAsHtmlForEditor()));
        }
      }
    }   
    return returnSet;
  }
 
  /**
   *
   * @param qtiDocument
   * @param thisItem
   * @return Returns a Set with the media file names referenced by thisItem.
   */
  private static Set<String> getMediaReferencesForItem(QTIDocument qtiDocument, Item thisItem) {
    return getMediaReferences(qtiDocument, thisItem, false);
  }
 
  /**
   *
   * @param qtiDocument
   * @param thisItem
   * @return Returns a Set with the media file names referenced by all except thisItem.
   */
  private static Set<String> getMediaReferencesExceptForItem(QTIDocument qtiDocument, Item thisItem) {
    return getMediaReferences(qtiDocument, thisItem, true);
  }
 
  /**
   * Extracts substrings between media/ and next ", and add them to a set.
   * The htmlString contains something like: ... img src=".../media/filename.jpg" ...
   * @param htmlString
   * @return
   */
  private static Set<String> getMediaFileNames(String htmlString) {
    HashSet<String> returnSet = new HashSet<String>();
    String current = htmlString;
    while(current.indexOf("media/")>0) {  
      current = current.substring(current.indexOf("media/")+6);    
      int position = current.indexOf("\"");
      if(position>0) {
        String filename = current.substring(0,position);
        returnSet.add(filename);     
        current = current.substring(position+1,current.length());     
      }
    }
    return returnSet;
  }
 
  /**
   * Deletes the files found in the referencedMediaSet.
   * @param referencedMediaSet
   * @param allMedia
   */
  public static void removeUnusedMedia(Set<String> deleteableSet, List<VFSItem> allMedia) {
    Iterator<VFSItem> itemIterator = allMedia.iterator();
    while(itemIterator.hasNext()) {
      VFSItem item = itemIterator.next();
      if(deleteableSet.contains(item.getName())) {
        //System.out.println("Delete unused media file: " + item.getName());
        item.delete();
      }
    }
  }
}
TOP

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

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.