/** * <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.ims.qti21.ui.editor.interactions; 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.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.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.core.util.Util; import org.olat.ims.qti21.model.xml.interactions.FIBAssessmentItemBuilder.NumericalEntry; import org.olat.ims.qti21.ui.editor.AssessmentTestEditorController; import uk.ac.ed.ph.jqtiplus.node.expression.operator.ToleranceMode; import uk.ac.ed.ph.jqtiplus.types.Identifier; /** * * Initial date: 24.02.2016<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class FIBNumericalEntrySettingsController extends FormBasicController { private static final String[] toleranceModeKeys = new String[]{ ToleranceMode.EXACT.name(), ToleranceMode.ABSOLUTE.name(), ToleranceMode.RELATIVE.name() }; private TextElement solutionEl; private TextElement placeholderEl; private TextElement expectedLengthEl; private SingleSelection toleranceModeEl; private TextElement lowerToleranceEl, upperToleranceEl; private final boolean restrictedEdit; private final NumericalEntry interaction; public FIBNumericalEntrySettingsController(UserRequest ureq, WindowControl wControl, NumericalEntry interaction, boolean restrictedEdit) { super(ureq, wControl, Util.createPackageTranslator(AssessmentTestEditorController.class, ureq.getLocale())); this.interaction = interaction; this.restrictedEdit = restrictedEdit; initForm(ureq); } public Identifier getResponseIdentifier() { return interaction.getResponseIdentifier(); } public Double getSolution() { return interaction.getSolution(); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { Double solution = interaction.getSolution(); String solString = solution == null ? "" : solution.toString(); solutionEl = uifactory.addTextElement("fib.solution", "fib.solution", 256, solString, formLayout); solutionEl.setEnabled(!restrictedEdit); if(!restrictedEdit && !StringHelper.containsNonWhitespace(solString)) { solutionEl.setFocus(true); } String placeholder = interaction.getPlaceholder(); placeholderEl = uifactory.addTextElement("fib.placeholder", "fib.placeholder", 256, placeholder, formLayout); placeholderEl.setEnabled(!restrictedEdit); Integer expectedLength = interaction.getExpectedLength(); String expectedLengthStr = expectedLength == null ? null : expectedLength.toString(); expectedLengthEl = uifactory.addTextElement("fib.expectedLength", "fib.expectedLength", 256, expectedLengthStr, formLayout); expectedLengthEl.setEnabled(!restrictedEdit); String[] toleranceModeValues = new String[] { translate("fib.tolerance.mode.exact"), translate("fib.tolerance.mode.absolute"), translate("fib.tolerance.mode.relative") }; toleranceModeEl = uifactory.addDropdownSingleselect("fib.tolerance.mode", "fib.tolerance.mode", formLayout, toleranceModeKeys, toleranceModeValues, null); toleranceModeEl.setEnabled(!restrictedEdit); toleranceModeEl.setHelpText(getToleranceHelp()); toleranceModeEl.setHelpUrlForManualPage("Test editor QTI 2.1 in detail#details_testeditor_fragetypen_ni"); if(interaction.getToleranceMode() != null) { for(String toleranceModeKey:toleranceModeKeys) { if(toleranceModeKey.equals(interaction.getToleranceMode().name())) { toleranceModeEl.select(toleranceModeKey, true); } } } if(!toleranceModeEl.isOneSelected()) { toleranceModeEl.select(toleranceModeKeys[0], true); } toleranceModeEl.addActionListener(FormEvent.ONCHANGE); Double lowerTolerance = interaction.getLowerTolerance(); String lowerToleranceString = lowerTolerance == null ? "" : lowerTolerance.toString(); lowerToleranceEl = uifactory.addTextElement("fib.tolerance.low", "fib.tolerance.low", 8, lowerToleranceString, formLayout); lowerToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); lowerToleranceEl.setEnabled(!restrictedEdit); Double upperTolerance = interaction.getUpperTolerance(); String upperToleranceString = upperTolerance == null ? "" : upperTolerance.toString(); upperToleranceEl = uifactory.addTextElement("fib.tolerance.up", "fib.tolerance.up", 8, upperToleranceString, formLayout); upperToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); upperToleranceEl.setEnabled(!restrictedEdit); updateToleranceUpAndLow(); // Submit Button FormLayoutContainer buttonsContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsContainer.setRootForm(mainForm); formLayout.add(buttonsContainer); if(!restrictedEdit) { uifactory.addFormSubmitButton("submit", buttonsContainer); } uifactory.addFormCancelButton("cancel", buttonsContainer, ureq, getWindowControl()); } private String getToleranceHelp() { StringBuilder sb = new StringBuilder(); sb.append("<ul class='list-unstyled'>") .append("<li><strong>").append(translate("fib.tolerance.mode.exact")).append(":</strong> ").append(translate("fib.tolerance.mode.exact.help")) .append("<li><strong>").append(translate("fib.tolerance.mode.absolute")).append(":</strong> ").append(translate("fib.tolerance.mode.absolute.help")) .append("<li><strong>").append(translate("fib.tolerance.mode.relative")).append(":</strong> ").append(translate("fib.tolerance.mode.relative.help")) .append("</ul>"); return sb.toString(); } private void updateToleranceUpAndLow() { if(toleranceModeEl.isOneSelected()) { String selectedKey = toleranceModeEl.getSelectedKey(); ToleranceMode mode = ToleranceMode.valueOf(selectedKey); boolean visible = mode == ToleranceMode.ABSOLUTE || mode == ToleranceMode.RELATIVE; lowerToleranceEl.setVisible(visible); upperToleranceEl.setVisible(visible); if(mode == ToleranceMode.RELATIVE) { lowerToleranceEl.setExampleKey("fib.tolerance.mode.relative.example", null); upperToleranceEl.setExampleKey("fib.tolerance.mode.relative.example", null); } else if(mode == ToleranceMode.ABSOLUTE) { lowerToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); upperToleranceEl.setExampleKey("fib.tolerance.mode.absolute.example", null); } } } @Override protected void doDispose() { // } @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; solutionEl.clearError(); if(StringHelper.containsNonWhitespace(solutionEl.getValue())) { try { Double.parseDouble(solutionEl.getValue()); } catch (NumberFormatException e) { solutionEl.setErrorKey("error.double", null); allOk &= false; } } else { solutionEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } expectedLengthEl.clearError(); if(StringHelper.containsNonWhitespace(expectedLengthEl.getValue())) { if(StringHelper.isLong(expectedLengthEl.getValue())) { try { Integer.parseInt(expectedLengthEl.getValue()); } catch(NumberFormatException e) { expectedLengthEl.setErrorKey("form.error.nointeger", null); allOk &= false; } } else { expectedLengthEl.setErrorKey("form.error.nointeger", null); allOk &= false; } } toleranceModeEl.clearError(); lowerToleranceEl.clearError(); upperToleranceEl.clearError(); if(!toleranceModeEl.isOneSelected()) { toleranceModeEl.setErrorKey("form.legende.mandatory", null); allOk &= false; } else { String selectedKey = toleranceModeEl.getSelectedKey(); ToleranceMode mode = ToleranceMode.valueOf(selectedKey); if(mode == ToleranceMode.ABSOLUTE || mode == ToleranceMode.RELATIVE) { allOk &= validateDouble(lowerToleranceEl); allOk &= validateDouble(upperToleranceEl); } } return allOk & super.validateFormLogic(ureq); } /** * Check if the value is a positive one. * * @param element The text element to validate * @return true if the text is a positive double */ private boolean validateDouble(TextElement element) { boolean allOk = true; element.clearError(); if(StringHelper.containsNonWhitespace(element.getValue())) { try { double val = Double.parseDouble(element.getValue()); if(val < 0.0d) { element.setErrorKey("error.positive.double", null); allOk &= false; } } catch (NumberFormatException e) { element.setErrorKey("error.double", null); allOk &= false; } } else { element.setErrorKey("form.legende.mandatory", null); allOk &= false; } return allOk; } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == toleranceModeEl) { updateToleranceUpAndLow(); } super.formInnerEvent(ureq, source, event); } @Override protected void formOK(UserRequest ureq) { interaction.setSolution(new Double(solutionEl.getValue())); interaction.setPlaceholder(placeholderEl.getValue()); if(StringHelper.containsNonWhitespace(expectedLengthEl.getValue())) { interaction.setExpectedLength(new Integer(expectedLengthEl.getValue())); } else { interaction.setExpectedLength(null); } String toleranceMode = toleranceModeEl.getSelectedKey(); interaction.setToleranceMode(ToleranceMode.valueOf(toleranceMode)); if(interaction.getToleranceMode() == ToleranceMode.ABSOLUTE || interaction.getToleranceMode() == ToleranceMode.RELATIVE) { interaction.setLowerTolerance(Double.parseDouble(lowerToleranceEl.getValue())); interaction.setUpperTolerance(Double.parseDouble(upperToleranceEl.getValue())); } fireEvent(ureq, Event.DONE_EVENT); } @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } }