From 799e419646832c40f9dec122b5cc04512113f12d Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Fri, 26 Feb 2021 06:57:41 +0100 Subject: [PATCH] OO-5313: let float the stop assessment mode button --- .../ui/tool/AssessmentToolController.java | 127 ++--------- .../tool/StopAssessmentWarningController.java | 213 ++++++++++++++++++ .../ui/tool/event/StopAssessmentEvent.java | 40 ++++ .../course/run/CourseRuntimeController.java | 2 +- 4 files changed, 272 insertions(+), 110 deletions(-) create mode 100644 src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java create mode 100644 src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java index 755d06ff5bc..7947b45ac67 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentToolController.java @@ -22,7 +22,6 @@ package org.olat.course.assessment.ui.tool; import java.util.Date; import java.util.List; -import org.olat.commons.calendar.CalendarUtils; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -32,32 +31,28 @@ import org.olat.core.gui.components.stack.PopEvent; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.stack.TooledStackedPanel.Align; import org.olat.core.gui.components.tree.TreeNode; -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.MainLayoutBasicController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; -import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; -import org.olat.core.util.Formatter; -import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.assessment.AssessmentMode; -import org.olat.course.assessment.AssessmentModeCoordinationService; import org.olat.course.assessment.AssessmentModeManager; import org.olat.course.assessment.AssessmentModule; import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.bulk.BulkAssessmentOverviewController; import org.olat.course.assessment.ui.tool.event.AssessmentModeStatusEvent; import org.olat.course.assessment.ui.tool.event.CourseNodeEvent; +import org.olat.course.assessment.ui.tool.event.StopAssessmentEvent; import org.olat.course.config.ui.AssessmentResetController; import org.olat.course.config.ui.AssessmentResetController.AssessmentResetEvent; import org.olat.course.nodeaccess.NodeAccessService; @@ -67,7 +62,6 @@ import org.olat.modules.assessment.ui.AssessedIdentityListState; import org.olat.modules.assessment.ui.AssessmentToolContainer; import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback; import org.olat.modules.assessment.ui.event.UserSelectionEvent; -import org.olat.modules.lecture.LectureService; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; @@ -88,20 +82,17 @@ public class AssessmentToolController extends MainLayoutBasicController implemen private Link overviewLink; private Link bulkAssessmentLink; private Link recalculateLink; - private Link stopAssessmentMode; private final TooledStackedPanel stackPanel; private final AssessmentToolContainer toolContainer; private final ButtonGroupComponent segmentButtonsCmp; private CloseableModalController cmc; - private ConfirmStopAssessmentModeController stopCtrl; private AssessmentCourseTreeController courseTreeCtrl; private AssessmentCourseOverviewController overviewCtrl; private BulkAssessmentOverviewController bulkAssessmentOverviewCtrl; private AssessmentResetController assessmentResetCtrl; + private StopAssessmentWarningController stopAssessmentCtrl; - @Autowired - private LectureService lectureService; @Autowired private CourseAssessmentService courseAssessmentService; @Autowired @@ -110,8 +101,6 @@ public class AssessmentToolController extends MainLayoutBasicController implemen private AssessmentService assessmentService; @Autowired private AssessmentModeManager assessmentModeManager; - @Autowired - private AssessmentModeCoordinationService assessmentModeCoordinationService; public AssessmentToolController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RepositoryEntry courseEntry, UserCourseEnvironment coachUserEnv, AssessmentToolSecurityCallback assessmentCallback) { @@ -132,82 +121,22 @@ public class AssessmentToolController extends MainLayoutBasicController implemen putInitialPanel(overviewCtrl.getInitialComponent()); } - public void assessmentModeMessage() { + public void assessmentModeMessage(UserRequest ureq) { List<AssessmentMode> modes = assessmentModeManager.getCurrentAssessmentMode(courseEntry, new Date()); if(!modes.isEmpty()) { - VelocityContainer warn = createVelocityContainer("assessment_mode_warn"); - if(modes.size() == 1) { - AssessmentMode mode = modes.get(0); - assessmemntModeMessageFormatting("assessment.mode.now", modes, warn); - if(canStopAssessmentMode(mode)) { - String modeName = mode.getName(); - String label = translate("assessment.tool.stop", new String[] { StringHelper.escapeHtml(modeName) }); - stopAssessmentMode = LinkFactory.createCustomLink("assessment.stop", "stop", label, Link.BUTTON_SMALL | Link.NONTRANSLATED, warn, this); - stopAssessmentMode.setIconLeftCSS("o_icon o_icon-fw o_as_mode_stop"); - if(assessmentModeCoordinationService.isDisadvantageCompensationExtensionTime(mode)) { - stopAssessmentMode.setIconRightCSS("o_icon o_icon-fw o_icon_disadvantage_compensation"); - } - stopAssessmentMode.setUserObject(mode); - } - } else { - assessmemntModeMessageFormatting("assessment.mode.several.now", modes, warn); + // don't use listenTo as the controller must survive the assessment tool controller + if(stopAssessmentCtrl != null) { + stopAssessmentCtrl.removeControllerListener(this); } - stackPanel.setMessageComponent(warn); + stopAssessmentCtrl = new StopAssessmentWarningController(ureq, getWindowControl(), stackPanel, + courseEntry, modes, assessmentCallback); + stopAssessmentCtrl.addControllerListener(this); + stackPanel.setMessageComponent(stopAssessmentCtrl.getInitialComponent()); } else { stackPanel.setMessageComponent(null); } } - private void assessmemntModeMessageFormatting(String i18nMessage, List<AssessmentMode> modes, VelocityContainer warn) { - Date begin = getBeginOfModes(modes); - Date end = getEndOfModes(modes); - - String start; - String stop; - Formatter formatter = Formatter.getInstance(getLocale()); - if(CalendarUtils.isSameDay(begin, end)) { - start = formatter.formatTimeShort(begin); - stop = formatter.formatTimeShort(end); - } else { - start = formatter.formatDateAndTime(begin); - stop = formatter.formatDateAndTime(end); - } - warn.contextPut("message", translate(i18nMessage, new String[] { start, stop })); - } - - private Date getBeginOfModes(List<AssessmentMode> modes) { - Date start = null; - for(AssessmentMode mode:modes) { - Date begin = mode.getBegin(); - if(start == null || (begin != null && begin.before(start))) { - start = begin; - } - } - return start; - } - - private Date getEndOfModes(List<AssessmentMode> modes) { - Date stop = null; - for(AssessmentMode mode:modes) { - Date end = mode.getEnd(); - if(stop == null || (end != null && end.after(stop))) { - stop = end; - } - } - return stop; - } - - private boolean canStopAssessmentMode(AssessmentMode mode) { - if(assessmentCallback.canStartStopAllAssessments()) { - return assessmentModeCoordinationService.canStop(mode); - } else if(mode.getLectureBlock() != null) { - List<Identity> teachers = lectureService.getTeachers(mode.getLectureBlock()); - return teachers.contains(getIdentity()) - && assessmentModeCoordinationService.canStop(mode); - } - return false; - } - public void initToolbar() { overviewLink = LinkFactory.createToolLink("overview", translate("overview"), this/*, "o_icon_user"*/); overviewLink.setElementCssClass("o_sel_assessment_tool_overview"); @@ -237,6 +166,9 @@ public class AssessmentToolController extends MainLayoutBasicController implemen if(stackPanel != null) { stackPanel.removeListener(this); } + if(stopAssessmentCtrl != null) { + stopAssessmentCtrl.removeControllerListener(this); + } } @Override @@ -271,8 +203,6 @@ public class AssessmentToolController extends MainLayoutBasicController implemen } else if(bulkAssessmentLink == source) { cleanUp(); doBulkAssessmentView(ureq); - } else if(stopAssessmentMode == source) { - doConfirmStop(ureq, (AssessmentMode)stopAssessmentMode.getUserObject()); } else if(stackPanel == source) { if(event instanceof PopEvent) { PopEvent pe = (PopEvent)event; @@ -319,14 +249,8 @@ public class AssessmentToolController extends MainLayoutBasicController implemen doSelectNodeView(ureq, cne.getIdent()); } } else if(event instanceof AssessmentModeStatusEvent) { - assessmentModeMessage(); + assessmentModeMessage(ureq); } - } else if(stopCtrl == source) { - if(event == Event.DONE_EVENT) { - doAfterStop(); - } - cmc.deactivate(); - cleanUp(); } else if(source == assessmentResetCtrl) { if (event instanceof AssessmentResetEvent) { AssessmentResetEvent are = (AssessmentResetEvent)event; @@ -334,6 +258,10 @@ public class AssessmentToolController extends MainLayoutBasicController implemen } cmc.deactivate(); cleanUp(); + } else if(stopAssessmentCtrl == source) { + if(event instanceof StopAssessmentEvent) { + overviewCtrl.reloadAssessmentModes(); + } } else if (source == cmc) { cmc.deactivate(); cleanUp(); @@ -344,11 +272,9 @@ public class AssessmentToolController extends MainLayoutBasicController implemen private void cleanUp() { removeAsListenerAndDispose(bulkAssessmentOverviewCtrl); removeAsListenerAndDispose(assessmentResetCtrl); - removeAsListenerAndDispose(stopCtrl); removeAsListenerAndDispose(cmc); bulkAssessmentOverviewCtrl = null; assessmentResetCtrl = null; - stopCtrl = null; cmc = null; } @@ -427,21 +353,4 @@ public class AssessmentToolController extends MainLayoutBasicController implemen segmentButtonsCmp.setSelectedButton(usersLink); return courseTreeCtrl; } - - private void doConfirmStop(UserRequest ureq, AssessmentMode mode) { - if(guardModalController(stopCtrl)) return; - - stopCtrl = new ConfirmStopAssessmentModeController(ureq, getWindowControl(), mode); - listenTo(stopCtrl); - - String title = translate("confirm.stop.title"); - cmc = new CloseableModalController(getWindowControl(), "close", stopCtrl.getInitialComponent(), true, title, true); - cmc.activate(); - listenTo(cmc); - } - - private void doAfterStop() { - assessmentModeMessage(); - overviewCtrl.reloadAssessmentModes(); - } } diff --git a/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java b/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java new file mode 100644 index 00000000000..e06c2511df9 --- /dev/null +++ b/src/main/java/org/olat/course/assessment/ui/tool/StopAssessmentWarningController.java @@ -0,0 +1,213 @@ +/** + * <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.assessment.ui.tool; + +import java.util.Date; +import java.util.List; + +import org.olat.commons.calendar.CalendarUtils; +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.stack.TooledStackedPanel; +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.Identity; +import org.olat.core.util.Formatter; +import org.olat.core.util.StringHelper; +import org.olat.course.assessment.AssessmentMode; +import org.olat.course.assessment.AssessmentModeCoordinationService; +import org.olat.course.assessment.AssessmentModeManager; +import org.olat.course.assessment.ui.tool.event.StopAssessmentEvent; +import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback; +import org.olat.modules.lecture.LectureService; +import org.olat.repository.RepositoryEntry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 25 févr. 2021<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class StopAssessmentWarningController extends BasicController { + + private Link stopAssessmentMode; + private final VelocityContainer mainVC; + private final TooledStackedPanel stackPanel; + + private final RepositoryEntry courseEntry; + private final AssessmentToolSecurityCallback assessmentCallback; + + private CloseableModalController cmc; + private ConfirmStopAssessmentModeController stopCtrl; + + @Autowired + private LectureService lectureService; + @Autowired + private AssessmentModeManager assessmentModeManager; + @Autowired + private AssessmentModeCoordinationService assessmentModeCoordinationService; + + public StopAssessmentWarningController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, + RepositoryEntry courseEntry, List<AssessmentMode> modes, AssessmentToolSecurityCallback assessmentCallback) { + super(ureq, wControl); + this.stackPanel = stackPanel; + this.courseEntry = courseEntry; + this.assessmentCallback = assessmentCallback; + mainVC = createVelocityContainer("assessment_mode_warn"); + assessmentModeMessage(modes); + putInitialPanel(mainVC); + } + + @Override + protected void doDispose() { + // + } + private void reloadAssessmentModeMessage() { + List<AssessmentMode> modes = assessmentModeManager.getCurrentAssessmentMode(courseEntry, new Date()); + if(modes.isEmpty()) { + stackPanel.setMessageComponent(null); + } else { + assessmentModeMessage(modes); + } + } + + private void assessmentModeMessage(List<AssessmentMode> modes) { + if(modes.size() == 1) { + AssessmentMode mode = modes.get(0); + assessmemntModeMessageFormatting("assessment.mode.now", modes, mainVC); + if(canStopAssessmentMode(mode)) { + String modeName = mode.getName(); + String label = translate("assessment.tool.stop", new String[] { StringHelper.escapeHtml(modeName) }); + if(stopAssessmentMode == null) { + stopAssessmentMode = LinkFactory.createCustomLink("assessment.stop", "stop", label, Link.BUTTON_SMALL | Link.NONTRANSLATED, mainVC, this); + } + stopAssessmentMode.setIconLeftCSS("o_icon o_icon-fw o_as_mode_stop"); + if(assessmentModeCoordinationService.isDisadvantageCompensationExtensionTime(mode)) { + stopAssessmentMode.setIconRightCSS("o_icon o_icon-fw o_icon_disadvantage_compensation"); + } + stopAssessmentMode.setUserObject(mode); + } + } else { + assessmemntModeMessageFormatting("assessment.mode.several.now", modes, mainVC); + } + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(stopAssessmentMode == source) { + doConfirmStop(ureq, (AssessmentMode)stopAssessmentMode.getUserObject()); + } + } + + @Override + protected void event(UserRequest ureq, Controller source, Event event) { + if(stopCtrl == source) { + if(event == Event.DONE_EVENT) { + doAfterStop(ureq); + } + cmc.deactivate(); + cleanUp(); + } else if(cmc == source) { + cleanUp(); + } + super.event(ureq, source, event); + } + + private void cleanUp() { + removeControllerListener(stopCtrl); + removeAsListenerAndDispose(cmc); + stopCtrl = null; + cmc = null; + } + + private boolean canStopAssessmentMode(AssessmentMode mode) { + if(assessmentCallback.canStartStopAllAssessments()) { + return assessmentModeCoordinationService.canStop(mode); + } else if(mode.getLectureBlock() != null) { + List<Identity> teachers = lectureService.getTeachers(mode.getLectureBlock()); + return teachers.contains(getIdentity()) + && assessmentModeCoordinationService.canStop(mode); + } + return false; + } + + private void assessmemntModeMessageFormatting(String i18nMessage, List<AssessmentMode> modes, VelocityContainer warn) { + Date begin = getBeginOfModes(modes); + Date end = getEndOfModes(modes); + + String start; + String stop; + Formatter formatter = Formatter.getInstance(getLocale()); + if(CalendarUtils.isSameDay(begin, end)) { + start = formatter.formatTimeShort(begin); + stop = formatter.formatTimeShort(end); + } else { + start = formatter.formatDateAndTime(begin); + stop = formatter.formatDateAndTime(end); + } + warn.contextPut("message", translate(i18nMessage, new String[] { start, stop })); + } + + private Date getBeginOfModes(List<AssessmentMode> modes) { + Date start = null; + for(AssessmentMode mode:modes) { + Date begin = mode.getBegin(); + if(start == null || (begin != null && begin.before(start))) { + start = begin; + } + } + return start; + } + + private Date getEndOfModes(List<AssessmentMode> modes) { + Date stop = null; + for(AssessmentMode mode:modes) { + Date end = mode.getEnd(); + if(stop == null || (end != null && end.after(stop))) { + stop = end; + } + } + return stop; + } + + private void doConfirmStop(UserRequest ureq, AssessmentMode mode) { + if(guardModalController(stopCtrl)) return; + + stopCtrl = new ConfirmStopAssessmentModeController(ureq, getWindowControl(), mode); + listenTo(stopCtrl); + + String title = translate("confirm.stop.title"); + cmc = new CloseableModalController(getWindowControl(), "close", stopCtrl.getInitialComponent(), true, title, true); + cmc.activate(); + listenTo(cmc); + } + + private void doAfterStop(UserRequest ureq) { + reloadAssessmentModeMessage(); + fireEvent(ureq, new StopAssessmentEvent()); + } +} diff --git a/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java b/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java new file mode 100644 index 00000000000..dbc71c7dc0e --- /dev/null +++ b/src/main/java/org/olat/course/assessment/ui/tool/event/StopAssessmentEvent.java @@ -0,0 +1,40 @@ +/** + * <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.assessment.ui.tool.event; + +import org.olat.core.gui.control.Event; + +/** + * + * Initial date: 25 févr. 2021<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class StopAssessmentEvent extends Event { + + private static final long serialVersionUID = -4403100324034839496L; + private static final String STOP_ASSESSMENT_EVENT = "stop-assessment-event"; + + public StopAssessmentEvent() { + super(STOP_ASSESSMENT_EVENT); + } + + +} diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index c5c6556bb9b..e8d13df84fb 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -1891,7 +1891,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im ctrl.activate(ureq, null, null); listenTo(ctrl); assessmentToolCtr = pushController(ureq, translate("command.openassessment"), ctrl); - assessmentToolCtr.assessmentModeMessage(); + assessmentToolCtr.assessmentModeMessage(ureq); currentToolCtr = assessmentToolCtr; setActiveTool(assessmentLink); ctrl.initToolbar(); -- GitLab