/** * <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.course.nodes.feed; import java.util.Locale; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; 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.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.tabbable.ActivateableTabbableDefaultController; import org.olat.core.gui.translator.Translator; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; 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.AbstractFeedCourseNode; import org.olat.course.nodes.CourseNodeFactory; import org.olat.course.run.userview.UserCourseEnvironment; import org.olat.course.tree.CourseEditorTreeModel; import org.olat.modules.ModuleConfiguration; import org.olat.modules.webFeed.FeedPreviewSecurityCallback; import org.olat.modules.webFeed.FeedSecurityCallback; import org.olat.modules.webFeed.ui.FeedUIFactory; import org.olat.repository.RepositoryEntry; import org.olat.repository.controllers.ReferencableEntriesSearchController; /** * The abstract feed course node edit controller. * * <P> * Initial Date: Mar 31, 2009 <br> * * @author gwassmann */ public abstract class FeedNodeEditController extends ActivateableTabbableDefaultController implements ControllerEventListener { // Constants public static final String PANE_TAB_FEED = "pane.tab.feed"; private static final String PANE_TAB_ACCESS = "pane.tab.access"; private static final String[] paneKeys = { PANE_TAB_ACCESS, PANE_TAB_FEED }; // More constants, mainly keys. private static final String CHOSEN_FEED_NAME = "chosen_feed_name"; private static final String NO_FEED_CHOSEN = "no.feed.chosen"; private static final String SHOW_PREVIEW_LINK = "showPreviewLink"; private static final String COMMAND_PREVIEW = "command.preview"; private static final String ERROR_REPOSITORY_ENTRY_MISSING = "error.repository.entry.missing"; private static final String BUTTON_CHOOSE_FEED = "button.choose.feed"; private static final String BUTTON_CHANGE_FEED = "button.change.feed"; private static final String BUTTON_CREATE_FEED = "button.create.feed"; // Components private TabbedPane tabbedPane; private Panel learningResource; private Link chooseButton, changeButton; private Link previewLink; private Link editLink; private VelocityContainer accessVC, contentVC; // Controllers private ConditionEditController readerCtr, posterCtr, moderatroCtr; private ReferencableEntriesSearchController searchController; private CloseableModalController cmc, cmcFeedCtr; private Controller feedController; // The actual node and its configuration for easy access. private ModuleConfiguration config; private AbstractFeedCourseNode node; private ICourse course; private FeedUIFactory uiFactory; private String resourceTypeName; /** * Constructor. The uiFactory is needed for preview controller and the * resourceTypeName for the repository search. * * @param courseNode * @param course * @param uce * @param uiFactory * @param resourceTypeName * @param ureq * @param control */ public FeedNodeEditController(AbstractFeedCourseNode courseNode, ICourse course, UserCourseEnvironment uce, FeedUIFactory uiFactory, String resourceTypeName, UserRequest ureq, WindowControl control) { super(ureq, control); this.course = course; this.node = courseNode; this.config = courseNode.getModuleConfiguration(); this.uiFactory = uiFactory; this.resourceTypeName = resourceTypeName; setTranslatorAndFallback(ureq.getLocale()); this.getClass().getSuperclass(); // Accessibility tab accessVC = new VelocityContainer("accessVC", FeedNodeEditController.class, "access", getTranslator(), this); CourseEditorTreeModel editorModel = course.getEditorTreeModel(); // Moderator precondition Condition moderatorCondition = node.getPreConditionModerator(); moderatroCtr = new ConditionEditController(ureq, getWindowControl(), uce, moderatorCondition, AssessmentHelper.getAssessableNodes(editorModel, node)); this.listenTo(moderatroCtr); accessVC.put("moderatorCondition", moderatroCtr.getInitialComponent()); // Poster precondition Condition posterCondition = node.getPreConditionPoster(); posterCtr = new ConditionEditController(ureq, getWindowControl(), uce, posterCondition, AssessmentHelper .getAssessableNodes(editorModel, node)); this.listenTo(posterCtr); accessVC.put("posterCondition", posterCtr.getInitialComponent()); // Reader precondition Condition readerCondition = node.getPreConditionReader(); readerCtr = new ConditionEditController(ureq, getWindowControl(), uce, readerCondition, AssessmentHelper .getAssessableNodes(editorModel, node)); this.listenTo(readerCtr); accessVC.put("readerCondition", readerCtr.getInitialComponent()); // Podcast tab. Embed the actual podcast learning contentVC into the // building block learningResource = new Panel("learning_resource_panel"); contentVC = new VelocityContainer("accessVC", FeedNodeEditController.class, "edit", getTranslator(), this); changeButton = LinkFactory.createButtonSmall(BUTTON_CHANGE_FEED, contentVC, this); changeButton.setElementCssClass("o_sel_feed_change_repofile"); chooseButton = LinkFactory.createButtonSmall(BUTTON_CREATE_FEED, contentVC, this); chooseButton.setElementCssClass("o_sel_feed_choose_repofile"); if (config.get(AbstractFeedCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY) != null) { // fetch repository entry to display the repository entry title of the // chosen cp RepositoryEntry re = courseNode.getReferencedRepositoryEntry(); if (re == null) { // we cannot display the entries name, because the repository entry has // been deleted since it was last embeded. this.showError(ERROR_REPOSITORY_ENTRY_MISSING); contentVC.contextPut(SHOW_PREVIEW_LINK, Boolean.FALSE); contentVC.contextPut(CHOSEN_FEED_NAME, translate(NO_FEED_CHOSEN)); } else { // no securitycheck on feeds, editable by everybody editLink = LinkFactory.createButtonSmall("edit", contentVC, this); contentVC.contextPut(SHOW_PREVIEW_LINK, Boolean.TRUE); String displayname = StringHelper.escapeHtml(re.getDisplayname()); previewLink = LinkFactory.createCustomLink(COMMAND_PREVIEW, COMMAND_PREVIEW, displayname, Link.NONTRANSLATED, contentVC, this); previewLink.setCustomEnabledLinkCSS("o_preview"); previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview"); previewLink.setTitle(getTranslator().translate(COMMAND_PREVIEW)); } } else { // no valid config yet contentVC.contextPut(SHOW_PREVIEW_LINK, Boolean.FALSE); contentVC.contextPut(CHOSEN_FEED_NAME, translate(NO_FEED_CHOSEN)); } learningResource.setContent(contentVC); } private void setTranslatorAndFallback(Locale locale) { // The implementing class Class<? extends FeedNodeEditController> thisClass = this.getClass(); Translator fallback = Util.createPackageTranslator(thisClass.getSuperclass(), locale); Translator translator = Util.createPackageTranslator(thisClass, locale, fallback); setTranslator(translator); } /** * @see org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController#getPaneKeys() */ @Override public String[] getPaneKeys() { return paneKeys; } /** * @see org.olat.core.gui.control.generic.tabbable.ActivateableTabbableDefaultController#getTabbedPane() */ @Override public TabbedPane getTabbedPane() { return tabbedPane; } /** * @see org.olat.core.gui.control.DefaultController#doDispose() */ @Override protected void doDispose() { if (cmc != null) { cmc.dispose(); cmc = null; } } @Override protected void event(UserRequest ureq, Component source, Event event) { if (source == chooseButton || source == changeButton) { searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq, resourceTypeName, translate(BUTTON_CHOOSE_FEED)); listenTo(searchController); cmc = new CloseableModalController(getWindowControl(), translate("close"), searchController.getInitialComponent(), true, translate(BUTTON_CREATE_FEED)); cmc.activate(); } else if (source == previewLink) { // Preview as modal dialogue only if the config is valid RepositoryEntry re = node.getReferencedRepositoryEntry(); if (re == null) { // The repository entry has been deleted meanwhile. showError("error.repoentrymissing"); } else { FeedSecurityCallback callback = new FeedPreviewSecurityCallback(); feedController = uiFactory.createMainController(re.getOlatResource(), ureq, getWindowControl(), callback, course .getResourceableId(), node.getIdent()); cmcFeedCtr = new CloseableModalController(getWindowControl(), translate("command.close"), feedController.getInitialComponent()); listenTo(cmcFeedCtr); cmcFeedCtr.activate(); } } else if (source == editLink) { boolean launched = CourseNodeFactory.getInstance().launchReferencedRepoEntryEditor(ureq, getWindowControl(), node); if(!launched) { RepositoryEntry re = node.getReferencedRepositoryEntry(); if (re == null) { showError("error.repoentrymissing"); } else { showError("error.wrongtype"); } } } } @Override public void event(UserRequest urequest, Controller source, Event event) { if (source == moderatroCtr) { if (event == Event.CHANGED_EVENT) { Condition cond = moderatroCtr.getCondition(); node.setPreConditionModerator(cond); fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT); } } else if (source == posterCtr) { if (event == Event.CHANGED_EVENT) { Condition cond = posterCtr.getCondition(); node.setPreConditionPoster(cond); fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT); } } else if (source == readerCtr) { if (event == Event.CHANGED_EVENT) { Condition cond = readerCtr.getCondition(); node.setPreConditionReader(cond); fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT); } } else if (source == searchController) { cmc.deactivate(); // repository search controller done if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) { RepositoryEntry re = searchController.getSelectedEntry(); if (re != null) { config.set(AbstractFeedCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey()); contentVC.contextPut("showPreviewLink", Boolean.TRUE); String displayname = StringHelper.escapeHtml(re.getDisplayname()); previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", displayname, Link.NONTRANSLATED, contentVC, this); previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview"); previewLink.setCustomEnabledLinkCSS("o_preview"); previewLink.setTitle(getTranslator().translate("command.preview")); // no securitycheck on feeds, editable by everybody editLink = LinkFactory.createButtonSmall("edit", contentVC, this); // fire event so the updated config is saved by the // editormaincontroller fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT); } } // else cancelled repo search } else if (source == cmcFeedCtr) { if (event == CloseableModalController.CLOSE_MODAL_EVENT) { cmcFeedCtr.dispose(); feedController.dispose(); } } } /** * @see org.olat.core.gui.control.generic.tabbable.TabbableController#addTabs(org.olat.core.gui.components.tabbedpane.TabbedPane) */ public void addTabs(TabbedPane tabbedPane) { this.tabbedPane = tabbedPane; tabbedPane.addTab(translate(PANE_TAB_ACCESS), accessVC); tabbedPane.addTab(translate(PANE_TAB_FEED), learningResource); } /** * remove ref to repo entry from the config * * @param moduleConfig */ public static void removeReference(ModuleConfiguration moduleConfig) { moduleConfig.remove(AbstractFeedCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY); } /** * set an repository reference to the feed course node * * @param re * @param moduleConfiguration */ public static void setReference(RepositoryEntry re, ModuleConfiguration moduleConfiguration) { moduleConfiguration.set(AbstractFeedCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey()); } }