/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <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> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.modules.assessment.ui; import java.math.BigDecimal; import org.olat.core.gui.UserRequest; 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.IntegerElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.TextElement; 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.form.flexible.impl.elements.FormSubmit; import org.olat.core.gui.components.link.Link; 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.id.Identity; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentModule; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; import org.olat.modules.assessment.model.AssessmentEntryStatus; import org.olat.modules.assessment.ui.event.AssessmentFormEvent; import org.olat.repository.RepositoryEntry; import org.springframework.beans.factory.annotation.Autowired; /** * Initial Date: Jun 24, 2004 * * @author gnaegi */ public class AssessmentForm extends FormBasicController { private TextElement score; private IntegerElement attempts; private SingleSelection passed; private TextElement userComment, coachComment; private FormSubmit submitButton; private FormLink saveAndDoneLink, reopenLink; private Double min, max, cut; private Identity assessedIdentity; private AssessmentEntry assessmentEntry; private RepositoryEntry testEntry; private final AssessableResource assessableElement; @Autowired private AssessmentService assessmentService; /** * Constructor for an assessment detail form. The form will be configured according * to the assessable course node parameters * @param name The form name * @param assessableCourseNode The course node * @param assessedIdentityWrapper The wrapped identity * @param trans The package translator */ public AssessmentForm(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, RepositoryEntry testEntry, AssessableResource assessableElement) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(AssessmentModule.class, getLocale(), getTranslator())); this.testEntry = testEntry; this.assessedIdentity = assessedIdentity; this.assessableElement = assessableElement; assessmentEntry = assessmentService.loadAssessmentEntry(assessedIdentity, testEntry, null, testEntry); initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormTitle("form.title", null); formLayout.setElementCssClass("o_sel_assessment_form"); if (assessableElement.hasAttemptsConfigured()) { Integer attemptsValue = assessmentEntry == null ? null : assessmentEntry.getAttempts(); attempts = uifactory.addIntegerElement("attempts", "form.attempts", (attemptsValue == null ? 0 : attemptsValue.intValue()), formLayout); attempts.setDisplaySize(3); attempts.setMinValueCheck(0, null); } if (assessableElement.hasScoreConfigured()) { min = assessableElement.getMinScoreConfiguration(); max = assessableElement.getMaxScoreConfiguration(); if (assessableElement.hasPassedConfigured()) { cut = assessableElement.getCutValueConfiguration(); } String minStr = AssessmentHelper.getRoundedScore(min); String maxStr = AssessmentHelper.getRoundedScore(max); uifactory.addStaticTextElement("minval", "form.min", ((min == null) ? translate("form.valueUndefined") : minStr), formLayout); uifactory.addStaticTextElement("maxval", "form.max", ((max == null) ? translate("form.valueUndefined") : maxStr), formLayout); // Use init variables from wrapper, already loaded from db score = uifactory.addTextElement("score","form.score" , 10, "", formLayout); score.setDisplaySize(4); score.setElementCssClass("o_sel_assessment_form_score"); score.setExampleKey("form.score.rounded", null); if (assessmentEntry != null && assessmentEntry.getScore() != null) { score.setValue(AssessmentHelper.getRoundedScore(assessmentEntry.getScore())); } // assessment overview with max score score.setRegexMatchCheck("(\\d+)||(\\d+\\.\\d{1,3})||(\\d+\\,\\d{1,3})", "form.error.wrongFloat"); } if (assessableElement.hasPassedConfigured()) { if (cut != null) { // Display cut value if defined String val = ((cut == null) ? translate("form.valueUndefined") : AssessmentHelper.getRoundedScore(cut)); uifactory.addStaticTextElement("cutval","form.cut", val, formLayout); } String[] trueFalseKeys = new String[] { "undefined", "true", "false" }; String[] passedNotPassedValues = new String[] { translate("form.passed.undefined"), translate("form.passed.true"), translate("form.passed.false") }; //passed = new StaticSingleSelectionElement("form.passed", trueFalseKeys, passedNotPassedValues); passed = uifactory.addRadiosVertical("passed", "form.passed", formLayout, trueFalseKeys, passedNotPassedValues); passed.setElementCssClass("o_sel_assessment_form_passed"); Boolean passedValue = assessmentEntry == null ? null : assessmentEntry.getPassed(); passed.select(passedValue == null ? "undefined" :passedValue.toString(), true); // When cut value is defined, no manual passed possible passed.setEnabled(cut == null); } if (assessableElement.hasCommentConfigured()) { // Use init variables from db, not available from wrapper String comment = assessmentEntry == null ? null : assessmentEntry.getComment(); if (comment == null) { comment = ""; } userComment = uifactory.addTextAreaElement("usercomment", "form.usercomment", 2500, 5, 40, true, comment, formLayout); } String coachCommentValue = assessmentEntry == null ? null : assessmentEntry.getCoachComment(); if (coachCommentValue == null) { coachCommentValue = ""; } coachComment = uifactory.addTextAreaElement("coachcomment", "form.coachcomment", 2500, 5, 40, true, coachCommentValue, formLayout); //why does the TextElement not use its default error key??? //userComment could be null for course elements of type Assessment (MSCourseNode) if(userComment!=null) { userComment.setNotLongerThanCheck(2500, "input.toolong"); } if(coachComment!=null) { coachComment.setNotLongerThanCheck(2500, "input.toolong"); } FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator()); formLayout.add(buttonGroupLayout); submitButton = uifactory.addFormSubmitButton("save", buttonGroupLayout); saveAndDoneLink = uifactory.addFormLink("save.done", buttonGroupLayout, Link.BUTTON); saveAndDoneLink.setElementCssClass("o_sel_assessment_form_save_and_close"); reopenLink = uifactory.addFormLink("reopen", buttonGroupLayout, Link.BUTTON); reopenLink.setElementCssClass("o_sel_assessment_form_reopen"); uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); updateStatus(assessmentEntry); } private void updateStatus(AssessmentEntry aEntry) { boolean closed = (aEntry != null && aEntry.getAssessmentStatus() == AssessmentEntryStatus.done); if(assessableElement.hasPassedConfigured()) { passed.setEnabled(!closed && cut == null); } if(assessableElement.hasScoreConfigured()) { score.setEnabled(!closed); } if(assessableElement.hasCommentConfigured()) { userComment.setEnabled(!closed); } coachComment.setEnabled(!closed); if (assessableElement.hasAttemptsConfigured()) { attempts.setEnabled(!closed); } submitButton.setVisible(!closed); saveAndDoneLink.setVisible(!closed); reopenLink.setVisible(closed); } @Override protected void doDispose() { // } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(saveAndDoneLink == source) { if(validateFormLogic(ureq)) { doUpdateAssessmentData(true); fireEvent(ureq, new AssessmentFormEvent(AssessmentFormEvent.ASSESSMENT_DONE, true)); } } else if(reopenLink == source) { doReopen(); fireEvent(ureq, new AssessmentFormEvent(AssessmentFormEvent.ASSESSMENT_CHANGED, false)); } super.formInnerEvent(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { doUpdateAssessmentData(false); fireEvent(ureq, new AssessmentFormEvent(AssessmentFormEvent.ASSESSMENT_CHANGED, true)); } @Override protected void formCancelled (UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } @Override protected boolean validateFormLogic(UserRequest ureq) { if (assessableElement.hasScoreConfigured()) { try { if(parseFloat(score) == null) { score.setErrorKey("form.error.wrongFloat", null); return false; } } catch (NumberFormatException e) { score.setErrorKey("form.error.wrongFloat", null); return false; } Float fscore = parseFloat(score); if ((min != null && fscore < min.floatValue()) || fscore < AssessmentHelper.MIN_SCORE_SUPPORTED) { score.setErrorKey("form.error.scoreOutOfRange", null); return false; } if ((max != null && fscore > max.floatValue()) || fscore > AssessmentHelper.MAX_SCORE_SUPPORTED) { score.setErrorKey("form.error.scoreOutOfRange", null); return false; } } return true; } private Float parseFloat(TextElement textEl) throws NumberFormatException { String scoreStr = textEl.getValue(); if(!StringHelper.containsNonWhitespace(scoreStr)) { return null; } int index = scoreStr.indexOf(','); if(index >= 0) { scoreStr = scoreStr.replace(',', '.'); return Float.parseFloat(scoreStr); } return Float.parseFloat(scoreStr); } private void doReopen() { assessmentEntry = assessmentService.loadAssessmentEntry(assessedIdentity, testEntry, null, testEntry); if (assessmentEntry != null) { assessmentEntry.setAssessmentStatus(AssessmentEntryStatus.inReview); assessmentEntry = assessmentService.updateAssessmentEntry(assessmentEntry); updateStatus(assessmentEntry); } } protected void doUpdateAssessmentData(boolean asDone) { assessmentEntry = assessmentService.loadAssessmentEntry(assessedIdentity, testEntry, null, testEntry); if(assessmentEntry == null) { assessmentEntry = assessmentService.getOrCreateAssessmentEntry(assessedIdentity, null, testEntry, null, testEntry); } if (assessableElement.hasAttemptsConfigured()) { if(StringHelper.containsNonWhitespace(attempts.getValue())) { Integer attemptsValue = Integer.parseInt(attempts.getValue()); assessmentEntry.setAttempts(attemptsValue); } else { assessmentEntry.setAttempts(null); } } if (assessableElement.hasScoreConfigured()) { if(StringHelper.containsNonWhitespace(score.getValue())) { BigDecimal scoreValue = new BigDecimal(score.getValue()); assessmentEntry.setScore(scoreValue); } } if (assessableElement.hasPassedConfigured()) { String selected = passed.getSelectedKey(); if("true".equals(selected)) { assessmentEntry.setPassed(Boolean.TRUE); } else if("false".equals(selected)) { assessmentEntry.setPassed(Boolean.FALSE); } else { assessmentEntry.setPassed(null); } } if(asDone) { assessmentEntry.setAssessmentStatus(AssessmentEntryStatus.done); } assessmentEntry = assessmentService.updateAssessmentEntry(assessmentEntry); flc.setDirty(true); } public void reloadData() { assessmentEntry = assessmentService.loadAssessmentEntry(assessedIdentity, testEntry, null, testEntry); if (assessableElement.hasAttemptsConfigured()) { Integer attemptsValue = assessmentEntry.getAttempts(); attempts.setIntValue(attemptsValue == null ? 0 : attemptsValue.intValue()); } if (assessableElement.hasScoreConfigured()) { if (assessmentEntry.getScore() != null) { score.setValue(AssessmentHelper.getRoundedScore(assessmentEntry.getScore())); } } if (assessableElement.hasPassedConfigured()) { Boolean passedValue = assessmentEntry.getPassed(); passed.select(passedValue == null ? "undefined" : passedValue.toString(), true); passed.setEnabled(cut == null); } if (assessableElement.hasCommentConfigured()) { String comment = assessmentEntry.getComment() == null ? "" : assessmentEntry.getComment(); userComment.setValue(comment); } String coachMsg = assessmentEntry.getCoachComment() == null ? "" : assessmentEntry.getCoachComment(); coachComment.setValue(coachMsg); updateStatus(assessmentEntry); } }