From 1a1f63e4b78f727df13967f7225dd801cf3141b7 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 19 Jul 2017 13:41:22 +0200
Subject: [PATCH] OO-2905: show the question in the statistics of an assessment
 item

---
 ...I21AssessmentItemStatisticsController.java |  11 +-
 .../statistics/QTI21ItemBodyController.java   | 131 ++++++++++++++++++
 .../QTI21StatisticResourceResult.java         |   7 +-
 .../statistics/_content/statistics_item.html  |  16 +--
 4 files changed, 153 insertions(+), 12 deletions(-)
 create mode 100644 src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java

diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
index 28f75e4dd8c..8db06fb3878 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21AssessmentItemStatisticsController.java
@@ -60,6 +60,7 @@ import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction;
 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.test.AssessmentItemRef;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 
 /**
  * 
@@ -78,15 +79,17 @@ public class QTI21AssessmentItemStatisticsController extends BasicController {
 	private final QTI21StatisticSearchParams searchParams;
 	private final QTI21StatisticResourceResult resourceResult;
 	
+	private final QTI21ItemBodyController itemBodyCtrl;
+	
 	@Autowired
 	private QTI21StatisticsManager qtiStatisticsManager;
 	
 	public QTI21AssessmentItemStatisticsController(UserRequest ureq, WindowControl wControl,
-			AssessmentItemRef itemRef, AssessmentItem item, String sectionTitle, QTI21StatisticResourceResult resourceResult,
+			AssessmentItemRef itemRef, ResolvedAssessmentItem resolvedAssessmentItem, String sectionTitle, QTI21StatisticResourceResult resourceResult,
 			boolean withFilter, boolean printMode) {
 		super(ureq, wControl);
 		
-		this.item = item;
+		item = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
 		this.itemRef = itemRef;
 		this.resourceResult = resourceResult;
 		searchParams = resourceResult.getSearchParams();
@@ -114,6 +117,10 @@ public class QTI21AssessmentItemStatisticsController extends BasicController {
 			mainVC.put("filter", filterCtrl.getInitialComponent());
 		}
 		
+		itemBodyCtrl = new QTI21ItemBodyController(ureq, getWindowControl(), itemRef, resolvedAssessmentItem, resourceResult);
+		listenTo(itemBodyCtrl);
+		mainVC.put("question", itemBodyCtrl.getInitialComponent());
+		
 		putInitialPanel(mainVC);
 		updateData(ureq);
 	}
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java
new file mode 100644
index 00000000000..21c70ef6a03
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21ItemBodyController.java
@@ -0,0 +1,131 @@
+/**
+ * <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.ui.statistics;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Date;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.CodeHelper;
+import org.olat.core.util.Util;
+import org.olat.fileresource.types.ImsQTI21Resource;
+import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator;
+import org.olat.ims.qti21.QTI21Service;
+import org.olat.ims.qti21.model.InMemoryAssessmentTestSession;
+import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
+import org.olat.ims.qti21.ui.ResourcesMapper;
+import org.olat.ims.qti21.ui.assessment.TerminatedStaticCandidateSessionContext;
+import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef;
+import uk.ac.ed.ph.jqtiplus.notification.NotificationLevel;
+import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder;
+import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
+import uk.ac.ed.ph.jqtiplus.running.ItemProcessingInitializer;
+import uk.ac.ed.ph.jqtiplus.running.ItemSessionController;
+import uk.ac.ed.ph.jqtiplus.running.ItemSessionControllerSettings;
+import uk.ac.ed.ph.jqtiplus.state.ItemProcessingMap;
+import uk.ac.ed.ph.jqtiplus.state.ItemSessionState;
+import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator;
+
+/**
+ * The controller is used as wrapper for the item body
+ * form item.
+ * 
+ * Initial date: 19 juil. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class QTI21ItemBodyController extends FormBasicController {
+	
+	private final String mapperUri;
+	private final URI assessmentObjectUri;
+	private final ResourceLocator inputResourceLocator;
+	private final ItemSessionController itemSessionController;
+	private final ResolvedAssessmentItem resolvedAssessmentItem;
+	
+	@Autowired
+	private QTI21Service qtiService;
+	
+	public QTI21ItemBodyController(UserRequest ureq, WindowControl wControl,
+			AssessmentItemRef itemRef, ResolvedAssessmentItem resolvedAssessmentItem, QTI21StatisticResourceResult resourceResult) {
+		super(ureq, wControl, LAYOUT_BAREBONE);
+		setTranslator(Util.createPackageTranslator(AssessmentTestDisplayController.class, getLocale(), getTranslator()));
+		
+		this.resolvedAssessmentItem = resolvedAssessmentItem;
+		itemSessionController = createNewItemSessionStateAndController();
+		
+		File itemFileRef = resourceResult.getAssessmentItemFile(itemRef);
+		File fUnzippedDirRoot = resourceResult.getUnzippedDirectory();
+		ResourceLocator fileResourceLocator = new PathResourceLocator(fUnzippedDirRoot.toPath());
+		inputResourceLocator = ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
+		assessmentObjectUri = itemFileRef.toURI();
+		mapperUri = registerCacheableMapper(null, "QTI21StatisticsElement::" + CodeHelper.getRAMUniqueID(),
+				new ResourcesMapper(assessmentObjectUri));
+
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		ItemBodyResultFormItem questionItem = new ItemBodyResultFormItem("question", resolvedAssessmentItem);
+		questionItem.setItemSessionState(itemSessionController.getItemSessionState());
+		questionItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(new InMemoryAssessmentTestSession()));
+		questionItem.setResourceLocator(inputResourceLocator);
+		questionItem.setAssessmentObjectUri(assessmentObjectUri);
+		questionItem.setMapperUri(mapperUri);
+		formLayout.add(questionItem);
+	}
+	
+	private ItemSessionController createNewItemSessionStateAndController() {
+        /* Resolve the underlying JQTI+ object */
+        final ItemProcessingMap itemProcessingMap = new ItemProcessingInitializer(resolvedAssessmentItem, true).initialize();
+
+        /* Create fresh state for session */
+        final ItemSessionState itemSessionState = new ItemSessionState();
+        final ItemSessionControllerSettings itemSessionControllerSettings = new ItemSessionControllerSettings();
+        itemSessionControllerSettings.setTemplateProcessingLimit(25);
+        itemSessionControllerSettings.setMaxAttempts(10);
+
+        /* Create controller and wire up notification recorder */
+        final ItemSessionController sessionController = new ItemSessionController(qtiService.jqtiExtensionManager(),
+                itemSessionControllerSettings, itemProcessingMap, itemSessionState);
+        sessionController.addNotificationListener(new NotificationRecorder(NotificationLevel.ERROR));
+
+        sessionController.initialize(new Date());
+        return sessionController;
+    }
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
index a66d7a8bdea..b433469c1f0 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
@@ -146,6 +146,10 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 		return new File(itemUri);
 	}
 	
+	public File getUnzippedDirectory() {
+		return FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource());
+	}
+	
 	public boolean canViewAnonymousUsers() {
 		return secCallback.canViewAnonymousUsers();
 	}
@@ -348,8 +352,7 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 	private Controller createAssessmentItemController(UserRequest ureq, WindowControl wControl,
 			AssessmentItemRef assessmentItemRef, String sectionTitle, boolean printMode) {
 		ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(assessmentItemRef);
-		AssessmentItem assessmentItem = resolvedAssessmentItem.getItemLookup().getRootNodeHolder().getRootNode();
-		Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, assessmentItem, sectionTitle, this, withFilter, printMode);
+		Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl, assessmentItemRef, resolvedAssessmentItem, sectionTitle, this, withFilter, printMode);
 		String iconCssClass = "o_mi_qtisc";
 		if(courseNode != null) {
 			ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, ctrl, courseNode, iconCssClass);
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
index 6997a37d561..2160d3f7192 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/_content/statistics_item.html
@@ -4,15 +4,15 @@
 </div>
 #end
 
+#if($sectionTitle)
+<h5>$r.translate("section"): $r.escapeHtml($sectionTitle)</h5>
+#end
+<h3><i class="o_icon $itemCss""> </i> $r.escapeHtml($title)</h3>
+#if($r.available("question"))
+	<h4>$r.translate("chart.item")</h4>
+	<div id="itemBody" class="clearfix">$r.render("question")</div>
+#end
 <div class="o_qti_statistics">
-	#if($sectionTitle)
-	<h5>$r.translate("section"): $r.escapeHtml($sectionTitle)</h5>
-	#end
-	<h3><i class="o_icon $itemCss""> </i> $r.escapeHtml($title)</h3>
-	#if($r.isNotEmpty($question))
-		<h4>$r.translate("chart.item")</h4>
-		<div class="o_qti_statistics_question clearfix">$r.escapeHtml($question)</div>
-	#end
 	<h4>$r.translate("fig.title")</h4>
 	<table class="o_qti_statistics_figures"><tbody>
 		#if($numOfParticipants)
-- 
GitLab