/** * <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.qti.statistics.ui; 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.CoreSpringFactory; 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.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.ims.qti.editor.beecom.objects.FIBResponse; import org.olat.ims.qti.editor.beecom.objects.Item; import org.olat.ims.qti.editor.beecom.objects.Question; import org.olat.ims.qti.editor.beecom.objects.Response; import org.olat.ims.qti.editor.beecom.objects.Section; import org.olat.ims.qti.statistics.QTIStatisticResourceResult; import org.olat.ims.qti.statistics.QTIStatisticSearchParams; import org.olat.ims.qti.statistics.QTIStatisticsManager; import org.olat.ims.qti.statistics.QTIType; import org.olat.ims.qti.statistics.model.StatisticsItem; /** * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class QTI12ItemStatisticsController extends BasicController { private final QTIStatisticSearchParams searchParams; private final QTIStatisticResourceResult resourceResult; private final QTIStatisticsManager qtiStatisticsManager; private final VelocityContainer mainVC; private final int numOfParticipants; private final String mediaBaseURL; private final Item item; private final SeriesFactory seriesfactory; public QTI12ItemStatisticsController(UserRequest ureq, WindowControl wControl, Section section, Item item, QTIStatisticResourceResult resourceResult, boolean printMode) { super(ureq, wControl); this.item = item; seriesfactory = new SeriesFactory(resourceResult, getTranslator()); qtiStatisticsManager = CoreSpringFactory.getImpl(QTIStatisticsManager.class); this.resourceResult = resourceResult; searchParams = resourceResult.getSearchParams(); mediaBaseURL = resourceResult.getResolver().getStaticsBaseURI() + "/"; numOfParticipants = resourceResult.getQTIStatisticAssessment().getNumOfParticipants(); int questionType = item.getQuestion().getType(); if(Question.TYPE_ESSAY == questionType) { mainVC = createVelocityContainer("statistics_item_essai"); initEssay(); } else { mainVC = createVelocityContainer("statistics_item"); StatisticsItem itemStats = initItemStatistics(); initItem(itemStats); } mainVC.put("d3loader", new StatisticsComponent("d3loader")); mainVC.contextPut("title", item.getTitle()); if(section != null) { mainVC.contextPut("sectionTitle", section.getTitle()); } mainVC.contextPut("questionType", item.getQuestion().getType()); mainVC.contextPut("question", getQuestion()); mainVC.contextPut("numOfParticipants", resourceResult.getQTIStatisticAssessment().getNumOfParticipants()); mainVC.contextPut("printMode", new Boolean(printMode)); putInitialPanel(mainVC); } @Override protected void doDispose() { // } @Override protected void event(UserRequest ureq, Component source, Event event) { // } protected StatisticsItem initItemStatistics() { boolean survey = QTIType.survey.equals(resourceResult.getType()); double maxScore; if(survey) { maxScore = 1d; } else if(item.getQuestion().isSingleCorrect()) { maxScore = item.getQuestion().getSingleCorrectScore(); } else { maxScore = item.getQuestion().getMaxValue(); } StatisticsItem itemStats = qtiStatisticsManager .getItemStatistics(item.getIdent(), maxScore, searchParams); 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); if(item.getQuestion().getType() != Question.TYPE_FIB) { mainVC.contextPut("notAnswered", notAnswered); } mainVC.contextPut("itemDifficulty", formatTwo(itemStats.getDifficulty())); mainVC.contextPut("averageScore", formatTwo(itemStats.getAverageScore())); } mainVC.contextPut("averageDuration", duration(itemStats.getAverageDuration())); return itemStats; } private String getQuestion() { String question; if(item.getQuestion().getType() == Question.TYPE_FIB) { StringBuilder questionSb = new StringBuilder(); List<Response> elements = item.getQuestion().getResponses(); if(elements != null) { for(Response element:elements) { if(element instanceof FIBResponse) { FIBResponse response = (FIBResponse)element; if(FIBResponse.TYPE_CONTENT.equals(response.getType())) { String content = response.getContent().renderAsHtml(mediaBaseURL); questionSb.append(content); } else if(FIBResponse.TYPE_BLANK.equals(response.getType())) { questionSb.append(" ___________________ "); } } } } question = questionSb.toString(); } else { question = item.getQuestion().getQuestion().renderAsHtml(mediaBaseURL); } return question; } protected void initItem(StatisticsItem itemStats) { Series series = seriesfactory.getSeries(item, itemStats); VelocityContainer vc = createVelocityContainer("hbar_item"); vc.contextPut("series", series); mainVC.put("questionChart", vc); mainVC.contextPut("series", series); } protected void initEssay() { boolean survey = QTIType.survey.equals(resourceResult.getType()); double maxScore; if(survey) { maxScore = 1d; } else if(item.getQuestion().isSingleCorrect()) { maxScore = item.getQuestion().getSingleCorrectScore(); } else { maxScore = item.getQuestion().getMaxValue(); } StatisticsItem itemStats = qtiStatisticsManager .getItemStatistics(item.getIdent(), maxScore, searchParams); mainVC.contextPut("solution", item.getQuestion().getSolutionText()); int numOfResults = itemStats.getNumOfResults(); if(!survey) { mainVC.contextPut("maxScore", maxScore); } mainVC.contextPut("averageDuration", duration(itemStats.getAverageDuration())); List<String> answers = qtiStatisticsManager.getAnswers(item.getIdent(), searchParams); List<String> cleanedAnswers = new ArrayList<>(); for (String string : answers) { String strippedAnswer = stripAnswerText(string); if(strippedAnswer == null || strippedAnswer.length() == 0) { numOfResults--; } else { cleanedAnswers.add(strippedAnswer); } } mainVC.contextPut("numOfResults", Math.max(0, numOfResults)); mainVC.contextPut("studentAnswers", cleanedAnswers); } private String stripAnswerText(String answerTextFromDB){ String result =""; int start = answerTextFromDB.indexOf("["); result = answerTextFromDB.substring(start+2); result = result.substring(0, result.length()-2); result = result.replaceAll("\\\\r\\\\n", "<br />"); return result; } }