/** * 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. * <p> * Initial code contributed and copyrighted by<br> * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ package de.bps.onyx.plugin.course.nodes.iq; import java.text.NumberFormat; import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; 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.IntegerElement; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.elements.SelectionElement; 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.gui.translator.Translator; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.Util; import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.iq.IQ12EditForm; import org.olat.course.nodes.iq.IQEditController; import org.olat.ims.qti.process.AssessmentInstance; import org.olat.modules.ModuleConfiguration; import org.olat.repository.RepositoryEntry; import de.bps.onyx.plugin.OnyxModule; import de.bps.onyx.plugin.OnyxModule.PlayerTemplate; import de.bps.webservices.clients.onyxreporter.OnyxReporterConnector; import de.bps.webservices.clients.onyxreporter.OnyxReporterException; /** * Test configuration form. Used for configuring Test, Self-test, and Questionnaire(aka Survey). * <p> * Initial Date: Mar 3, 2004 * * @author Mike Stock */ public class IQEditForm extends FormBasicController { //<OLATCE-982> private static final String ALLOW = "allow"; private MultipleSelectionElement allowShowSolutionBox; //</OLATCE-982> //<OLATCE-2009> private MultipleSelectionElement allowSuspensionBox; //</OLATCE-2009> private SelectionElement enableMenu; private SelectionElement displayMenu; private SelectionElement displayScoreProgress; private SelectionElement displayQuestionProgress; private SelectionElement displayQuestionTitle; private SingleSelection sequence; private SelectionElement enableCancel; private SelectionElement enableSuspend; private SingleSelection summary; private SelectionElement limitAttempts; private IntegerElement attempts; private SingleSelection menuRenderOptions; private SelectionElement scoreInfo; private SelectionElement showResultsDateDependentButton; private DateChooser startDateElement; private DateChooser endDateElement; private SelectionElement showResultsAfterFinishTest; private SelectionElement showResultsOnHomePage; private FormLayoutContainer variablesCont; private ModuleConfiguration modConfig; private String configKeyType; private SingleSelection template; private TextElement cutValue; private final CourseNode courseNode; private boolean isAssessment, isSelfTest, isSurvey; //<OLATCE-1012> private RepositoryEntry repoEntry; private final static OLog log = Tracing.createLoggerFor(IQEditForm.class); //</OLATCE-1012> /** * Constructor for the qti configuration form * * @param ureq * @param wControl * @param modConfig */ // <OLATCE-654> public IQEditForm(UserRequest ureq, WindowControl wControl, ModuleConfiguration modConfig, CourseNode courseNode, RepositoryEntry repoEntry) { // </OLATCE-654> super (ureq, wControl); //<OLATCE-1012> this.repoEntry = repoEntry; //</OLATCE-1012> Translator translator = Util.createPackageTranslator(IQ12EditForm.class, getLocale(), getTranslator()); setTranslator(translator); this.courseNode = courseNode; this.modConfig = modConfig; configKeyType = (String) modConfig.get(IQEditController.CONFIG_KEY_TYPE); isAssessment = configKeyType.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS); isSelfTest = configKeyType.equals(AssessmentInstance.QMD_ENTRY_TYPE_SELF); isSurvey = configKeyType.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY); initForm(ureq); } @Override protected boolean validateFormLogic(UserRequest ureq) { startDateElement.clearError(); endDateElement.clearError(); if (startDateElement.isVisible()) { if (startDateElement.isEmpty()) { startDateElement.setErrorKey("qti.form.date.start.error.mandatory", null); return false; } else { if (startDateElement.getDate() == null) { startDateElement.setErrorKey("qti.form.date.error.format", null); return false; } } if (!endDateElement.isEmpty()) { if (endDateElement.getDate() == null) { endDateElement.setErrorKey("qti.form.date.error.format", null); return false; } if (endDateElement.getDate().before(startDateElement.getDate())) { endDateElement.setErrorKey("qti.form.date.error.endbeforebegin", null); return false; } } } return true; } @Override protected void formOK(UserRequest ureq) { modConfig.set(IQEditController.CONFIG_KEY_TEMPLATE, getTemplate()); if (!isSurvey) { modConfig.set(IQEditController.CONFIG_KEY_ATTEMPTS, getAttempts()); modConfig.set(IQEditController.CONFIG_KEY_CUTVALUE, getCutValue()); } modConfig.set(IQEditController.CONFIG_KEY_DATE_DEPENDENT_RESULTS, new Boolean(isShowResultsDateDependent())); modConfig.set(IQEditController.CONFIG_KEY_RESULTS_START_DATE, getShowResultsStartDate()); modConfig.set(IQEditController.CONFIG_KEY_RESULTS_END_DATE, getShowResultsEndDate()); modConfig.set(IQEditController.CONFIG_KEY_RESULT_ON_HOME_PAGE, isShowResultsOnHomePage()); //<OLATCE-982> modConfig.set(IQEditController.CONFIG_KEY_ALLOW_SHOW_SOLUTION, allowShowSolution()); //</OLATCE-982> //<OLATCE-2009> modConfig.set(IQEditController.CONFIG_KEY_ALLOW_SUSPENSION_ALLOWED, allowSuspension()); //</OLATCE-2009> fireEvent(ureq, Event.DONE_EVENT); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { String variablePages = velocity_root + "/variables.html"; variablesCont = FormLayoutContainer.createCustomFormLayout("variables", getTranslator(), variablePages); variablesCont.setLabel("outcomes.title", null); variablesCont.setVisible(false); variablesCont.setRootForm(mainForm); formLayout.add(variablesCont); limitAttempts = uifactory.addCheckboxesVertical("limitAttempts", "qti.form.limit.attempts", formLayout, new String[] { "xx" }, new String[] { null }, 1); Integer confAttempts = (Integer) modConfig.get(IQEditController.CONFIG_KEY_ATTEMPTS); if (confAttempts == null) { confAttempts = new Integer(0); } attempts = uifactory.addIntegerElement("qti.form.attempts", confAttempts, formLayout); attempts.setDisplaySize(2); attempts.setMinValueCheck(1, null); attempts.setMaxValueCheck(20, null); // Only assessments have a limitation on number of attempts if (isAssessment) { limitAttempts.select("xx", confAttempts > 0); limitAttempts.addActionListener(FormEvent.ONCLICK); } else { limitAttempts.select("xx", false); limitAttempts.setVisible(false); attempts.setVisible(false); } //<OLATCE-982> Boolean confAllowShowSolution = modConfig.getBooleanEntry(IQEditController.CONFIG_KEY_ALLOW_SHOW_SOLUTION); String[] allowShowSolution=new String[]{ALLOW}; String[] valuesShowSolution = new String[]{""}; //Surveys do not have a solution if(!isSurvey){ allowShowSolutionBox = uifactory.addCheckboxesVertical("allowShowSolution", "qti.form.allowShowSolution", formLayout, allowShowSolution, valuesShowSolution, 1); allowShowSolutionBox.addActionListener(FormEvent.ONCLICK); if(confAllowShowSolution!=null){ allowShowSolutionBox.select(ALLOW, confAllowShowSolution); } else if (isSelfTest){ allowShowSolutionBox.select(ALLOW, true); } } //</OLATCE-982> //<OLATCE-2009> Boolean confAllowSuspension = modConfig.getBooleanEntry(IQEditController.CONFIG_KEY_ALLOW_SUSPENSION_ALLOWED); String[] allowSuspension = new String[] { ALLOW }; String[] valuesSuspesion = new String[] { "" }; allowSuspensionBox = uifactory.addCheckboxesHorizontal("allowSuspension", "qti.form.allowSuspension", formLayout, allowSuspension, valuesSuspesion); allowSuspensionBox.addActionListener(FormEvent.ONCLICK); if (confAllowSuspension != null) { allowSuspensionBox.select(ALLOW, confAllowSuspension); } else if (isSelfTest) { allowSuspensionBox.select(ALLOW, false); } //</OLATCE-2009> //select onyx template String[] values = new String[OnyxModule.PLAYERTEMPLATES.size()]; String[] keys = new String[OnyxModule.PLAYERTEMPLATES.size()]; int i = 0; for (PlayerTemplate pt : OnyxModule.PLAYERTEMPLATES) { keys[i] = pt.id; values[i] = getTranslator().translate(pt.i18nkey); ++i; } template = uifactory.addDropdownSingleselect("qti.form.onyx.template", formLayout, keys, values, null); try { if (modConfig.get(IQEditController.CONFIG_KEY_TEMPLATE) != null) { template.select(modConfig.get(IQEditController.CONFIG_KEY_TEMPLATE).toString(), true); } } catch (RuntimeException e) { log.warn("Template not found", e); } //<OLATCE-1342> if(repoEntry == null || repoEntry.getOlatResource() == null){ getWindowControl().setWarning(translate("qti.form.onyx.nocontent")); } else { //the cutvalue if (!isSurvey) { cutValue = uifactory.addTextElement("qti.form.onyx.cutvalue", "qti.form.onyx.cutvalue", 20, "", formLayout); if (modConfig.get(IQEditController.CONFIG_KEY_CUTVALUE) != null) { cutValue.setValue(modConfig.get(IQEditController.CONFIG_KEY_CUTVALUE).toString()); } else { cutValue.setValue(""); } //<OLATCE-1012> try { OnyxReporterConnector onyxReporter = new OnyxReporterConnector(); Map<String, String> outcomes = onyxReporter.getPossibleOutcomeVariables(repoEntry); if(outcomes.containsKey("PASS")){ uifactory.addStaticTextElement("qti.form.onyx.cutvalue.passed.overwrite", null, translate("qti.form.onyx.cutvalue.passed.overwrite"), formLayout); } } catch (OnyxReporterException e) { log.warn("Unable to get outcome variables for the test!", e); } //</OLATCE-1012> } //</OLATCE-1342> } // migration: check if old tests have no summary String configuredSummary = (String) modConfig.get(IQEditController.CONFIG_KEY_SUMMARY); boolean noSummary = configuredSummary != null && configuredSummary.equals(AssessmentInstance.QMD_ENTRY_SUMMARY_NONE) ? true : false; Boolean showResultOnHomePage = modConfig.getBooleanEntry(IQEditController.CONFIG_KEY_RESULT_ON_HOME_PAGE); boolean confEnableShowResultOnHomePage = (showResultOnHomePage != null) ? showResultOnHomePage.booleanValue() : false; confEnableShowResultOnHomePage = !noSummary && confEnableShowResultOnHomePage; showResultsOnHomePage = uifactory.addCheckboxesVertical("qti_enableResultsOnHomePage", "qti.form.results.onhomepage", formLayout, new String[] { "xx" }, new String[] { null }, 1); showResultsOnHomePage.select("xx", confEnableShowResultOnHomePage); showResultsOnHomePage.addActionListener(FormEvent.ONCLICK); showResultsOnHomePage.setVisible(!isSurvey); Boolean showResultsActive = modConfig.getBooleanEntry(IQEditController.CONFIG_KEY_DATE_DEPENDENT_RESULTS); boolean showResultsDateDependent = false; // default false if (showResultsActive != null) { showResultsDateDependent = showResultsActive.booleanValue(); } showResultsDateDependentButton = uifactory.addCheckboxesVertical("qti_showresult", "qti.form.show.results", formLayout, new String[] { "xx" }, new String[] { null }, 1); if (isAssessment || isSelfTest) { showResultsDateDependentButton.select("xx", showResultsDateDependent); showResultsDateDependentButton.addActionListener(FormEvent.ONCLICK); } else { showResultsDateDependentButton.setEnabled(false); } Date startDate = (Date) modConfig.get(IQEditController.CONFIG_KEY_RESULTS_START_DATE); startDateElement = uifactory.addDateChooser("qti_form_start_date", "qti.form.date.start", null, formLayout); startDateElement.setDateChooserTimeEnabled(true); if (startDate != null) { startDateElement.setDate(startDate); } startDateElement.setMandatory(true); Date endDate = (Date) modConfig.get(IQEditController.CONFIG_KEY_RESULTS_END_DATE); endDateElement = uifactory.addDateChooser("qti_form_end_date", "qti.form.date.end", null, formLayout); endDateElement.setDateChooserTimeEnabled(true); if (endDate != null) { endDateElement.setDate(endDate); } uifactory.addFormSubmitButton("submit", formLayout); update(); } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { update(); } private void update() { if (!limitAttempts.isSelected(0)) { attempts.setIntValue(0); } attempts.setVisible(limitAttempts.isVisible() && limitAttempts.isSelected(0)); attempts.setMandatory(attempts.isVisible()); attempts.clearError(); showResultsDateDependentButton.setVisible(showResultsOnHomePage.isSelected(0)); if (!startDateElement.isVisible()) { startDateElement.setValue(""); } startDateElement.clearError(); startDateElement.setVisible(showResultsDateDependentButton.isVisible() && showResultsDateDependentButton.isSelected(0)); endDateElement.clearError(); if (!endDateElement.isVisible()) { endDateElement.setValue(""); } endDateElement.setVisible(startDateElement.isVisible()); } public void update(RepositoryEntry testEntry) { variablesCont.contextPut("onyxDisplayName", testEntry.getDisplayname()); variablesCont.contextPut("showOutcomes", Boolean.TRUE); Map<String, String> outcomes = new HashMap<String, String>(); try { OnyxReporterConnector onyxReporter = new OnyxReporterConnector(); outcomes = onyxReporter.getPossibleOutcomeVariables(courseNode); } catch (OnyxReporterException e) { getWindowControl().setWarning(translate("reporter.unavailable")); } variablesCont.contextPut("outcomes", outcomes); variablesCont.setVisible(outcomes.size() > 0); } /** * @return true: menu is enabled */ public boolean isEnableMenu() { return enableMenu.isSelected(0); } /** * @return true: menu should be displayed */ public boolean isDisplayMenu() { return displayMenu.isSelected(0); } /** * @return true: score progress is enabled */ public boolean isDisplayScoreProgress() { return displayScoreProgress.isSelected(0); } /** * @return true: score progress is enabled */ public boolean isDisplayQuestionProgress() { return displayQuestionProgress.isSelected(0); } /** * @return true: question title is enabled */ public boolean isDisplayQuestionTitle() { return displayQuestionTitle.isSelected(0); } /** * @return sequence configuration: section or item */ public String getSequence() { return sequence.getSelectedKey(); } /** * @return true: cancel is enabled */ public boolean isEnableCancel() { return enableCancel.isSelected(0); } /** * @return true: suspend is enabled */ public boolean isEnableSuspend() { return enableSuspend.isSelected(0); } /** * @return summary type: compact or detailed */ public String getSummary() { return summary.getSelectedKey(); } /** * @return number of max attempts */ public Integer getAttempts() { final Integer a = attempts.getIntValue(); return a == 0 ? null : attempts.getIntValue(); } /** * @return true if only section title should be rendered */ public Boolean isMenuRenderSectionsOnly() { return Boolean.valueOf(menuRenderOptions.getSelectedKey()); } /** * @return true: score-info on start-page is enabled */ public boolean isEnableScoreInfo() { return scoreInfo.isSelected(0); } /** * @return true is the results are shown date dependent */ public boolean isShowResultsDateDependent() { return showResultsDateDependentButton.isSelected(0); } /** * @return Returns the start date for the result visibility. */ public Date getShowResultsStartDate() { return startDateElement.getDate(); } /** * @return Returns the end date for the result visibility. */ public Date getShowResultsEndDate() { return endDateElement.getDate(); } /** * @return Returns true if the results are shown after test finished. */ public boolean isShowResultsAfterFinishTest() { return showResultsAfterFinishTest.isSelected(0); } /** * @return Returns true if the results are shown on the test home page. */ public boolean isShowResultsOnHomePage() { return showResultsOnHomePage.isSelected(0); } /** * @return Returns the points needes to pass an onyx test. */ public Float getCutValue() { String val = cutValue.getValue(); Float f = Float.NaN; try { f = Float.valueOf(val); } catch (Exception e) { try { NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN); f = Float.valueOf(nf.parse(val).floatValue()); } catch (ParseException e1) { //ooops } } cutValue.setValue(f.toString()); return f; } /** * @return Returns the chosen template of an onyx test. */ public String getTemplate() { return template.getSelectedKey(); } @Override protected void doDispose() { // } //<OLATCE-982> public boolean allowShowSolution(){ boolean allow = false; if(allowShowSolutionBox != null){ allow = allowShowSolutionBox.isAtLeastSelected(1); } return allow; } //</OLATCE-982> //<OLATCE-2009> public boolean allowSuspension() { boolean allow = false; if (allowSuspensionBox != null && allowSuspensionBox.isVisible()) { allow = allowSuspensionBox.isAtLeastSelected(1); } return allow; } //</OLATCE-2009> }