/** * 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. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.ims.qti.process.elements; import java.util.Iterator; import java.util.List; import org.dom4j.Element; import org.olat.ims.qti.container.ItemContext; import org.olat.ims.qti.container.Output; import org.olat.ims.qti.container.Variable; import org.olat.ims.qti.container.Variables; import org.olat.ims.qti.container.qtielements.Hint; import org.olat.ims.qti.container.qtielements.Solution; import org.olat.ims.qti.process.QTIHelper; /** * */ public class QTI_respcondition { /** * Response Condition * * ims qti 1.2.1 respcondition * <!ELEMENT respcondition (qticomment? , conditionvar , setvar* , displayfeedback*)> * <!ELEMENT conditionvar (not | and | or | unanswered | other | varequal | varlt | varlte | * vargt | vargte | varsubset | varinside | varsubstring | durequal | durlt | durlte | durgt | durgte)+> * * <!ELEMENT setvar (#PCDATA)> * <!ATTLIST setvar %I_VarName; action (Set | Add | Subtract | Multiply | Divide ) 'Set' > * mit I_VarName = varname CDATA 'SCORE' * <setvar action="Set" varname="SCORE">10</setvar> * * <!ELEMENT displayfeedback (#PCDATA)> * <!ATTLIST displayfeedback feedbacktype (Response | Solution | Hint ) 'Response' %I_LinkRefId; > * mit I_LinkRefId = linkrefid CDATA #REQUIRED" * e.g. <displayfeedback feedbacktype = "Solution" linkrefid = "CorrectSoln"/> * * ??? should be ? ? <conditionvar><or>...</or><varequal>...</varequal></conditionvar> does not make sense * but <conditionvar> <varequal respident = "Word-1">KITTENS</varequal> <varequal respident = "Word-2">HATS</varequal> </conditionvar> makes sense, so treat members of conditionvar as children of an "and" element * @param node_respcond */ public boolean process(Element el_respcond, ItemContext itc, EvalContext ect) { // 1. evaluate conditionvar // 2. if true, set variables // and setCurrentDisplayFeedback (TODO: assuming there is only one displayfeedback in a respcondition) Variables vars; Element el_condVar = (Element) el_respcond.selectSingleNode("conditionvar"); String respcondtitle = el_respcond.attributeValue("title"); QTI_and qtiAnd = QTIHelper.getQTI_and(); boolean fulfilled = qtiAnd.eval(el_condVar, itc, ect); // continue to set variables and display feedback if question was answered correctly if (fulfilled) { vars = itc.getVariables(); List setvars = el_respcond.selectNodes("setvar"); for (Iterator iter = setvars.iterator(); iter.hasNext();) { Element element = (Element) iter.next(); String action = element.attributeValue("action"); String varName = element.attributeValue("varname"); if (varName == null) varName = "SCORE"; varName.trim(); String varVal = element.getText(); Variable var = vars.getVariable(varName); if (var == null) throw new RuntimeException("var "+varName+" is in setvar, but was not declared "); if (action.equals("Set")) { var.setValue(varVal); } else { // we are doing Integer or float arithmetic // Add | Subtract | Multiply | Divide if (action.equals("Add")) { var.add(varVal); } else if (action.equals("Subtract")) { var.subtract(varVal); } else if (action.equals("Multiply")) { var.multiply(varVal); } else if (action.equals("Divide")) { var.divide(varVal); } } } // set displayfeedback //<displayfeedback feedbacktype = "Response" linkrefid = "Correct"/> //<!ATTLIST displayfeedback feedbacktype (Response | Solution | Hint ) 'Response' %I_LinkRefId; > Output output = itc.getOutput(); List fbs = el_respcond.selectNodes("displayfeedback"); for (Iterator it_fbs = fbs.iterator(); it_fbs.hasNext();) { Element el_dispfb = (Element) it_fbs.next(); String linkRefId = el_dispfb.attributeValue("linkrefid"); // must exist (dtd) String feedbacktype = el_dispfb.attributeValue("feedbacktype"); // must exist (dtd) Element el_resolved = (Element) itc.getEl_item().selectSingleNode(".//itemfeedback[@ident='" + linkRefId + "']"); if (el_resolved == null) continue; if (feedbacktype.equals("Response")) { // additional (olat) rule: // we want to render the original answer again in the simple case where the respcondition was generated // by the olat export and contains only one varequal. /* <response_label ident = "2"> <flow_mat> <material> <mattext texttype="text/html">...</mattext> </material> </flow_mat> </response_label> ... <respcondition title="_olat_resp_feedback" continue="Yes"> <conditionvar> <varequal respident="Frage6549" case="Yes">2</varequal> </conditionvar> <displayfeedback linkrefid="2"/> </respcondition> In this case, it is possible (and wished) to trace the feedback back to the answer which triggered this feedback. Such a respcondition is identified by the title which is exactly "_olat_resp_feedback". */ Element el_chosenanswer = null; if (respcondtitle != null && respcondtitle.equals("_olat_resp_feedback")) { Element el_vareq = (Element) el_respcond.selectSingleNode(".//varequal"); String answerident = el_vareq.getText(); el_chosenanswer = (Element) itc.getEl_item().selectSingleNode(".//response_label[@ident='" + answerident + "']//material"); } output.addItem_El_response(el_chosenanswer,el_resolved); // give the whole itemfeedback to render } else if (feedbacktype.equals("Solution")) { Element el_solution = (Element) el_resolved.selectSingleNode(".//solution"); if (el_solution != null) output.setSolution(new Solution(el_solution)); } else if (feedbacktype.equals("Hint")) { //<!ENTITY % I_FeedbackStyle " feedbackstyle (Complete | Incremental | Multilevel | Proprietary ) 'Complete'"> Element el_hint = (Element) el_resolved.selectSingleNode(".//hint"); output.setHint(new Hint(el_hint)); } } } return fulfilled; } }