Index: lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java
===================================================================
diff -u -r0cf1ce0d39dab80bbb0e11968010c727f5e002e4 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java (.../QuestionExporter.java) (revision 0cf1ce0d39dab80bbb0e11968010c727f5e002e4)
+++ lams_common/src/java/org/lamsfoundation/lams/questions/QuestionExporter.java (.../QuestionExporter.java) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -126,8 +126,8 @@
* @return Path to the created ZIP file
*/
public String exportQTIPackage() {
- if (log.isDebugEnabled()) {
- log.debug("Exporting QTI ZIP package \"" + packageTitle + "\"");
+ if (QuestionExporter.log.isDebugEnabled()) {
+ QuestionExporter.log.debug("Exporting QTI ZIP package \"" + packageTitle + "\"");
}
try {
String rootDir = FileUtil.createTempDirectory(QuestionExporter.EXPORT_TEMP_FOLDER_SUFFIX);
@@ -189,12 +189,16 @@
for (Question question : questions) {
Element itemElem = null;
- if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType())) {
+ if (Question.QUESTION_TYPE_MULTIPLE_CHOICE.equals(question.getType())
+ || Question.QUESTION_TYPE_TRUE_FALSE.equals(question.getType())
+ || Question.QUESTION_TYPE_MULTIPLE_RESPONSE.equals(question.getType())) {
itemElem = exportMultipleChoiceQuestion(question);
+ } else if (Question.QUESTION_TYPE_ESSAY.equals(question.getType())) {
+ itemElem = exportEssayQuestion(question);
}
if (itemElem == null) {
- QuestionExporter.log.warn("Unknow type \"" + question.getType() + " of question \""
+ QuestionExporter.log.warn("Unknow type \"" + question.getType() + "\" of question \""
+ question.getTitle() + "\"");
} else {
sectionElem.appendChild(itemElem);
@@ -205,7 +209,7 @@
}
/**
- * Creates a XML element with contents of a single multiple choice question.
+ * Creates a XML element with contents of a single multiple choice or true/false or multiple response question.
*/
private Element exportMultipleChoiceQuestion(Question question) {
Element itemElem = doc.createElement("item");
@@ -224,15 +228,17 @@
String responseLidIdentifier = "QUE_" + itemId + "_RL";
Element responseLidElem = (Element) presentationElem.appendChild(doc.createElement("response_lid"));
responseLidElem.setAttribute("ident", responseLidIdentifier);
- responseLidElem.setAttribute("rcardinality", "Single");
+ responseLidElem.setAttribute("rcardinality",
+ Question.QUESTION_TYPE_MULTIPLE_RESPONSE.equals(question.getType()) ? "Multiple" : "Single");
responseLidElem.setAttribute("rtiming", "No");
// question feedback (displayed no matter what answer was choosed)
List feedbackList = new ArrayList();
+ String correctFeedbackLabel = null;
String incorrectFeedbackLabel = null;
Element overallFeedbackElem = null;
if (!StringUtils.isBlank(question.getFeedback())) {
- overallFeedbackElem = createFeedbackElem("_ALL", question.getFeedback());
+ overallFeedbackElem = createFeedbackElem("_ALL", question.getFeedback(), "All");
feedbackList.add(overallFeedbackElem);
}
@@ -242,6 +248,23 @@
// iterate through answers, collecting some info along the way
for (Answer answer : question.getAnswers()) {
+ // just labels for feedback for correct/incorrect answer
+ boolean isCorrect = answer.getScore() > 0;
+ if (!StringUtils.isBlank(answer.getFeedback())) {
+ if (!isCorrect && (incorrectFeedbackLabel == null)) {
+ Element feedbackElem = createFeedbackElem("_IC", answer.getFeedback(), "Candidate");
+ feedbackList.add(feedbackElem);
+ incorrectFeedbackLabel = feedbackElem.getAttribute("ident");
+ } else if (isCorrect && (correctFeedbackLabel == null)) {
+ Element feedbackElem = createFeedbackElem("_C", answer.getFeedback(), "Candidate");
+ feedbackList.add(feedbackElem);
+ correctFeedbackLabel = feedbackElem.getAttribute("ident");
+ }
+ }
+ }
+
+ // proper iteration
+ for (Answer answer : question.getAnswers()) {
Element responseLabelElem = (Element) renderChoiceElem.appendChild(doc.createElement("response_label"));
itemId++;
answerId++;
@@ -254,37 +277,27 @@
appendMaterialElements(materialElem, answer.getText());
}
- // just labels for feedback for correct/incorrect answer
- boolean isCorrect = answer.getScore() > 0;
- Element feedbackElem = null;
- if (!StringUtils.isBlank(answer.getFeedback())) {
- feedbackElem = createFeedbackElem((isCorrect ? "_C" : "_IC"), answer.getFeedback());
- feedbackList.add(feedbackElem);
-
- if (!isCorrect && (incorrectFeedbackLabel == null)) {
- incorrectFeedbackLabel = feedbackElem.getAttribute("ident");
- }
- }
-
// mark which answer is correct by setting score for each of them
Element respconditionElem = doc.createElement("respcondition");
Element conditionvarElem = (Element) respconditionElem.appendChild(doc.createElement("conditionvar"));
Element varequalElem = (Element) conditionvarElem.appendChild(doc.createElement("varequal"));
varequalElem.setAttribute("respident", responseLidIdentifier);
varequalElem.setTextContent(answerLabel);
+ boolean isCorrect = answer.getScore() > 0;
Element setvarElem = (Element) respconditionElem.appendChild(doc.createElement("setvar"));
setvarElem.setAttribute("varname", "que_score");
- setvarElem.setAttribute("action", isCorrect ? "Set" : "Add");
+ setvarElem.setAttribute("action",
+ isCorrect && !Question.QUESTION_TYPE_MULTIPLE_RESPONSE.equals(question.getType()) ? "Set" : "Add");
setvarElem.setTextContent(String.valueOf(answer.getScore()));
// link feedback for correct/incorrect answer
- if (feedbackElem != null) {
+ if (isCorrect) {
Element displayfeedbackElem = (Element) respconditionElem.appendChild(doc
.createElement("displayfeedback"));
displayfeedbackElem.setAttribute("feedbacktype", "Response");
- displayfeedbackElem.setAttribute("linkrefid", feedbackElem.getAttribute("ident"));
- } else if (!isCorrect && (incorrectFeedbackLabel != null)) {
+ displayfeedbackElem.setAttribute("linkrefid", correctFeedbackLabel);
+ } else {
Element displayfeedbackElem = (Element) respconditionElem.appendChild(doc
.createElement("displayfeedback"));
displayfeedbackElem.setAttribute("feedbacktype", "Response");
@@ -304,7 +317,7 @@
if (overallFeedbackElem != null) {
Element respconditionElem = doc.createElement("respcondition");
Element conditionvarElem = (Element) respconditionElem.appendChild(doc.createElement("conditionvar"));
- conditionvarElem.appendChild(doc.createElement("elem"));
+ conditionvarElem.appendChild(doc.createElement("other"));
Element displayfeedbackElem = (Element) respconditionElem.appendChild(doc.createElement("displayfeedback"));
displayfeedbackElem.setAttribute("feedbacktype", "Response");
displayfeedbackElem.setAttribute("linkrefid", overallFeedbackElem.getAttribute("ident"));
@@ -332,13 +345,61 @@
}
/**
+ * Creates a XML element with contents of a single essay question.
+ */
+ private Element exportEssayQuestion(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");
+ renderFibElem.setAttribute("rows", "5");
+ renderFibElem.setAttribute("columns", "50");
+ itemId++;
+ Element responseLabelElem = (Element) renderFibElem.appendChild(doc.createElement("response_label"));
+ responseLabelElem.setAttribute("ident", "QUE_" + itemId + "_ANS");
+
+ // just a single feedback element
+ if (!StringUtils.isBlank(question.getFeedback())) {
+ Element overallFeedbackElem = createFeedbackElem("_ALL", question.getFeedback(), "All");
+
+ Element resprocessingElem = (Element) itemElem.appendChild(doc.createElement("resprocessing"));
+ 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 feedback XML element.
*/
- private Element createFeedbackElem(String labelSuffix, String feedback) {
+ private Element createFeedbackElem(String labelSuffix, String feedback, String type) {
itemId++;
String label = "QUE_" + itemId + labelSuffix;
Element feedbackElem = doc.createElement("itemfeedback");
feedbackElem.setAttribute("ident", label);
+ feedbackElem.setAttribute("view", type);
Element materialElem = (Element) feedbackElem.appendChild(doc.createElement("material"));
appendMaterialElements(materialElem, feedback);
Index: lams_tool_assessment/conf/language/lams/ApplicationResources.properties
===================================================================
diff -u -r9dcdc46408a8664a0fb27f09ae58a340c15f5764 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_tool_assessment/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 9dcdc46408a8664a0fb27f09ae58a340c15f5764)
+++ lams_tool_assessment/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -257,6 +257,7 @@
label.authoring.basic.export.questions =Export questions
label.authoring.advance.display.summary =Display all questions and answers once the learner finishes.
label.authoring.basic.import.qti =Import IMS QTI
+label.authoring.basic.export.qti =Export IMS QTI
advanced.reflectOnActivity =Add a notebook at end of Assessment with the following instructions:
monitor.summary.td.addNotebook =Add a notebook at end of Assessment
monitor.summary.td.notebookInstructions =Notebook instructions
Index: lams_tool_assessment/conf/xdoclet/struts-actions.xml
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_tool_assessment/conf/xdoclet/struts-actions.xml (.../struts-actions.xml) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_assessment/conf/xdoclet/struts-actions.xml (.../struts-actions.xml) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -85,6 +85,13 @@
+
+
+
Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java (.../AuthoringAction.java) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java (.../AuthoringAction.java) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -35,6 +35,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -61,6 +62,7 @@
import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException;
import org.lamsfoundation.lams.questions.Answer;
import org.lamsfoundation.lams.questions.Question;
+import org.lamsfoundation.lams.questions.QuestionExporter;
import org.lamsfoundation.lams.questions.QuestionParser;
import org.lamsfoundation.lams.tool.ToolAccessMode;
import org.lamsfoundation.lams.tool.assessment.AssessmentConstants;
@@ -141,6 +143,9 @@
if (param.equals("saveQTI")) {
return saveQTI(mapping, form, request, response);
}
+ if (param.equals("exportQTI")) {
+ return exportQTI(mapping, form, request, response);
+ }
if (param.equals("removeQuestion")) {
return removeQuestion(mapping, form, request, response);
}
@@ -372,7 +377,7 @@
}
assessmentPO.setCreatedBy(assessmentUser);
-
+
// ************************* Handle assessment questions *******************
// Handle assessment questions
Set questions = new LinkedHashSet();
@@ -572,8 +577,8 @@
assessmentQuestion.setTitle(question.getTitle());
assessmentQuestion.setQuestion(QuestionParser.processHTMLField(question.getText(), false, contentFolderID,
question.getResourcesFolderPath()));
- assessmentQuestion.setGeneralFeedback(QuestionParser.processHTMLField(question.getFeedback(), false, contentFolderID,
- question.getResourcesFolderPath()));
+ assessmentQuestion.setGeneralFeedback(QuestionParser.processHTMLField(question.getFeedback(), false,
+ contentFolderID, question.getResourcesFolderPath()));
assessmentQuestion.setPenaltyFactor(0);
int questionGrade = 1;
@@ -759,6 +764,118 @@
}
/**
+ * Prepares Assessment content for QTI packing
+ */
+ @SuppressWarnings("rawtypes")
+ private ActionForward exportQTI(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) throws UnsupportedEncodingException {
+ String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID);
+ SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID);
+
+ SortedSet questionList = getQuestionList(sessionMap);
+ List questions = new LinkedList();
+ for (AssessmentQuestion assessmentQuestion : questionList) {
+ Question question = new Question();
+ List answers = new ArrayList();
+
+ switch (assessmentQuestion.getType()) {
+
+ case AssessmentConstants.QUESTION_TYPE_MULTIPLE_CHOICE:
+ if (assessmentQuestion.isMultipleAnswersAllowed()) {
+ question.setType(Question.QUESTION_TYPE_MULTIPLE_RESPONSE);
+ int correctAnswerCount = 0;
+
+ for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getQuestionOptions()) {
+ if (assessmentAnswer.getGrade() > 0) {
+ correctAnswerCount++;
+ }
+ }
+
+ Float correctAnswerScore = correctAnswerCount > 0 ? new Integer(100 / correctAnswerCount)
+ .floatValue() : null;
+ int incorrectAnswerCount = assessmentQuestion.getQuestionOptions().size() - correctAnswerCount;
+ Float incorrectAnswerScore = incorrectAnswerCount > 0 ? new Integer(-100 / incorrectAnswerCount)
+ .floatValue() : null;
+
+ for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getQuestionOptions()) {
+ Answer answer = new Answer();
+ boolean isCorrectAnswer = assessmentAnswer.getGrade() > 0;
+
+ answer.setText(assessmentAnswer.getOptionString());
+ answer.setScore(isCorrectAnswer ? correctAnswerScore : incorrectAnswerScore);
+ answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getFeedbackOnCorrect()
+ : assessmentQuestion.getFeedbackOnIncorrect());
+
+ answers.add(assessmentAnswer.getSequenceId(), answer);
+ }
+ } else {
+ question.setType(Question.QUESTION_TYPE_MULTIPLE_CHOICE);
+
+ for (AssessmentQuestionOption assessmentAnswer : assessmentQuestion.getQuestionOptions()) {
+ Answer answer = new Answer();
+ boolean isCorrectAnswer = assessmentAnswer.getGrade() == 1F;
+
+ answer.setText(assessmentAnswer.getOptionString());
+ answer.setScore(isCorrectAnswer ? new Integer(assessmentQuestion.getDefaultGrade())
+ .floatValue() : 0);
+ answer.setFeedback(isCorrectAnswer ? assessmentQuestion.getFeedbackOnCorrect()
+ : assessmentQuestion.getFeedbackOnIncorrect());
+
+ answers.add(assessmentAnswer.getSequenceId(), answer);
+ }
+ }
+
+ break;
+
+ case AssessmentConstants.QUESTION_TYPE_TRUE_FALSE:
+ question.setType(Question.QUESTION_TYPE_TRUE_FALSE);
+ boolean isTrueCorrect = assessmentQuestion.getCorrectAnswer();
+
+ // true/false question is basically the same for QTI, just with special answers
+ Answer trueAnswer = new Answer();
+ trueAnswer.setText("True");
+ trueAnswer.setScore(isTrueCorrect ? new Integer(assessmentQuestion.getDefaultGrade()).floatValue() : 0);
+ trueAnswer.setFeedback(isTrueCorrect ? assessmentQuestion.getFeedbackOnCorrect() : assessmentQuestion
+ .getFeedbackOnIncorrect());
+ answers.add(trueAnswer);
+
+ Answer falseAnswer = new Answer();
+ falseAnswer.setText("False");
+ falseAnswer.setScore(!isTrueCorrect ? new Integer(assessmentQuestion.getDefaultGrade()).floatValue()
+ : 0);
+ falseAnswer.setFeedback(!isTrueCorrect ? assessmentQuestion.getFeedbackOnCorrect() : assessmentQuestion
+ .getFeedbackOnIncorrect());
+ answers.add(falseAnswer);
+
+ break;
+
+ case AssessmentConstants.QUESTION_TYPE_ESSAY:
+ // not much to do with essay
+ question.setType(Question.QUESTION_TYPE_ESSAY);
+ answers = null;
+
+ break;
+
+ default:
+ continue;
+ }
+
+ question.setTitle(assessmentQuestion.getTitle());
+ question.setText(assessmentQuestion.getQuestion());
+ question.setFeedback(assessmentQuestion.getGeneralFeedback());
+ question.setAnswers(answers);
+
+ questions.add(assessmentQuestion.getSequenceId() - 1, question);
+ }
+
+ String title = request.getParameter("title");
+ QuestionExporter exporter = new QuestionExporter(title, questions.toArray(Question.QUESTION_ARRAY_TYPE));
+ exporter.exportQTIPackage(request, response);
+
+ return null;
+ }
+
+ /**
* Remove assessment question from HttpSession list and update page display. As authoring rule, all persist only
* happen when user submit whole page. So this remove is just impact HttpSession values.
*
@@ -796,9 +913,9 @@
questionReferenceToDelete = questionReference;
}
}
- //check if we need to delete random question reference
+ // check if we need to delete random question reference
if ((questionReferenceToDelete == null) && (questionReferences.size() > questionList.size())) {
- //find the first random question
+ // find the first random question
for (QuestionReference questionReference : questionReferences) {
if (questionReference.isRandomQuestion()) {
questionReferenceToDelete = questionReference;
Index: lams_tool_assessment/web/pages/authoring/basic.jsp
===================================================================
diff -u -ra1e990f3ee5ec7091752683571061da802f58bb2 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_tool_assessment/web/pages/authoring/basic.jsp (.../basic.jsp) (revision a1e990f3ee5ec7091752683571061da802f58bb2)
+++ lams_tool_assessment/web/pages/authoring/basic.jsp (.../basic.jsp) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -150,7 +150,7 @@
};
function importQTI(){
- window.open('questionFile.jsp',
+ window.open('questions/questionFile.jsp',
'QuestionFile','width=500,height=200,scrollbars=yes');
}
@@ -167,7 +167,12 @@
});
}
-
+ function exportQTI(){
+ var frame = document.getElementById("downloadFileDummyIframe"),
+ title = encodeURIComponent(document.getElementsByName("assessment.title")[0].value);
+ frame.src = ''
+ + '&title=' + title;
+ }
@@ -225,8 +230,17 @@
-
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/AuthoringAction.java
===================================================================
diff -u -r0cf1ce0d39dab80bbb0e11968010c727f5e002e4 -rcc1b2b3fdc49088abf515c55bc8533c762e95412
--- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/AuthoringAction.java (.../AuthoringAction.java) (revision 0cf1ce0d39dab80bbb0e11968010c727f5e002e4)
+++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/AuthoringAction.java (.../AuthoringAction.java) (revision cc1b2b3fdc49088abf515c55bc8533c762e95412)
@@ -544,7 +544,6 @@
private ActionForward exportQTI(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws UnsupportedEncodingException {
String sessionMapID = WebUtil.readStrParam(request, ScratchieConstants.ATTR_SESSION_MAP_ID);
- request.setAttribute(ScratchieConstants.ATTR_SESSION_MAP_ID, sessionMapID);
SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID);
SortedSet itemList = getItemList(sessionMap);
List questions = new LinkedList();