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