From 3234848453a5c344f6e2bd329a286d4a09f35c4f Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 7 Sep 2016 16:12:46 +0200
Subject: [PATCH] OO-1593: support video in conversion from QTI 1.2 to  QTI
 2.1, fix issue with conversion of gap text

---
 .../ims/qti21/pool/QTI12To21Converter.java    | 35 ++++++++++++++-----
 .../interactions/EssayEditorController.java   |  2 +-
 .../interactions/KPrimEditorController.java   | 22 +++++-------
 .../MultipleChoiceEditorController.java       | 20 +++++------
 .../SingleChoiceEditorController.java         | 19 ++++------
 .../ims/qti21/pool/qti12_4questiontypes.xml   | 18 +++++++---
 6 files changed, 66 insertions(+), 50 deletions(-)

diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java b/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java
index 35c58576e2a..a63f41a75db 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI12To21Converter.java
@@ -291,9 +291,17 @@ public class QTI12To21Converter {
 		List<Response> responses = question.getResponses();
 		for(Response response:responses) {
 			String responseText = response.getContent().renderAsHtmlForEditor();
-			SimpleChoice newChoice = AssessmentItemFactory
+			SimpleChoice newChoice;
+			if(StringHelper.isHtml(responseText)) {
+				newChoice = AssessmentItemFactory
+						.createSimpleChoice(interaction, "", itemBuilder.getQuestionType().getPrefix());
+				htmlBuilder.appendHtml(newChoice, responseText);
+			} else {
+				newChoice = AssessmentItemFactory
 					.createSimpleChoice(interaction, responseText, itemBuilder.getQuestionType().getPrefix());
+			}
 			itemBuilder.addSimpleChoice(newChoice);
+			
 			if(response.isCorrect()) {
 				itemBuilder.setCorrectAnswer(newChoice.getIdentifier());
 			}	
@@ -323,8 +331,17 @@ public class QTI12To21Converter {
 		List<Response> responses = question.getResponses();
 		for(Response response:responses) {
 			String responseText = response.getContent().renderAsHtmlForEditor();
-			SimpleChoice newChoice = AssessmentItemFactory
+
+			SimpleChoice newChoice;
+			if(StringHelper.isHtml(responseText)) {
+				newChoice = AssessmentItemFactory
+						.createSimpleChoice(interaction, "", itemBuilder.getQuestionType().getPrefix());
+				htmlBuilder.appendHtml(newChoice, responseText);
+			} else {
+				newChoice = AssessmentItemFactory
 					.createSimpleChoice(interaction, responseText, itemBuilder.getQuestionType().getPrefix());
+			}
+			
 			itemBuilder.addSimpleChoice(newChoice);
 			if(response.isCorrect()) {
 				itemBuilder.addCorrectAnswer(newChoice.getIdentifier());
@@ -402,16 +419,21 @@ public class QTI12To21Converter {
 				FIBResponse gap = (FIBResponse)response;
 				if(FIBResponse.TYPE_BLANK.equals(gap.getType())) {
 					String responseId = itemBuilder.generateResponseIdentifier();
+					
+					StringBuilder entryString = new StringBuilder();
+					entryString.append(" <textentryinteraction responseidentifier=\"").append(responseId).append("\"");
+					
 					TextEntry entry = itemBuilder.createTextEntry(responseId);
 					entry.setCaseSensitive("Yes".equals(gap.getCaseSensitive()));
 					if(gap.getMaxLength() > 0) {
 						entry.setExpectedLength(gap.getMaxLength());
+						entryString.append(" expectedlength=\"").append(gap.getMaxLength()).append("\"");
 					} else if(gap.getSize() > 0) {
 						entry.setExpectedLength(gap.getSize());
+						entryString.append(" expectedlength=\"").append(gap.getSize()).append("\"");
 					}
 					parseAlternatives(gap.getCorrectBlank(), gap.getPoints(), entry);
-					
-					String entryString = " <textEntryInteraction responseIdentifier=\"" + responseId + "\"/>";
+					entryString.append("></textentryinteraction>");
 					sb.append(entryString);
 				} else if(FIBResponse.TYPE_CONTENT.equals(gap.getType())) {
 					Material text = gap.getContent();
@@ -421,10 +443,7 @@ public class QTI12To21Converter {
 			}
 		}
 		
-		String fib = sb.toString();
-		if(!fib.startsWith("<p") && !fib.startsWith("<div")) {
-			fib = "<p>" + fib + "</p>";
-		}
+		String fib = "<div>" + sb.toString() + "</div>";
 		itemBuilder.setQuestion(fib);
 		return itemBuilder;
 	}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
index d8cf636a523..dc52e195aa1 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/EssayEditorController.java
@@ -163,7 +163,7 @@ public class EssayEditorController extends FormBasicController {
 		//title
 		itemBuilder.setTitle(titleEl.getValue());
 		//question
-		String questionText = textEl.getValue();
+		String questionText = textEl.getRawValue();
 		itemBuilder.setQuestion(questionText);
 		
 		itemBuilder.setPlaceholder(placeholderEl.getValue());
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
index 1d89cd4b177..8e7f35b38c6 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/KPrimEditorController.java
@@ -68,9 +68,7 @@ public class KPrimEditorController extends FormBasicController {
 	private final List<KprimWrapper> choiceWrappers = new ArrayList<>();
 
 	private int count = 0;
-	private final File itemFile;
-	private final File rootDirectory;
-	private final VFSContainer rootContainer;
+	private final VFSContainer itemContainer;
 	
 	private final boolean restrictedEdit;
 	private final KPrimAssessmentItemBuilder itemBuilder;
@@ -79,11 +77,12 @@ public class KPrimEditorController extends FormBasicController {
 			File rootDirectory, VFSContainer rootContainer, File itemFile, boolean restrictedEdit) {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
-		this.itemFile = itemFile;
 		this.itemBuilder = itemBuilder;
-		this.rootDirectory = rootDirectory;
-		this.rootContainer = rootContainer;
 		this.restrictedEdit = restrictedEdit;
+		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		initForm(ureq);
 	}
 
@@ -97,10 +96,7 @@ public class KPrimEditorController extends FormBasicController {
 		
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
-		
-		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
-		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
-		
+
 		String description = itemBuilder.getQuestion();
 		textEl = uifactory.addRichTextElementForQTI21("desc", "form.imd.descr", description, 8, -1, itemContainer,
 				metadata, ureq.getUserSession(), getWindowControl());
@@ -154,7 +150,7 @@ public class KPrimEditorController extends FormBasicController {
 	private void wrapAnswer(UserRequest ureq, SimpleAssociableChoice choice) {
 		String choiceContent =  itemBuilder.getHtmlHelper().flowStaticString(choice.getFlowStatics());
 		String choiceId = "answer" + count++;
-		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, null,
+		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer,
 				answersCont, ureq.getUserSession(), getWindowControl());
 		choiceEl.setUserObject(choice);
 		answersCont.add("choiceId", choiceEl);
@@ -184,7 +180,7 @@ public class KPrimEditorController extends FormBasicController {
 		//title
 		itemBuilder.setTitle(titleEl.getValue());
 		//question
-		String questionText = textEl.getValue();
+		String questionText = textEl.getRawValue();
 		itemBuilder.setQuestion(questionText);
 		
 		//shuffle
@@ -202,7 +198,7 @@ public class KPrimEditorController extends FormBasicController {
 		List<SimpleAssociableChoice> choiceList = new ArrayList<>();
 		for(KprimWrapper choiceWrapper:choiceWrappers) {
 			SimpleAssociableChoice choice = choiceWrapper.getSimpleChoice();
-			String answer = choiceWrapper.getAnswer().getValue();
+			String answer = choiceWrapper.getAnswer().getRawValue();
 			itemBuilder.getHtmlHelper().appendHtml(choice, answer);
 			choiceList.add(choice);
 		}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
index 5f3b6394444..5594eb605e7 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/MultipleChoiceEditorController.java
@@ -67,9 +67,7 @@ public class MultipleChoiceEditorController extends FormBasicController {
 	private FormLayoutContainer answersCont;
 	private final List<SimpleChoiceWrapper> choiceWrappers = new ArrayList<>();
 	
-	private final File itemFile;
-	private final File rootDirectory;
-	private final VFSContainer rootContainer;
+	private final VFSContainer itemContainer;
 	
 	private int count = 0;
 	private final boolean restrictedEdit;
@@ -85,10 +83,11 @@ public class MultipleChoiceEditorController extends FormBasicController {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
-		this.itemFile = itemFile;
-		this.rootDirectory = rootDirectory;
-		this.rootContainer = rootContainer;
 		this.restrictedEdit = restrictedEdit;
+		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		initForm(ureq);
 	}
 
@@ -103,9 +102,6 @@ public class MultipleChoiceEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
 		
-		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
-		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
-		
 		String description = itemBuilder.getQuestion();
 		textEl = uifactory.addRichTextElementForQTI21("desc", "form.imd.descr", description, 8, -1, itemContainer,
 				metadata, ureq.getUserSession(), getWindowControl());
@@ -170,7 +166,7 @@ public class MultipleChoiceEditorController extends FormBasicController {
 	private void wrapAnswer(UserRequest ureq, SimpleChoice choice) {
 		String choiceContent =  itemBuilder.getHtmlHelper().flowStaticString(choice.getFlowStatics());
 		String choiceId = "answer" + count++;
-		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, null,
+		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer,
 				answersCont, ureq.getUserSession(), getWindowControl());
 		choiceEl.setUserObject(choice);
 		answersCont.add("choiceId", choiceEl);
@@ -234,7 +230,7 @@ public class MultipleChoiceEditorController extends FormBasicController {
 		//title
 		itemBuilder.setTitle(titleEl.getValue());
 		//question
-		String questionText = textEl.getValue();
+		String questionText = textEl.getRawValue();
 		itemBuilder.setQuestion(questionText);
 		
 		if(!restrictedEdit) {
@@ -263,7 +259,7 @@ public class MultipleChoiceEditorController extends FormBasicController {
 		for(SimpleChoiceWrapper choiceWrapper:choiceWrappers) {
 			SimpleChoice choice = choiceWrapper.getSimpleChoice();
 			//text
-			String answer = choiceWrapper.getAnswer().getValue();
+			String answer = choiceWrapper.getAnswer().getRawValue();
 			itemBuilder.getHtmlHelper().appendHtml(choice, answer);
 			choiceList.add(choice);
 		}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
index 04cd70e6284..6a67b86e55e 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/SingleChoiceEditorController.java
@@ -66,9 +66,7 @@ public class SingleChoiceEditorController extends FormBasicController {
 	private final List<SimpleChoiceWrapper> choiceWrappers = new ArrayList<>();
 	
 	private int count = 0;
-	private final File itemFile;
-	private final File rootDirectory;
-	private final VFSContainer rootContainer;
+	private final VFSContainer itemContainer;
 	private final boolean restrictedEdit;
 	private final SingleChoiceAssessmentItemBuilder itemBuilder;
 	
@@ -82,10 +80,11 @@ public class SingleChoiceEditorController extends FormBasicController {
 		super(ureq, wControl, "simple_choices_editor");
 		setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale()));
 		this.itemBuilder = itemBuilder;
-		this.itemFile = itemFile;
-		this.rootDirectory = rootDirectory;
-		this.rootContainer = rootContainer;
 		this.restrictedEdit = restrictedEdit;
+		
+		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
+		itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
+		
 		initForm(ureq);
 	}
 
@@ -100,9 +99,6 @@ public class SingleChoiceEditorController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "form.imd.title", -1, itemBuilder.getTitle(), metadata);
 		titleEl.setMandatory(true);
 
-		String relativePath = rootDirectory.toPath().relativize(itemFile.toPath().getParent()).toString();
-		VFSContainer itemContainer = (VFSContainer)rootContainer.resolve(relativePath);
-		
 		String description = itemBuilder.getQuestion();
 		textEl = uifactory.addRichTextElementForQTI21("desc", "form.imd.descr", description, 8, -1, itemContainer,
 				metadata, ureq.getUserSession(), getWindowControl());
@@ -166,7 +162,7 @@ public class SingleChoiceEditorController extends FormBasicController {
 	private void wrapAnswer(UserRequest ureq, SimpleChoice choice) {
 		String choiceContent =  itemBuilder.getHtmlHelper().flowStaticString(choice.getFlowStatics());
 		String choiceId = "answer" + count++;
-		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, null,
+		RichTextElement choiceEl = uifactory.addRichTextElementForQTI21(choiceId, "form.imd.answer", choiceContent, 8, -1, itemContainer,
 				answersCont, ureq.getUserSession(), getWindowControl());
 		choiceEl.setUserObject(choice);
 		answersCont.add("choiceId", choiceEl);
@@ -231,7 +227,6 @@ public class SingleChoiceEditorController extends FormBasicController {
 		itemBuilder.setTitle(titleEl.getValue());
 		//question
 		String questionText = textEl.getRawValue();
-		System.out.println(questionText);
 		itemBuilder.setQuestion(questionText);
 		
 		Identifier correctAnswerIdentifier = null;
@@ -257,7 +252,7 @@ public class SingleChoiceEditorController extends FormBasicController {
 		for(SimpleChoiceWrapper choiceWrapper:choiceWrappers) {
 			SimpleChoice choice = choiceWrapper.getSimpleChoice();
 			//text
-			String answer = choiceWrapper.getAnswer().getValue();
+			String answer = choiceWrapper.getAnswer().getRawValue();
 			itemBuilder.getHtmlHelper().appendHtml(choice, answer);
 			choiceList.add(choice);
 		}
diff --git a/src/test/java/org/olat/ims/qti21/pool/qti12_4questiontypes.xml b/src/test/java/org/olat/ims/qti21/pool/qti12_4questiontypes.xml
index 38c496d2bd3..069beab81d5 100644
--- a/src/test/java/org/olat/ims/qti21/pool/qti12_4questiontypes.xml
+++ b/src/test/java/org/olat/ims/qti21/pool/qti12_4questiontypes.xml
@@ -21,14 +21,24 @@
       <item ident="QTIEDIT:SCQ:8000138058" title="Neue Frage">
         <presentation>
           <material>
-            <mattext texttype="text/html"><![CDATA[Neue Frage]]></mattext>
+            <mattext texttype="text/html"><![CDATA[Neue Frage<br /><br /><span id="olatFlashMovieViewer549242" class="olatFlashMovieViewer" style="display:block;border:solid 1px #000; width:320px; height:240px;">
+<script src="/raw/fx-111111x11/movie/player.js" type="text/javascript"></script>
+<script type="text/javascript" defer="defer">
+BPlayer.insertPlayer("media/demo-video.mp4","olatFlashMovieViewer549242",320,240,0,0,"video",undefined,false,false,true,undefined);
+</script>
+</span>]]></mattext>
           </material>
           <response_lid ident="8000138060" rcardinality="Single" rtiming="No">
             <render_choice shuffle="No" minnumber="1" maxnumber="1">
               <flow_label class="List">
                 <response_label ident="8000138063" rshuffle="Yes">
                   <material>
-                    <mattext texttype="text/html"><![CDATA[Richtige Antwort]]></mattext>
+                    <mattext texttype="text/html"><![CDATA[Richtige Antwort<br /><br /><span id="olatFlashMovieViewer656727" class="olatFlashMovieViewer" style="display:block;border:solid 1px #000; width:320px; height:240px;">
+<script src="/raw/fx-111111x11/movie/player.js" type="text/javascript"></script>
+<script type="text/javascript" defer="defer">
+BPlayer.insertPlayer("media/demo-video.mp4","olatFlashMovieViewer656727",320,240,0,0,"video",undefined,false,false,true,undefined);
+</script>
+</span>]]></mattext>
                   </material>
                 </response_label>
               </flow_label>
@@ -344,7 +354,7 @@
         <presentation label="notset">
           <flow>
             <material>
-              <mattext texttype="text/html"><![CDATA[<p>To be or</p>]]></mattext>
+              <mattext texttype="text/html"><![CDATA[To be or]]></mattext>
             </material>
             <response_str ident="8000177110" rcardinality="Single">
               <render_fib columns="3" maxchars="10">
@@ -366,7 +376,7 @@
             <conditionvar>
               <and>
                 <or>
-                  <varequal respident="8000177110" case="No"><![CDATA[not]]></varequal>
+                  <varequal respident="8000177110" case="No"><![CDATA[New text element<br />Et encor<br />bla]]></varequal>
                 </or>
               </and>
             </conditionvar>
-- 
GitLab