/**
* <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.cl.ui;
import java.util.Date;
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.DateChooser;
import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
import org.olat.core.gui.components.form.flexible.elements.RichTextElement;
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.Form;
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.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.util.StringHelper;
import org.olat.course.nodes.CheckListCourseNode;
import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.MSCourseNode;
import org.olat.course.nodes.cl.model.CheckboxList;
import org.olat.course.nodes.cl.ui.wizard.GeneratorData;
import org.olat.modules.ModuleConfiguration;
/**
*
* Initial date: 04.02.2014<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class CheckListConfigurationController extends FormBasicController {
private static final String[] onKeys = new String[]{ "on" };
private static final String[] outputKeys = new String[]{ "cutvalue", "sum", "coach"};
private MultipleSelectionElement dueDateEl, scoreGrantedEl, passedEl, commentEl;
private SingleSelection outputEl, numOfCheckListEl, sumCheckboxEl;
private TextElement minPointsEl, maxPointsEl, cutValueEl, titlePrefixEl;
private RichTextElement tipUserEl, tipCoachEl;
private DateChooser dueDateChooserEl;
private final ModuleConfiguration config;
private final boolean inUse;
private final boolean wizard;
private GeneratorData data;
private static final String[] numOfKeys = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" };
public CheckListConfigurationController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, boolean inUse) {
super(ureq, wControl);
wizard = false;
this.inUse = inUse;
config = courseNode.getModuleConfiguration();
initForm(ureq);
}
public CheckListConfigurationController(UserRequest ureq, WindowControl wControl, ModuleConfiguration config,
GeneratorData data, Form rootForm) {
super(ureq, wControl, LAYOUT_DEFAULT, null, rootForm);
wizard = true;
inUse = false;
this.data = data;
this.config = config;
initForm(ureq);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
if(wizard) {
titlePrefixEl = uifactory.addTextElement("titelprefix", "title.prefix", 64, "", formLayout);
titlePrefixEl.setMandatory(true);
numOfCheckListEl = uifactory.addDropdownSingleselect("num.of.checklist", "num.of.checklist", formLayout, numOfKeys, numOfKeys, null);
numOfCheckListEl.select(numOfKeys[0], true);
numOfCheckListEl.setMandatory(true);
uifactory.addSpacerElement("spacer-wiz", formLayout, false);
} else {
setFormTitle("config.title");
setFormDescription("config.description");
setFormContextHelp("Assessment#_checklist_kursbaustein");
if(inUse) {
setFormWarning("config.warning.inuse");
}
}
//due date
Boolean dueDateBool = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_CLOSE_AFTER_DUE_DATE);
Date dueDate = (Date)config.get(CheckListCourseNode.CONFIG_KEY_DUE_DATE);
String[] theValues = new String[] { "" };
dueDateEl = uifactory.addCheckboxesHorizontal("duedate", "config.due.date.on", formLayout, onKeys, theValues);
dueDateEl.addActionListener(FormEvent.ONCHANGE);
if(dueDateBool != null && dueDateBool.booleanValue()) {
dueDateEl.select(onKeys[0], true);
}
dueDateChooserEl = uifactory.addDateChooser("config.due.date", dueDate, formLayout);
dueDateChooserEl.setDateChooserTimeEnabled(true);
dueDateChooserEl.setMandatory(true);
if(dueDateBool != null && dueDateBool.booleanValue()) {
dueDateEl.select(onKeys[0], true);
dueDateChooserEl.setVisible(true);
} else {
dueDateChooserEl.setVisible(false);
}
uifactory.addSpacerElement("spacer-duedate", formLayout, false);
//points
Boolean scoreGrantedBool = (Boolean)config.get(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD);
Float minVal = (Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MIN);
Float maxVal = (Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MAX);
String[] pointsValues = new String[]{ translate("config.points.on") };
scoreGrantedEl = uifactory.addCheckboxesHorizontal("points", "config.points", formLayout, onKeys, pointsValues);
scoreGrantedEl.addActionListener(FormEvent.ONCHANGE);
if(scoreGrantedBool == null || (scoreGrantedBool != null && scoreGrantedBool.booleanValue())) {
scoreGrantedEl.select(onKeys[0], true);
}
String minValStr = minVal == null ? "" : Float.toString(minVal.floatValue());
minPointsEl = uifactory.addTextElement("pointsmin", "config.points.min", 4, minValStr, formLayout);
minPointsEl.setMandatory(true);
minPointsEl.setDisplaySize(5);
String maxValStr = maxVal == null ? "" : Float.toString(maxVal.floatValue());
maxPointsEl = uifactory.addTextElement("pointsmax", "config.points.max", 4, maxValStr, formLayout);
maxPointsEl.setMandatory(true);
maxPointsEl.setDisplaySize(5);
updateScoreVisibility();
uifactory.addSpacerElement("spacer-points", formLayout, false);
//passed
Float cutVal = (Float)config.get(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE);
Boolean passedBool = (Boolean)config.get(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD);
Boolean passedSum = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CHECKBOX);
Integer sumCutValue = (Integer)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CUTVALUE);
Boolean manualCorr = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_MANUAL_CORRECTION);
passedEl = uifactory.addCheckboxesHorizontal("passed", "config.passed", formLayout, onKeys, theValues);
passedEl.addActionListener(FormEvent.ONCHANGE);
if(passedBool == null || (passedBool != null && passedBool.booleanValue())) {
passedEl.select(onKeys[0], true);
}
String[] outputValues = new String[]{
translate("config.output.cutvalue"), translate("config.output.sum"), translate("config.output.coach")
};
outputEl = uifactory.addRadiosVertical("output", "config.output", formLayout, outputKeys, outputValues);
outputEl.addActionListener(FormEvent.ONCHANGE);
String cutValStr = cutVal == null ? "" : Float.toString(cutVal.floatValue());
cutValueEl = uifactory.addTextElement("cutvalue", "config.cutvalue", 4, cutValStr, formLayout);
cutValueEl.setDisplaySize(5);
cutValueEl.setMandatory(true);
String[] numKeys = getAvailableSumCutValues();
sumCheckboxEl = uifactory.addDropdownSingleselect("sum.cutvalue", "sum.cutvalue", formLayout, numKeys, numKeys, null);
if(sumCutValue == null || sumCutValue.intValue() <= 0) {
sumCheckboxEl.select(numKeys[0], true);
} else if(sumCutValue.intValue() > 0 && sumCutValue.intValue() < numKeys.length) {
sumCheckboxEl.select(numKeys[sumCutValue.intValue()], true);
} else {
sumCheckboxEl.select(numKeys[numKeys.length - 1], true);
}
if(passedSum != null && passedSum.booleanValue()) {
outputEl.select(outputKeys[1], true);
}
if(manualCorr != null && manualCorr.booleanValue()) {
outputEl.select(outputKeys[2], true);
}
if((cutVal != null && cutVal.floatValue() > -0.1) || !outputEl.isOneSelected()) {
outputEl.select(outputKeys[0], true);
}
updatePassedAndOutputVisibilty();
uifactory.addSpacerElement("spacer-passed", formLayout, false);
//comment
commentEl = uifactory.addCheckboxesHorizontal("comment", "config.comment", formLayout, onKeys, theValues);
Boolean commentBool = (Boolean)config.get(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD);
if(commentBool != null && commentBool.booleanValue()) {
commentEl.select(onKeys[0], true);
}
String iu = (String)config.get(MSCourseNode.CONFIG_KEY_INFOTEXT_USER);
tipUserEl = uifactory.addRichTextElementForStringDataMinimalistic("tip.user", "config.tip.user", iu, 5, -1, formLayout,
getWindowControl());
String ic = (String)config.get(MSCourseNode.CONFIG_KEY_INFOTEXT_COACH);
tipCoachEl = uifactory.addRichTextElementForStringDataMinimalistic("tip.coach", "config.tip.coach", ic, 5, -1, formLayout,
getWindowControl());
if(!wizard) {
FormLayoutContainer buttonsLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
formLayout.add(buttonsLayout);
uifactory.addFormSubmitButton("submit", "submit", buttonsLayout);
}
}
@Override
protected void doDispose() {
//
}
@Override
protected void formOK(UserRequest ureq) {
if(wizard) {
String prefix = titlePrefixEl.getValue();
data.setNodePrefix(prefix);
int numOfChecklist = numOfCheckListEl.getSelected();
data.setNumOfNodes(numOfChecklist + 1);
}
//due date
boolean closeAfterDueDate = dueDateEl.isAtLeastSelected(1);
config.set(CheckListCourseNode.CONFIG_KEY_CLOSE_AFTER_DUE_DATE, new Boolean(closeAfterDueDate));
Date dueDate = dueDateChooserEl.getDate();
if(dueDate != null) {
config.set(CheckListCourseNode.CONFIG_KEY_DUE_DATE, dueDate);
} else {
config.remove(CheckListCourseNode.CONFIG_KEY_DUE_DATE);
}
//score
Boolean sf = new Boolean(scoreGrantedEl.isSelected(0));
config.set(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD, sf);
if (sf.booleanValue()) {
config.set(MSCourseNode.CONFIG_KEY_SCORE_MIN, new Float(minPointsEl.getValue()));
config.set(MSCourseNode.CONFIG_KEY_SCORE_MAX, new Float(maxPointsEl.getValue()));
} else {
config.remove(MSCourseNode.CONFIG_KEY_SCORE_MIN);
config.remove(MSCourseNode.CONFIG_KEY_SCORE_MAX);
}
// mandatory passed flag
Boolean pf = new Boolean(passedEl.isSelected(0));
config.set(MSCourseNode.CONFIG_KEY_HAS_PASSED_FIELD, pf);
config.remove(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE);
config.remove(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CUTVALUE);
config.set(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CHECKBOX, Boolean.FALSE);
config.set(CheckListCourseNode.CONFIG_KEY_PASSED_MANUAL_CORRECTION, Boolean.FALSE);
if (pf.booleanValue()) {
String output = outputEl.getSelectedKey();
if("cutvalue".equals(output)) {
config.set(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE, new Float(cutValueEl.getValue()));
} else if("sum".equals(output)) {
config.set(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CHECKBOX, Boolean.TRUE);
int sumCutValue = Integer.parseInt(sumCheckboxEl.getSelectedKey());
config.set(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CUTVALUE, new Integer(sumCutValue));
} else if("coach".equals(output)) {
config.set(CheckListCourseNode.CONFIG_KEY_PASSED_MANUAL_CORRECTION, Boolean.TRUE);
}
}
// mandatory comment flag
config.set(MSCourseNode.CONFIG_KEY_HAS_COMMENT_FIELD, new Boolean(commentEl.isSelected(0)));
// set info text only if something is in there
String iu = tipUserEl.getValue();
if (StringHelper.containsNonWhitespace(iu)) {
config.set(MSCourseNode.CONFIG_KEY_INFOTEXT_USER, iu);
} else {
config.remove(MSCourseNode.CONFIG_KEY_INFOTEXT_USER);
}
String ic = tipCoachEl.getValue();
if (StringHelper.containsNonWhitespace(ic)) {
config.set(MSCourseNode.CONFIG_KEY_INFOTEXT_COACH, ic);
} else {
config.remove(MSCourseNode.CONFIG_KEY_INFOTEXT_COACH);
}
fireEvent(ureq, Event.DONE_EVENT);
}
@Override
protected boolean validateFormLogic(UserRequest ureq) {
boolean allOk = true;
//wizardery need title prefix and number of checklist to be defined
if(wizard) {
titlePrefixEl.clearError();
if(!StringHelper.containsNonWhitespace(titlePrefixEl.getValue())) {
titlePrefixEl.setErrorKey("form.legende.mandatory", null);
allOk &= false;
}
numOfCheckListEl.clearError();
if(!numOfCheckListEl.isOneSelected()) {
numOfCheckListEl.setErrorKey("form.legende.mandatory", null);
allOk &= false;
}
}
// score flag
minPointsEl.clearError();
maxPointsEl.clearError();
if (scoreGrantedEl.isSelected(0)) {
float min = toFloat(minPointsEl.getValue());
float max = toFloat(maxPointsEl.getValue());
if (Float.isNaN(min) || min < 0.0f) {
minPointsEl.setErrorKey("form.error.wrongFloat", null);
allOk &= false;
}
if (Float.isNaN(max) || max < 0.0f) {
maxPointsEl.setErrorKey("form.error.wrongFloat", null);
allOk &= false;
}
if (!Float.isNaN(min) && !Float.isNaN(min) && min > max) {
maxPointsEl.setErrorKey("form.error.minGreaterThanMax", null);
allOk &= false;
}
}
cutValueEl.clearError();
outputEl.clearError();
if(passedEl.isSelected(0)) {
if(outputEl.isOneSelected()) {
String selectKey = outputEl.getSelectedKey();
if("cutvalue".equals(selectKey)) {
float cut = toFloat(cutValueEl.getValue());
if (Float.isNaN(cut) || cut < 0.0f) {
cutValueEl.setErrorKey("form.error.wrongFloat", null);
allOk &= false;
}
}
} else {
maxPointsEl.setErrorKey("form.legende.mandatory", null);
}
}
dueDateChooserEl.clearError();
if(dueDateEl.isAtLeastSelected(1)) {
if (dueDateChooserEl.isEmpty()) {
dueDateChooserEl.setErrorKey("form.error.date", null);
allOk &= false;
}
}
return allOk & super.validateFormLogic(ureq);
}
private float toFloat(String val) {
float ret;
try {
ret = Float.parseFloat(val);
} catch (NumberFormatException e) {
ret = Float.NaN;
}
return ret;
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(dueDateEl == source) {
if(!wizard) {
boolean selected = dueDateEl.isAtLeastSelected(1);
dueDateChooserEl.setVisible(selected);
}
} else if(scoreGrantedEl == source) {
updateScoreVisibility();
} else if(passedEl == source) {
updatePassedAndOutputVisibilty();
} else if(outputEl == source) {
updatePassedAndOutputVisibilty();
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void event(UserRequest ureq, Controller source, Event event) {
if(source instanceof CheckListBoxListEditController) {
if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
//update the number of box available
String[] numKeys = getAvailableSumCutValues();
int currentSelection = sumCheckboxEl.getSelected();
sumCheckboxEl.setKeysAndValues(numKeys, numKeys, null);
if(currentSelection >= numKeys.length) {
//if the number is smaller, update the selection to fit in the new range
sumCheckboxEl.select(numKeys[numKeys.length - 1], true);
} else {
sumCheckboxEl.select(numKeys[currentSelection], true);
}
}
}
super.event(ureq, source, event);
}
private String[] getAvailableSumCutValues() {
int currentNumOfCheckbox;
if(data == null) {
CheckboxList list = (CheckboxList)config.get(CheckListCourseNode.CONFIG_KEY_CHECKBOX);
currentNumOfCheckbox = list == null ? 0 : list.getNumOfCheckbox();
} else {
currentNumOfCheckbox = data.getNumOfCheckbox();
}
String[] numKeys = new String[currentNumOfCheckbox + 1];
for(int i=0; i<=currentNumOfCheckbox; i++) {
numKeys[i] = Integer.toString(i);
}
return numKeys;
}
private void updateScoreVisibility() {
boolean granted = scoreGrantedEl.isSelected(0);
minPointsEl.setVisible(granted);
minPointsEl.setMandatory(granted);
maxPointsEl.setVisible(granted);
maxPointsEl.setMandatory(granted);
}
private void updatePassedAndOutputVisibilty() {
if(passedEl.isSelected(0)) {
outputEl.setVisible(true);
String selectKey = outputEl.getSelectedKey();
if("cutvalue".equals(selectKey)) {
cutValueEl.setVisible(true);
sumCheckboxEl.setVisible(false);
} else if("sum".equals(selectKey)) {
cutValueEl.setVisible(false);
sumCheckboxEl.setVisible(true);
} else if("coach".equals(selectKey)) {
cutValueEl.setVisible(false);
sumCheckboxEl.setVisible(false);
}
} else {
outputEl.setVisible(false);
cutValueEl.setVisible(false);
sumCheckboxEl.setVisible(false);
}
}
}