/**
* 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.container.qtielements;
import java.util.List;
import java.util.Map;
import org.dom4j.Element;
import org.olat.core.logging.AssertException;
import org.olat.core.util.StringHelper;
import org.olat.core.util.openxml.OpenXMLDocument;
import org.olat.core.util.openxml.OpenXMLDocument.Style;
import org.olat.core.util.openxml.OpenXMLDocument.Unit;
import org.olat.ims.qti.container.ItemInput;
import org.w3c.dom.Node;
/**
* Initial Date: 25.11.2004
*
* @author Mike Stock
*/
public class Response_label extends GenericQTIElement {
private static final long serialVersionUID = -4391486220424218044L;
/**
* Comment for <code>xmlClass</code>
*/
public static final String xmlClass = "response_label";
private static String PARA = "ยง";
/**
* @param el_element
*/
public Response_label(Element el_element) {
super(el_element);
}
/**
* @see org.olat.ims.qti.container.qtielements.QTIElement#render(StringBuilder,
* RenderInstructions)
*/
@Override
public void render(StringBuilder buffer, RenderInstructions ri) {
ItemInput iinput = (ItemInput) ri.get(RenderInstructions.KEY_ITEM_INPUT);
String responseIdent = (String) ri.get(RenderInstructions.KEY_RESPONSE_IDENT);
// find parent render_xxx element
String renderClass = (String) ri.get(RenderInstructions.KEY_RENDER_CLASS);
if(renderClass == null) {
//we don't know what to do
} else if (renderClass.equals("choice")) {
renderChoice(buffer, ri, iinput);
} else if (renderClass.equals("kprim")) {
buffer.append("<tr><td class='o_qti_item_kprim_input'><input id=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\" type=\"radio\" class=\"radio\" name=\"");
appendParameterIdent(buffer, ri);
buffer.append("\" value=\"" + getQTIIdent() + ":correct");
if (iinput != null && !iinput.isEmpty()) {
List<String> responses = iinput.getAsList(responseIdent);
if (responses != null && responses.contains(getQTIIdent() + ":correct")) buffer.append("\" checked=\"checked");
}
buffer.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\"/>");
buffer.append("</td><td class='o_qti_item_kprim_input'><input id=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\" type=\"radio\" class=\"radio\" name=\"");
appendParameterIdent(buffer, ri);
buffer.append("\" value=\"" + getQTIIdent() + ":wrong");
if (iinput != null && !iinput.isEmpty()) {
List<String> responses = iinput.getAsList(responseIdent);
if (responses != null && responses.contains(getQTIIdent() + ":wrong")) buffer.append("\" checked=\"checked");
}
buffer.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\"/>");
buffer.append("</td><td>");
super.render(buffer, ri);
buffer.append("</td></tr>");
ri.put(RenderInstructions.KEY_FLOW_LABEL, new Integer(RenderInstructions.RENDER_FLOW_BLOCK));
addBr(ri, buffer);
} else if (renderClass.equals("fib")) {
Integer rows = (Integer) ri.get(RenderInstructions.KEY_FIB_ROWS);
Integer columns = (Integer) ri.get(RenderInstructions.KEY_FIB_COLUMNS);
Integer maxlength = (Integer) ri.get(RenderInstructions.KEY_FIB_MAXLENGTH);
if (rows == null || columns == null || maxlength == null) throw new AssertException(
"Rows and/or columns attribute not specified for render_fib.");
if (rows.intValue() > 1) {
// render as textarea
buffer.append("<textarea id=\"QTI_").append(getQTIIdent()).append("\" name=\"");
appendParameterIdent(buffer, ri);
buffer.append("\" class='form-control' rows=\"").append(rows).append("\" cols=\"").append(columns)
.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\">");
if (iinput != null && !iinput.isEmpty() && iinput.getSingle(responseIdent) != null) {
buffer.append(iinput.getSingle(getQTIIdent()));
}
buffer.append("</textarea>");
} else {
// render as input string
buffer.append("<span> </span><input id=\"QTI_").append(getQTIIdent()).append("\" name=\"");
appendParameterIdent(buffer, ri);
buffer.append("\" type=\"text\" size=\"").append(columns).append("\" maxlength=\"").append(maxlength);
if (iinput != null && !iinput.isEmpty() && iinput.getSingle(responseIdent) != null) {
buffer.append("\" value=\"").append(StringHelper.escapeHtml(iinput.getSingle(getQTIIdent())));
}
buffer.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\" /><span> </span>");
}
addBr(ri, buffer);
}
}
private void renderChoice(StringBuilder buffer, RenderInstructions ri, ItemInput iinput) {
String responseIdent = (String) ri.get(RenderInstructions.KEY_RESPONSE_IDENT);
// render multiple/single choice
buffer.append("<div class='form-group o_qti_item_choice_option");
if (!wantBr(ri)){
buffer.append("_flow");
}
buffer.append("'>");
Object o = ri.get(RenderInstructions.KEY_RENDER_AUTOENUM_LIST);
if (o != null) {
String[] s = o.toString().split(",");
o = ri.get(RenderInstructions.KEY_RENDER_AUTOENUM_IDX);
int i = o == null ? 0 : Integer.valueOf(o.toString());
buffer.append("<div class=\"o_qti_item_choice_option_autoenum\">");
if (s.length > i) {
buffer.append("<span>").append(s[i]).append("</span>");
ri.put(RenderInstructions.KEY_RENDER_AUTOENUM_IDX, Integer.toString(i+1));
}
buffer.append("</div>");
}
Integer rCardinality = (Integer) ri.get(RenderInstructions.KEY_RESPONSE_RCARDINALITY);
if (rCardinality == null) {
throw new AssertException("Cardinality must be set previousely to call respnse_label.render for a render_choice class.");
}
if (rCardinality.intValue() == Response_lid.RCARDINALITY_SINGLE) {
// single choice
buffer.append("<div class='radio'>")
.append("<label for=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\">")
.append("<input id=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\" type='radio' name=\"")
.append("qti").append(PARA).append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(PARA)
.append(ri.get(RenderInstructions.KEY_RESPONSE_IDENT)).append(PARA).append("choice")
.append("\" value=\"").append(getQTIIdent());
if (iinput != null && !iinput.isEmpty()) {
String response = iinput.getSingle(responseIdent);
if (response.equals(getQTIIdent())) buffer.append("\" checked=\"checked");
}
buffer.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\" />");
super.render(buffer, ri);
buffer.append("</label></div>");
} else if (rCardinality.intValue() == Response_lid.RCARDINALITY_MULTIPLE) {
// multiple choice
buffer.append("<div class='checkbox'>")
.append("<label for=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\">")
.append("<input id=\"QTI_").append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(getQTIIdent()).append("\" type='checkbox' class='o_checkbox' name=\"");
appendParameterIdent(buffer, ri);
buffer.append("\" value=\"").append(getQTIIdent());
if (iinput != null) {
List<String> responses = iinput.getAsList(responseIdent);
if (responses != null && responses.contains(getQTIIdent())) buffer.append("\" checked=\"checked");
}
buffer.append("\" onchange=\"return setFormDirty('ofo_iq_item')\" onclick=\"return setFormDirty('ofo_iq_item')\" />");
super.render(buffer, ri);
buffer.append("</label></div>");
}
buffer.append("</div>");
}
private void addBr (RenderInstructions ri, StringBuilder buffer) {
if (wantBr(ri)) buffer.append("<br />");
}
private boolean wantBr (RenderInstructions ri) {
Integer flowLabelClass = (Integer) ri.get(RenderInstructions.KEY_FLOW_LABEL);
if (flowLabelClass != null) {
return flowLabelClass.intValue() == RenderInstructions.RENDER_FLOW_LIST;
} else {
return true;
}
}
private void appendParameterIdent(StringBuilder buffer, RenderInstructions ri) {
buffer.append("qti").append(PARA).append(ri.get(RenderInstructions.KEY_ITEM_IDENT)).append(PARA).append(
ri.get(RenderInstructions.KEY_RESPONSE_IDENT)).append(PARA).append(getQTIIdent());
}
@Override
public void renderOpenXML(OpenXMLDocument document, RenderInstructions ri) {
String renderClass = (String) ri.get(RenderInstructions.KEY_RENDER_CLASS);
if(renderClass == null) {
//we don't know what to do
} else if(renderClass.equals("choice")) {
Node row = document.createTableRow();
//answer
Node answerCell = row.appendChild(document.createTableCell("E9EAF2", 4560, Unit.pct));
document.pushCursor(answerCell);
super.renderOpenXML(document, ri);
document.popCursor(answerCell);
//checkbox
boolean correct = isCorrectMCResponse(ri);
appendCheckBox(correct, row, document);
//append row
document.getCursor().appendChild(row);
} else if (renderClass.equals("kprim")) {
Node row = document.createTableRow();
//answer
Node answerCell = row.appendChild(document.createTableCell("E9EAF2", 4120, Unit.pct));
document.pushCursor(answerCell);
super.renderOpenXML(document, ri);
document.popCursor(answerCell);
//checkbox
boolean correct = isCorrectKPrimResponse(ri, "correct");
appendCheckBox(correct, row, document);
boolean wrong = isCorrectKPrimResponse(ri, "wrong");
appendCheckBox(wrong, row, document);
//append row
document.getCursor().appendChild(row);
} else if (renderClass.equals("fib")) {
Boolean render = (Boolean)ri.get(RenderInstructions.KEY_RENDER_CORRECT_RESPONSES);
@SuppressWarnings("unchecked")
Map<String,String> iinput = (Map<String,String>)ri.get(RenderInstructions.KEY_CORRECT_RESPONSES_MAP);
if(render != null && render.booleanValue() && iinput != null
&& StringHelper.containsNonWhitespace(iinput.get(getQTIIdent()))) {
//show the response
String response = iinput.get(getQTIIdent());
response = response.replace(";", ", ");
document.appendText(response, false, Style.underline);
} else {
Integer rows = (Integer)ri.get(RenderInstructions.KEY_FIB_ROWS);
if (rows != null && rows.intValue() > 1) {
document.appendFillInBlanckWholeLine(rows.intValue());
} else {
Integer maxlength = (Integer)ri.get(RenderInstructions.KEY_FIB_MAXLENGTH);
int length = (maxlength == null ? 8 : maxlength.intValue()) / 2;
document.appendFillInBlanck(length, false);
}
}
}
}
private void appendCheckBox(boolean checked, Node row, OpenXMLDocument document) {
Node checkboxCell = row.appendChild(document.createTableCell(null, 369, Unit.pct));
Node responseEl = document.createCheckbox(checked);
Node wrapEl = document.wrapInParagraph(responseEl);
//Node responseEl = document.createParagraphEl("OK");
checkboxCell.appendChild(wrapEl);
}
private boolean isCorrectMCResponse(RenderInstructions ri) {
Boolean render = (Boolean)ri.get(RenderInstructions.KEY_RENDER_CORRECT_RESPONSES);
if(render == null || !render.booleanValue()) return false;
@SuppressWarnings("unchecked")
Map<String,String> iinput = (Map<String,String>)ri.get(RenderInstructions.KEY_CORRECT_RESPONSES_MAP);
if(iinput != null && iinput.containsKey(getQTIIdent())) {
return true;
}
return false;
}
private boolean isCorrectKPrimResponse(RenderInstructions ri, String add) {
Boolean render = (Boolean)ri.get(RenderInstructions.KEY_RENDER_CORRECT_RESPONSES);
if(render == null || !render.booleanValue()) return false;
@SuppressWarnings("unchecked")
Map<String,String> iinput = (Map<String,String>)ri.get(RenderInstructions.KEY_CORRECT_RESPONSES_MAP);
if(iinput != null && iinput.containsKey(getQTIIdent() + ":" + add)) {
return true;
}
return false;
}
}