Index: lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java,v diff -u -r1.3 -r1.4 --- lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java 27 Mar 2014 12:36:27 -0000 1.3 +++ lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java 29 Mar 2014 07:37:32 -0000 1.4 @@ -193,6 +193,10 @@ || Question.QUESTION_TYPE_TRUE_FALSE.equals(question.getType()) || Question.QUESTION_TYPE_MULTIPLE_RESPONSE.equals(question.getType())) { itemElem = exportMultipleChoiceQuestion(question); + } else if (Question.QUESTION_TYPE_FILL_IN_BLANK.equals(question.getType())) { + itemElem = exportFillInBlankQuestion(question); + } else if (Question.QUESTION_TYPE_MATCHING.equals(question.getType())) { + itemElem = exportMatchingPairsQuestion(question); } else if (Question.QUESTION_TYPE_ESSAY.equals(question.getType())) { itemElem = exportEssayQuestion(question); } @@ -345,6 +349,112 @@ } /** + * Creates a XML element with contents of a single matchin pairs question. + */ + private Element exportMatchingPairsQuestion(Question question) { + Element itemElem = doc.createElement("item"); + itemElem.setAttribute("title", question.getTitle()); + itemId++; + itemElem.setAttribute("ident", "QUE_" + itemId); + + // QTI metadata indicating that this is a matching pairs question + Element itemmetadataElem = (Element) itemElem.appendChild(doc.createElement("itemmetadata")); + Element itemtypeElem = (Element) itemmetadataElem.appendChild(doc.createElement("qmd_itemtype")); + itemtypeElem.setTextContent("Matching"); + + // question text + Element presentationElem = (Element) itemElem.appendChild(doc.createElement("presentation")); + if (!StringUtils.isBlank(question.getText())) { + Element materialElem = (Element) presentationElem.appendChild(doc.createElement("material")); + appendMaterialElements(materialElem, question.getText()); + } + + int answerIndex = 0; + List matchAnswerIdents = new ArrayList(question.getAnswers().size()); + List respconditionElems = new ArrayList(question.getAnswers().size()); + for (Answer answer : question.getAnswers()) { + itemId++; + String responseLidIdentifier = "QUE_" + itemId + "_RL"; + Element responseLidElem = (Element) presentationElem.appendChild(doc.createElement("response_lid")); + responseLidElem.setAttribute("ident", responseLidIdentifier); + // answer text + Element materialElem = (Element) responseLidElem.appendChild(doc.createElement("material")); + appendMaterialElements(materialElem, answer.getText()); + + Element renderchoiceElem = (Element) responseLidElem.appendChild(doc.createElement("render_choice")); + renderchoiceElem.setAttribute("shuffle", "No"); + + // find matching answers + int matchAnswerIndex = 0; + for (Answer matchAnswer : question.getMatchAnswers()) { + Element responselabelElem = (Element) renderchoiceElem.appendChild(doc.createElement("response_label")); + + // repeat each matchin answer for each answer, keeping the same IDs + String matchAnswerIdent = null; + if (matchAnswerIdents.size() > matchAnswerIndex) { + matchAnswerIdent = matchAnswerIdents.get(matchAnswerIndex); + } else { + itemId++; + matchAnswerIdent = "QUE_" + itemId + "_A" + (matchAnswerIndex + 1); + matchAnswerIdents.add(matchAnswerIdent); + } + responselabelElem.setAttribute("ident", matchAnswerIdent); + + materialElem = (Element) responselabelElem.appendChild(doc.createElement("material")); + appendMaterialElements(materialElem, matchAnswer.getText()); + + if (matchAnswerIndex == question.getMatchMap().get(answerIndex)) { + Element respconditionElem = doc.createElement("respcondition"); + respconditionElem.setAttribute("title", "Matching " + responseLidIdentifier + " Resp Condition 1"); + Element conditionvarElem = (Element) respconditionElem.appendChild(doc + .createElement("conditionvar")); + Element varequalElem = (Element) conditionvarElem.appendChild(doc.createElement("varequal")); + varequalElem.setAttribute("respident", responseLidIdentifier); + varequalElem.setTextContent(matchAnswerIdent); + + Element setvarElem = (Element) respconditionElem.appendChild(doc.createElement("setvar")); + setvarElem.setAttribute("varname", "que_score"); + setvarElem.setAttribute("action", "Add"); + setvarElem.setTextContent(String.valueOf(answer.getScore())); + + respconditionElems.add(respconditionElem); + } + + matchAnswerIndex++; + } + + answerIndex++; + } + + Element resprocessingElem = (Element) itemElem.appendChild(doc.createElement("resprocessing")); + Element outcomesElem = (Element) resprocessingElem.appendChild(doc.createElement("outcomes")); + Element decvarElem = (Element) outcomesElem.appendChild(doc.createElement("decvar")); + decvarElem.setAttribute("vartype", "decimal"); + decvarElem.setAttribute("defaultval", "0"); + decvarElem.setAttribute("varname", "que_score"); + + for (Element respconditionElem : respconditionElems) { + resprocessingElem.appendChild(respconditionElem); + } + + // just a single feedback element + if (!StringUtils.isBlank(question.getFeedback())) { + Element overallFeedbackElem = createFeedbackElem("_ALL", question.getFeedback(), "All"); + + Element respconditionElem = (Element) resprocessingElem.appendChild(doc.createElement("respcondition")); + Element conditionvarElem = (Element) respconditionElem.appendChild(doc.createElement("conditionvar")); + conditionvarElem.appendChild(doc.createElement("other")); + Element displayfeedbackElem = (Element) respconditionElem.appendChild(doc.createElement("displayfeedback")); + displayfeedbackElem.setAttribute("feedbacktype", "Response"); + displayfeedbackElem.setAttribute("linkrefid", overallFeedbackElem.getAttribute("ident")); + + itemElem.appendChild(overallFeedbackElem); + } + + return itemElem; + } + + /** * Creates a XML element with contents of a single essay question. */ private Element exportEssayQuestion(Question question) { @@ -392,6 +502,74 @@ } /** + * Creates a XML element with contents of a single fill in blanks question. + */ + private Element exportFillInBlankQuestion(Question question) { + Element itemElem = doc.createElement("item"); + itemElem.setAttribute("title", question.getTitle()); + itemId++; + itemElem.setAttribute("ident", "QUE_" + itemId); + + // question text + Element presentationElem = (Element) itemElem.appendChild(doc.createElement("presentation")); + if (!StringUtils.isBlank(question.getText())) { + Element materialElem = (Element) presentationElem.appendChild(doc.createElement("material")); + appendMaterialElements(materialElem, question.getText()); + } + + // just a single response element + itemId++; + Element responseStrElem = (Element) presentationElem.appendChild(doc.createElement("response_str")); + responseStrElem.setAttribute("ident", "QUE_" + itemId + "_RS"); + Element renderFibElem = (Element) responseStrElem.appendChild(doc.createElement("render_fib")); + renderFibElem.setAttribute("fibtype", "String"); + renderFibElem.setAttribute("prompt", "Box"); + itemId++; + Element responseLabelElem = (Element) renderFibElem.appendChild(doc.createElement("response_label")); + responseLabelElem.setAttribute("ident", "QUE_" + itemId + "_ANS"); + + // just a single feedback element + Element overallFeedbackElem = null; + if (!StringUtils.isBlank(question.getFeedback())) { + overallFeedbackElem = createFeedbackElem("_ALL", question.getFeedback(), "All"); + } + + Element resprocessingElem = (Element) itemElem.appendChild(doc.createElement("resprocessing")); + Element outcomesElem = (Element) resprocessingElem.appendChild(doc.createElement("outcomes")); + Element decvarElem = (Element) outcomesElem.appendChild(doc.createElement("decvar")); + decvarElem.setAttribute("vartype", "decimal"); + decvarElem.setAttribute("defaultval", "0"); + decvarElem.setAttribute("varname", "que_score"); + + for (Answer answer : question.getAnswers()) { + // mark which answer is correct by setting score for each of them + Element respconditionElem = (Element) resprocessingElem.appendChild(doc.createElement("respcondition")); + Element conditionvarElem = (Element) respconditionElem.appendChild(doc.createElement("conditionvar")); + Element varequalElem = (Element) conditionvarElem.appendChild(doc.createElement("varequal")); + varequalElem.setAttribute("respident", responseStrElem.getAttribute("ident")); + varequalElem.setTextContent(answer.getText()); + + Element setvarElem = (Element) respconditionElem.appendChild(doc.createElement("setvar")); + setvarElem.setAttribute("varname", "que_score"); + setvarElem.setAttribute("action", "Add"); + setvarElem.setTextContent(String.valueOf(answer.getScore())); + + if (overallFeedbackElem != null) { + Element displayfeedbackElem = (Element) respconditionElem.appendChild(doc + .createElement("displayfeedback")); + displayfeedbackElem.setAttribute("feedbacktype", "Response"); + displayfeedbackElem.setAttribute("linkrefid", overallFeedbackElem.getAttribute("ident")); + } + } + + if (overallFeedbackElem != null) { + itemElem.appendChild(overallFeedbackElem); + } + + return itemElem; + } + + /** * Creates a feedback XML element. */ private Element createFeedbackElem(String labelSuffix, String feedback, String type) { Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java,v diff -u -r1.28 -r1.29 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java 27 Mar 2014 12:36:26 -0000 1.28 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java 29 Mar 2014 07:37:34 -0000 1.29 @@ -40,6 +40,7 @@ import java.util.Map; import java.util.Set; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; import javax.servlet.ServletException; @@ -586,8 +587,10 @@ // options are different depending on the type if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType()) || Question.QUESTION_TYPE_FILL_IN_BLANK.equals(question.getType())) { + boolean isMultipleChoice = Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType()); + // setting answers is very similar in both types, so they were put together here - if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType())) { + if (isMultipleChoice) { assessmentQuestion.setType(AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE); assessmentQuestion.setMultipleAnswersAllowed(false); assessmentQuestion.setShuffle(false); @@ -615,10 +618,11 @@ assessmentAnswer.setFeedback(answer.getFeedback()); if ((answer.getScore() != null) && (answer.getScore() > 0)) { - if (correctAnswer == null) { + // for fill in blanks question all answers are correct and get full grade + if (!isMultipleChoice || correctAnswer == null) { // whatever the correct answer holds, it becomes the question score questionGrade = new Double(Math.ceil(answer.getScore())).intValue(); - // 100% goes to single correct answer + // 100% goes to the correct answer assessmentAnswer.setGrade(1); correctAnswer = answerText; } else { @@ -781,6 +785,7 @@ switch (assessmentQuestion.getType()) { case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE: + if (assessmentQuestion.isMultipleAnswersAllowed()) { question.setType(Question.QUESTION_TYPE_MULTIPLE_RESPONSE); int correctAnswerCount = 0; @@ -808,6 +813,7 @@ answers.add(assessmentAnswer.getSequenceId(), answer); } + } else { question.setType(Question.QUESTION_TYPE_MULTIPLE_CHOICE); @@ -824,7 +830,21 @@ answers.add(assessmentAnswer.getSequenceId(), answer); } } + break; + case AssessmentConstants.QUESTION_TYPE_SHORT_ANSWER: + question.setType(Question.QUESTION_TYPE_FILL_IN_BLANK); + + for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getQuestionOptions()) { + // only answer which has more than 0% is considered a correct one + if (assessmentAnswer.getGrade() > 0) { + Answer answer = new Answer(); + answer.setText(assessmentAnswer.getOptionString()); + answer.setScore(new Integer(assessmentQuestion.getDefaultGrade()).floatValue()); + + answers.add(answer); + } + } break; case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE: @@ -846,16 +866,38 @@ falseAnswer.setFeedback(!isTrueCorrect ? assessmentQuestion.getFeedbackOnCorrect() : assessmentQuestion .getFeedbackOnIncorrect()); answers.add(falseAnswer); + break; + case AssessmentConstants.QUESTION_TYPE_MATCHING_PAIRS: + question.setType(Question.QUESTION_TYPE_MATCHING); + + int answerIndex = 0; + float score = assessmentQuestion.getDefaultGrade() / assessmentQuestion.getQuestionOptions().size(); + question.setMatchAnswers(new ArrayList(assessmentQuestion.getQuestionOptions().size())); + question.setMatchMap(new TreeMap()); + for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getQuestionOptions()) { + Answer answer = new Answer(); + + answer.setText(assessmentAnswer.getQuestion()); + answer.setScore(score); + answer.setFeedback(assessmentAnswer.getFeedback()); + answers.add(answer); + + Answer matchingAnswer = new Answer(); + matchingAnswer.setText(assessmentAnswer.getOptionString()); + question.getMatchAnswers().add(matchingAnswer); + question.getMatchMap().put(answerIndex, answerIndex); + answerIndex++; + } + break; - + case AssessmentConstants.QUESTION_TYPE_ESSAY: // not much to do with essay question.setType(Question.QUESTION_TYPE_ESSAY); answers = null; - break; - + default: continue; }