/**
* 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.
*/
package org.olat.course.nodes.cp;
import java.io.File;
import org.olat.basesecurity.BaseSecurityManager;
import org.olat.basesecurity.Constants;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.SelectionElement;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.stack.BreadcrumbPanel;
import org.olat.core.gui.components.tabbedpane.TabbedPane;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.ControllerEventListener;
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.gui.control.generic.iframe.DeliveryOptions;
import org.olat.core.gui.control.generic.iframe.DeliveryOptionsConfigurationController;
import org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController;
import org.olat.core.id.Identity;
import org.olat.core.id.Roles;
import org.olat.core.logging.AssertException;
import org.olat.core.util.StringHelper;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.course.ICourse;
import org.olat.course.assessment.AssessmentHelper;
import org.olat.course.condition.Condition;
import org.olat.course.condition.ConditionEditController;
import org.olat.course.editor.NodeEditController;
import org.olat.course.nodes.CPCourseNode;
import org.olat.course.nodes.CourseNodeFactory;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.fileresource.FileResourceManager;
import org.olat.fileresource.types.ImsCPFileResource;
import org.olat.ims.cp.CPManager;
import org.olat.ims.cp.ui.CPPackageConfig;
import org.olat.modules.ModuleConfiguration;
import org.olat.modules.cp.CPUIFactory;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.controllers.ReferencableEntriesSearchController;
/**
* Description:<BR/> Edit controller for content packaging course nodes <P/>
*
* Initial Date: Oct 13, 2004
* @author Felix Jost
* @author BPS (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
*/
public class CPEditController extends ActivateableTabbableDefaultController implements ControllerEventListener {
public static final String PANE_TAB_CPCONFIG = "pane.tab.cpconfig";
private static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility";
private static final String PANE_TAB_DELIVERYOPTIONS = "pane.tab.deliveryOptions";
public static final String CONFIG_KEY_REPOSITORY_SOFTKEY = "reporef";
private static final String VC_CHOSENCP = "chosencp";
public static final String CONFIG_DELIVERYOPTIONS = "deliveryOptions";
// NLS support:
public static final String NLS_ERROR_CPREPOENTRYMISSING = "error.cprepoentrymissing";
private static final String NLS_NO_CP_CHOSEN = "no.cp.chosen";
private static final String NLS_CONDITION_ACCESSIBILITY_TITLE = "condition.accessibility.title";
private static final String NLS_COMMAND_CHOOSECP = "command.choosecp";
private static final String NLS_COMMAND_CREATECP = "command.createcp";
private static final String NLS_COMMAND_CHANGECP = "command.changecp";
private Panel main;
private VelocityContainer cpConfigurationVc;
private ModuleConfiguration config;
private ReferencableEntriesSearchController searchController;
private DeliveryOptionsConfigurationController deliveryOptionsCtrl;
private ConditionEditController accessibilityCondContr;
private CPCourseNode cpNode;
private CompMenuForm cpMenuForm;
private TabbedPane myTabbedPane;
final static String[] paneKeys = { PANE_TAB_CPCONFIG, PANE_TAB_ACCESSIBILITY };
private Link previewLink;
private Link editLink;
private Link chooseCPButton;
private Link changeCPButton;
private Controller previewCtr;
private CloseableModalController cmc;
private final BreadcrumbPanel stackPanel;
/**
* @param cpNode
* @param ureq
* @param wControl
* @param course
*/
public CPEditController(CPCourseNode cpNode, UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, UserCourseEnvironment euce) {
super(ureq, wControl);
this.cpNode = cpNode;
this.config = cpNode.getModuleConfiguration();
this.stackPanel = stackPanel;
main = new Panel("cpmain");
cpConfigurationVc = createVelocityContainer("edit");
chooseCPButton = LinkFactory.createButtonSmall(NLS_COMMAND_CREATECP, cpConfigurationVc, this);
chooseCPButton.setElementCssClass("o_sel_cp_choose_repofile");
changeCPButton = LinkFactory.createButtonSmall(NLS_COMMAND_CHANGECP, cpConfigurationVc, this);
changeCPButton.setElementCssClass("o_sel_cp_change_repofile");
DeliveryOptions parentConfig = null;
if (config.get(CONFIG_KEY_REPOSITORY_SOFTKEY) != null) {
// fetch repository entry to display the repository entry title of the chosen cp
RepositoryEntry re = getCPReference(config, false);
if (re == null) { // we cannot display the entries name, because the
// repository entry had been deleted between the time when it was chosen here, and now
showError(NLS_ERROR_CPREPOENTRYMISSING);
cpConfigurationVc.contextPut("showPreviewButton", Boolean.FALSE);
cpConfigurationVc.contextPut(VC_CHOSENCP, translate("no.cp.chosen"));
} else {
if (isEditable(ureq.getIdentity(), ureq.getUserSession().getRoles(), re)) {
editLink = LinkFactory.createButtonSmall("edit", cpConfigurationVc, this);
}
cpConfigurationVc.contextPut("showPreviewButton", Boolean.TRUE);
String displayname = StringHelper.escapeHtml(re.getDisplayname());
previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", displayname, Link.NONTRANSLATED, cpConfigurationVc, this);
previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview");
previewLink.setTitle(getTranslator().translate("command.preview"));
CPPackageConfig cpConfig = CPManager.getInstance().getCPPackageConfig(re.getOlatResource());
parentConfig = (cpConfig == null ? null : cpConfig.getDeliveryOptions());
}
} else {
// no valid config yet
cpConfigurationVc.contextPut("showPreviewButton", Boolean.FALSE);
cpConfigurationVc.contextPut(VC_CHOSENCP, translate(NLS_NO_CP_CHOSEN));
}
Boolean cpMenu = config.getBooleanEntry(NodeEditController.CONFIG_COMPONENT_MENU);
cpMenuForm = new CompMenuForm(ureq, wControl, cpMenu);
listenTo(cpMenuForm);
cpConfigurationVc.put("cpMenuForm", cpMenuForm.getInitialComponent());
// Accessibility precondition
Condition accessCondition = cpNode.getPreConditionAccess();
accessibilityCondContr = new ConditionEditController(ureq, getWindowControl(), euce,
accessCondition, AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), cpNode));
listenTo(accessibilityCondContr);
DeliveryOptions deliveryOptions = (DeliveryOptions)config.get(CPEditController.CONFIG_DELIVERYOPTIONS);
deliveryOptionsCtrl = new DeliveryOptionsConfigurationController(ureq, getWindowControl(), deliveryOptions, "Knowledge Transfer#_cp_layout", parentConfig);
listenTo(deliveryOptionsCtrl);
main.setContent(cpConfigurationVc);
}
/**
* @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
* org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
*/
public void event(UserRequest ureq, Component source, Event event) {
if (source == chooseCPButton || source == changeCPButton) {
removeAsListenerAndDispose(searchController);
searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq,
ImsCPFileResource.TYPE_NAME, translate(NLS_COMMAND_CHOOSECP));
listenTo(searchController);
removeAsListenerAndDispose(cmc);
cmc = new CloseableModalController(
getWindowControl(), translate("close"), searchController.getInitialComponent(), true, translate(NLS_COMMAND_CREATECP)
);
listenTo(cmc);
cmc.activate();
} else if (source == previewLink){
// Preview as modal dialogue only if the config is valid
RepositoryEntry re = getCPReference(config, false);
if (re == null) { // we cannot preview it, because the repository entry
// had been deleted between the time when it was chosen here, and now
showError(NLS_ERROR_CPREPOENTRYMISSING);
} else {
File cpRoot = FileResourceManager.getInstance().unzipFileResource(re.getOlatResource());
Boolean showMenuB = config.getBooleanEntry(NodeEditController.CONFIG_COMPONENT_MENU);
// pre: showMenuB != null
removeAsListenerAndDispose(previewCtr);
DeliveryOptions previewOptions = deliveryOptionsCtrl.getOptionsForPreview();
previewCtr = CPUIFactory.getInstance().createMainLayoutPreviewController_v2(ureq, getWindowControl(), new LocalFolderImpl(cpRoot),
showMenuB.booleanValue(), previewOptions);
stackPanel.pushController(translate("preview.cp"), previewCtr);
}
} else if (source == editLink) {
CourseNodeFactory.getInstance().launchReferencedRepoEntryEditor(ureq, getWindowControl(), cpNode);
}
}
/**
* @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
* org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
*/
public void event(UserRequest urequest, Controller source, Event event) {
if (source == searchController) {
if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
// search controller done
// -> close closeable modal controller
cmc.deactivate();
RepositoryEntry re = searchController.getSelectedEntry();
if (re != null) {
setCPReference(re, config);
cpConfigurationVc.contextPut("showPreviewButton", Boolean.TRUE);
String displayname = StringHelper.escapeHtml(re.getDisplayname());
previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", displayname, Link.NONTRANSLATED, cpConfigurationVc, this);
previewLink.setCustomEnabledLinkCSS("o_preview");
previewLink.setTitle(getTranslator().translate("command.preview"));
// remove existing edit link, add new one if user is allowed to edit this CP
if (editLink != null) {
cpConfigurationVc.remove(editLink);
editLink = null;
}
if (isEditable(urequest.getIdentity(), urequest.getUserSession().getRoles(), re)) {
editLink = LinkFactory.createButtonSmall("edit", cpConfigurationVc, this);
}
// fire event so the updated config is saved by the editormaincontroller
fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
CPPackageConfig cpConfig = CPManager.getInstance().getCPPackageConfig(re.getOlatResource());
if(cpConfig != null && cpConfig.getDeliveryOptions() != null) {
deliveryOptionsCtrl.setParentDeliveryOptions(cpConfig.getDeliveryOptions());
}
}
}
// else cancelled repo search
} else if (source == accessibilityCondContr) {
if (event == Event.CHANGED_EVENT) {
Condition cond = accessibilityCondContr.getCondition();
cpNode.setPreConditionAccess(cond);
fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
}
} else if (source == cpMenuForm) {
if (event == Event.DONE_EVENT) {
config.setBooleanEntry(NodeEditController.CONFIG_COMPONENT_MENU, cpMenuForm.isCpMenu());
fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
}
} else if (source == deliveryOptionsCtrl) {
if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
config.set(CPEditController.CONFIG_DELIVERYOPTIONS, deliveryOptionsCtrl.getDeliveryOptions());
fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
}
}
}
/**
* @param identity
* @param repository entry
* @return
*/
private boolean isEditable(Identity identity, Roles roles, RepositoryEntry re) {
return (BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_ADMIN)
|| RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identity, re)
|| RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(identity, roles, re));
}
/**
* @see org.olat.core.gui.control.generic.tabbable.TabbableDefaultController#addTabs(org.olat.core.gui.components.TabbedPane)
*/
public void addTabs(TabbedPane tabbedPane) {
myTabbedPane = tabbedPane;
tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate(NLS_CONDITION_ACCESSIBILITY_TITLE)));
tabbedPane.addTab(translate(PANE_TAB_CPCONFIG), main);
tabbedPane.addTab(translate(PANE_TAB_DELIVERYOPTIONS), deliveryOptionsCtrl.getInitialComponent());
}
/**
* @param config the moduleConfig
* @param strict an assertion exception is thrown if no entry is found when
* strict is set to true, otherwise, null is returned
* @return the repositoryentry or null if not in strict mode and no entry
* found
* @throws AssertException when in strict mode and no entry is found
*/
public static RepositoryEntry getCPReference(ModuleConfiguration config, boolean strict) {
if (config == null) {
if (strict) throw new AssertException("missing config in CP");
else return null;
}
String repoSoftkey = (String) config.get(CPEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
if (repoSoftkey == null) {
if (strict) throw new AssertException("invalid config when being asked for references");
else return null;
}
RepositoryManager rm = RepositoryManager.getInstance();
RepositoryEntry entry = rm.lookupRepositoryEntryBySoftkey(repoSoftkey, strict);
// entry can be null only if !strict
return entry;
}
/**
* Remove the reference to the repository entry.
*
* @param moduleConfiguration
*/
public static void removeCPReference(ModuleConfiguration moduleConfiguration) {
moduleConfiguration.remove(CPEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
}
/**
* Set the referenced repository entry.
*
* @param re
* @param moduleConfiguration
*/
public static void setCPReference(RepositoryEntry re, ModuleConfiguration moduleConfiguration) {
moduleConfiguration.set(CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey());
}
/**
* @param moduleConfiguration
* @return boolean
*/
public static boolean isModuleConfigValid(ModuleConfiguration moduleConfiguration) {
return (moduleConfiguration.get(CONFIG_KEY_REPOSITORY_SOFTKEY) != null);
}
/**
* @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
*/
protected void doDispose() {
//child controllers registered with listenTo() get disposed in BasicController
if (previewCtr != null) {
previewCtr.dispose();
previewCtr = null;
}
}
public String[] getPaneKeys() {
return paneKeys;
}
public TabbedPane getTabbedPane() {
return myTabbedPane;
}
}
class CompMenuForm extends FormBasicController {
/**
* Simple form for asking whether component menu should be shown or not.
*
* @author Lars Eberle (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
*/
private SelectionElement cpMenu;
private boolean compMenuConfig;
CompMenuForm(UserRequest ureq, WindowControl wControl, Boolean compMenuConfig) {
super(ureq, wControl);
this.compMenuConfig = compMenuConfig == null ? true:compMenuConfig.booleanValue();
initForm(ureq);
}
public boolean isCpMenu() {
return cpMenu.isSelected(0);
}
@Override
protected void formOK(UserRequest ureq) {
fireEvent (ureq, Event.DONE_EVENT);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
cpMenu = uifactory.addCheckboxesHorizontal("cpMenu", "display.config.compMenu", formLayout, new String[]{"xx"}, new String[]{null});
cpMenu.select("xx",compMenuConfig);
uifactory.addFormSubmitButton("submit", formLayout);
}
@Override
protected void doDispose() {
//
}
}