/** * <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 static org.olat.ims.qti.statistics.ui.StatisticFormatter.duration; import static org.olat.ims.qti.statistics.ui.StatisticFormatter.formatTwo; import java.util.ArrayList; import java.util.List; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.chart.StatisticsComponent; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.util.StringHelper; import org.olat.ims.qti.statistics.QTIType; import org.olat.ims.qti.statistics.model.StatisticsItem; import org.olat.ims.qti21.QTI21StatisticsManager; import org.olat.ims.qti21.model.QTI21QuestionType; import org.olat.ims.qti21.model.QTI21StatisticSearchParams; import org.olat.ims.qti21.model.xml.QtiNodesExtractor; import org.olat.ims.qti21.ui.statistics.interactions.HotspotInteractionStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.HottextInteractionStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.KPrimStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.MatchStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.SimpleChoiceInteractionStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.TextEntryInteractionsStatisticsController; import org.olat.ims.qti21.ui.statistics.interactions.UnsupportedInteractionController; import org.olat.modules.assessment.ui.UserFilterController; import org.olat.modules.assessment.ui.event.UserFilterEvent; import org.springframework.beans.factory.annotation.Autowired; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; import uk.ac.ed.ph.jqtiplus.node.item.interaction.ChoiceInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.EndAttemptInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.HotspotInteraction; import uk.ac.ed.ph.jqtiplus.node.item.interaction.HottextInteraction; 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; /** * * Initial date: 03.02.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class QTI21AssessmentItemStatisticsController extends BasicController { private final VelocityContainer mainVC; private UserFilterController filterCtrl; private final AssessmentItem item; private final AssessmentItemRef itemRef; private final QTI21StatisticSearchParams searchParams; private final QTI21StatisticResourceResult resourceResult; @Autowired private QTI21StatisticsManager qtiStatisticsManager; public QTI21AssessmentItemStatisticsController(UserRequest ureq, WindowControl wControl, AssessmentItemRef itemRef, AssessmentItem item, String sectionTitle, QTI21StatisticResourceResult resourceResult, boolean withFilter, boolean printMode) { super(ureq, wControl); this.item = item; this.itemRef = itemRef; this.resourceResult = resourceResult; searchParams = resourceResult.getSearchParams(); mainVC = createVelocityContainer("statistics_item"); mainVC.put("d3loader", new StatisticsComponent("d3loader")); mainVC.contextPut("title", item.getTitle()); if(StringHelper.containsNonWhitespace(sectionTitle)) { mainVC.contextPut("sectionTitle", sectionTitle); } mainVC.contextPut("printMode", new Boolean(printMode)); QTI21QuestionType type = QTI21QuestionType.getTypeRelax(item); if(type != null) { mainVC.contextPut("itemCss", type.getCssClass()); } else { mainVC.contextPut("itemCss", "o_mi_qtiunkown"); } if(withFilter && (resourceResult.canViewAnonymousUsers() || resourceResult.canViewNonParticipantUsers())) { filterCtrl = new UserFilterController(ureq, getWindowControl(), resourceResult.canViewNonParticipantUsers(), resourceResult.canViewAnonymousUsers(), resourceResult.isViewNonParticipantUsers(), resourceResult.isViewAnonymousUsers()); listenTo(filterCtrl); mainVC.put("filter", filterCtrl.getInitialComponent()); } putInitialPanel(mainVC); updateData(ureq); } @Override protected void doDispose() { // } private void updateData(UserRequest ureq) { StatisticsItem itemStats = initItemStatistics(); List<String> interactionIds = initInteractionControllers(ureq, itemStats); mainVC.contextPut("interactionIds", interactionIds); } private List<String> initInteractionControllers(UserRequest ureq, StatisticsItem itemStats) { List<Interaction> interactions = item.getItemBody().findInteractions(); List<String> interactionIds = new ArrayList<>(interactions.size()); int counter = 0; List<TextEntryInteraction> textEntryInteractions = new ArrayList<>(); for(Interaction interaction:interactions) { if(interaction instanceof TextEntryInteraction) { textEntryInteractions.add((TextEntryInteraction)interaction); } else if(interaction instanceof EndAttemptInteraction) { continue; } else { Component cmp = interactionControllerFactory(ureq, interaction, itemStats); String componentId = "interaction" + counter++; mainVC.put(componentId, cmp); interactionIds.add(componentId); } } if(textEntryInteractions.size() > 0) { Controller interactionCtrl = new TextEntryInteractionsStatisticsController(ureq, getWindowControl(), itemRef, item, textEntryInteractions, resourceResult); listenTo(interactionCtrl); String componentId = "interaction" + counter++; mainVC.put(componentId, interactionCtrl.getInitialComponent()); interactionIds.add(componentId); } return interactionIds; } private Component interactionControllerFactory(UserRequest ureq, Interaction interaction, StatisticsItem itemStats) { Controller interactionCtrl = null; if(interaction instanceof ChoiceInteraction) { interactionCtrl = new SimpleChoiceInteractionStatisticsController(ureq, getWindowControl(), itemRef, item, (ChoiceInteraction)interaction, itemStats, resourceResult); } else if(interaction instanceof MatchInteraction) { String responseIdentifier = interaction.getResponseIdentifier().toString(); if(responseIdentifier.startsWith("KPRIM_")) { interactionCtrl = new KPrimStatisticsController(ureq, getWindowControl(), itemRef, item, (MatchInteraction)interaction, resourceResult); } else { interactionCtrl = new MatchStatisticsController(ureq, getWindowControl(), itemRef, item, (MatchInteraction)interaction, resourceResult); } } else if(interaction instanceof HotspotInteraction) { interactionCtrl = new HotspotInteractionStatisticsController(ureq, getWindowControl(), itemRef, item, (HotspotInteraction)interaction, itemStats, resourceResult); } else if(interaction instanceof HottextInteraction) { interactionCtrl = new HottextInteractionStatisticsController(ureq, getWindowControl(), itemRef, item, (HottextInteraction)interaction, itemStats, resourceResult); } if(interactionCtrl == null) { interactionCtrl = new UnsupportedInteractionController(ureq, getWindowControl(), interaction); } listenTo(interactionCtrl); return interactionCtrl.getInitialComponent(); } protected StatisticsItem initItemStatistics() { boolean survey = QTIType.survey.equals(resourceResult.getType()); double maxScore = 0.0d; Double maxScoreSettings = QtiNodesExtractor.extractMaxScore(item); if(maxScoreSettings != null) { maxScore = maxScoreSettings.doubleValue(); } StatisticsItem itemStats = qtiStatisticsManager .getAssessmentItemStatistics(itemRef.getIdentifier().toString(), maxScore, searchParams); int numOfParticipants = resourceResult.getQTIStatisticAssessment().getNumOfParticipants(); if(survey) { long notAnswered = numOfParticipants - itemStats.getNumOfResults(); mainVC.contextPut("notAnswered", notAnswered); } else { long rightAnswers = itemStats.getNumOfCorrectAnswers(); long wrongAnswers = itemStats.getNumOfIncorrectAnswers(); long notAnswered = numOfParticipants - rightAnswers - wrongAnswers; mainVC.contextPut("maxScore", maxScore); mainVC.contextPut("rightAnswers", rightAnswers); mainVC.contextPut("wrongAnswers", wrongAnswers); mainVC.contextPut("notAnswered", notAnswered); mainVC.contextPut("itemDifficulty", formatTwo(itemStats.getDifficulty())); mainVC.contextPut("averageScore", formatTwo(itemStats.getAverageScore())); mainVC.contextPut("numOfParticipants", numOfParticipants); } mainVC.contextPut("averageDuration", duration(itemStats.getAverageDuration())); return itemStats; } @Override protected void event(UserRequest ureq, Component source, Event event) { // } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(filterCtrl == source) { if(event instanceof UserFilterEvent) { UserFilterEvent ufe = (UserFilterEvent)event; resourceResult.setViewAnonymousUsers(ufe.isWithAnonymousUser()); resourceResult.setViewNonPaticipantUsers(ufe.isWithNonParticipantUsers()); updateData(ureq); } } super.event(ureq, source, event); } }