/**
* <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.modules.scorm.assessment;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.table.BaseTableDataModelWithoutFilter;
import org.olat.core.gui.components.table.DefaultColumnDescriptor;
import org.olat.core.gui.components.table.StaticColumnDescriptor;
import org.olat.core.gui.components.table.TableController;
import org.olat.core.gui.components.table.TableDataModel;
import org.olat.core.gui.components.table.TableEvent;
import org.olat.core.gui.components.table.TableGuiConfiguration;
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.gui.control.generic.modal.DialogBoxController;
import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.User;
import org.olat.core.id.UserConstants;
import org.olat.core.util.StringHelper;
import org.olat.course.nodes.ScormCourseNode;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.modules.scorm.server.servermodels.ScoUtils;
/**
*
* Description:<br>
* Show the assessment's details of SCORM course for a selected user. A popup shows all the
* CMI datas of the SCOs visited by the user
*
* <P>
* Initial Date: 17 août 2009 <br>
* @author srosse
*/
public class ScormResultDetailsController extends BasicController {
private static final String CMI_RAW_SCORE = "cmi.core.score.raw";
private static final String CMI_TOTAL_TIME = "cmi.core.total_time";
private VelocityContainer main;
private TableController summaryTableCtr;
private TableController cmiTableCtr;
private CloseableModalController cmc;
private Link resetButton;
private DialogBoxController resetConfirmationBox;
private final ScormCourseNode node;
private final UserCourseEnvironment coachCourseEnv;
private final UserCourseEnvironment assessedUserCourseEnv;
public ScormResultDetailsController(UserRequest ureq, WindowControl wControl, ScormCourseNode node,
UserCourseEnvironment coachCourseEnv, UserCourseEnvironment assessedUserCourseEnv) {
super(ureq, wControl);
this.node = node;
this.coachCourseEnv = coachCourseEnv;
this.assessedUserCourseEnv = assessedUserCourseEnv;
init(ureq);
}
protected void init(UserRequest ureq) {
main = createVelocityContainer("scores");
TableGuiConfiguration summaryTableConfig = new TableGuiConfiguration();
summaryTableConfig.setDownloadOffered(true);
summaryTableCtr = new TableController(summaryTableConfig, ureq, getWindowControl(), getTranslator());
summaryTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("summary.column.header.date", 0, null, ureq.getLocale()));
summaryTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("summary.column.header.duration", 1, null, ureq.getLocale()));
summaryTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("summary.column.header.assesspoints", 2, null, ureq.getLocale()));
summaryTableCtr.addColumnDescriptor(new StaticColumnDescriptor("sel", "summary.column.header.details", getTranslator().translate("select")));
CourseEnvironment courseEnv = assessedUserCourseEnv.getCourseEnvironment();
String username = assessedUserCourseEnv.getIdentityEnvironment().getIdentity().getName();
// <OLATCE-289>
Map<Date, List<CmiData>> rawDatas = ScormAssessmentManager.getInstance().visitScoDatasMultiResults(username, courseEnv, node);
summaryTableCtr.setTableDataModel(new SummaryTableDataModelMultiResults(rawDatas));
// </OLATCE-289>
listenTo(summaryTableCtr);
main.put("summary", summaryTableCtr.getInitialComponent());
if(!coachCourseEnv.isCourseReadOnly()) {
resetButton = LinkFactory.createButton("reset", main, this);
main.put("resetButton", resetButton);
}
putInitialPanel(main);
}
@Override
protected void doDispose() {
//
}
@Override
protected void event(UserRequest ureq, Component source, Event event) {
if(source == resetButton) {
String title = translate("reset.title");
User user = assessedUserCourseEnv.getIdentityEnvironment().getIdentity().getUser();
String name = user.getProperty(UserConstants.FIRSTNAME, null) + " " + user.getProperty(UserConstants.LASTNAME, null);
String text = translate("reset.text", new String[]{name});
resetConfirmationBox = activateOkCancelDialog(ureq, title, text, resetConfirmationBox);
}
}
@Override
public void event(UserRequest ureq, Controller source, Event event) {
if (source == summaryTableCtr) {
TableEvent tEvent = (TableEvent)event;
if (tEvent.getActionId().equals("sel")) {
TableGuiConfiguration tableConfig = new TableGuiConfiguration();
tableConfig.setPreferencesOffered(true, "scormAssessmentDetails");
removeAsListenerAndDispose(cmiTableCtr);
cmiTableCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
listenTo(cmiTableCtr);
cmiTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("cmis.column.header.itemId", 0, null, ureq.getLocale()));
cmiTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("cmis.column.header.translatedKey", 1, null, ureq.getLocale()));
cmiTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("cmis.column.header.key", 2, null, ureq.getLocale()));
cmiTableCtr.addColumnDescriptor(new DefaultColumnDescriptor("cmis.column.header.value", 3, null, ureq.getLocale()));
// <BPS-252> BPS-252_3
int rowId = tEvent.getRowId();
List<CmiData> data = ((SummaryTableDataModelMultiResults)summaryTableCtr.getTableDataModel()).getObject(rowId);
cmiTableCtr.setTableDataModel(new CmiTableDataModel(getTranslator(), data));
// </BPS-252> BPS-252_3
removeAsListenerAndDispose(cmc);
cmc = new CloseableModalController(getWindowControl(), translate("close"), cmiTableCtr.getInitialComponent());
listenTo(cmc);
cmc.activate();
}
} else if ( source == resetConfirmationBox) {
if (DialogBoxUIFactory.isOkEvent(event)) {
//delete scorm
String username = assessedUserCourseEnv.getIdentityEnvironment().getIdentity().getName();
CourseEnvironment courseEnv = assessedUserCourseEnv.getCourseEnvironment();
ScormAssessmentManager.getInstance().deleteResults(username, courseEnv, node);
fireEvent(ureq, Event.DONE_EVENT);
}
}
}
public static class CmiTableDataModel extends BaseTableDataModelWithoutFilter<CmiData> {
private final List<CmiData> datas;
private final Translator translator;
private final Pattern pattern = Pattern.compile("[0-9]");
public CmiTableDataModel(Translator translator, List<CmiData> datas) {
this.datas = datas;
this.translator = translator;
}
public int getColumnCount() {
return 3;
}
public int getRowCount() {
return datas.size();
}
public Object getValueAt(int row, int col) {
CmiData data = datas.get(row);
switch(col) {
case 0: return data.getItemId();
case 1:
String key = data.getKey();
String translation;
try {
Matcher matcher = pattern.matcher(key);
if(matcher.find()) {
String pos = key.substring(matcher.start(), matcher.end());
if(matcher.find()) {
String pos2 = key.substring(matcher.start(), matcher.end());
key = key.replace(pos + ".", "").replace(pos2 + ".", "");
translation = translator.translate(key, new String[]{pos,pos2});
}
else {
key = key.replace(pos + ".", "");
translation = translator.translate(key, new String[]{pos});
}
}
else {
translation = translator.translate(key);
}
if(translation == null || translation.length() > 150) {
return data.getKey();
}
return translation;
}
catch(Exception ex) {
return key;
}
case 2: return data.getKey();
case 3: return data.getValue();
default: return "ERROR";
}
}
}
// <OLATCE-289>
/**
* Description:<br>
* A TableDataModel for multi scorm results files.
*
* <P>
* Initial Date: 07.01.2010 <br>
* @author thomasw
*/
public static class SummaryTableDataModelMultiResults implements TableDataModel<List<CmiData>> {
private final Map<Date, List<CmiData>> objects;
/**
* Array of Keys of the Object-Map. The Key is at the same time the
* String representation of the last modified date.
*/
private Date[] objectKeys;
public SummaryTableDataModelMultiResults(Map<Date, List<CmiData>> datas) {
objects = datas;
if(objects != null) {
objectKeys = objects.keySet().toArray(new Date[objects.size()]);
}
}
public int getColumnCount() {
return 3;
}
public int getRowCount() {
return objects == null ? 0 : objects.size();
}
public Object getValueAt(int row, int col) {
Date dateKey = objectKeys[row];
List<CmiData> cmiObject = objects.get(dateKey);
String[] result = calcTimeAndScore(cmiObject);
switch (col) {
case 0:
return dateKey;
case 1:
return result[0];
case 2:
return result[1];
default: return "ERROR";
}
}
private String[] calcTimeAndScore(List<CmiData> cmiObject) {
double score = 0;
String totalTime = null;
for(CmiData data:cmiObject) {
String key = data.getKey();
if(CMI_RAW_SCORE.equals(key)) {
String value = data.getValue();
if(StringHelper.containsNonWhitespace(value)) {
try {
score += Double.parseDouble(value);
} catch (NumberFormatException e) {
//fail silently
}
}
}
else if(CMI_TOTAL_TIME.equals(key)) {
String value = data.getValue();
if(StringHelper.containsNonWhitespace(value)) {
if(totalTime == null) {
totalTime = value;
}
else {
totalTime = ScoUtils.addTimes(totalTime, value);
}
}
}
}
String[] result = new String[2];
result[0] = totalTime;
result[1] = "" + score;
return result;
}
@Override
public Object createCopyWithEmptyList() {
return new SummaryTableDataModelMultiResults(new HashMap<Date, List<CmiData>>());
}
@Override
public List<CmiData> getObject(int row) {
Date dateKey = objectKeys[row];
List<CmiData> cmiObject = objects.get(dateKey);
return cmiObject;
}
@Override
public void setObjects(List<List<CmiData>> objects) {
//
}
}
// </OLATCE-289>
}