/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <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 the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <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>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.ims.qti21.model.xml;
import static org.olat.ims.qti21.QTI21Constants.MAXSCORE_CLX_IDENTIFIER;
import static org.olat.ims.qti21.QTI21Constants.MINSCORE_CLX_IDENTIFIER;
import static org.olat.ims.qti21.QTI21Constants.SCORE_CLX_IDENTIFIER;
import static org.olat.ims.qti21.QTI21Constants.SCORE_IDENTIFIER;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.olat.core.helpers.Settings;
import org.olat.core.util.StringHelper;
import org.olat.ims.qti21.QTI21Constants;
import org.olat.ims.qti21.model.IdentifierGenerator;
import org.olat.ims.qti21.model.QTI21QuestionType;
import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.TextEntryAlternative;
import uk.ac.ed.ph.jqtiplus.group.NodeGroupList;
import uk.ac.ed.ph.jqtiplus.group.item.ItemBodyGroup;
import uk.ac.ed.ph.jqtiplus.group.item.interaction.PromptGroup;
import uk.ac.ed.ph.jqtiplus.group.item.interaction.choice.SimpleChoiceGroup;
import uk.ac.ed.ph.jqtiplus.group.outcome.declaration.OutcomeDeclarationGroup;
import uk.ac.ed.ph.jqtiplus.node.QtiNode;
import uk.ac.ed.ph.jqtiplus.node.content.ItemBody;
import uk.ac.ed.ph.jqtiplus.node.content.basic.TextRun;
import uk.ac.ed.ph.jqtiplus.node.content.xhtml.object.Object;
import uk.ac.ed.ph.jqtiplus.node.content.xhtml.text.P;
import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue;
import uk.ac.ed.ph.jqtiplus.node.expression.general.Correct;
import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.And;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gt;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gte;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.IsNull;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Lt;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Multiple;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Not;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Shape;
import uk.ac.ed.ph.jqtiplus.node.expression.operator.Sum;
import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
import uk.ac.ed.ph.jqtiplus.node.item.CorrectResponse;
import uk.ac.ed.ph.jqtiplus.node.item.ModalFeedback;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.ChoiceInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.DrawingInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.ExtendedTextInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.HotspotInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.HottextInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.MatchInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.TextEntryInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.UploadInteraction;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleAssociableChoice;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleChoice;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.choice.SimpleMatchSet;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.content.Hottext;
import uk.ac.ed.ph.jqtiplus.node.item.interaction.graphic.HotspotChoice;
import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.MapEntry;
import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.Mapping;
import uk.ac.ed.ph.jqtiplus.node.item.response.declaration.ResponseDeclaration;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseCondition;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElse;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseElseIf;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseIf;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseProcessing;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.ResponseRule;
import uk.ac.ed.ph.jqtiplus.node.item.response.processing.SetOutcomeValue;
import uk.ac.ed.ph.jqtiplus.node.outcome.declaration.OutcomeDeclaration;
import uk.ac.ed.ph.jqtiplus.node.shared.FieldValue;
import uk.ac.ed.ph.jqtiplus.node.shared.declaration.DefaultValue;
import uk.ac.ed.ph.jqtiplus.node.test.View;
import uk.ac.ed.ph.jqtiplus.node.test.VisibilityMode;
import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier;
import uk.ac.ed.ph.jqtiplus.types.Identifier;
import uk.ac.ed.ph.jqtiplus.value.BaseType;
import uk.ac.ed.ph.jqtiplus.value.Cardinality;
import uk.ac.ed.ph.jqtiplus.value.DirectedPairValue;
import uk.ac.ed.ph.jqtiplus.value.FloatValue;
import uk.ac.ed.ph.jqtiplus.value.IdentifierValue;
import uk.ac.ed.ph.jqtiplus.value.Orientation;
import uk.ac.ed.ph.jqtiplus.value.StringValue;
/**
*
* Initial date: 03.07.2015<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class AssessmentItemFactory {
public static AssessmentItem createSingleChoice(String title, String defaultAnswer) {
AssessmentItem assessmentItem = createAssessmentItem(QTI21QuestionType.sc, title);
//define correct answer
Identifier responseDeclarationId = Identifier.assumedLegal("RESPONSE_1");
Identifier correctResponseId = IdentifierGenerator.newAsIdentifier("sc");
ResponseDeclaration responseDeclaration = createSingleChoiceCorrectResponseDeclaration(assessmentItem, responseDeclarationId, correctResponseId);
assessmentItem.getNodeGroups().getResponseDeclarationGroup().getResponseDeclarations().add(responseDeclaration);
//outcomes
appendDefaultOutcomeDeclarations(assessmentItem, 1.0d);
//the single choice interaction
ItemBody itemBody = appendDefaultItemBody(assessmentItem);
ChoiceInteraction choiceInteraction = appendChoiceInteraction(itemBody, responseDeclarationId, 1, true);
appendSimpleChoice(choiceInteraction, defaultAnswer, correctResponseId);
//response processing
ResponseProcessing responseProcessing = createResponseProcessing(assessmentItem, responseDeclarationId);
assessmentItem.getNodeGroups().getResponseProcessingGroup().setResponseProcessing(responseProcessing);
return assessmentItem;
}
public static AssessmentItem createAssessmentItem(QTI21QuestionType type, String defaultTitle) {
AssessmentItem assessmentItem = new AssessmentItem();
if(type != null) {
assessmentItem.setIdentifier(IdentifierGenerator.newAsString(type.getPrefix()));
} else {
assessmentItem.setIdentifier(IdentifierGenerator.newAsString("item"));
}
assessmentItem.setTitle(defaultTitle);
assessmentItem.setToolName(QTI21Constants.TOOLNAME);
assessmentItem.setToolVersion(Settings.getVersion());
assessmentItem.setAdaptive(Boolean.FALSE);
assessmentItem.setTimeDependent(Boolean.FALSE);
return assessmentItem;
}
/**
* Append the itemBody with an empty paragraph.
*
* @param assessmentItem
* @return
*/
public static ItemBody appendDefaultItemBody(AssessmentItem assessmentItem) {
NodeGroupList nodeGroups = assessmentItem.getNodeGroups();
//the single choice interaction
ItemBodyGroup itemBodyGroup = nodeGroups.getItemBodyGroup();
ItemBody itemBody = new ItemBody(assessmentItem);
itemBodyGroup.setItemBody(itemBody);
return itemBody;
}
/**
* Append the default outcome declaration for score, max score and feedback basic.
*
* @param assessmentItem
*/
public static void appendDefaultOutcomeDeclarations(AssessmentItem assessmentItem, double maxScore) {
NodeGroupList nodeGroups = assessmentItem.getNodeGroups();
//outcomes
OutcomeDeclarationGroup outcomeDeclarations = nodeGroups.getOutcomeDeclarationGroup();
//outcome score
OutcomeDeclaration scoreOutcomeDeclaration = createOutcomeDeclarationForScore(assessmentItem);
outcomeDeclarations.getOutcomeDeclarations().add(scoreOutcomeDeclaration);
// outcome max score
OutcomeDeclaration maxScoreOutcomeDeclaration = createOutcomeDeclarationForMaxScore(assessmentItem, maxScore);
outcomeDeclarations.getOutcomeDeclarations().add(maxScoreOutcomeDeclaration);
// outcome min score
OutcomeDeclaration minScoreOutcomeDeclaration = createOutcomeDeclarationForMinScore(assessmentItem, 0.0d);
outcomeDeclarations.getOutcomeDeclarations().add(minScoreOutcomeDeclaration);
// outcome feedback
OutcomeDeclaration feedbackOutcomeDeclaration = createOutcomeDeclarationForFeedbackBasic(assessmentItem);
outcomeDeclarations.getOutcomeDeclarations().add(feedbackOutcomeDeclaration);
}
public static HotspotInteraction appendHotspotInteraction(ItemBody itemBody, Identifier responseDeclarationId, Identifier correctResponseId) {
HotspotInteraction hotspotInteraction = new HotspotInteraction(itemBody);
hotspotInteraction.setResponseIdentifier(responseDeclarationId);
hotspotInteraction.setMaxChoices(1);
itemBody.getBlocks().add(hotspotInteraction);
Object graphicObject = new Object(hotspotInteraction);
graphicObject.setType("image/png");
graphicObject.setWidth("400");
graphicObject.setHeight("320");
hotspotInteraction.setObject(graphicObject);
HotspotChoice choice = new HotspotChoice(hotspotInteraction);
choice.setIdentifier(correctResponseId);
choice.setFixed(Boolean.FALSE);
choice.setShape(Shape.CIRCLE);
List<Integer> coords = new ArrayList<>();
coords.add(new Integer(55));
coords.add(new Integer(77));
coords.add(new Integer(8));
choice.setCoords(coords);
hotspotInteraction.getHotspotChoices().add(choice);
return hotspotInteraction;
}
/*
<responseDeclaration identifier="RESPONSE" cardinality="single" baseType="identifier">
<correctResponse>
<value>Choice0</value>
</correctResponse>
</responseDeclaration>
*/
public static ResponseDeclaration createHotspotEntryResponseDeclarationSingle(AssessmentItem assessmentItem,
Identifier responseIdentifier, Identifier correctAnswerIdentifier) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(responseIdentifier);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.IDENTIFIER);
//correct response
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
appendIdentifierValue(correctResponse, correctAnswerIdentifier);
return responseDeclaration;
}
public static ResponseDeclaration createHotspotCorrectResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId, List<Identifier> correctResponseIds) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
if(correctResponseIds == null || correctResponseIds.size() == 0 || correctResponseIds.size() > 1) {
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
} else {
responseDeclaration.setCardinality(Cardinality.SINGLE);
}
responseDeclaration.setBaseType(BaseType.IDENTIFIER);
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
for(Identifier correctResponseId:correctResponseIds) {
appendIdentifierValue(correctResponse, correctResponseId);
}
return responseDeclaration;
}
public static TextEntryInteraction appendTextEntryInteraction(ItemBody itemBody, Identifier responseDeclarationId) {
P paragraph = new P(itemBody);
TextRun text = new TextRun(paragraph, "New text");
paragraph.getInlines().add(text);
TextEntryInteraction textInteraction = new TextEntryInteraction(paragraph);
textInteraction.setResponseIdentifier(responseDeclarationId);
paragraph.getInlines().add(textInteraction);
itemBody.getBlocks().add(paragraph);
return textInteraction;
}
public static ResponseDeclaration createNumericalEntryResponseDeclaration(AssessmentItem assessmentItem,
Identifier declarationId, double response) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.FLOAT);
//correct response
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
appendFloatValue(correctResponse, response);
return responseDeclaration;
}
public static ResponseDeclaration createTextEntryResponseDeclaration(AssessmentItem assessmentItem,
Identifier declarationId, String response, Double score, boolean caseSensitive,
List<TextEntryAlternative> alternatives) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.STRING);
//correct response
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
appendStringValue(correctResponse, response);
// mapping
Mapping mapping = new Mapping(responseDeclaration);
mapping.setDefaultValue(0.0d);
responseDeclaration.setMapping(mapping);
{//map correct response
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(new StringValue(response));
mapEntry.setMappedValue(score);
mapEntry.setCaseSensitive(new Boolean(caseSensitive));
mapping.getMapEntries().add(mapEntry);
}
//map alternatives
if(alternatives != null && alternatives.size() > 0) {
for(TextEntryAlternative alternative:alternatives) {
if(StringHelper.containsNonWhitespace(alternative.getAlternative())) {
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(new StringValue(alternative.getAlternative()));
mapEntry.setMappedValue(score);
mapEntry.setCaseSensitive(new Boolean(caseSensitive));
mapping.getMapEntries().add(mapEntry);
}
}
}
return responseDeclaration;
}
/**
* For the all answers get the point
* @param assessmentItem
* @param declarationId
* @param response
* @param alternatives
* @return
*/
public static ResponseDeclaration createTextEntryResponseDeclaration(AssessmentItem assessmentItem,
Identifier declarationId, String response, List<TextEntryAlternative> alternatives) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.STRING);
//correct response
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
appendStringValue(correctResponse, response);
if(alternatives != null) {
for(TextEntryAlternative alternative:alternatives) {
appendStringValue(correctResponse, alternative.getAlternative());
}
}
return responseDeclaration;
}
public static ExtendedTextInteraction appendExtendedTextInteraction(ItemBody itemBody, Identifier responseDeclarationId) {
ExtendedTextInteraction textInteraction = new ExtendedTextInteraction(itemBody);
textInteraction.setResponseIdentifier(responseDeclarationId);
itemBody.getBlocks().add(textInteraction);
return textInteraction;
}
public static ResponseDeclaration createExtendedTextResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.STRING);
return responseDeclaration;
}
public static UploadInteraction appendUploadInteraction(ItemBody itemBody, Identifier responseDeclarationId) {
UploadInteraction textInteraction = new UploadInteraction(itemBody);
textInteraction.setResponseIdentifier(responseDeclarationId);
itemBody.getBlocks().add(textInteraction);
return textInteraction;
}
public static ResponseDeclaration createUploadResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.FILE);
return responseDeclaration;
}
public static DrawingInteraction appendDrawingInteraction(ItemBody itemBody, Identifier responseDeclarationId) {
DrawingInteraction textInteraction = new DrawingInteraction(itemBody);
textInteraction.setResponseIdentifier(responseDeclarationId);
itemBody.getBlocks().add(textInteraction);
return textInteraction;
}
public static ResponseDeclaration createDrawingResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.FILE);
return responseDeclaration;
}
public static MatchInteraction appendMatchInteractionForKPrim(ItemBody itemBody, Identifier responseDeclarationId, String defaultAnswer) {
MatchInteraction matchInteraction = new MatchInteraction(itemBody);
matchInteraction.setResponseIdentifier(responseDeclarationId);
matchInteraction.setMaxAssociations(4);
matchInteraction.setShuffle(false);
itemBody.getBlocks().add(matchInteraction);
PromptGroup prompts = new PromptGroup(matchInteraction);
matchInteraction.getNodeGroups().add(prompts);
SimpleMatchSet questionMatchSet = new SimpleMatchSet(matchInteraction);
matchInteraction.getSimpleMatchSets().add(questionMatchSet);
String[] classic = new String[]{ "a", "b", "c", "d" };
for(int i=0; i<4; i++) {
SimpleAssociableChoice correctChoice = new SimpleAssociableChoice(questionMatchSet);
correctChoice.setMatchMax(1);
correctChoice.setMatchMin(1);
correctChoice.setIdentifier(IdentifierGenerator.newNumberAsIdentifier(classic[i]));
P question = getParagraph(correctChoice, defaultAnswer + " " + classic[i]);
correctChoice.getFlowStatics().add(question);
questionMatchSet.getSimpleAssociableChoices().add(correctChoice);
}
SimpleMatchSet correctWrongMatchSet = new SimpleMatchSet(matchInteraction);
matchInteraction.getSimpleMatchSets().add(correctWrongMatchSet);
SimpleAssociableChoice correctChoice = new SimpleAssociableChoice(correctWrongMatchSet);
correctChoice.setMatchMax(4);
correctChoice.setFixed(Boolean.TRUE);
correctChoice.setIdentifier(QTI21Constants.CORRECT_IDENTIFIER);
correctChoice.getFlowStatics().add(new TextRun(correctChoice, "+"));
correctWrongMatchSet.getSimpleAssociableChoices().add(correctChoice);
SimpleAssociableChoice wrongChoice = new SimpleAssociableChoice(correctWrongMatchSet);
wrongChoice.setMatchMax(4);
wrongChoice.setFixed(Boolean.TRUE);
wrongChoice.setIdentifier(QTI21Constants.WRONG_IDENTIFIER);
wrongChoice.getFlowStatics().add(new TextRun(correctChoice, "-"));
correctWrongMatchSet.getSimpleAssociableChoices().add(wrongChoice);
return matchInteraction;
}
public static ResponseDeclaration createKPrimResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId,
Map<Identifier,Identifier> associations, double maxScore) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.DIRECTED_PAIR);
return appendAssociationKPrimResponseDeclaration(responseDeclaration, associations, maxScore);
}
public static ResponseDeclaration appendAssociationKPrimResponseDeclaration(ResponseDeclaration responseDeclaration,
Map<Identifier,Identifier> associations, double maxScore) {
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.DIRECTED_PAIR);
//correct response
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
for(Map.Entry<Identifier,Identifier> association:associations.entrySet()) {
Identifier choiceId = association.getKey();
Identifier correctwrongId = association.getValue();
DirectedPairValue dpValue = new DirectedPairValue(choiceId, correctwrongId);
FieldValue fValue = new FieldValue(correctResponse, dpValue);
correctResponse.getFieldValues().add(fValue);
}
double mappedValue = maxScore;
if(associations.size() > 0) {
mappedValue = maxScore / associations.size();
}
// mapping
Mapping mapping = new Mapping(responseDeclaration);
mapping.setDefaultValue(-mappedValue);
responseDeclaration.setMapping(mapping);
for(Map.Entry<Identifier,Identifier> association:associations.entrySet()) {
Identifier choiceId = association.getKey();
Identifier correctwrongId = association.getValue();
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(new DirectedPairValue(choiceId, correctwrongId));
mapEntry.setMappedValue(mappedValue);
mapping.getMapEntries().add(mapEntry);
}
return responseDeclaration;
}
public static MatchInteraction appendMatchInteraction(ItemBody itemBody, Identifier responseDeclarationId) {
MatchInteraction matchInteraction = new MatchInteraction(itemBody);
matchInteraction.setResponseIdentifier(responseDeclarationId);
matchInteraction.setMaxAssociations(0);
matchInteraction.setShuffle(false);
itemBody.getBlocks().add(matchInteraction);
PromptGroup prompts = new PromptGroup(matchInteraction);
matchInteraction.getNodeGroups().add(prompts);
SimpleMatchSet sourceMatchSet = new SimpleMatchSet(matchInteraction);
matchInteraction.getSimpleMatchSets().add(sourceMatchSet);
String[] classic = new String[]{ "A", "B" };
for(int i=0; i<2; i++) {
SimpleAssociableChoice sourceChoice = new SimpleAssociableChoice(sourceMatchSet);
sourceChoice.setMatchMax(0);
sourceChoice.setMatchMin(0);
sourceChoice.setIdentifier(IdentifierGenerator.newNumberAsIdentifier(classic[i]));
P question = getParagraph(sourceChoice, classic[i]);
sourceChoice.getFlowStatics().add(question);
sourceMatchSet.getSimpleAssociableChoices().add(sourceChoice);
}
SimpleMatchSet targetMatchSet = new SimpleMatchSet(matchInteraction);
matchInteraction.getSimpleMatchSets().add(targetMatchSet);
String[] target = new String[]{ "M", "N" };
for(int i=0; i<2; i++) {
SimpleAssociableChoice targetChoice = new SimpleAssociableChoice(sourceMatchSet);
targetChoice.setMatchMax(0);
targetChoice.setMatchMin(0);
targetChoice.setIdentifier(IdentifierGenerator.newNumberAsIdentifier(target[i]));
P question = getParagraph(targetChoice, target[i]);
targetChoice.getFlowStatics().add(question);
targetMatchSet.getSimpleAssociableChoices().add(targetChoice);
}
return matchInteraction;
}
public static SimpleAssociableChoice createSimpleAssociableChoice(String text, SimpleMatchSet matchSet) {
SimpleAssociableChoice targetChoice = new SimpleAssociableChoice(matchSet);
targetChoice.setMatchMax(0);
targetChoice.setMatchMin(0);
targetChoice.setIdentifier(IdentifierGenerator.newNumberAsIdentifier("sa"));
P question = getParagraph(targetChoice, text);
targetChoice.getFlowStatics().add(question);
return targetChoice;
}
public static ResponseDeclaration createMatchResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId,
Map<Identifier, List<Identifier>> associations, double maxScore) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.DIRECTED_PAIR);
return appendAssociationMatchResponseDeclaration(responseDeclaration, associations, maxScore);
}
public static ResponseDeclaration appendAssociationMatchResponseDeclaration(ResponseDeclaration responseDeclaration,
Map<Identifier, List<Identifier>> associations, double maxScore) {
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.DIRECTED_PAIR);
//correct response
int numOfassociations = 0;
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
for(Map.Entry<Identifier,List<Identifier>> association:associations.entrySet()) {
Identifier sourceChoiceId = association.getKey();
List<Identifier> targetChoiceIds = association.getValue();
for(Identifier targetChoiceId:targetChoiceIds) {
DirectedPairValue dpValue = new DirectedPairValue(sourceChoiceId, targetChoiceId);
FieldValue fValue = new FieldValue(correctResponse, dpValue);
correctResponse.getFieldValues().add(fValue);
numOfassociations++;
}
}
double mappedValue = maxScore;
if(numOfassociations > 0) {
mappedValue = maxScore / numOfassociations;
}
// mapping
Mapping mapping = new Mapping(responseDeclaration);
mapping.setDefaultValue(-mappedValue);
responseDeclaration.setMapping(mapping);
for(Map.Entry<Identifier,List<Identifier>> association:associations.entrySet()) {
Identifier sourceChoiceId = association.getKey();
List<Identifier> targetChoiceIds = association.getValue();
for(Identifier targetChoiceId:targetChoiceIds) {
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(new DirectedPairValue(sourceChoiceId, targetChoiceId));
mapEntry.setMappedValue(mappedValue);
mapping.getMapEntries().add(mapEntry);
}
}
return responseDeclaration;
}
public static ChoiceInteraction appendChoiceInteraction(ItemBody itemBody, Identifier responseDeclarationId, int maxChoices, boolean shuffle) {
ChoiceInteraction choiceInteraction = new ChoiceInteraction(itemBody);
choiceInteraction.setMaxChoices(maxChoices);
choiceInteraction.setShuffle(shuffle);
choiceInteraction.setResponseIdentifier(responseDeclarationId);
itemBody.getBlocks().add(choiceInteraction);
PromptGroup prompts = new PromptGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(prompts);
SimpleChoiceGroup singleChoices = new SimpleChoiceGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(singleChoices);
return choiceInteraction;
}
public static ResponseDeclaration createSingleChoiceCorrectResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId, Identifier correctResponseId) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.IDENTIFIER);
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
appendIdentifierValue(correctResponse, correctResponseId);
return responseDeclaration;
}
public static ResponseDeclaration createMultipleChoiceCorrectResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId, List<Identifier> correctResponseIds) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.IDENTIFIER);
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
for(Identifier correctResponseId:correctResponseIds) {
appendIdentifierValue(correctResponse, correctResponseId);
}
return responseDeclaration;
}
public static HottextInteraction appendHottextInteraction(ItemBody itemBody, Identifier responseDeclarationId, int maxChoices) {
HottextInteraction hottextInteraction = new HottextInteraction(itemBody);
hottextInteraction.setMaxChoices(maxChoices);
hottextInteraction.setResponseIdentifier(responseDeclarationId);
itemBody.getBlocks().add(hottextInteraction);
PromptGroup prompts = new PromptGroup(hottextInteraction);
hottextInteraction.getNodeGroups().add(prompts);
return hottextInteraction;
}
public static Hottext appendHottext(P parent, Identifier responseId, String text) {
Hottext hottext = new Hottext(parent);
hottext.setIdentifier(responseId);
hottext.getInlineStatics().add(new TextRun(hottext, text));
parent.getInlines().add(hottext);
return hottext;
}
public static ResponseDeclaration createHottextCorrectResponseDeclaration(AssessmentItem assessmentItem, Identifier declarationId, List<Identifier> correctResponseIds) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(declarationId);
responseDeclaration.setCardinality(Cardinality.MULTIPLE);
responseDeclaration.setBaseType(BaseType.IDENTIFIER);
CorrectResponse correctResponse = new CorrectResponse(responseDeclaration);
responseDeclaration.setCorrectResponse(correctResponse);
for(Identifier correctResponseId:correctResponseIds) {
appendIdentifierValue(correctResponse, correctResponseId);
}
return responseDeclaration;
}
//<responseDeclaration identifier="HINTREQUEST" cardinality="single" baseType="boolean"/>
public static ResponseDeclaration createHintRequestResponseDeclaration(AssessmentItem assessmentItem) {
ResponseDeclaration responseDeclaration = new ResponseDeclaration(assessmentItem);
responseDeclaration.setIdentifier(QTI21Constants.HINT_REQUEST_IDENTIFIER);
responseDeclaration.setCardinality(Cardinality.SINGLE);
responseDeclaration.setBaseType(BaseType.BOOLEAN);
return responseDeclaration;
}
public static SimpleChoice createSimpleChoice(ChoiceInteraction choiceInteraction, String text, String prefix) {
SimpleChoice newChoice = new SimpleChoice(choiceInteraction);
newChoice.setIdentifier(IdentifierGenerator.newAsIdentifier(prefix));
P firstChoiceText = AssessmentItemFactory.getParagraph(newChoice, text);
newChoice.getFlowStatics().add(firstChoiceText);
return newChoice;
}
public static SimpleChoice appendSimpleChoice(ChoiceInteraction choiceInteraction, String text, String prefix) {
SimpleChoice newChoice = createSimpleChoice(choiceInteraction, text, prefix);
choiceInteraction.getNodeGroups().getSimpleChoiceGroup().getSimpleChoices().add(newChoice);
return newChoice;
}
public static SimpleChoice appendSimpleChoice(ChoiceInteraction choiceInteraction, String text, Identifier identifier) {
SimpleChoice newChoice = new SimpleChoice(choiceInteraction);
newChoice.setIdentifier(identifier);
P firstChoiceText = AssessmentItemFactory.getParagraph(newChoice, text);
newChoice.getFlowStatics().add(firstChoiceText);
choiceInteraction.getNodeGroups().getSimpleChoiceGroup().getSimpleChoices().add(newChoice);
return newChoice;
}
private static void appendIdentifierValue(CorrectResponse correctResponse, Identifier correctResponseId) {
FieldValue fieldValue = new FieldValue(correctResponse);
IdentifierValue identifierValue = new IdentifierValue(correctResponseId);
fieldValue.setSingleValue(identifierValue);
correctResponse.getFieldValues().add(fieldValue);
}
private static void appendStringValue(CorrectResponse correctResponse, String response) {
FieldValue fieldValue = new FieldValue(correctResponse);
StringValue identifierValue = new StringValue(response);
fieldValue.setSingleValue(identifierValue);
correctResponse.getFieldValues().add(fieldValue);
}
private static void appendFloatValue(CorrectResponse correctResponse, double response) {
FieldValue fieldValue = new FieldValue(correctResponse);
FloatValue identifierValue = new FloatValue(response);
fieldValue.setSingleValue(identifierValue);
correctResponse.getFieldValues().add(fieldValue);
}
/*
<mapping defaultValue="0">
<mapEntry mapKey="idd072fa37-f4c3-4532-a2fb-4458fa23e919" mappedValue="2.0" />
<mapEntry mapKey="ide18af420-393e-43dc-b194-7af94663b576" mappedValue="-0.5" />
<mapEntry mapKey="id72eb2dda-4053-45ba-a9f8-cc101f3e3987" mappedValue="2.0" />
</mapping>
*/
public static Mapping appendMapping(ResponseDeclaration responseDeclaration, Map<Identifier,Double> map) {
Mapping mapping = new Mapping(responseDeclaration);
mapping.setDefaultValue(0d);
responseDeclaration.setMapping(mapping);
for(Map.Entry<Identifier, Double> entry:map.entrySet()) {
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(new IdentifierValue(entry.getKey()));
mapEntry.setMappedValue(entry.getValue());
mapping.getMapEntries().add(mapEntry);
}
return mapping;
}
public static Mapping appendPairMapping(ResponseDeclaration responseDeclaration, Map<DirectedPairValue,Double> map) {
Mapping mapping = new Mapping(responseDeclaration);
mapping.setDefaultValue(0d);
responseDeclaration.setMapping(mapping);
for(Map.Entry<DirectedPairValue, Double> entry:map.entrySet()) {
MapEntry mapEntry = new MapEntry(mapping);
mapEntry.setMapKey(entry.getKey());
mapEntry.setMappedValue(entry.getValue());
mapping.getMapEntries().add(mapEntry);
}
return mapping;
}
/**
* Create an outcome declaration with SCORE as identifier, single and float
* and 0 as default value.
*
* @param assessmentItem
* @return
*/
public static OutcomeDeclaration createOutcomeDeclarationForScore(AssessmentItem assessmentItem) {
OutcomeDeclaration scoreOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
scoreOutcomeDeclaration.setIdentifier(QTI21Constants.SCORE_IDENTIFIER);
scoreOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
scoreOutcomeDeclaration.setBaseType(BaseType.FLOAT);
DefaultValue scoreDefaultVal = new DefaultValue(scoreOutcomeDeclaration);
scoreOutcomeDeclaration.setDefaultValue(scoreDefaultVal);
FieldValue scoreDefaultFieldVal = new FieldValue(scoreDefaultVal, FloatValue.ZERO);
scoreDefaultVal.getFieldValues().add(scoreDefaultFieldVal);
return scoreOutcomeDeclaration;
}
/*
<outcomeDeclaration identifier="SCORE_RESPONSE_2" cardinality="single" baseType="float" view="testConstructor">
<defaultValue>
<value>0</value>
</defaultValue>
</outcomeDeclaration>
*/
public static OutcomeDeclaration createOutcomeDeclarationForScoreResponse(AssessmentItem assessmentItem, String scoreIdentifier) {
OutcomeDeclaration scoreOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
scoreOutcomeDeclaration.setIdentifier(Identifier.parseString(scoreIdentifier));
scoreOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
scoreOutcomeDeclaration.setBaseType(BaseType.FLOAT);
DefaultValue scoreDefaultVal = new DefaultValue(scoreOutcomeDeclaration);
scoreOutcomeDeclaration.setDefaultValue(scoreDefaultVal);
FieldValue scoreDefaultFieldVal = new FieldValue(scoreDefaultVal, FloatValue.ZERO);
scoreDefaultVal.getFieldValues().add(scoreDefaultFieldVal);
return scoreOutcomeDeclaration;
}
/**
* Rule which ensure that the final score is not above the max. score value.
*/
public static ResponseRule createMaxScoreBoundLimitRule(ResponseProcessing responseProcessing) {
/*
<responseCondition>
<responseIf>
<gt>
<variable identifier="SCORE" /><variable identifier="MAXSCORE" />
</gt>
<setOutcomeValue identifier="SCORE">
<variable identifier="MAXSCORE" />
</setOutcomeValue>
</responseIf>
</responseCondition>
*/
ResponseCondition rule = new ResponseCondition(responseProcessing);
ResponseIf responseIf = new ResponseIf(rule);
rule.setResponseIf(responseIf);
Gt gt = new Gt(responseIf);
responseIf.setExpression(gt);
Variable scoreVar = new Variable(gt);
scoreVar.setIdentifier(SCORE_CLX_IDENTIFIER);
gt.getExpressions().add(scoreVar);
Variable maxScoreVar = new Variable(gt);
maxScoreVar.setIdentifier(MAXSCORE_CLX_IDENTIFIER);
gt.getExpressions().add(maxScoreVar);
SetOutcomeValue setOutcomeValue = new SetOutcomeValue(responseIf);
setOutcomeValue.setIdentifier(SCORE_IDENTIFIER);
Variable maxScoreOutcomeVar = new Variable(setOutcomeValue);
maxScoreOutcomeVar.setIdentifier(MAXSCORE_CLX_IDENTIFIER);
setOutcomeValue.setExpression(maxScoreOutcomeVar);
responseIf.getResponseRules().add(setOutcomeValue);
return rule;
}
public static OutcomeDeclaration createOutcomeDeclarationForMaxScore(AssessmentItem assessmentItem, double maxScore) {
OutcomeDeclaration maxScoreOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
maxScoreOutcomeDeclaration.setIdentifier(QTI21Constants.MAXSCORE_IDENTIFIER);
maxScoreOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
maxScoreOutcomeDeclaration.setBaseType(BaseType.FLOAT);
DefaultValue maxScoreDefaultVal = new DefaultValue(maxScoreOutcomeDeclaration);
maxScoreOutcomeDeclaration.setDefaultValue(maxScoreDefaultVal);
FieldValue maxScoreDefaultFieldVal = new FieldValue(maxScoreDefaultVal, new FloatValue(maxScore));
maxScoreDefaultVal.getFieldValues().add(maxScoreDefaultFieldVal);
return maxScoreOutcomeDeclaration;
}
/**
* Rule which ensure that the final score is not under the min. score value.
*/
public static ResponseRule createMinScoreBoundLimitRule(ResponseProcessing responseProcessing) {
/*
<responseCondition>
<responseIf>
<lt>
<variable identifier="SCORE" /><variable identifier="MINSCORE" />
</lt>
<setOutcomeValue identifier="SCORE">
<variable identifier="MINSCORE" />
</setOutcomeValue>
</responseIf>
</responseCondition>
*/
ResponseCondition rule = new ResponseCondition(responseProcessing);
ResponseIf responseIf = new ResponseIf(rule);
rule.setResponseIf(responseIf);
Lt lt = new Lt(responseIf);
responseIf.setExpression(lt);
Variable scoreVar = new Variable(lt);
scoreVar.setIdentifier(SCORE_CLX_IDENTIFIER);
lt.getExpressions().add(scoreVar);
Variable minScoreVar = new Variable(lt);
minScoreVar.setIdentifier(MINSCORE_CLX_IDENTIFIER);
lt.getExpressions().add(minScoreVar);
SetOutcomeValue setOutcomeValue = new SetOutcomeValue(responseIf);
setOutcomeValue.setIdentifier(SCORE_IDENTIFIER);
Variable minScoreOutcomeVar = new Variable(setOutcomeValue);
minScoreOutcomeVar.setIdentifier(MINSCORE_CLX_IDENTIFIER);
setOutcomeValue.setExpression(minScoreOutcomeVar);
responseIf.getResponseRules().add(setOutcomeValue);
return rule;
}
public static OutcomeDeclaration createOutcomeDeclarationForMinScore(AssessmentItem assessmentItem, double minScore) {
OutcomeDeclaration maxScoreOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
maxScoreOutcomeDeclaration.setIdentifier(QTI21Constants.MINSCORE_IDENTIFIER);
maxScoreOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
maxScoreOutcomeDeclaration.setBaseType(BaseType.FLOAT);
List<View> views = new ArrayList<>();
views.add(View.TEST_CONSTRUCTOR);
maxScoreOutcomeDeclaration.setViews(views);
DefaultValue maxScoreDefaultVal = new DefaultValue(maxScoreOutcomeDeclaration);
maxScoreOutcomeDeclaration.setDefaultValue(maxScoreDefaultVal);
FieldValue maxScoreDefaultFieldVal = new FieldValue(maxScoreDefaultVal, new FloatValue(minScore));
maxScoreDefaultVal.getFieldValues().add(maxScoreDefaultFieldVal);
return maxScoreOutcomeDeclaration;
}
public static OutcomeDeclaration createOutcomeDeclarationForFeedbackBasic(AssessmentItem assessmentItem) {
OutcomeDeclaration feedbackOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
feedbackOutcomeDeclaration.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
feedbackOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
feedbackOutcomeDeclaration.setBaseType(BaseType.IDENTIFIER);
DefaultValue feedbackDefaultVal = new DefaultValue(feedbackOutcomeDeclaration);
feedbackOutcomeDeclaration.setDefaultValue(feedbackDefaultVal);
FieldValue feedbackDefaultFieldVal = new FieldValue(feedbackDefaultVal, new IdentifierValue("none"));
feedbackDefaultVal.getFieldValues().add(feedbackDefaultFieldVal);
List<View> views = new ArrayList<>();
views.add(View.TEST_CONSTRUCTOR);
feedbackOutcomeDeclaration.setViews(views);
return feedbackOutcomeDeclaration;
}
public static OutcomeDeclaration createOutcomeDeclarationForHint(AssessmentItem assessmentItem) {
OutcomeDeclaration feedbackOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
feedbackOutcomeDeclaration.setIdentifier(QTI21Constants.HINT_FEEDBACKMODAL_IDENTIFIER);
feedbackOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
feedbackOutcomeDeclaration.setBaseType(BaseType.IDENTIFIER);
return feedbackOutcomeDeclaration;
}
public static OutcomeDeclaration createOutcomeDeclarationForFeedbackModal(AssessmentItem assessmentItem) {
OutcomeDeclaration feedbackOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
feedbackOutcomeDeclaration.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER);
feedbackOutcomeDeclaration.setCardinality(Cardinality.MULTIPLE);
feedbackOutcomeDeclaration.setBaseType(BaseType.IDENTIFIER);
List<View> views = new ArrayList<>();
views.add(View.TEST_CONSTRUCTOR);
feedbackOutcomeDeclaration.setViews(views);
return feedbackOutcomeDeclaration;
}
public static OutcomeDeclaration createOutcomeDeclarationForCorrectSolutionFeedbackModal(AssessmentItem assessmentItem) {
OutcomeDeclaration feedbackOutcomeDeclaration = new OutcomeDeclaration(assessmentItem);
feedbackOutcomeDeclaration.setIdentifier(QTI21Constants.CORRECT_SOLUTION_IDENTIFIER);
feedbackOutcomeDeclaration.setCardinality(Cardinality.SINGLE);
feedbackOutcomeDeclaration.setBaseType(BaseType.IDENTIFIER);
List<View> views = new ArrayList<>();
views.add(View.TEST_CONSTRUCTOR);
feedbackOutcomeDeclaration.setViews(views);
return feedbackOutcomeDeclaration;
}
public static ChoiceInteraction createSingleChoiceInteraction(AssessmentItem assessmentItem, Identifier responseDeclarationId,
Orientation orientation, List<String> classAtrr) {
ChoiceInteraction choiceInteraction = new ChoiceInteraction(assessmentItem.getItemBody());
choiceInteraction.setMaxChoices(1);
choiceInteraction.setShuffle(true);
if(orientation != null) {
choiceInteraction.setOrientation(orientation);
}
choiceInteraction.setResponseIdentifier(responseDeclarationId);
if(classAtrr != null && classAtrr.size() > 0) {
choiceInteraction.setClassAttr(classAtrr);
}
PromptGroup prompts = new PromptGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(prompts);
SimpleChoiceGroup singleChoices = new SimpleChoiceGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(singleChoices);
return choiceInteraction;
}
public static ChoiceInteraction createMultipleChoiceInteraction(AssessmentItem assessmentItem, Identifier responseDeclarationId,
Orientation orientation, List<String> classAtrr) {
ChoiceInteraction choiceInteraction = new ChoiceInteraction(assessmentItem.getItemBody());
choiceInteraction.setMaxChoices(0);
choiceInteraction.setShuffle(true);
if(orientation != null) {
choiceInteraction.setOrientation(orientation);
}
if(classAtrr != null && classAtrr.size() > 0) {
choiceInteraction.setClassAttr(classAtrr);
}
choiceInteraction.setResponseIdentifier(responseDeclarationId);
PromptGroup prompts = new PromptGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(prompts);
SimpleChoiceGroup singleChoices = new SimpleChoiceGroup(choiceInteraction);
choiceInteraction.getNodeGroups().add(singleChoices);
return choiceInteraction;
}
public static void ensureFeedbackBasicOutcomeDeclaration(AssessmentItem assessmentItem) {
OutcomeDeclaration feedbackBasicDeclaration = assessmentItem.getOutcomeDeclaration(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
if(feedbackBasicDeclaration == null) {
feedbackBasicDeclaration = createOutcomeDeclarationForFeedbackBasic(assessmentItem);
assessmentItem.getOutcomeDeclarations().add(feedbackBasicDeclaration);
}
}
public static ModalFeedback createModalFeedback(AssessmentItem assessmentItem, Identifier identifier, String title, String text) {
return createModalFeedback(assessmentItem, QTI21Constants.FEEDBACKMODAL_IDENTIFIER, identifier, title, text);
}
public static ModalFeedback createModalFeedback(AssessmentItem assessmentItem, Identifier outcomeIdentifier, Identifier identifier,
String title, String text) {
/*
<modalFeedback identifier="Feedback1041659806" outcomeIdentifier="FEEDBACKMODAL" showHide="show" title="Wrong answer">
<p>Feedback answer</p>
</modalFeedback>
*/
ModalFeedback modalFeedback = new ModalFeedback(assessmentItem);
modalFeedback.setIdentifier(identifier);
modalFeedback.setOutcomeIdentifier(outcomeIdentifier);
modalFeedback.setVisibilityMode(VisibilityMode.parseVisibilityMode("show"));
modalFeedback.getAttributes().getStringAttribute(ModalFeedback.ATTR_TITLE_NAME).setValue(title);
new AssessmentHtmlBuilder().appendHtml(modalFeedback, text);
/*List<Block> blocks = new AssessmentHTMLBuilder().parseHtml(text);
for(Block block:blocks) {
if(block instanceof FlowStatic) {
modalFeedback.getFlowStatics().add((FlowStatic)block);
}
}*/
return modalFeedback;
}
public static ResponseCondition createModalFeedbackBasicRule(ResponseProcessing responseProcessing,
Identifier feedbackIdentifier, String inCorrect, boolean hint) {
ResponseCondition rule = new ResponseCondition(responseProcessing);
/*
<responseIf>
<and>
<match>
<baseValue baseType="identifier">correct</baseValue>
<variable identifier="FEEDBACKBASIC" />
</match>
</and>
<setOutcomeValue identifier="FEEDBACKMODAL">
<multiple>
<variable identifier="FEEDBACKMODAL" />
<baseValue baseType="identifier">Feedback261171147</baseValue>
</multiple>
</setOutcomeValue>
</responseIf>
*/
ResponseIf responseIf = new ResponseIf(rule);
rule.setResponseIf(responseIf);
{//rule
And and = new And(responseIf);
responseIf.getExpressions().add(and);
Match match = new Match(and);
and.getExpressions().add(match);
BaseValue feedbackVal = new BaseValue(match);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue(inCorrect));
match.getExpressions().add(feedbackVal);
Variable variable = new Variable(match);
variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKBASIC));
match.getExpressions().add(variable);
//not match the HINT
if(hint) {
IsNull isNull = new IsNull(and);
and.getExpressions().add(isNull);
Variable hintVar = new Variable(isNull);
hintVar.setIdentifier(QTI21Constants.HINT_FEEDBACKMODAL_CLX_IDENTIFIER);
isNull.getExpressions().add(hintVar);
}
}
{//outcome
SetOutcomeValue feedbackVar = new SetOutcomeValue(responseIf);
feedbackVar.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER);
Multiple multiple = new Multiple(feedbackVar);
feedbackVar.setExpression(multiple);
Variable variable = new Variable(multiple);
variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKMODAL));
multiple.getExpressions().add(variable);
BaseValue feedbackVal = new BaseValue(feedbackVar);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue(feedbackIdentifier));
multiple.getExpressions().add(feedbackVal);
responseIf.getResponseRules().add(feedbackVar);
}
return rule;
}
/**
* Generate the special case for "correct solution" feedback which is almost the same as
* incorrect feedback.
*
* @param responseProcessing
* @param feedbackIdentifier
* @return
*/
public static ResponseCondition createCorrectSolutionModalFeedbackBasicRule(ResponseProcessing responseProcessing,
Identifier correctSolutionFeedbackIdentifier, Identifier incorrectFeedbackIdentifier, boolean hint) {
ResponseCondition rule = new ResponseCondition(responseProcessing);
/*
<responseIf>
<and>
<match>
<baseValue baseType="identifier">incorrect</baseValue>
<variable identifier="FEEDBACKBASIC" />
</match>
</and>
<setOutcomeValue identifier="FEEDBACKMODAL">
<multiple>
<variable identifier="FEEDBACKMODAL" />
<baseValue baseType="identifier">Feedback261171147</baseValue>
</multiple>
</setOutcomeValue>
<setOutcomeValue identifier="SOLUTIONMODAL">
<baseValue baseType="identifier">Feedback261171147</baseValue>
</setOutcomeValue>
</responseIf>
*/
ResponseIf responseIf = new ResponseIf(rule);
rule.setResponseIf(responseIf);
{//rule
And and = new And(responseIf);
responseIf.getExpressions().add(and);
Match match = new Match(and);
and.getExpressions().add(match);
BaseValue feedbackVal = new BaseValue(match);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue(QTI21Constants.INCORRECT));
match.getExpressions().add(feedbackVal);
Variable variable = new Variable(match);
variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKBASIC));
match.getExpressions().add(variable);
//not match the HINT
if(hint) {
IsNull isNull = new IsNull(and);
and.getExpressions().add(isNull);
Variable hintVar = new Variable(isNull);
hintVar.setIdentifier(QTI21Constants.HINT_FEEDBACKMODAL_CLX_IDENTIFIER);
isNull.getExpressions().add(hintVar);
}
}
if(incorrectFeedbackIdentifier != null) {//outcome incorrect
SetOutcomeValue feedbackVar = new SetOutcomeValue(responseIf);
feedbackVar.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER);
Multiple multiple = new Multiple(feedbackVar);
feedbackVar.setExpression(multiple);
Variable variable = new Variable(multiple);
variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKMODAL));
multiple.getExpressions().add(variable);
BaseValue feedbackVal = new BaseValue(feedbackVar);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue(incorrectFeedbackIdentifier));
multiple.getExpressions().add(feedbackVal);
responseIf.getResponseRules().add(feedbackVar);
}
if(correctSolutionFeedbackIdentifier != null) {//outcome correct solution
SetOutcomeValue feedbackVar = new SetOutcomeValue(responseIf);
feedbackVar.setIdentifier(QTI21Constants.CORRECT_SOLUTION_IDENTIFIER);
BaseValue feedbackVal = new BaseValue(feedbackVar);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue(correctSolutionFeedbackIdentifier));
feedbackVar.getExpressions().add(feedbackVal);
responseIf.getResponseRules().add(feedbackVar);
}
return rule;
}
public static ResponseProcessing createResponseProcessing(AssessmentItem assessmentItem, Identifier responseId) {
ResponseProcessing responseProcessing = new ResponseProcessing(assessmentItem);
ResponseCondition rule = new ResponseCondition(responseProcessing);
//if no response
ResponseIf responseIf = new ResponseIf(rule);
rule.setResponseIf(responseIf);
IsNull isNull = new IsNull(responseIf);
responseIf.getExpressions().add(isNull);
Variable variable = new Variable(isNull);
variable.setIdentifier(ComplexReferenceIdentifier.parseString(responseId.toString()));
isNull.getExpressions().add(variable);
{
SetOutcomeValue feedbackVar = new SetOutcomeValue(responseIf);
feedbackVar.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
BaseValue feedbackVal = new BaseValue(feedbackVar);
feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
feedbackVal.setSingleValue(new IdentifierValue("empty"));
feedbackVar.setExpression(feedbackVal);
responseIf.getResponseRules().add(feedbackVar);
}
//else if correct response
ResponseElseIf responseElseIf = new ResponseElseIf(rule);
rule.getResponseElseIfs().add(responseElseIf);
//match
{
Match match = new Match(responseElseIf);
responseElseIf.getExpressions().add(match);
Variable responseVar = new Variable(match);
responseVar.setIdentifier(ComplexReferenceIdentifier.parseString(responseId.toString()));
match.getExpressions().add(responseVar);
Correct correct = new Correct(match);
correct.setIdentifier(ComplexReferenceIdentifier.parseString(responseId.toString()));
match.getExpressions().add(correct);
}
// outcome score
{
SetOutcomeValue scoreOutcomeVar = new SetOutcomeValue(responseIf);
scoreOutcomeVar.setIdentifier(QTI21Constants.SCORE_IDENTIFIER);
responseElseIf.getResponseRules().add(scoreOutcomeVar);
Sum sum = new Sum(scoreOutcomeVar);
scoreOutcomeVar.getExpressions().add(sum);
Variable scoreVar = new Variable(sum);
scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER);
sum.getExpressions().add(scoreVar);
Variable maxScoreVar = new Variable(sum);
maxScoreVar.setIdentifier(QTI21Constants.MAXSCORE_CLX_IDENTIFIER);
sum.getExpressions().add(maxScoreVar);
}
// outcome feedback
{
SetOutcomeValue correctFeedbackVar = new SetOutcomeValue(responseIf);
correctFeedbackVar.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
BaseValue correctFeedbackVal = new BaseValue(correctFeedbackVar);
correctFeedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
correctFeedbackVal.setSingleValue(QTI21Constants.CORRECT_IDENTIFIER_VALUE);
correctFeedbackVar.setExpression(correctFeedbackVal);
responseElseIf.getResponseRules().add(correctFeedbackVar);
}
// else failed
ResponseElse responseElse = new ResponseElse(rule);
rule.setResponseElse(responseElse);
{// feedback incorrect
SetOutcomeValue incorrectFeedbackVar = new SetOutcomeValue(responseIf);
incorrectFeedbackVar.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
BaseValue incorrectFeedbackVal = new BaseValue(incorrectFeedbackVar);
incorrectFeedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER);
incorrectFeedbackVal.setSingleValue(QTI21Constants.INCORRECT_IDENTIFIER_VALUE);
incorrectFeedbackVar.setExpression(incorrectFeedbackVal);
responseElse.getResponseRules().add(incorrectFeedbackVar);
}
responseProcessing.getResponseRules().add(rule);
return responseProcessing;
}
/**
* This generate a response rule which compare the max score and the score
* to set the feedback as "correct".
*
<responseCondition>
<responseIf>
<and>
<not>
<match>
<variable identifier="FEEDBACKBASIC" />
<baseValue baseType="identifier">empty</baseValue>
</match>
</not>
<equal toleranceMode="exact">
<variable identifier="SCORE" />
<variable identifier="MAXSCORE" />
</equal>
</and>
<setOutcomeValue identifier="FEEDBACKBASIC">
<baseValue baseType="identifier">correct</baseValue>
</setOutcomeValue>
</responseIf>
</responseCondition>
*/
public static ResponseCondition createModalFeedbackResponseConditionByScore(ResponseProcessing responseProcessing) {
ResponseCondition responseCondition = new ResponseCondition(responseProcessing);
ResponseIf responseIf = new ResponseIf(responseCondition);
responseCondition.setResponseIf(responseIf);
And and = new And(responseIf);
responseIf.getExpressions().add(and);
Not not = new Not(and);
and.getExpressions().add(not);
Match match = new Match(not);
not.getExpressions().add(match);
Variable feedbackbasicVar = new Variable(match);
feedbackbasicVar.setIdentifier(QTI21Constants.FEEDBACKBASIC_CLX_IDENTIFIER);
match.getExpressions().add(feedbackbasicVar);
BaseValue emptyValue = new BaseValue(match);
emptyValue.setBaseTypeAttrValue(BaseType.IDENTIFIER);
emptyValue.setSingleValue(QTI21Constants.EMPTY_IDENTIFIER_VALUE);
match.getExpressions().add(emptyValue);
//SCORE >= MAXSCORE ( > is for security and special case where the max score is smalle than the sum of correct answers)
Gte greaterOrEqual = new Gte(and);
and.getExpressions().add(greaterOrEqual);
Variable scoreVar = new Variable(greaterOrEqual);
scoreVar.setIdentifier(QTI21Constants.SCORE_CLX_IDENTIFIER);
greaterOrEqual.getExpressions().add(scoreVar);
Variable maxScoreVar = new Variable(greaterOrEqual);
maxScoreVar.setIdentifier(QTI21Constants.MAXSCORE_CLX_IDENTIFIER);
greaterOrEqual.getExpressions().add(maxScoreVar);
//outcome value
SetOutcomeValue correctOutcomeValue = new SetOutcomeValue(responseIf);
correctOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKBASIC_IDENTIFIER);
responseIf.getResponseRules().add(correctOutcomeValue);
BaseValue correctValue = new BaseValue(correctOutcomeValue);
correctValue.setBaseTypeAttrValue(BaseType.IDENTIFIER);
correctValue.setSingleValue(QTI21Constants.CORRECT_IDENTIFIER_VALUE);
correctOutcomeValue.setExpression(correctValue);
return responseCondition;
}
public static P getParagraph(QtiNode parent, String content) {
P paragraph = new P(parent);
TextRun text = new TextRun(paragraph, content);
paragraph.getInlines().add(text);
return paragraph;
}
public static String coordsString(List<Integer> coords) {
StringBuilder sb = new StringBuilder();
if(coords != null && coords.size() > 0) {
for(Integer coord:coords) {
if(sb.length() > 0) sb.append(",");
sb.append(coord.intValue());
}
}
return sb.toString();
}
public static List<Integer> coordsList(String coords) {
List<Integer> list = new ArrayList<>();
if(StringHelper.containsNonWhitespace(coords)) {
for(StringTokenizer tokenizer = new StringTokenizer(coords, ","); tokenizer.hasMoreElements(); ) {
String coord = tokenizer.nextToken();
list.add(new Integer(Math.round(Float.parseFloat(coord))));
}
}
return list;
}
}