/** * 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.portfolio.ui.artefacts.view; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.olat.NewControllerFactory; 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.FormLink; import org.olat.core.gui.components.form.flexible.elements.TextBoxListElement; 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.link.Link; 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.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.filter.FilterFactory; import org.olat.portfolio.EPArtefactHandler; import org.olat.portfolio.EPLoggingAction; import org.olat.portfolio.EPUIFactory; import org.olat.portfolio.PortfolioModule; import org.olat.portfolio.manager.EPFrontendManager; import org.olat.portfolio.model.artefacts.AbstractArtefact; import org.olat.portfolio.model.structel.PortfolioStructure; import org.olat.portfolio.ui.artefacts.collect.EPCollectStepForm00; import org.olat.portfolio.ui.artefacts.collect.EPCollectStepForm03; import org.olat.portfolio.ui.artefacts.collect.EPReflexionChangeEvent; import org.olat.resource.OLATResource; import org.olat.util.logging.activity.LoggingResourceable; import org.springframework.beans.factory.annotation.Autowired; /** * Description:<br> * Shows an Artefact itself * * <P> * Initial Date: 09.07.2010 <br> * * @author Roman Haag, roman.haag@frentix.com, frentix GmbH */ public class EPArtefactViewController extends FormBasicController { private AbstractArtefact artefact; private TextElement title; @Autowired private EPFrontendManager ePFMgr; private FormLink deleteBtn; private DialogBoxController delYesNoDialog; private Map<String, Boolean> artAttribConfig; private boolean artefactChooseMode; private FormLink chooseBtn; private TextBoxListElement tblE; private boolean viewOnlyMode; private boolean artefactInClosedMap; @Autowired private PortfolioModule portfolioModule; private final boolean detailsLinkEnabled; private CloseableModalController artefactBox; private FormLink detailsLink; private FormLink reflexionBtn; private EPCollectStepForm03 reflexionCtrl; private FormLink descriptionBtn; private EPCollectStepForm00 descriptionCtrl; private CloseableCalloutWindowController calloutCtrl; public EPArtefactViewController(UserRequest ureq, WindowControl wControl, AbstractArtefact artefact, Map<String, Boolean> artAttribConfig, boolean artefactChooseMode, boolean viewOnlyMode, boolean detailsLink) { super(ureq, wControl, "singleArtefact"); this.artefact = artefact; this.artefactChooseMode = artefactChooseMode; this.artefactInClosedMap = ePFMgr.isArtefactClosed(artefact); this.viewOnlyMode = viewOnlyMode; this.detailsLinkEnabled = detailsLink; if (viewOnlyMode){ artAttribConfig = ePFMgr.getArtefactAttributeConfig(null); //get a default config // only enable a minimal set, not users settings artAttribConfig.put("artefact.author", true); artAttribConfig.put("artefact.description", true); artAttribConfig.put("artefact.reflexion", true); artAttribConfig.put("artefact.source", true); artAttribConfig.put("artefact.sourcelink", true); artAttribConfig.put("artefact.title", false); artAttribConfig.put("artefact.date", true); artAttribConfig.put("artefact.tags", true); artAttribConfig.put("artefact.used.in.maps", true); artAttribConfig.put("artefact.handlerdetails", true); } if (artefactChooseMode){ artAttribConfig = ePFMgr.getArtefactAttributeConfig(null); //get a default config // only enable a minimal set, not users settings artAttribConfig.put("artefact.author", false); artAttribConfig.put("artefact.description", true); artAttribConfig.put("artefact.reflexion", false); artAttribConfig.put("artefact.source", true); artAttribConfig.put("artefact.sourcelink", false); artAttribConfig.put("artefact.title", false); artAttribConfig.put("artefact.date", true); artAttribConfig.put("artefact.tags", false); artAttribConfig.put("artefact.used.in.maps", false); } if (artAttribConfig==null){ artAttribConfig = ePFMgr.getArtefactAttributeConfig(getIdentity()); } this.artAttribConfig = artAttribConfig; initForm(ureq); } /** * load without a config will display artefact with default displayconfig / or users preferences * use this, when no ArtefactAttributeSettingsController is in the view to make settings! * @param ureq * @param wControl */ public EPArtefactViewController(UserRequest ureq, WindowControl wControl, AbstractArtefact artefact){ this(ureq, wControl, artefact, null, false, false, false); } /** * load without a config in view-only mode (mostly in popups) * @param ureq * @param wControl * @param artefact * @param viewOnlyMode */ public EPArtefactViewController(UserRequest ureq, WindowControl wControl, AbstractArtefact artefact, boolean viewOnlyMode){ this(ureq, wControl, artefact, null, false, viewOnlyMode, false); } /** * @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) { if(detailsLinkEnabled && !artefactChooseMode) { detailsLink = uifactory.addFormLink("details.link", formLayout, Link.BUTTON); detailsLink.setElementCssClass("o_sel_artefact_details"); } title = uifactory.addInlineTextElement("title", artefact.getTitle(), formLayout, this); flc.contextPut("cssClosed", artefactInClosedMap ? "o_artefact_closed" : ""); flc.contextPut("viewOnly", viewOnlyMode); if (viewOnlyMode || artefactInClosedMap) title.setEnabled(false); // get tags and prepare textboxlist-component List<String> tagL = ePFMgr.getArtefactTags(artefact); Map<String, String> tagLM = new HashMap<String,String>(); for (String tag : tagL) { tagLM.put(tag, tag); } tblE = uifactory.addTextBoxListElement("tagTextbox", null, "tag.textboxlist.hint", tagLM, formLayout, getTranslator()); if (viewOnlyMode || artefactInClosedMap) { tblE.setEnabled(false); } else { Map<String, String> allUsersTags = ePFMgr.getUsersMostUsedTags(getIdentity(), -1); tblE.setAutoCompleteContent(allUsersTags); } // get maps wherein this artefact is linked and create links to them List<PortfolioStructure> linkedMaps = ePFMgr.getReferencedMapsForArtefact(artefact); if (linkedMaps != null && linkedMaps.size() != 0) { List<FormLink> selectMapNames = new ArrayList<FormLink>(linkedMaps.size()); int count = 0; for (PortfolioStructure ePMap : linkedMaps) { String mapTitle = StringHelper.escapeHtml(ePMap.getTitle()); FormLink selectMap = uifactory.addFormLink("map-" + count++, "map", mapTitle, null, formLayout, Link.NONTRANSLATED); selectMap.setUserObject(ePMap.getOlatResource()); selectMap.setEnabled(!viewOnlyMode && !artefactChooseMode); selectMapNames.add(selectMap); } flc.contextPut("maps", selectMapNames); } // build link to original source if (StringHelper.containsNonWhitespace(artefact.getBusinessPath())) { String sourceLink = createLinkToArtefactSource(ureq, artefact.getBusinessPath()); flc.contextPut("artefactSourceLink", sourceLink); } // create a delete button deleteBtn = uifactory.addFormLink("delete.artefact", formLayout, Link.BUTTON); deleteBtn.setIconLeftCSS("o_icon o_icon_delete"); deleteBtn.addActionListener(FormEvent.ONCLICK); if (viewOnlyMode || artefactChooseMode || artefactInClosedMap) deleteBtn.setVisible(false); // let the artefact-handler paint what is special for this kind of artefact EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(artefact.getResourceableTypeName()); Controller detCtrl = artHandler.createDetailsController(ureq, getWindowControl(), artefact, viewOnlyMode || artefactInClosedMap); if (detCtrl != null) { flc.put("detailsController", detCtrl.getInitialComponent()); } // create edit buttons the adapt meta-data if (!(viewOnlyMode || artefactChooseMode || artefactInClosedMap)){ String reflexion = artefact.getReflexion(); reflexion = FilterFactory.getHtmlTagAndDescapingFilter().filter(reflexion); reflexion = StringHelper.xssScan(reflexion); reflexion = Formatter.truncate(reflexion, 50); if (!StringHelper.containsNonWhitespace(reflexion)) { reflexion = "  "; // show a link even if empty } reflexionBtn = uifactory.addFormLink("reflexionBtn", reflexion, null, formLayout, Link.NONTRANSLATED); reflexionBtn.setIconLeftCSS("o_icon o_icon_inline_editable"); String description = artefact.getDescription(); description = FilterFactory.getHtmlTagAndDescapingFilter().filter(description); description = Formatter.truncate(description, 50); description = StringHelper.xssScan(description); if (!StringHelper.containsNonWhitespace(description)) { description = "  "; // show a link even if empty } descriptionBtn = uifactory.addFormLink("descriptionBtn", description, null, formLayout, Link.NONTRANSLATED); descriptionBtn.setIconLeftCSS("o_icon o_icon_inline_editable"); } // if in artefactChooseMode, add an "choose this" button if(artefactChooseMode) { chooseBtn = uifactory.addFormLink("choose.artefact", formLayout, Link.BUTTON); chooseBtn.addActionListener(FormEvent.ONCLICK); } flc.contextPut("artefact", artefact); setArtAttribConfig(artAttribConfig); } protected void setArtAttribConfig(Map<String, Boolean> attribConfig) { flc.contextRemove("artAttribConfig"); flc.contextPut("artAttribConfig", attribConfig); } private void doOpenLinkToMap(UserRequest ureq, OLATResource mapResource) { String businessPath = "[" + mapResource.getResourceableTypeName() + ":" + mapResource.getResourceableId() + "]"; NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); } private String createLinkToArtefactSource(UserRequest ureq, String businessPath){ BusinessControlFactory bCF = BusinessControlFactory.getInstance(); List<ContextEntry> ceList = bCF.createCEListFromString(businessPath); boolean valid = (ceList.size() > 0) && NewControllerFactory.getInstance().validateCEWithContextControllerCreator(ureq, getWindowControl(), ceList.get(0)); String busLink = bCF.getAsURIString(ceList, true); if (valid && StringHelper.containsNonWhitespace(busLink)){ return "<a href=\"" + busLink + "\">" + translate("artefact.open.source") + "</a>"; } else return translate("artefact.no.source"); } /** * @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); if (source == deleteBtn) { String text = translate("delete.artefact.text", StringHelper.escapeHtml(artefact.getTitle())); delYesNoDialog = activateYesNoDialog(ureq, translate("delete.artefact"), text, delYesNoDialog); } else if (source == chooseBtn){ fireEvent(ureq, new EPArtefactChoosenEvent(artefact)); } else if (source == detailsLink) { popupArtefact(ureq); } else if (source == reflexionBtn) { popupReflexionCallout(ureq); } else if (source == descriptionBtn){ popupDescriptionCallout(ureq); } else if(source == tblE){ List<String> actualTags = tblE.getValueList(); ePFMgr.setArtefactTags(getIdentity(), artefact, actualTags); } else if(source instanceof FormLink) { FormLink link = (FormLink)source; if("map".equals(link.getCmd())) { OLATResource map = (OLATResource)link.getUserObject(); doOpenLinkToMap(ureq, map); } } } private void popupDescriptionCallout(UserRequest ureq) { descriptionCtrl = new EPCollectStepForm00(ureq, getWindowControl(), artefact); listenTo(descriptionCtrl); instantiateCalloutController(ureq, descriptionCtrl.getInitialComponent(), descriptionBtn); } private void popupReflexionCallout(UserRequest ureq) { reflexionCtrl = new EPCollectStepForm03(ureq, getWindowControl(), artefact); listenTo(reflexionCtrl); instantiateCalloutController(ureq, reflexionCtrl.getInitialComponent(), reflexionBtn); } /** * re-use the same callout-controller, as there can be only one anyway * @param ureq * @param content * @param button */ private void instantiateCalloutController(UserRequest ureq, Component content, FormLink button){ removeAsListenerAndDispose(calloutCtrl); calloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), content, button, artefact.getTitle(), true, null); listenTo(calloutCtrl); calloutCtrl.activate(); } protected void popupArtefact(UserRequest ureq) { String boxTitle = translate("view.artefact.header"); artefactBox = EPUIFactory.getAndActivatePopupArtefactController(artefact, ureq, getWindowControl(), boxTitle); listenTo(artefactBox); } /** * @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) */ @Override protected void event(UserRequest ureq, Controller source, Event event) { super.event(ureq, source, event); if (source == delYesNoDialog) { if (DialogBoxUIFactory.isYesEvent(event)) { ePFMgr.deleteArtefact(artefact); flc.setVisible(false); fireEvent(ureq, new EPArtefactDeletedEvent(artefact)); ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapPortfolioOres(artefact)); ThreadLocalUserActivityLogger.log(EPLoggingAction.EPORTFOLIO_ARTEFACT_REMOVED, getClass()); } } else if (source == reflexionCtrl && event instanceof EPReflexionChangeEvent){ EPReflexionChangeEvent refEv = (EPReflexionChangeEvent) event; artefact.setReflexion(refEv.getReflexion()); ePFMgr.updateArtefact(artefact); calloutCtrl.deactivate(); closeCalloutController(); initForm(ureq); } else if (source == calloutCtrl){ closeCalloutController(); } else if (source == descriptionCtrl) { ePFMgr.updateArtefact(artefact); calloutCtrl.deactivate(); closeCalloutController(); initForm(ureq); } } private void closeCalloutController(){ removeAsListenerAndDispose(calloutCtrl); calloutCtrl = null; } /** * @see org.olat.core.gui.components.form.flexible.impl.FormBasicController#formOK(org.olat.core.gui.UserRequest) */ @Override protected void formOK(UserRequest ureq) { String newTitle = title.getValue(); artefact.setTitle(newTitle); ePFMgr.updateArtefact(artefact); initForm(ureq); } /** * @see org.olat.core.gui.control.DefaultController#doDispose() */ @Override protected void doDispose() { // nothing to dispose } }