/**
* <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.modules.qpool.ui.metadata;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.getQItemTypeKeyValues;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.getQLicenseKeyValues;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.toBigDecimal;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.toInt;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.validateBigDecimal;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.validateElementLogic;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.validateRights;
import static org.olat.modules.qpool.ui.metadata.MetaUIFactory.validateSelection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
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.IntegerElement;
import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
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.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
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.generic.closablewrapper.CloseableModalController;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.modules.qpool.QPoolService;
import org.olat.modules.qpool.QuestionItem;
import org.olat.modules.qpool.QuestionItemShort;
import org.olat.modules.qpool.TaxonomyLevel;
import org.olat.modules.qpool.manager.MetadataConverterHelper;
import org.olat.modules.qpool.model.QEducationalContext;
import org.olat.modules.qpool.model.QuestionItemImpl;
import org.olat.modules.qpool.ui.QuestionsController;
import org.olat.modules.qpool.ui.metadata.MetaUIFactory.KeyValues;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* Initial date: 02.05.2013<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class MetadataBulkChangeController extends FormBasicController {
private static final String[] EMPTY_VALUES = new String[]{ "" };
//general
private TextElement titleEl, keywordsEl, coverageEl, addInfosEl, languageEl;
private Link selectContext;
private FormLayoutContainer selectContextCont;
private CloseableModalController cmc;
//educational
private SingleSelection contextEl;
private FormLayoutContainer learningTimeContainer;
private IntegerElement learningTimeDayElement, learningTimeHourElement, learningTimeMinuteElement, learningTimeSecondElement;
//question
private SingleSelection typeEl, assessmentTypeEl;
private TextElement difficultyEl, stdevDifficultyEl, differentiationEl, numAnswerAltEl;
//lifecycle
private TextElement versionEl;
private SingleSelection statusEl;
//technical
private TextElement editorEl, editorVersionEl;
private SingleSelection formatEl;
//rights
private KeyValues licenseKeys;
private SingleSelection copyrightEl;
private TextElement descriptionEl;
private FormLayoutContainer rightsWrapperCont;
private TaxonomySelectionController selectionCtrl;
private Map<MultipleSelectionElement,FormLayoutContainer> checkboxContainer
= new HashMap<>();
private final List<MultipleSelectionElement> checkboxSwitch = new ArrayList<>();
private TaxonomyLevel selectedTaxonomicPath;
private List<QuestionItem> updatedItems;
private final List<QuestionItemShort> items;
@Autowired
private QPoolService qpoolService;
public MetadataBulkChangeController(UserRequest ureq, WindowControl wControl, List<QuestionItemShort> items) {
super(ureq, wControl, "bulk_change");
setTranslator(Util.createPackageTranslator(QuestionsController.class, getLocale(), getTranslator()));
this.items = items;
initForm(ureq);
}
public List<QuestionItem> getUpdatedItems() {
return updatedItems == null ? Collections.<QuestionItem>emptyList() : updatedItems;
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
setFormDescription("bulk.change.description");
initGeneralForm(formLayout);
initEducationalForm(formLayout);
initQuestionForm(formLayout);
initLifecycleForm(formLayout);
initTechnicalForm(formLayout);
initRightsForm(formLayout);
FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
buttonsCont.setRootForm(mainForm);
formLayout.add(buttonsCont);
uifactory.addFormSubmitButton("ok", "ok", buttonsCont);
uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
}
private void initGeneralForm(FormItemContainer formLayout) {
FormLayoutContainer generalCont = FormLayoutContainer.createDefaultFormLayout("general", getTranslator());
generalCont.setRootForm(mainForm);
formLayout.add(generalCont);
titleEl = uifactory.addTextElement("general.title", "general.title", 1000, null, generalCont);
decorate(titleEl, generalCont);
keywordsEl = uifactory.addTextElement("general.keywords", "general.keywords", 1000, null, generalCont);
decorate(keywordsEl, generalCont);
coverageEl = uifactory.addTextElement("general.coverage", "general.coverage", 1000, null, generalCont);
decorate(coverageEl, generalCont);
addInfosEl = uifactory.addTextElement("general.additional.informations", "general.additional.informations.long",
256, "", generalCont);
decorate(addInfosEl, generalCont);
languageEl = uifactory.addTextElement("general.language", "general.language", 10, "", generalCont);
decorate(languageEl, generalCont);
//classification
String selectContextPage = velocity_root + "/edit_edu_context.html";
selectContextCont = FormLayoutContainer.createCustomFormLayout("classification.taxonomic.path", getTranslator(), selectContextPage);
selectContextCont.setLabel("classification.taxonomic.path", null);
selectContextCont.contextPut("path", "");
generalCont.add(selectContextCont);
selectContextCont.setRootForm(mainForm);
selectContext = LinkFactory.createButton("select", selectContextCont.getFormItemComponent(), this);
decorate(selectContextCont, generalCont);
}
private void initEducationalForm(FormItemContainer formLayout) {
FormLayoutContainer eduCont = FormLayoutContainer.createDefaultFormLayout("educational", getTranslator());
eduCont.setRootForm(mainForm);
formLayout.add(eduCont);
String page = velocity_root + "/learning_time.html";
learningTimeContainer = FormLayoutContainer.createCustomFormLayout("educational.learningTime", getTranslator(), page);
learningTimeContainer.setRootForm(mainForm);
eduCont.add(learningTimeContainer);
decorate(learningTimeContainer, eduCont);
learningTimeDayElement = uifactory.addIntegerElement("learningTime.day", "", 0, learningTimeContainer);
learningTimeDayElement.setDisplaySize(3);
learningTimeHourElement = uifactory.addIntegerElement("learningTime.hour", "", 0, learningTimeContainer);
learningTimeHourElement.setDisplaySize(3);
learningTimeMinuteElement = uifactory.addIntegerElement("learningTime.minute", "", 0, learningTimeContainer);
learningTimeMinuteElement.setDisplaySize(3);
learningTimeSecondElement = uifactory.addIntegerElement("learningTime.second", "", 0, learningTimeContainer);
learningTimeSecondElement.setDisplaySize(3);
KeyValues contexts = MetaUIFactory.getContextKeyValues(getTranslator(), qpoolService);
contextEl = uifactory.addDropdownSingleselect("educational.context", "educational.context", eduCont,
contexts.getKeys(), contexts.getValues(), null);
decorate(contextEl, eduCont);
}
private void initQuestionForm(FormItemContainer formLayout) {
FormLayoutContainer questionCont = FormLayoutContainer.createDefaultFormLayout("question", getTranslator());
questionCont.setRootForm(mainForm);
formLayout.add(questionCont);
KeyValues typeKeys = getQItemTypeKeyValues(getTranslator(), qpoolService);
typeEl = uifactory.addDropdownSingleselect("question.type", "question.type", questionCont, typeKeys.getKeys(), typeKeys.getValues(), null);
decorate(typeEl, questionCont);
difficultyEl = uifactory.addTextElement("question.difficulty", "question.difficulty", 10, null, questionCont);
difficultyEl.setExampleKey("question.difficulty.example", null);
difficultyEl.setDisplaySize(4);
decorate(difficultyEl, questionCont);
stdevDifficultyEl = uifactory.addTextElement("question.stdevDifficulty", "question.stdevDifficulty", 10, null, questionCont);
stdevDifficultyEl.setExampleKey("question.stdevDifficulty.example", null);
stdevDifficultyEl.setDisplaySize(4);
decorate(stdevDifficultyEl, questionCont);
differentiationEl = uifactory.addTextElement("question.differentiation", "question.differentiation", 10, null, questionCont);
differentiationEl.setExampleKey("question.differentiation.example", null);
differentiationEl.setDisplaySize(4);
decorate(differentiationEl, questionCont);
numAnswerAltEl = uifactory.addTextElement("question.numOfAnswerAlternatives", "question.numOfAnswerAlternatives", 10, null, questionCont);
numAnswerAltEl.setDisplaySize(4);
decorate(numAnswerAltEl, questionCont);
KeyValues types = MetaUIFactory.getAssessmentTypes(getTranslator());
assessmentTypeEl = uifactory.addDropdownSingleselect("question.assessmentType", "question.assessmentType", questionCont,
types.getKeys(), types.getValues(), null);
decorate(assessmentTypeEl, questionCont);
}
private void initLifecycleForm(FormItemContainer formLayout) {
FormLayoutContainer lifecycleCont = FormLayoutContainer.createDefaultFormLayout("lifecycle", getTranslator());
lifecycleCont.setRootForm(mainForm);
formLayout.add(lifecycleCont);
versionEl = uifactory.addTextElement("lifecycle.version", "lifecycle.version", 50, null, lifecycleCont);
decorate(versionEl, lifecycleCont);
KeyValues status = MetaUIFactory.getStatus(getTranslator());
statusEl = uifactory.addDropdownSingleselect("lifecycle.status", "lifecycle.status", lifecycleCont,
status.getKeys(), status.getValues(), null);
decorate(statusEl, lifecycleCont);
}
private void initTechnicalForm(FormItemContainer formLayout) {
FormLayoutContainer technicalCont = FormLayoutContainer.createDefaultFormLayout("technical", getTranslator());
technicalCont.setRootForm(mainForm);
formLayout.add(technicalCont);
editorEl = uifactory.addTextElement("technical.editor", "technical.editor", 50, null, technicalCont);
decorate(editorEl, technicalCont);
editorVersionEl = uifactory.addTextElement("technical.editorVersion", "technical.editorVersion", 50, null, technicalCont);
decorate(editorVersionEl, technicalCont);
KeyValues formats = MetaUIFactory.getFormats();
formatEl = uifactory.addDropdownSingleselect("technical.format", "technical.format", technicalCont,
formats.getKeys(), formats.getValues(), null);
decorate(formatEl, technicalCont);
}
private void initRightsForm(FormItemContainer formLayout) {
FormLayoutContainer rightsCont = FormLayoutContainer.createDefaultFormLayout("rights", getTranslator());
rightsCont.setRootForm(mainForm);
formLayout.add(rightsCont);
rightsWrapperCont = FormLayoutContainer.createDefaultFormLayout("rights.copyright", getTranslator());
rightsWrapperCont.setRootForm(mainForm);
rightsCont.add(rightsWrapperCont);
decorate(rightsWrapperCont, rightsCont);
licenseKeys = getQLicenseKeyValues(qpoolService);
copyrightEl = uifactory.addDropdownSingleselect("rights.copyright.sel", "rights.copyright", rightsWrapperCont,
licenseKeys.getKeys(), licenseKeys.getValues(), null);
copyrightEl.addActionListener(FormEvent.ONCHANGE);
copyrightEl.select("none", true);
descriptionEl = uifactory.addTextAreaElement("rights.description", "rights.description", 1000, 6, 40, true, null, rightsWrapperCont);
}
private FormItem decorate(FormItem item, FormLayoutContainer formLayout) {
String itemName = item.getName();
MultipleSelectionElement checkbox = uifactory.addCheckboxesHorizontal("cbx_" + itemName, itemName, formLayout, new String[] { itemName }, EMPTY_VALUES);
checkbox.select(itemName, false);
checkbox.addActionListener(FormEvent.ONCLICK);
checkbox.setUserObject(item);
checkboxSwitch.add(checkbox);
item.setLabel(null, null);
item.setVisible(false);
item.setUserObject(checkbox);
checkboxContainer.put(checkbox, formLayout);
formLayout.moveBefore(checkbox, item);
return item;
}
@Override
protected void doDispose() {
//
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(checkboxSwitch.contains(source)) {
MultipleSelectionElement checkbox = (MultipleSelectionElement)source;
FormItem item = (FormItem)checkbox.getUserObject();
item.setVisible(checkbox.isAtLeastSelected(1));
checkboxContainer.get(checkbox).setDirty(true);
} else if(copyrightEl == source) {
descriptionEl.setVisible(copyrightEl.isVisible() && copyrightEl.getSelectedKey().equals(licenseKeys.getLastKey()));
rightsWrapperCont.setDirty(true);
} else {
super.formInnerEvent(ureq, source, event);
}
}
@Override
public void event(UserRequest ureq, Component source, Event event) {
if(source == selectContext) {
doOpenSelection(ureq);
} else {
super.event(ureq, source, event);
}
}
@Override
protected void event(UserRequest ureq, Controller source, Event event) {
if(source == cmc) {
cleanUp();
} else if(selectionCtrl == source) {
if(Event.DONE_EVENT == event) {
selectedTaxonomicPath = selectionCtrl.getSelectedLevel();
if(selectedTaxonomicPath == null) {
selectContextCont.contextPut("path", "");
} else {
String path = selectedTaxonomicPath.getMaterializedPathNames();
if(StringHelper.containsNonWhitespace(path)) {
if(!path.endsWith("/")) {
path += "/";
}
path += selectedTaxonomicPath.getField();
}
selectContextCont.contextPut("path", path);
}
}
cmc.deactivate();
cleanUp();
}
super.event(ureq, source, event);
}
private void cleanUp() {
removeAsListenerAndDispose(selectionCtrl);
removeAsListenerAndDispose(cmc);
selectionCtrl = null;
cmc = null;
}
private void doOpenSelection(UserRequest ureq) {
selectionCtrl = new TaxonomySelectionController(ureq, getWindowControl());
listenTo(selectionCtrl);
cmc = new CloseableModalController(getWindowControl(), translate("close"),
selectionCtrl.getInitialComponent(), true, translate("classification.taxonomic.path"));
cmc.activate();
listenTo(cmc);
}
@Override
protected boolean validateFormLogic(UserRequest ureq) {
boolean allOk = true;
//general
allOk &= validateElementLogic(titleEl, titleEl.getMaxLength(), true, isEnabled(titleEl));
allOk &= validateElementLogic(keywordsEl, keywordsEl.getMaxLength(), false, isEnabled(keywordsEl));
allOk &= validateElementLogic(coverageEl, coverageEl.getMaxLength(), false, isEnabled(coverageEl));
allOk &= validateElementLogic(addInfosEl, addInfosEl.getMaxLength(), false, isEnabled(addInfosEl));
allOk &= validateElementLogic(languageEl, languageEl.getMaxLength(), true, isEnabled(languageEl));
//educational
allOk &= validateBigDecimal(difficultyEl, 0.0d, 1.0d, true);
allOk &= validateBigDecimal(stdevDifficultyEl, 0.0d, 1.0d, true);
allOk &= validateBigDecimal(differentiationEl, -1.0d, 1.0d, true);
//lifecycle
allOk &= validateElementLogic(versionEl, versionEl.getMaxLength(), true, isEnabled(versionEl));
allOk &= validateSelection(statusEl, isEnabled(statusEl));
//technical
allOk &= validateElementLogic(editorEl, editorEl.getMaxLength(), true, isEnabled(editorEl));
allOk &= validateElementLogic(editorVersionEl, editorVersionEl.getMaxLength(), true, isEnabled(editorVersionEl));
allOk &= validateSelection(formatEl, isEnabled(formatEl));
//rights
allOk &= validateRights(copyrightEl, descriptionEl, licenseKeys, isEnabled(rightsWrapperCont));
return allOk & super.validateFormLogic(ureq);
}
private boolean isEnabled(FormItem item) {
return ((MultipleSelectionElement)item.getUserObject()).isAtLeastSelected(1);
}
@Override
protected void formOK(UserRequest ureq) {
updatedItems = new ArrayList<QuestionItem>();
for(QuestionItemShort item : items) {
QuestionItem fullItem = qpoolService.loadItemById(item.getKey());
if(fullItem instanceof QuestionItemImpl) {
QuestionItemImpl itemImpl = (QuestionItemImpl)fullItem;
formOKGeneral(itemImpl);
formOKEducational(itemImpl);
formOKQuestion(itemImpl);
formOKLifecycle(itemImpl);
formOKTechnical(itemImpl);
if(isEnabled(rightsWrapperCont)) {
RightsMetadataEditController.formOKRights(itemImpl, copyrightEl, descriptionEl, licenseKeys, qpoolService);
}
QuestionItem merged = qpoolService.updateItem(itemImpl);
updatedItems.add(merged);
}
}
fireEvent(ureq, Event.DONE_EVENT);
}
private void formOKGeneral(QuestionItemImpl itemImpl) {
if(isEnabled(titleEl))
itemImpl.setTitle(titleEl.getValue());
if(isEnabled(keywordsEl))
itemImpl.setKeywords(keywordsEl.getValue());
if(isEnabled(coverageEl))
itemImpl.setCoverage(coverageEl.getValue());
if(isEnabled(addInfosEl))
itemImpl.setAdditionalInformations(addInfosEl.getValue());
if(isEnabled(languageEl))
itemImpl.setLanguage(languageEl.getValue());
if(isEnabled(selectContextCont) && selectedTaxonomicPath != null) {
itemImpl.setTaxonomyLevel(selectedTaxonomicPath);
}
}
private void formOKEducational(QuestionItemImpl itemImpl) {
if(isEnabled(contextEl)) {
if(contextEl.isOneSelected()) {
QEducationalContext context = qpoolService.getEducationlContextByLevel(contextEl.getSelectedKey());
itemImpl.setEducationalContext(context);
} else {
itemImpl.setEducationalContext(null);
}
}
if(isEnabled(learningTimeContainer)) {
int day = learningTimeDayElement.getIntValue();
int hour = learningTimeHourElement.getIntValue();
int minute = learningTimeMinuteElement.getIntValue();
int seconds = learningTimeSecondElement.getIntValue();
String timeStr = MetadataConverterHelper.convertDuration(day, hour, minute, seconds);
itemImpl.setEducationalLearningTime(timeStr);
}
}
private void formOKQuestion(QuestionItemImpl itemImpl) {
if(isEnabled(typeEl) && typeEl.isOneSelected()) {
String typeKey = typeEl.getSelectedKey();
itemImpl.setType(qpoolService.getItemType(typeKey));
}
if(isEnabled(difficultyEl))
itemImpl.setDifficulty(toBigDecimal(difficultyEl.getValue()));
if(isEnabled(stdevDifficultyEl))
itemImpl.setStdevDifficulty(toBigDecimal(stdevDifficultyEl.getValue()));
if(isEnabled(differentiationEl))
itemImpl.setDifferentiation(toBigDecimal(differentiationEl.getValue()));
if(isEnabled(numAnswerAltEl))
itemImpl.setNumOfAnswerAlternatives(toInt(numAnswerAltEl.getValue()));
if(isEnabled(typeEl)) {
String assessmentType = assessmentTypeEl.isOneSelected() ? assessmentTypeEl.getSelectedKey() : null;
itemImpl.setAssessmentType(assessmentType);
}
}
private void formOKLifecycle(QuestionItemImpl itemImpl) {
if(isEnabled(statusEl) && statusEl.isOneSelected())
itemImpl.setStatus(statusEl.getSelectedKey());
if(isEnabled(versionEl))
itemImpl.setItemVersion(versionEl.getValue());
}
private void formOKTechnical(QuestionItemImpl itemImpl) {
if(isEnabled(editorEl))
itemImpl.setEditor(editorEl.getValue());
if(isEnabled(editorVersionEl))
itemImpl.setEditorVersion(editorVersionEl.getValue());
if(isEnabled(formatEl) && formatEl.isOneSelected())
itemImpl.setFormat(formatEl.getSelectedKey());
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
}