Skip to content
Snippets Groups Projects
Commit 9f1731dd authored by fkiefer's avatar fkiefer
Browse files

OO-2688 Make QTI 1 and QTI 2 Excel results download configurable

parent a169f70d
No related branches found
No related tags found
No related merge requests found
Showing
with 577 additions and 32 deletions
......@@ -305,7 +305,7 @@ public class ArchiverMainController extends MainLayoutBasicController {
contentCtr = new GenericArchiveController(ureq, getWindowControl(), ores, new IQSURVCourseNode());
main.setContent(contentCtr.getInitialComponent());
} else if (menuCommand.equals(CMD_QTITESTRESULTS)) {
contentCtr = new GenericArchiveController(ureq, getWindowControl(), ores, new IQTESTCourseNode(), new IQSELFCourseNode());
contentCtr = new TestArchiveController(ureq, getWindowControl(), ores, new IQTESTCourseNode(), new IQSELFCourseNode());
main.setContent(contentCtr.getInitialComponent());
} else if (menuCommand.equals(CMD_SCOREACCOUNTING)) {
contentCtr = new ScoreAccountingArchiveController(ureq, getWindowControl(), ores);
......
/**
* <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.course.archiver;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
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.translator.Translator;
import org.olat.core.util.Util;
import org.olat.core.util.prefs.Preferences;
import org.olat.course.nodes.CourseNode;
import org.olat.ims.qti.export.OptionsChooseForm;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
import org.springframework.beans.factory.annotation.Autowired;
/**
* user interface to determine export config
*
* Initial Date: 11.04.2017
* @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
*/
public class ExportOptionsController extends FormBasicController {
private static final String ITEMCOLS = "itemcols";
private static final String POSCOL = "poscol";
private static final String POINTCOL = "pointcol";
private static final String TIMECOLS = "timecols";
private MultipleSelectionElement downloadOptionsEl;
private String[] optionKeys, optionVals;
@Autowired
private FormatConfigHelper configHelper;
public ExportOptionsController(UserRequest ureq, WindowControl wControl, CourseNode courseNode) {
super(ureq, wControl);
Translator fallback = Util.createPackageTranslator(OptionsChooseForm.class, getLocale());
setTranslator(Util.createPackageTranslator(getTranslator(), fallback, getLocale()));
optionKeys = new String[]{ITEMCOLS, POSCOL, POINTCOL, TIMECOLS};
optionVals = new String[] {
translate("form.itemcols"),
translate("form.poscol"),
translate("form.pointcol"),
translate("form.timecols")
};
initForm(ureq);
}
@Override
protected void doDispose() {
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
downloadOptionsEl = uifactory.addCheckboxesVertical("setting", "form.title", formLayout, optionKeys, optionVals, 1);
QTIExportItemFormatConfig c = configHelper.doLoadQTIExportFormatConfig(ureq);
downloadOptionsEl.select(ITEMCOLS, c.hasResponseCols());
downloadOptionsEl.select(POSCOL, c.hasPositionsOfResponsesCol());
downloadOptionsEl.select(POINTCOL, c.hasPointCol());
downloadOptionsEl.select(TIMECOLS, c.hasTimeCols());
FormItemContainer buttonContainer = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
formLayout.add(buttonContainer);
uifactory.addFormSubmitButton("save", buttonContainer);
uifactory.addFormCancelButton("cancel", buttonContainer, ureq, getWindowControl());
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
@Override
protected boolean validateFormLogic(UserRequest ureq) {
boolean allOk = true;
allOk &= downloadOptionsEl.isAtLeastSelected(1);
if(!allOk) {
downloadOptionsEl.setErrorKey("nodechoose.config.error", null);
}
return allOk &= super.validateFormLogic(ureq);
}
@Override
protected void formOK(UserRequest ureq) {
doUpdateMemberListConfig(ureq);
fireEvent(ureq, Event.DONE_EVENT);
}
private void doUpdateMemberListConfig(UserRequest ureq) {
// save new config in GUI prefs
Preferences guiPrefs = ureq.getUserSession().getGuiPreferences();
if (guiPrefs != null) {
boolean itemcols = downloadOptionsEl.isSelected(0);
boolean poscol = downloadOptionsEl.isSelected(1);
boolean pointcol = downloadOptionsEl.isSelected(2);
boolean timecols = downloadOptionsEl.isSelected(3);
configHelper.updateQTIExportFormatConfig(ureq, itemcols, poscol, pointcol, timecols);
}
}
}
/**
* <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.course.archiver;
import org.olat.core.gui.UserRequest;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.prefs.Preferences;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.course.nodes.ArchiveOptions;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
import org.springframework.stereotype.Service;
import com.thoughtworks.xstream.XStream;
/**
* this class reads and writes XML serialized config data to personal gui prefs and retrieves them
*
* Initial Date: 21.04.2017
* @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
*/
@Service
public class FormatConfigHelper {
private static final String QTI_EXPORT_ITEM_FORMAT_CONFIG = "QTIExportItemFormatConfig";
private static final OLog log = Tracing.createLoggerFor(FormatConfigHelper.class);
private static XStream configXstream = XStreamHelper.createXStreamInstance();
static {
configXstream.alias(QTI_EXPORT_ITEM_FORMAT_CONFIG, QTIExportFormatConfig.class);
}
public QTIExportItemFormatConfig doLoadQTIExportFormatConfig(UserRequest ureq) {
QTIExportItemFormatConfig formatConfig = null;
if (ureq != null) {
try {
Preferences guiPrefs = ureq.getUserSession().getGuiPreferences();
String formatConfigString = (String) guiPrefs.get(ExportOptionsController.class, QTI_EXPORT_ITEM_FORMAT_CONFIG);
Object formatObject = configXstream.fromXML(formatConfigString);
formatConfig = (QTIExportFormatConfig) formatObject;
} catch (Exception e) {
log.error("could not establish object from xml", e);
formatConfig = new QTIExportFormatConfig(true, true, true, true);
}
}
return formatConfig;
}
public void updateQTIExportFormatConfig(UserRequest ureq, boolean itemcols, boolean poscol, boolean pointcol, boolean timecols) {
// save new config in GUI prefs
Preferences guiPrefs = ureq.getUserSession().getGuiPreferences();
if (guiPrefs != null) {
QTIExportItemFormatConfig formatConfig = new QTIExportFormatConfig(itemcols, poscol, pointcol, timecols);
try {
String formatConfigString = configXstream.toXML(formatConfig);
guiPrefs.putAndSave(ExportOptionsController.class, QTI_EXPORT_ITEM_FORMAT_CONFIG, formatConfigString);
} catch (Exception e) {
log.error("",e);
}
}
}
public ArchiveOptions getArchiveOptions(UserRequest ureq) {
ArchiveOptions options = new ArchiveOptions();
QTIExportItemFormatConfig formatConfig = null;
if (ureq != null) {
try {
Preferences guiPrefs = ureq.getUserSession().getGuiPreferences();
String formatConfigString = (String) guiPrefs.get(ExportOptionsController.class, QTI_EXPORT_ITEM_FORMAT_CONFIG);
Object formatObject = configXstream.fromXML(formatConfigString);
formatConfig = (QTIExportFormatConfig) formatObject;
} catch (Exception e) {
log.error("could not establish object from xml", e);
formatConfig = new QTIExportFormatConfig(true, true, true, true);
}
}
options.setQtiExportItemFormatConfig(formatConfig);
return options;
}
}
......@@ -58,17 +58,22 @@ import org.olat.group.BusinessGroup;
/**
* @author schnider Comment: Archives the User selected wiki's to the personal
* folder of this user.
* @author fkiefer
*/
public class GenericArchiveController extends BasicController {
private static final String CMD_SELECT_NODE = "cmd.select.node";
private final Panel main;
private final VelocityContainer nodeChoose;
private TableController nodeListCtr;
private NodeTableDataModel nodeTableModel;
private CloseableModalController cmc;
private ChooseGroupController chooseGroupCtrl;
private boolean hideTitle;
private ArchiveOptions options;
private final CourseNode[] nodeTypes;
private final OLATResourceable ores;
......@@ -86,8 +91,11 @@ public class GenericArchiveController extends BasicController {
this.nodeTypes = nodeTypes;
main = new Panel("main");
VelocityContainer nodeChoose = createVelocityContainer("nodechoose");
nodeChoose = createVelocityContainer("nodechoose");
nodeChoose.contextPut("nodeType", nodeTypes[0].getType());
options = new ArchiveOptions();
doNodeChoose(ureq, nodeChoose);
putInitialPanel(main);
}
......@@ -241,7 +249,6 @@ public class GenericArchiveController extends BasicController {
}
private void archiveNode(UserRequest ureq, CourseNode node, BusinessGroup group) {
ArchiveOptions options = new ArchiveOptions();
options.setGroup(group);
ArchiveResource aResource = new ArchiveResource(node, ores, options, getLocale());
ureq.getDispatchResult().setResultingMediaResource(aResource);
......@@ -253,4 +260,17 @@ public class GenericArchiveController extends BasicController {
protected void doDispose() {
//
}
public boolean isHideTitle() {
return hideTitle;
}
public void setHideTitle(boolean hideTitle) {
this.hideTitle = hideTitle;
nodeChoose.contextPut("hideTitle", hideTitle);
}
public void setOptions(ArchiveOptions options) {
this.options = options;
}
}
\ No newline at end of file
/**
* <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.course.archiver;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
/**
* data container to persist result export config
*
* Initial Date: 18.04.2017
* @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
*/
public class QTIExportFormatConfig implements QTIExportItemFormatConfig {
private boolean responseCols;
private boolean positionsOfResponsesCol;
private boolean pointCol;
private boolean timeCols;
public QTIExportFormatConfig(boolean resCols, boolean posOfResCol, boolean pointCol, boolean timeCols){
this.responseCols = resCols;
this.positionsOfResponsesCol = posOfResCol;
this.pointCol = pointCol;
this.timeCols = timeCols;
}
public boolean hasResponseCols() {
return responseCols;
}
public boolean hasPositionsOfResponsesCol() {
return positionsOfResponsesCol;
}
public boolean hasPointCol() {
return pointCol;
}
public boolean hasTimeCols() {
return timeCols;
}
public void setPointCol(boolean pointColConfigured) {
this.pointCol = pointColConfigured;
}
public void setPositionsOfResponsesCol(boolean positionsOfResponsesColConfigured) {
this.positionsOfResponsesCol = positionsOfResponsesColConfigured;
}
public void setResponseCols(boolean responseColsConfigured) {
this.responseCols = responseColsConfigured;
}
public void setTimeCols(boolean timeColsConfigured) {
this.timeCols = timeColsConfigured;
}
}
/**
* <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.course.archiver;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
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.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.id.OLATResourceable;
import org.olat.course.nodes.CourseNode;
import org.springframework.beans.factory.annotation.Autowired;
/**
* wrapper for GenericArchiveController to handle individual export configuration
*
* Initial Date: 19.04.2017
* @author fkiefer, fabian.kiefer@frentix.com, www.frentix.com
*/
public class TestArchiveController extends BasicController {
private Link downloadOptionsEl;
private GenericArchiveController genericArchiveController;
private CloseableModalController cmc;
private ExportOptionsController exportOptionsCtrl;
private final CourseNode[] nodeTypes;
@Autowired
private FormatConfigHelper configHelper;
protected TestArchiveController(UserRequest ureq, WindowControl wControl, OLATResourceable ores, CourseNode... nodeTypes) {
super(ureq, wControl);
this.nodeTypes = nodeTypes;
VelocityContainer nodeChoose = createVelocityContainer("testarchive");
nodeChoose.contextPut("nodeType", nodeTypes[0].getType());
downloadOptionsEl = LinkFactory.createButton("download.options", nodeChoose, this);
downloadOptionsEl.setIconLeftCSS("o_icon o_icon_tools");
genericArchiveController = new GenericArchiveController(ureq, wControl, ores, nodeTypes);
genericArchiveController.setHideTitle(true);
genericArchiveController.setOptions(configHelper.getArchiveOptions(ureq));
listenTo(genericArchiveController);
nodeChoose.put("genericArchiveController", genericArchiveController.getInitialComponent());
putInitialPanel(nodeChoose);
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
if (source == downloadOptionsEl) {
doOpenExportOptios(ureq);
}
}
@Override
protected void event(UserRequest ureq, Controller source, Event event) {
if (source == exportOptionsCtrl) {
if (event == Event.DONE_EVENT) {
genericArchiveController.setOptions(configHelper.getArchiveOptions(ureq));
}
cmc.deactivate();
cleanUpPopups();
}
}
/**
* Aggressive clean up all popup controllers
*/
protected void cleanUpPopups() {
removeAsListenerAndDispose(exportOptionsCtrl);
removeAsListenerAndDispose(cmc);
exportOptionsCtrl = null;
cmc = null;
}
@Override
protected void doDispose() {
// nothing to dispose
}
private void doOpenExportOptios(UserRequest ureq) {
exportOptionsCtrl = new ExportOptionsController(ureq, getWindowControl(), nodeTypes[0]);
listenTo(exportOptionsCtrl);
cmc = new CloseableModalController(getWindowControl(), translate("close"), exportOptionsCtrl.getInitialComponent(),
true, translate("download.options"));
cmc.activate();
listenTo(cmc);
}
}
<h4>$r.translate("$nodeType")</h4>
#if (!$hideTitle)
<h4>$r.translate("$nodeType")</h4>
#end
#if($hasNodes)
#if (!$hideTitle)
<p>$r.translate("nodechoose.intro.$nodeType")</p>
#end
<p>$r.render("nodeTable")</p>
#else
<p>$r.translate("overview.nonodes.$nodeType")</p>
......
<div class="o_header_with_buttons">
<h4>$r.translate("$nodeType")</h4>
#if ($r.available("download.options"))
<div class="pull-right">
$r.render("download.options")
</div>
#end
</div>
<p>$r.translate("nodechoose.intro.$nodeType") $r.translate("nodechoose.intro.config")</p>
<p>$r.render("genericArchiveController")</p>
......@@ -33,6 +33,7 @@ course.res.feedback=Die Datei <b>{0}</b> mit den Resultaten liegt in Ihrem pers\
course.res.intro=Klicken Sie den untenstehenden 'Start'-Knopf um Endresultate von Tests, Bewertungen und Aufgaben zu archivieren.
course.res.title=Kursresultate
dialog=Dateidiskussionen
download.options=Download Optionen konfigurieren
iqtest=Testergebnisse
iqsurv=Ergebnisse des Fragebogens
pf=Teilnehmer Ordner
......@@ -77,6 +78,8 @@ menu.scorm=SCORM Resultate
menu.scorm.alt=SCORM Resultate
menu.wikis=Wikis
menu.wikis.alt=Wikis archivieren
nodechoose.intro.config=Das Archiv enth\u00E4lt: alle Benutzer, alle Fragen, alle Items. \u00E4ndern Sie die Download-Konfiguration mit der Schaltfl\u00E4che oben.
nodechoose.config.error=Bitte w\u00E4hlen Sie mindestens eine Konfiguration.
nodechoose.intro.pf=W\u00E4hlen Sie einen Kursbaustein aus, um dessen Ordnerinhalte zu archivieren.
nodechoose.intro.cl=W\u00E4hlen Sie im folgenden Dialog den Checklisten Baustein aus, der ausgewertet werden soll
nodechoose.intro.iqtest=W\u00E4hlen Sie einen Kursbaustein aus, um dessen Testergebnisse zu archivieren.
......@@ -112,3 +115,4 @@ table.action.select=Ausw\u00E4hlen
table.header.node=Kursbaustein
tool.name=Datenarchivierung
wiki=Wikis
form.title=Optionen einstellen:
\ No newline at end of file
......@@ -34,6 +34,7 @@ course.res.intro=Click the 'Start' button below in order to archive final result
course.res.title=Course results
pf=Participant Folder
dialog=File dialogs
download.options=Configure download options
iqtest=Test and self-test results
iqsurv=Questionnaire results
fo=Forums
......@@ -77,6 +78,8 @@ menu.scorm=SCORM results
menu.scorm.alt=SCORM results
menu.wikis=Wikis
menu.wikis.alt=Archive Wikis
nodechoose.intro.config=The archive will contain: all users, all questions, all items. Change download configuration using button above.
nodechoose.config.error=Please choose at least one configuration.
nodechoose.intro.pf=Choose a course element to archive the content of the participant folder.
nodechoose.intro.cl=Please select the checklist element you wish to archive.
nodechoose.intro.iqtest=Select a course element to archive its test results.
......@@ -112,3 +115,4 @@ table.action.select=Select
table.header.node=Course element
tool.name=Archive tool
wiki=Wikis
form.title=Setup options:
\ No newline at end of file
......@@ -23,18 +23,21 @@ import java.util.List;
import org.olat.core.id.Identity;
import org.olat.group.BusinessGroup;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
/**
*
* Initial date: 20.12.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
* @author fkiefer
*/
public class ArchiveOptions {
private BusinessGroup group;
private List<Identity> identities;
private QTIExportItemFormatConfig qtiExportItemFormatConfig;
public BusinessGroup getGroup() {
return group;
}
......@@ -50,4 +53,14 @@ public class ArchiveOptions {
public void setIdentities(List<Identity> identities) {
this.identities = identities;
}
public QTIExportItemFormatConfig getQtiExportItemFormatConfig() {
return qtiExportItemFormatConfig;
}
public void setQtiExportItemFormatConfig(QTIExportItemFormatConfig qtiExportItemFormatConfig) {
this.qtiExportItemFormatConfig = qtiExportItemFormatConfig;
}
}
......@@ -28,8 +28,10 @@ package org.olat.course.nodes;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipOutputStream;
import org.olat.admin.user.imp.TransientIdentity;
......@@ -79,9 +81,15 @@ import org.olat.fileresource.types.ImsQTI21Resource;
import org.olat.ims.qti.QTI12ResultDetailsController;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.QTIResultSet;
import org.olat.ims.qti.export.QTIExportEssayItemFormatConfig;
import org.olat.ims.qti.export.QTIExportFIBItemFormatConfig;
import org.olat.ims.qti.export.QTIExportFormatter;
import org.olat.ims.qti.export.QTIExportFormatterCSVType1;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
import org.olat.ims.qti.export.QTIExportKPRIMItemFormatConfig;
import org.olat.ims.qti.export.QTIExportMCQItemFormatConfig;
import org.olat.ims.qti.export.QTIExportManager;
import org.olat.ims.qti.export.QTIExportSCQItemFormatConfig;
import org.olat.ims.qti.fileresource.TestFileResource;
import org.olat.ims.qti.process.AssessmentInstance;
import org.olat.ims.qti.process.FilePersister;
......@@ -676,6 +684,15 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
String shortTitle = getShortTitle();
QTIExportManager qem = QTIExportManager.getInstance();
QTIExportFormatter qef = new QTIExportFormatterCSVType1(locale, "\t", "\"", "\r\n", false);
if (options.getQtiExportItemFormatConfig() != null) {
Map<Class<?>, QTIExportItemFormatConfig> itemConfigs = new HashMap<>();
Class<?>[] itemTypes = new Class<?>[] {QTIExportSCQItemFormatConfig.class, QTIExportMCQItemFormatConfig.class,
QTIExportKPRIMItemFormatConfig.class, QTIExportFIBItemFormatConfig.class, QTIExportEssayItemFormatConfig.class};
for (Class<?> itemClass : itemTypes) {
itemConfigs.put(itemClass, options.getQtiExportItemFormatConfig());
}
qef.setMapWithExportItemConfigs(itemConfigs);
}
return qem.selectAndExportResults(qef, courseResourceableId, shortTitle, getIdent(), re, exportStream, locale, ".xls");
}
} catch (IOException e) {
......
......@@ -51,10 +51,12 @@ import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
import org.olat.core.util.openxml.workbookstyle.CellStyle;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.archiver.QTIExportFormatConfig;
import org.olat.course.nodes.CourseNode;
import org.olat.fileresource.FileResourceManager;
import org.olat.ims.qti.export.QTIArchiver;
import org.olat.ims.qti.export.QTIExportFormatter;
import org.olat.ims.qti.export.QTIExportItemFormatConfig;
import org.olat.ims.qti.export.helper.IdentityAnonymizerCallback;
import org.olat.ims.qti21.AssessmentItemSession;
import org.olat.ims.qti21.AssessmentResponse;
......@@ -134,6 +136,7 @@ public class QTI21ArchiveFormat {
private IdentityAnonymizerCallback anonymizerCallback;
private final QTI21StatisticSearchParams searchParams;
private QTIExportItemFormatConfig exportConfig;
private List<ItemInfos> itemInfos;
private final Map<String, InteractionArchive> interactionArchiveMap = new HashMap<>();
......@@ -144,6 +147,10 @@ public class QTI21ArchiveFormat {
public QTI21ArchiveFormat(Locale locale, QTI21StatisticSearchParams searchParams) {
this.searchParams = searchParams;
this.exportConfig = searchParams.getArchiveOptions().getQtiExportItemFormatConfig();
if (exportConfig == null) {
exportConfig = new QTIExportFormatConfig(true, true, true, true);
}
userManager = CoreSpringFactory.getImpl(UserManager.class);
qtiService = CoreSpringFactory.getImpl(QTI21ServiceImpl.class);
......@@ -295,14 +302,25 @@ public class QTI21ArchiveFormat {
List<ItemInfos> infos = getItemInfos();
for(int i=0; i<infos.size(); i++) {
int delta = col;
ItemInfos item = infos.get(i);
List<Interaction> interactions = item.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeHeader1(item.getAssessmentItem(), interaction, i, j, header1Row, col, workbook);
if (exportConfig.hasResponseCols() || exportConfig.hasPointCol() || exportConfig.hasTimeCols()) {
List<Interaction> interactions = item.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeHeader1(item.getAssessmentItem(), interaction, i, j, header1Row, col, workbook);
}
}
if (!exportConfig.hasResponseCols()) {
col -= col - delta;
}
if (exportConfig.hasPointCol()) {
col++;
}
col += 3;//score, start, duration
if (exportConfig.hasTimeCols()) {
col += 2;
}
}
}
......@@ -337,16 +355,21 @@ public class QTI21ArchiveFormat {
List<ItemInfos> infos = getItemInfos();
for(int i=0; i<infos.size(); i++) {
ItemInfos info = infos.get(i);
List<Interaction> interactions = info.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeHeader2(info.getAssessmentItem(), interaction, i, j, header2Row, col, workbook);
if (exportConfig.hasResponseCols()) {
List<Interaction> interactions = info.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeHeader2(info.getAssessmentItem(), interaction, i, j, header2Row, col, workbook);
}
}
if (exportConfig.hasPointCol()) {
header2Row.addCell(col++, translator.translate("item.score"), headerStyle);
}
if (exportConfig.hasTimeCols()) {
header2Row.addCell(col++, translator.translate("item.start"), headerStyle);
header2Row.addCell(col++, translator.translate("item.duration"), headerStyle);
}
header2Row.addCell(col++, translator.translate("item.score"), headerStyle);
header2Row.addCell(col++, translator.translate("item.start"), headerStyle);
header2Row.addCell(col++, translator.translate("item.duration"), headerStyle);
}
}
......@@ -437,22 +460,33 @@ public class QTI21ArchiveFormat {
String itemRefIdentifier = itemRef.getIdentifier().toString();
AssessmentItemSession itemSession = responses.getItemSession(itemRefIdentifier);
List<Interaction> interactions = info.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
AssessmentResponse response = responses
.getResponse(itemRefIdentifier, interaction.getResponseIdentifier());
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeInteractionData(info.getAssessmentItem(), response, interaction, j, dataRow, col, workbook);
if (exportConfig.hasResponseCols()) {
List<Interaction> interactions = info.getInteractions();
for(int j=0; j<interactions.size(); j++) {
Interaction interaction = interactions.get(j);
AssessmentResponse response = responses
.getResponse(itemRefIdentifier, interaction.getResponseIdentifier());
col = interactionArchiveMap.get(interaction.getQtiClassName())
.writeInteractionData(info.getAssessmentItem(), response, interaction, j, dataRow, col, workbook);
}
}
//score, start, duration
if(itemSession == null) {
col += 3;
if (itemSession == null) {
if (exportConfig.hasPointCol()) {
col++;
}
if (exportConfig.hasTimeCols()) {
col += 2;
}
} else {
dataRow.addCell(col++, itemSession.getScore(), null);
dataRow.addCell(col++, itemSession.getCreationDate(), workbook.getStyles().getTimeStyle());
dataRow.addCell(col++, toDurationInMilliseconds(itemSession.getDuration()), null);
if (exportConfig.hasPointCol()) {
dataRow.addCell(col++, itemSession.getScore(), null);
}
if (exportConfig.hasTimeCols()) {
dataRow.addCell(col++, itemSession.getCreationDate(), workbook.getStyles().getTimeStyle());
dataRow.addCell(col++, toDurationInMilliseconds(itemSession.getDuration()), null);
}
}
}
}
......
......@@ -42,6 +42,8 @@ public class QTI21StatisticSearchParams {
private List<Group> limitToGroups;
private List<Identity> limitToIdentities;
private ArchiveOptions archiveOptions;
private boolean viewAnonymUsers;
private boolean viewAllUsers;
private boolean viewNonMembers;
......@@ -50,6 +52,7 @@ public class QTI21StatisticSearchParams {
this.testEntry = testEntry;
this.courseEntry = courseEntry;
this.nodeIdent = nodeIdent;
this.archiveOptions = options;
if(options == null) {
viewAnonymUsers = true;
......@@ -131,4 +134,14 @@ public class QTI21StatisticSearchParams {
public void setViewAnonymUsers(boolean viewAnonymUsers) {
this.viewAnonymUsers = viewAnonymUsers;
}
public ArchiveOptions getArchiveOptions() {
return archiveOptions;
}
public void setArchiveOptions(ArchiveOptions archiveOptions) {
this.archiveOptions = archiveOptions;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment