/** * 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) frentix GmbH<br> * http://www.frentix.com<br> * <p> */ package org.olat.user.propertyhandlers; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Vector; 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.MultipleSelectionElement; 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.MultipleSelectionElementImpl; 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.Util; import org.olat.user.UserPropertiesConfig; import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> * Provides a controller which lets the user choose from a set of interests. The interests to choose from are defined in an XML configuration file. * * <P> * Initial Date: Aug 5, 2009 <br> * @author twuersch */ public class UserInterestsController extends FormBasicController { /** The user interests checkboxes. Note that there is one list element per <b>group</b> of checkboxes, not per checkbox. */ private List<MultipleSelectionElement> checkboxGroups; /** The available user interests loaded from the XML file. */ private List<UserInterestsCategory> availableUserInterests; /** The selected user interests */ private String selectedInterestsIDs; private final int maxNumOfInterests; @Autowired private UserPropertiesConfig userPropertiesConfig; /** * Creates this controller. * * @param ureq The user request. * @param wControl The window control. */ public UserInterestsController(UserRequest ureq, WindowControl wControl, String selectedInterestsIDs, List<UserInterestsCategory> availableUserInterests) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(UserInterestsPropertyHandler.PACKAGE_UINTERESTS, getLocale(), getTranslator())); this.checkboxGroups = new ArrayList<>(); this.availableUserInterests = availableUserInterests; this.selectedInterestsIDs = selectedInterestsIDs; maxNumOfInterests = userPropertiesConfig.getMaxNumOfInterests(); initForm(ureq); } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#doDispose() */ @Override protected void doDispose() { // Nothing to dispose. } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest) */ @Override protected void formOK(UserRequest ureq) { fireEvent(ureq, Event.DONE_EVENT); } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formCancelled(org.olat.core.gui.UserRequest) */ @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#initForm(org.olat.core.gui.components.form.flexible.FormItemContainer, org.olat.core.gui.control.Controller, org.olat.core.gui.UserRequest) */ @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormDescription("userinterests.description"); // Draw the checkboxes for (int i = 0; i < this.availableUserInterests.size(); i++) { UserInterestsCategory category = this.availableUserInterests.get(i); Vector<String> keys = new Vector<String>(); for (UserInterestsCategory subcategory : category.getSubcategories()) { keys.add(UserInterestsPropertyHandler.SUBCATEGORY_I18N_PREFIX + subcategory.getId()); } String[] values = new String[keys.size()]; for (int j = 0; j < values.length; j++) { values[j] = translate(keys.get(j)); } MultipleSelectionElement interestCheckboxes = uifactory.addCheckboxesVertical("interest_" + category.getId(), formLayout, keys.toArray(new String[0]), values, null, 2); this.checkboxGroups.add(interestCheckboxes); interestCheckboxes.setLabel(UserInterestsPropertyHandler.CATEGORY_I18N_PREFIX + category.getId(), null); interestCheckboxes.addActionListener(FormEvent.ONCHANGE); if (i != this.availableUserInterests.size() - 1) { uifactory.addSpacerElement("spacer_" + category.getId(), formLayout, false); } } // Check boxes for the given interests this.setSelectedInterests(this.selectedInterestsIDs); // Disable the checkboxes if already the maximum number is selected. if (getSelectionCount() >= maxNumOfInterests) { Set<String> currentSelection = getCurrentSelection(); for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { MultipleSelectionElementImpl multipleSelectionElementImpl = (MultipleSelectionElementImpl)checkboxGroup; Set<String> allUncheckedCheckboxes = new HashSet<String>(multipleSelectionElementImpl.getKeys()); allUncheckedCheckboxes.removeAll(currentSelection); multipleSelectionElementImpl.setEnabled(allUncheckedCheckboxes, false); } showWarning("form.warning.maxNumber"); } // Add submit and cancel buttons final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator()); formLayout.add(buttonLayout); uifactory.addFormSubmitButton("finish", buttonLayout); uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl()); } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formInnerEvent(org.olat.core.gui.UserRequest, org.olat.core.gui.components.form.flexible.FormItem, org.olat.core.gui.components.form.flexible.impl.FormEvent) */ @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { super.formInnerEvent(ureq, source, event); // did the user click on a check box? if (this.checkboxGroups.contains(source)) { // find out which checkboxes are selected at the moment. Set<String> currentSelection = getCurrentSelection(); // if the user has not selected the maximum number of boxes... if (getSelectionCount() < maxNumOfInterests) { // ...enable all checkboxes for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { MultipleSelectionElementImpl multipleSelectionElementImpl = (MultipleSelectionElementImpl)checkboxGroup; multipleSelectionElementImpl.setEnabled(multipleSelectionElementImpl.getKeys(), true); } } else { // ... otherwise, disable all checkboxes except the selected ones. for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { MultipleSelectionElementImpl multipleSelectionElementImpl = (MultipleSelectionElementImpl)checkboxGroup; Set<String> allUncheckedCheckboxes = new HashSet<String>(multipleSelectionElementImpl.getKeys()); allUncheckedCheckboxes.removeAll(currentSelection); multipleSelectionElementImpl.setEnabled(allUncheckedCheckboxes, false); } showWarning("form.warning.maxNumber"); } } } /** * Returns a string which contains the identifiers of the selected checkboxes, delimited by colons. * * @return a string which contains the i18n keys of the selected checkboxes, delimited by colons. */ public String getSelectedInterests() { // Retrieve the i18n keys of the selected checkboxes Set<String> selectedInterestsKeysAsSet = new HashSet<String>(); for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { selectedInterestsKeysAsSet.addAll(checkboxGroup.getSelectedKeys()); } if (selectedInterestsKeysAsSet.size() > 0) { // convert these keys into IDs @SuppressWarnings("hiding") Set<String> selectedInterestsIDs = new HashSet<String>(); for (String selectedInterestKey : selectedInterestsKeysAsSet) { selectedInterestsIDs.add(selectedInterestKey.replace(UserInterestsPropertyHandler.SUBCATEGORY_I18N_PREFIX, "")); } StringBuffer selectedInterestsKeys = new StringBuffer(); selectedInterestsKeys.append(":"); for (String selectedInterestID : selectedInterestsIDs) { selectedInterestsKeys.append(selectedInterestID); selectedInterestsKeys.append(":"); } return selectedInterestsKeys.toString(); } else { return ""; } } /** * Selects all checkboxes whose i18n keys are contained in the space-delimited <code>selectedInterestsKeys</code>. * * @param selectedInterestsIDs */ public void setSelectedInterests(String selectedInterestsIDs) { if (selectedInterestsIDs != null) { Set<String> selectedInterestsIDsAsSet = new HashSet<String>(Arrays.asList(selectedInterestsIDs.trim().split(":"))); // for each ID we get, ... for (String selectedInterestID : selectedInterestsIDsAsSet) { if (!selectedInterestID.equals("")) { // ... we have to loop over all checkbox groups since we don't know which one the ID belongs to. for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { String key = UserInterestsPropertyHandler.SUBCATEGORY_I18N_PREFIX + selectedInterestID; MultipleSelectionElementImpl checkboxGroupImpl = (MultipleSelectionElementImpl)checkboxGroup; if (checkboxGroupImpl.getKeys().contains(key)) { checkboxGroup.select(key, true); } } } } } } private int getSelectionCount() { int selectionCount = 0; for(MultipleSelectionElement checkboxGroup : this.checkboxGroups) { selectionCount += checkboxGroup.getSelectedKeys().size(); } return selectionCount; } private Set<String> getCurrentSelection() { Set<String> currentSelection = new HashSet<String>(); for (MultipleSelectionElement checkboxGroup : this.checkboxGroups) { currentSelection.addAll(checkboxGroup.getSelectedKeys()); } return currentSelection; } }