diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java index ae629d0d930fe7988cda54ae742bca3175902465..09435d40e4ff5aa7f7f3335ef064083c57fc2d21 100644 --- a/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java +++ b/src/main/java/org/olat/ims/qti21/manager/QTI21StatisticsManagerImpl.java @@ -87,6 +87,7 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { } else { sb.append(" and asession.subIdent is null"); } + sb.append(" and asession.authorMode=false"); if(finished) { sb.append(" and asession.finishTime is not null"); @@ -126,7 +127,9 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { private void decorateRSetQuery(TypedQuery<?> query, QTI21StatisticSearchParams searchParams) { query.setParameter("testEntryKey", searchParams.getTestEntry().getKey()); - if(searchParams.getCourseEntry() != null) { + if(searchParams.getCourseEntry() == null) { + query.setParameter("repositoryEntryKey", searchParams.getTestEntry().getKey()); + } else { query.setParameter("repositoryEntryKey", searchParams.getCourseEntry().getKey()); } if(searchParams.getNodeIdent() != null ) { @@ -147,7 +150,7 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { @Override public StatisticAssessment getAssessmentStatistics(QTI21StatisticSearchParams searchParams) { StringBuilder sb = new StringBuilder(); - sb.append("select asession.score, asession.passed, asession.duration from qtiassessmenttestsession asession "); + sb.append("select asession.score, asession.manualScore, asession.passed, asession.duration from qtiassessmenttestsession asession "); decorateRSet(sb, searchParams, true); sb.append(" order by asession.key asc"); @@ -170,7 +173,14 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { int dataPos = 0; boolean hasScore = false; for(Object[] rawData:rawDatas) { - BigDecimal score = (BigDecimal)rawData[0]; + int pos = 0; + BigDecimal score = (BigDecimal)rawData[pos++]; + BigDecimal manualScore = (BigDecimal)rawData[pos++]; + if(score == null) { + score = manualScore; + } else if(manualScore != null) { + score = score.add(manualScore); + } if(score != null) { double scored = score.doubleValue(); scores[dataPos] = scored; @@ -179,7 +189,7 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { hasScore = true; } - Boolean passed = (Boolean)rawData[1]; + Boolean passed = (Boolean)rawData[pos++]; if(passed != null) { if(passed.booleanValue()) { numOfPassed++; @@ -188,7 +198,7 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { } } - Long duration = (Long)rawData[2]; + Long duration = (Long)rawData[pos++]; if(duration != null) { double durationd = duration.doubleValue(); double durationSecond = Math.round(durationd / 1000d); @@ -232,11 +242,11 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { QTI21StatisticSearchParams searchParams) { StringBuilder sb = new StringBuilder(); - sb.append("select isession.score, count(isession.key), avg(isession.duration) from qtiassessmentitemsession isession ") + sb.append("select isession.score, isession.manualScore, count(isession.key), avg(isession.duration) from qtiassessmentitemsession isession ") .append(" inner join isession.assessmentTestSession asession"); decorateRSet(sb, searchParams, true); sb.append(" and isession.assessmentItemIdentifier=:itemIdent and isession.duration > 0") - .append(" group by isession.score"); + .append(" group by isession.score, isession.manualScore"); TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Object[].class) @@ -254,15 +264,23 @@ public class QTI21StatisticsManagerImpl implements QTI21StatisticsManager { long numOfIncorrectAnswers = 0; for(Object[] result:results) { - double score = ((Number)result[0]).doubleValue(); - long numOfResults = ((Number)result[1]).longValue(); - double averageDuration = ((Number)result[2]).doubleValue(); + BigDecimal score = (BigDecimal)result[0]; + BigDecimal manualScore = (BigDecimal)result[1]; + if(score == null) { + score = manualScore; + } else if(manualScore != null) { + score = score.add(manualScore); + } + + long numOfResults = ((Number)result[2]).longValue(); + double averageDuration = ((Number)result[3]).doubleValue(); //average - totalScore += (score * numOfResults); + double dScore = score == null ? 0.0d : score.doubleValue(); + totalScore += (dScore * numOfResults); totalResults += numOfResults; - if((maxScore - score) < 0.0001) { + if((maxScore - dScore) < 0.0001) { numOfCorrectAnswers += numOfResults; } else { numOfIncorrectAnswers += numOfResults; diff --git a/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java b/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java index 9d213fe3a84a62d9fb84a786602bd16202c0416b..98836350853f8245ceb17cada4785aed44c13f42 100644 --- a/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java +++ b/src/main/java/org/olat/ims/qti21/manager/openxml/QTI21WordExport.java @@ -343,66 +343,76 @@ public class QTI21WordExport implements MediaResource { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { - String tag = localName.toLowerCase(); - if("choiceinteraction".equals(tag)) { - responseIdentifier = attributes.getValue("responseidentifier"); - } else if("simplechoice".equals(tag)) { - if(currentTable == null) { - startTable(); - } - currentTable.addRowEl(); - currentTable.addCellEl(factory.createTableCell("E9EAF2", 4560, Unit.pct), 1); - simpleChoiceIdentifier = attributes.getValue("identifier"); - } else if("textentryinteraction".equals(tag)) { - startTextEntryInteraction(tag, attributes); - } else if("extendedtextinteraction".equals(tag)) { - startExtendedTextInteraction(attributes); - } else if("hotspotinteraction".equals(tag)) { - startHotspotInteraction(attributes); - } else if("inlinechoiceinteraction".equals(tag)) { - - } else if("hottextinteraction".equals(tag)) { - - } else if("hottext".equals(tag)) { - - } else if("matchinteraction".equals(tag)) { - renderElement = false; - - Interaction interaction = getInteractionByResponseIdentifier(attributes); - if(interaction instanceof MatchInteraction) { - MatchInteraction matchInteraction = (MatchInteraction)interaction; - QTI21QuestionType type = QTI21QuestionType.getTypeOfMatch(assessmentItem, matchInteraction); - if(type == QTI21QuestionType.kprim) { - startKPrim(matchInteraction); + switch(tag) { + case "choiceinteraction": + responseIdentifier = attributes.getValue("responseidentifier"); + break; + case "simplechoice": + if(currentTable == null) { + startTable(); + } + currentTable.addRowEl(); + currentTable.addCellEl(factory.createTableCell("E9EAF2", 4560, Unit.pct), 1); + simpleChoiceIdentifier = attributes.getValue("identifier"); + break; + case "textentryinteraction": + startTextEntryInteraction(tag, attributes); + break; + case "extendedtextinteraction": + startExtendedTextInteraction(attributes); + break; + case "hotspotinteraction": + startHotspotInteraction(attributes); + break; + case "inlinechoiceinteraction": + case "hottextinteraction": + case "hottext": + break; + case "matchinteraction": + renderElement = false; + + Interaction interaction = getInteractionByResponseIdentifier(attributes); + if(interaction instanceof MatchInteraction) { + MatchInteraction matchInteraction = (MatchInteraction)interaction; + QTI21QuestionType type = QTI21QuestionType.getTypeOfMatch(assessmentItem, matchInteraction); + if(type == QTI21QuestionType.kprim) { + startKPrim(matchInteraction); + } + } + break; + case "gapmatchinteraction": + break; + case "selectpointinteraction": + startSelectPointInteraction(attributes); + break; + case "graphicassociateinteraction": + startGraphicAssociateInteraction(attributes); + break; + case "graphicorderinteraction": + startGraphicOrderInteraction(attributes); + break; + case "graphicgapmatchinteraction": + case "associateinteraction": + case "uploadinteraction": + break; + case "positionobjectinteraction": + startPositionObjectInteraction(attributes); + break; + case "sliderinteraction": + break; + case "drawinginteraction": + startDrawingInteraction(attributes); + break; + case "simplematchset": + case "simpleassociablechoice": + //do nothing + break; + default: { + if(renderElement) { + super.startElement(uri, localName, qName, attributes); } } - } else if("gapmatchinteraction".equals(tag)) { - - } else if("selectpointinteraction".equals(tag)) { - startSelectPointInteraction(attributes); - } else if("graphicassociateinteraction".equals(tag)) { - startGraphicAssociateInteraction(attributes); - } else if("graphicorderinteraction".equals(tag)) { - startGraphicOrderInteraction(attributes); - } else if("graphicgapmatchinteraction".equals(tag)) { - // - } else if("associateinteraction".equals(tag)) { - // - } else if("uploadinteraction".equals(tag)) { - // - } else if("positionobjectinteraction".equals(tag)) { - startPositionObjectInteraction(attributes); - } else if("sliderinteraction".equals(tag)) { - // - } else if("drawinginteraction".equals(tag)) { - startDrawingInteraction(attributes); - } else if("simplematchset".equals(tag)) { - //do nothing - } else if("simpleassociablechoice".equals(tag)) { - //do nothing - } else if(renderElement) { - super.startElement(uri, localName, qName, attributes); } } @@ -416,34 +426,42 @@ public class QTI21WordExport implements MediaResource { @Override public void endElement(String uri, String localName, String qName) { String tag = localName.toLowerCase(); - if("choiceinteraction".equals(tag)) { - endTable(); - } else if("simplechoice".equals(tag)) { - Element checkboxCell = factory.createTableCell(null, 369, Unit.pct); - Node checkboxNode = currentTable.addCellEl(checkboxCell, 1); - - boolean checked = false; - if(withResponses) { - Identifier identifier = Identifier.assumedLegal(simpleChoiceIdentifier); - List<Identifier> correctAnswers = CorrectResponsesUtil - .getCorrectIdentifierResponses(assessmentItem, Identifier.assumedLegal(responseIdentifier)); - checked = correctAnswers.contains(identifier); + switch(tag) { + case "choiceinteraction": + endTable(); + break; + case "simplechoice": + Element checkboxCell = factory.createTableCell(null, 369, Unit.pct); + Node checkboxNode = currentTable.addCellEl(checkboxCell, 1); + + boolean checked = false; + if(withResponses) { + Identifier identifier = Identifier.assumedLegal(simpleChoiceIdentifier); + List<Identifier> correctAnswers = CorrectResponsesUtil + .getCorrectIdentifierResponses(assessmentItem, Identifier.assumedLegal(responseIdentifier)); + checked = correctAnswers.contains(identifier); + } + + Node responseEl = factory.createCheckbox(checked); + Node wrapEl = factory.wrapInParagraph(responseEl); + checkboxNode.appendChild(wrapEl); + closeCurrentTableRow(); + break; + case "textentryinteraction": + //auto closing tag + case "extendedtextinteraction": + //auto closing tag + case "hotspotinteraction": + //all work done during start + break; + case "matchinteraction": + renderElement = true; + break; + default: { + if(renderElement) { + super.endElement(uri, localName, qName); + } } - - Node responseEl = factory.createCheckbox(checked); - Node wrapEl = factory.wrapInParagraph(responseEl); - checkboxNode.appendChild(wrapEl); - closeCurrentTableRow(); - } else if("textentryinteraction".equals(tag)) { - //auto closing tag - } else if("extendedtextinteraction".equals(tag)) { - //auto closing tag - } else if("hotspotinteraction".equals(tag)) { - //all work done during start - } else if("matchinteraction".equals(tag)) { - renderElement = true; - } else if(renderElement) { - super.endElement(uri, localName, qName); } } diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java index 5ac473bf48df86c3b04da46ea4fe8b373e50269b..fefa388fd11d0fa8e4e045ade75b7ae1a4c2c6e7 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21RuntimeStatisticsController.java @@ -73,9 +73,9 @@ public class QTI21RuntimeStatisticsController extends BasicController implements public QTI21RuntimeStatisticsController(UserRequest ureq, WindowControl wControl, RepositoryEntry testEntry, AssessmentToolOptions asOptions) { super(ureq, wControl); - this.options = new ArchiveOptions(); - this.options.setGroup(asOptions.getGroup()); - this.options.setIdentities(asOptions.getIdentities()); + options = new ArchiveOptions(); + options.setGroup(asOptions.getGroup()); + options.setIdentities(asOptions.getIdentities()); searchParams = new QTI21StatisticSearchParams(testEntry, null, null); if(asOptions.getGroup() != null) { 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 4d3f301dd028fa7bf6469457835b62b6ccb4fe16..4cb1dff4b558a004b51ea79599c1ddceae0f794c 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 @@ -177,13 +177,7 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { rootTreeNode.setTitle(test.getTitle()); rootTreeNode.setUserObject(test); rootTreeNode.setIconCssClass("o_icon o_icon-lg o_qtiassessment_icon"); - - //list all test parts - List<TestPart> parts = test.getChildAbstractParts(); - int counter = 0; - for(TestPart part:parts) { - buildRecursively(part, ++counter, rootTreeNode); - } + buildRecursively(test, rootTreeNode); return treeModel; } @@ -202,13 +196,29 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult { resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false); AssessmentTest test = resolvedAssessmentTest.getTestLookup().getRootNodeHolder().getRootNode(); + buildRecursively(test, rootTreeNode); + return subTreeModel; + } + + private void buildRecursively(AssessmentTest test, GenericTreeNode rootTreeNode) { //list all test parts - List<TestPart> parts = test.getChildAbstractParts(); - int counter = 0; - for(TestPart part:parts) { - buildRecursively(part, ++counter, rootTreeNode); + List<TestPart> parts = test.getTestParts(); + if(parts.size() == 1) { + TreeNode firstItem = null; + List<AssessmentSection> sections = test.getTestParts().get(0).getAssessmentSections(); + for(AssessmentSection section:sections) { + TreeNode itemNode = buildRecursively(section, rootTreeNode); + if(firstItem == null) { + firstItem = itemNode; + } + } + rootTreeNode.setDelegate(firstItem); + } else { + int counter = 0; + for(TestPart part:parts) { + buildRecursively(part, ++counter, rootTreeNode); + } } - return subTreeModel; } private void buildRecursively(TestPart part, int pos, TreeNode parentNode) { diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsSecurityCallback.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsSecurityCallback.java index 332ecadcd4b868a4ab7c05a4d459e95ed8e04fa3..fed5423547d8dcfe66b210f25a8d5ee95f1491e8 100644 --- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsSecurityCallback.java +++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticsSecurityCallback.java @@ -30,7 +30,7 @@ public class QTI21StatisticsSecurityCallback { private boolean anonymousUsers; private boolean nonParticipantUsers; - public QTI21StatisticsSecurityCallback(boolean anonymousUsers, boolean nonParticipantUsers) { + public QTI21StatisticsSecurityCallback(boolean nonParticipantUsers, boolean anonymousUsers) { this.anonymousUsers = anonymousUsers; this.nonParticipantUsers = nonParticipantUsers; }