/** * <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.nodes.portfolio; import java.util.Date; import org.olat.NewControllerFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.link.Link; 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.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.BusinessControl; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseModule; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentManager; import org.olat.course.highscore.ui.HighScoreRunController; import org.olat.course.nodes.MSCourseNode; import org.olat.course.nodes.PortfolioCourseNode; import org.olat.course.nodes.portfolio.PortfolioCourseNodeConfiguration.DeadlineType; import org.olat.course.run.scoring.ScoreAccounting; import org.olat.course.run.scoring.ScoreEvaluation; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.modules.ModuleConfiguration; import org.olat.modules.portfolio.Binder; import org.olat.modules.portfolio.BinderStatus; import org.olat.modules.portfolio.PortfolioLoggingAction; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.handler.BinderTemplateResource; import org.olat.portfolio.EPLoggingAction; import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.model.structel.EPStructuredMap; import org.olat.portfolio.model.structel.PortfolioStructureMap; import org.olat.repository.RepositoryEntry; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; /** * * Description:<br> * Portfolio run controller. You can take a map if you are in some learning * groups of the course. The controller check if there is a deadline for * the map and if yes, set it. * * <P> * Initial Date: 6 oct. 2010 <br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ public class PortfolioCourseNodeRunController extends FormBasicController { private PortfolioStructureMap copyMap; private PortfolioStructureMap templateMap; private Binder copyBinder; private Binder templateBinder; private final PortfolioCourseNode courseNode; private final ModuleConfiguration config; private final OLATResourceable courseOres; private FormLink newMapLink; private FormLink selectMapLink; private StaticTextElement newMapMsgEl, deadlineDateText; private FormLayoutContainer infosContainer, assessmentInfosContainer; private DialogBoxController restoreBinderCtrl; private Formatter formatter; private final UserCourseEnvironment userCourseEnv; @Autowired private EPFrontendManager ePFMgr; @Autowired private PortfolioService portfolioService; public PortfolioCourseNodeRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, PortfolioCourseNode courseNode) { super(ureq, wControl, "run"); this.courseNode = courseNode; this.config = courseNode.getModuleConfiguration(); this.userCourseEnv = userCourseEnv; Long courseResId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); courseOres = OresHelper.createOLATResourceableInstance(CourseModule.class, courseResId); formatter = Formatter.getInstance(getLocale()); RepositoryEntry mapEntry = courseNode.getReferencedRepositoryEntry(); if(mapEntry != null) { if(BinderTemplateResource.TYPE_NAME.equals(mapEntry.getOlatResource().getResourceableTypeName())) { templateBinder = portfolioService.getBinderByResource(mapEntry.getOlatResource()); } else { templateMap = (PortfolioStructureMap) ePFMgr.loadPortfolioStructure(mapEntry.getOlatResource()); } } initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { infosContainer = FormLayoutContainer.createDefaultFormLayout("infos", getTranslator()); formLayout.add(infosContainer); String assessmentPage = velocity_root + "/assessment_infos.html"; assessmentInfosContainer = FormLayoutContainer.createCustomFormLayout("assessmentInfos", getTranslator(), assessmentPage); assessmentInfosContainer.setVisible(false); formLayout.add(assessmentInfosContainer); VelocityContainer mainVC = ((FormLayoutContainer) formLayout).getFormItemComponent(); if (courseNode.getModuleConfiguration().getBooleanSafe(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD,false)){ HighScoreRunController highScoreCtr = new HighScoreRunController(ureq, getWindowControl(), userCourseEnv, courseNode, this.mainForm); if (highScoreCtr.isViewHighscore()) { Component highScoreComponent = highScoreCtr.getInitialComponent(); mainVC.put("highScore", highScoreComponent); } } Object text = config.get(PortfolioCourseNodeConfiguration.NODE_TEXT); String explanation = (text instanceof String) ? (String)text : ""; if(StringHelper.containsNonWhitespace(explanation)) { uifactory.addStaticTextElement("explanation.text", explanation, infosContainer); } String deadlineconfig = (String)config.get(PortfolioCourseNodeConfiguration.DEADLINE_TYPE); if (!DeadlineType.none.name().equals(deadlineconfig) && deadlineconfig!=null){ // show deadline-config String deadLineLabel = "map.deadline." + deadlineconfig + ".label"; String deadLineInfo = ""; if (deadlineconfig.equals(DeadlineType.absolut.name())){ Formatter f = Formatter.getInstance(getLocale()); deadLineInfo = f.formatDate((Date)config.get(PortfolioCourseNodeConfiguration.DEADLINE_DATE)); } else { deadLineInfo = getDeadlineRelativeInfo(); } deadlineDateText = uifactory.addStaticTextElement("deadline", deadLineLabel, deadLineInfo, infosContainer); } if(templateMap != null || templateBinder != null) { updateUI(); } } private String getDeadlineRelativeInfo(){ String[] args = new String[3]; String month = (String)config.get(PortfolioCourseNodeConfiguration.DEADLINE_MONTH); if (StringHelper.containsNonWhitespace(month)) args[0] = translate("map.deadline.info.month", month); else args[0] = ""; String week = (String)config.get(PortfolioCourseNodeConfiguration.DEADLINE_WEEK); if (StringHelper.containsNonWhitespace(week)) args[1] = translate("map.deadline.info.week", week); else args[1] = ""; String day = (String)config.get(PortfolioCourseNodeConfiguration.DEADLINE_DAY); if (StringHelper.containsNonWhitespace(day)) args[2] = translate("map.deadline.info.day", day); else args[2] = ""; String deadLineInfo = translate("map.deadline.info", args); return deadLineInfo; } protected void updateUI() { if(templateMap != null) { copyMap = ePFMgr.loadPortfolioStructureMap(getIdentity(), templateMap, courseOres, courseNode.getIdent(), null); } else if(templateBinder != null) { RepositoryEntry courseEntry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); copyBinder = portfolioService.getBinder(getIdentity(), templateBinder, courseEntry, courseNode.getIdent()); } if(copyMap == null && (copyBinder == null || copyBinder.getBinderStatus() == BinderStatus.deleted)) { updateEmptyUI(); } else { updateSelectedUI(); } if(selectMapLink != null) { selectMapLink.setVisible(copyMap != null || (copyBinder != null && copyBinder.getBinderStatus() != BinderStatus.deleted)); } if(newMapLink != null) { newMapLink.setVisible(copyMap == null && (copyBinder == null || copyBinder.getBinderStatus() == BinderStatus.deleted)); } if(newMapMsgEl != null) { newMapMsgEl.setVisible(copyMap == null && (copyBinder == null || copyBinder.getBinderStatus() == BinderStatus.deleted)); } } private void updateEmptyUI() { String title = ""; if(templateMap != null) { title = StringHelper.escapeHtml(templateMap.getTitle()); } else if(templateBinder != null) { title = StringHelper.escapeHtml(templateBinder.getTitle()); } String msg = translate("map.available", new String[]{ title }); if(newMapMsgEl == null) { newMapMsgEl = uifactory.addStaticTextElement("map.available", msg, infosContainer); } newMapMsgEl.setLabel(null, null); FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonGroupLayout.setRootForm(mainForm); infosContainer.add(buttonGroupLayout); if(newMapLink == null) { newMapLink = uifactory.addFormLink("map.new", buttonGroupLayout, Link.BUTTON); newMapLink.setElementCssClass("o_sel_ep_new_map_template"); } } private void updateSelectedUI() { if(selectMapLink == null) { selectMapLink = uifactory.addFormLink("select", "select.mymap", "select.mymap", infosContainer, Link.LINK); selectMapLink.setElementCssClass("o_sel_ep_select_map"); } else { selectMapLink.setVisible(true); } if(copyMap != null) { updateSelectedMapUI(); } else if(copyBinder != null) { updateSelectedBinderUI(); } } private void updateSelectedBinderUI() { String copyTitle = StringHelper.escapeHtml(copyBinder.getTitle()); selectMapLink.getComponent().setCustomDisplayText(copyTitle); updateCopyDate(copyBinder.getCopyDate()); updateAssessmentInfos(copyBinder.getReturnDate()); updateDeadlineText(copyBinder.getDeadLine()); } private void updateSelectedMapUI() { String copyTitle = StringHelper.escapeHtml(copyMap.getTitle()); selectMapLink.getComponent().setCustomDisplayText(copyTitle); // show results, when already handed in EPStructuredMap structuredMap = (EPStructuredMap)copyMap; updateCopyDate(structuredMap.getCopyDate()); updateAssessmentInfos(structuredMap.getReturnDate()); updateDeadlineText(structuredMap.getDeadLine()); } private void updateCopyDate(Date copyDate) { if(copyDate != null) { String copyDateStr = formatter.formatDateAndTime(copyDate); uifactory.addStaticTextElement("map.copyDate", copyDateStr, infosContainer); } } /** * Show absolute deadline when task is taken. nothing if taken map still has a deadline configured. * @param deadline */ private void updateDeadlineText(Date deadlineDate) { if (deadlineDateText != null && deadlineDate != null) { String deadline = formatter.formatDateAndTime(deadlineDate); deadlineDateText.setValue(deadline); deadlineDateText.setLabel("map.deadline.absolut.label", null); } } private void updateAssessmentInfos(Date returnDate) { if(returnDate != null || copyBinder != null) { String rDate = formatter.formatDateAndTime(returnDate); uifactory.addStaticTextElement("map.returnDate", rDate, infosContainer); // Fetch all score and passed and calculate score accounting for the entire course ScoreAccounting scoreAccounting = userCourseEnv.getScoreAccounting(); scoreAccounting.evaluateAll(); ScoreEvaluation scoreEval = scoreAccounting.evalCourseNode(courseNode); boolean resultsVisible = scoreEval.getUserVisible() == null || scoreEval.getUserVisible().booleanValue(); assessmentInfosContainer.contextPut("resultsVisible", resultsVisible); //score assessmentInfosContainer.contextPut("hasScoreField", new Boolean(courseNode.hasScoreConfigured())); if(courseNode.hasScoreConfigured()) { Float score = scoreEval.getScore(); Float minScore = courseNode.getMinScoreConfiguration(); Float maxScore = courseNode.getMaxScoreConfiguration(); assessmentInfosContainer.contextPut("scoreMin", AssessmentHelper.getRoundedScore(minScore)); assessmentInfosContainer.contextPut("scoreMax", AssessmentHelper.getRoundedScore(maxScore)); assessmentInfosContainer.contextPut("score", AssessmentHelper.getRoundedScore(score)); } //passed assessmentInfosContainer.contextPut("hasPassedField", new Boolean(courseNode.hasPassedConfigured())); if(courseNode.hasPassedConfigured()) { Boolean passed = scoreEval.getPassed(); assessmentInfosContainer.contextPut("passed", passed); assessmentInfosContainer.contextPut("hasPassedValue", new Boolean(passed != null)); Float cutValue = courseNode.getCutValueConfiguration(); assessmentInfosContainer.contextPut("passedCutValue", AssessmentHelper.getRoundedScore(cutValue)); } // get comment if(resultsVisible) { AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager(); String comment = am.getNodeComment(courseNode, getIdentity()); assessmentInfosContainer.contextPut("hasCommentField", new Boolean(comment != null)); if (comment != null) { assessmentInfosContainer.contextPut("comment", comment); } } assessmentInfosContainer.setVisible(true); } else { assessmentInfosContainer.setVisible(false); } } @Override protected void doDispose() { // } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(restoreBinderCtrl == source) { if(DialogBoxUIFactory.isYesEvent(event)) { doRestore(); updateUI(); } } super.event(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { // } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == newMapLink) { RepositoryEntry courseEntry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry(); Date deadline = courseNode.getDeadline(); if(templateMap != null) { copyMap = ePFMgr.assignStructuredMapToUser(getIdentity(), templateMap, courseEntry, courseNode.getIdent(), null, deadline); if(copyMap != null) { showInfo("map.copied", StringHelper.escapeHtml(templateMap.getTitle())); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapPortfolioOres(copyMap)); ThreadLocalUserActivityLogger.log(EPLoggingAction.EPORTFOLIO_TASK_STARTED, getClass()); } } else if(templateBinder != null) { if(copyBinder == null) { copyBinder = portfolioService.assignBinder(getIdentity(), templateBinder, courseEntry, courseNode.getIdent(), deadline); if(copyBinder != null) { showInfo("map.copied", StringHelper.escapeHtml(templateBinder.getTitle())); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrap(copyBinder)); ThreadLocalUserActivityLogger.log(PortfolioLoggingAction.PORTFOLIO_TASK_STARTED, getClass()); } } else if(copyBinder != null && copyBinder.getBinderStatus() == BinderStatus.deleted) { String title = translate("trashed.binder.confirm.title"); String text = translate("trashed.binder.confirm.descr", new String[]{ StringHelper.escapeHtml(copyBinder.getTitle()) }); restoreBinderCtrl = activateYesNoDialog(ureq, title, text, restoreBinderCtrl); restoreBinderCtrl.setUserObject(copyBinder); return; } } updateUI(); } else if (source == selectMapLink) { String resourceUrl; if(copyMap != null) { resourceUrl = "[HomeSite:" + getIdentity().getKey() + "][Portfolio:0][EPStructuredMap:" + copyMap.getKey() + "]"; } else if(copyBinder != null) { resourceUrl = "[HomeSite:" + getIdentity().getKey() + "][PortfolioV2:0][MyBinders:0][Binder:" + copyBinder.getKey() + "]"; } else { return; } BusinessControl bc = BusinessControlFactory.getInstance().createFromString(resourceUrl); WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl()); NewControllerFactory.getInstance().launch(ureq, bwControl); } } private void doRestore() { copyBinder = portfolioService.getBinderByKey(copyBinder.getKey()); copyBinder.setBinderStatus(BinderStatus.open); copyBinder = portfolioService.updateBinder(copyBinder); showInfo("restore.binder.success"); } }