/** * 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.editor; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.olat.core.CoreSpringFactory; 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.FormLink; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.impl.Form; 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.velocity.VelocityContainer; 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.gui.control.generic.wizard.BasicStep; import org.olat.core.gui.control.generic.wizard.PrevNextFinishConfig; import org.olat.core.gui.control.generic.wizard.Step; import org.olat.core.gui.control.generic.wizard.StepFormBasicController; import org.olat.core.gui.control.generic.wizard.StepFormController; import org.olat.core.gui.control.generic.wizard.StepsEvent; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.id.OLATResourceable; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.course.nodes.CourseNode; import org.olat.course.properties.CoursePropertyManager; import org.olat.course.run.environment.CourseEnvironment; import org.olat.properties.Property; import org.olat.repository.CatalogEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.manager.CatalogManager; import org.olat.repository.ui.catalog.CatalogEntryAddController; /** * * Description:<br> * Step to set the course in the catalog * * <P> * Initial Date: 16 mars 2011 <br> * @author srosse, stephane.rosse@frentix.com, http://wwww.frentix.com */ class PublishStepCatalog extends BasicStep { private final PrevNextFinishConfig prevNextConfig; private final CourseEnvironment courseEnv; private final CourseNode rootNode; public PublishStepCatalog(UserRequest ureq, ICourse course, boolean hasPublishableChanges) { super(ureq); this.courseEnv = course.getCourseEnvironment(); this.rootNode = course.getRunStructure().getRootNode(); setI18nTitleAndDescr("publish.catalog.header", null); if(hasPublishableChanges) { setNextStep(new PublishStep00a(ureq)); prevNextConfig = PrevNextFinishConfig.BACK_NEXT_FINISH; } else { setNextStep(Step.NOSTEP); prevNextConfig = PrevNextFinishConfig.BACK_FINISH; } } @Override public PrevNextFinishConfig getInitialPrevNextFinishConfig() { return prevNextConfig; } @Override public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext stepsRunContext, Form form) { return new PublishStepCatalogForm(ureq, wControl, form, stepsRunContext, courseEnv, rootNode); } static class PublishStepCatalogForm extends StepFormBasicController { private FormLink addToCatalog; private SingleSelection catalogBox; private CloseableModalController cmc; private Controller catalogAddController; private final List<FormLink> deleteLinks = new ArrayList<FormLink>();; private final RepositoryEntry repositoryEntry; private final CatalogManager catalogManager; private final CourseEnvironment courseEnv; private final CourseNode rootNode; public PublishStepCatalogForm(UserRequest ureq, WindowControl control, Form rootForm, StepsRunContext runContext, CourseEnvironment courseEnv, CourseNode rootNode) { super(ureq, control, rootForm, runContext, LAYOUT_CUSTOM, "publish_catalog"); OLATResourceable ores = OresHelper.createOLATResourceableInstance(CourseModule.class, courseEnv.getCourseResourceableId()); repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, true); catalogManager = CoreSpringFactory.getImpl(CatalogManager.class); this.courseEnv = courseEnv; this.rootNode = rootNode; initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { CoursePropertyManager cpm = courseEnv.getCoursePropertyManager(); Property prop = cpm.findCourseNodeProperty(rootNode, null, null, "catalog-choice"); String value = prop == null ? null : prop.getStringValue(); List<CatalogEntry> catalogEntries = catalogManager.getCatalogCategoriesFor(repositoryEntry); if("no".equals(value) && !catalogEntries.isEmpty()) { value = "yes"; } FormItemContainer fc = FormLayoutContainer.createDefaultFormLayout("catalogSettings", getTranslator()); fc.setRootForm(mainForm); formLayout.add("catalogSettings", fc); final String[] keys = new String[]{"yes","no"}; final String[] values = new String[] { translate("yes"), translate("no") }; catalogBox = uifactory.addDropdownSingleselect("catalogBox", "publish.catalog.box", fc, keys, values, null); catalogBox.addActionListener(FormEvent.ONCHANGE); if(!StringHelper.containsNonWhitespace(value)) { value = "yes"; } catalogBox.select(value, true); flc.contextPut("choice", value); boolean activate = "yes".equals(value); addToCatalog = uifactory.addFormLink("publish.catalog.add", flc, Link.BUTTON_SMALL); addToCatalog.setElementCssClass("o_sel_publish_add_to_catalog"); addToCatalog.setVisible(activate); for(CatalogEntry entry:catalogEntries) { CategoryLabel label = new CategoryLabel(entry, entry.getParent(), getPath(entry)); FormLink link = uifactory.addFormLink(label.getCategoryUUID(), "delete", null, flc, Link.LINK); link.setUserObject(label); deleteLinks.add(link); } flc.contextPut("categories", deleteLinks); } private String getPath(CatalogEntry entry) { String path = ""; CatalogEntry tempEntry = entry; while (tempEntry != null) { path = "/" + tempEntry.getName() + path; tempEntry = tempEntry.getParent(); } return path; } private void deleteCategory(CategoryLabel category) { for(FormLink deleteLink:deleteLinks) { CategoryLabel label = (CategoryLabel)deleteLink.getUserObject(); if(category.equals(label)) { label.setDeleted(true); deleteLink.setVisible(false); flc.setDirty(true); } } } private void doAddCatalog(UserRequest ureq) { List<CategoryLabel> categories = new ArrayList<CategoryLabel>(); for(FormLink deleteLink:deleteLinks) { CategoryLabel label = (CategoryLabel)deleteLink.getUserObject(); categories.add(label); } removeAsListenerAndDispose(catalogAddController); catalogAddController = new SpecialCatalogEntryAddController(ureq, getWindowControl(), repositoryEntry, categories); listenTo(catalogAddController); removeAsListenerAndDispose(cmc); cmc = new CloseableModalController(getWindowControl(), "close", catalogAddController.getInitialComponent(), true, translate("publish.catalog.add")); listenTo(cmc); cmc.activate(); } @Override protected void doDispose() { // } @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; catalogBox.clearError(); if(catalogBox.isOneSelected() && catalogBox.isSelected(0) && isDeleteLinksEmpty()) { catalogBox.setErrorKey("publish.catalog.error", null); allOk &= false; } return allOk && super.validateFormLogic(ureq); } /** * Show if there is active delete links (which is the same has having active categories) * @return */ private boolean isDeleteLinksEmpty() { if(deleteLinks == null || deleteLinks.isEmpty()) return true; boolean visible = false; for(FormLink deleteLink:deleteLinks) { visible |= deleteLink.isVisible(); } return !visible; } @Override protected void event(UserRequest ureq, Controller source, Event event) { if(source == cmc) { removeAsListenerAndDispose(catalogAddController); removeAsListenerAndDispose(cmc); catalogAddController = null; cmc = null; } else if (catalogAddController == source) { if(event instanceof AddToCategoryEvent) { AddToCategoryEvent e = (AddToCategoryEvent)event; CatalogEntry category = e.getCategory(); CatalogEntry parentCategory = e.getParentCategory(); CategoryLabel label = new CategoryLabel(category, parentCategory, getPath(parentCategory)); FormLink link = uifactory.addFormLink(label.getCategoryUUID(), "delete", null, flc, Link.LINK); link.setUserObject(label); deleteLinks.add(link); catalogBox.clearError(); closeAddCatalog(); } else if (event instanceof UndoCategoryEvent) { UndoCategoryEvent e = (UndoCategoryEvent)event; CategoryLabel undelete = e.getUndelete(); for(FormLink deleteLink:deleteLinks) { CategoryLabel label = (CategoryLabel)deleteLink.getUserObject(); if(label.equals(undelete)) { label.setDeleted(false); deleteLink.setVisible(true); break; } } closeAddCatalog(); } else if (event == Event.CANCELLED_EVENT) { closeAddCatalog(); } } else { super.event(ureq, source, event); } } private void closeAddCatalog() { if(cmc != null) cmc.deactivate(); removeAsListenerAndDispose(catalogAddController); removeAsListenerAndDispose(cmc); catalogAddController = null; cmc = null; } @Override protected void formOK(UserRequest ureq) { if(catalogBox.isOneSelected()) { String val = catalogBox.getSelectedKey(); addToRunContext("catalogChoice", val); List<CategoryLabel> categories = new ArrayList<CategoryLabel>(); for(FormLink deletedLink:deleteLinks) { CategoryLabel cat = (CategoryLabel)deletedLink.getUserObject(); categories.add(cat); } addToRunContext("categories", categories); } fireEvent(ureq, StepsEvent.ACTIVATE_NEXT); } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(catalogBox == source) { //updateCategories(); catalogBox.clearError(); if(catalogBox.isOneSelected() && catalogBox.isSelected(0)) { addToCatalog.setVisible(true); flc.contextPut("choice", "yes"); if(deleteLinks == null || deleteLinks.isEmpty()) { doAddCatalog(ureq); } } else { addToCatalog.setVisible(false); flc.contextPut("choice", "no"); } } else if (source == addToCatalog) { doAddCatalog(ureq); } else if (deleteLinks.contains(source)) { CategoryLabel label = (CategoryLabel)source.getUserObject(); deleteCategory(label); //do by delete updateCategories(); } else { super.formInnerEvent(ureq, source, event); } } } public static class SpecialCatalogEntryAddController extends CatalogEntryAddController { private final RepositoryEntry toBeAddedEntry; private final List<CategoryLabel> categories; public SpecialCatalogEntryAddController(UserRequest ureq, WindowControl wControl, RepositoryEntry toBeAddedEntry, List<CategoryLabel> categories) { super(ureq, wControl, toBeAddedEntry, true, false); this.toBeAddedEntry = toBeAddedEntry; this.categories = categories; } @Override protected VelocityContainer createVelocityContainer(String page) { setTranslator(Util.createPackageTranslator(CatalogEntryAddController.class, getLocale())); velocity_root = Util.getPackageVelocityRoot(CatalogEntryAddController.class); return super.createVelocityContainer(page); } @Override protected void insertNode(UserRequest ureq, Long newParentId) { CatalogManager cm = CoreSpringFactory.getImpl(CatalogManager.class); CatalogEntry newParent = cm.loadCatalogEntry(newParentId); // check first if this repo entry is already attached to this new parent for (CategoryLabel label:categories) { CatalogEntry category = label.getCategory(); if(category.getKey() == null) { category = label.getParentCategory(); } if(category.equalsByPersistableKey(newParent)) { if(label.isDeleted()) { fireEvent(ureq, new UndoCategoryEvent(label)); } else { showError("catalog.tree.add.already.exists", toBeAddedEntry.getDisplayname()); } return; } } CatalogEntry newEntry = cm.createCatalogEntry(); newEntry.setRepositoryEntry(toBeAddedEntry); newEntry.setName(toBeAddedEntry.getDisplayname()); newEntry.setDescription(toBeAddedEntry.getDescription()); newEntry.setType(CatalogEntry.TYPE_LEAF); newEntry.setParent(newParent); fireEvent(ureq, new AddToCategoryEvent(newEntry, newParent)); } } public static class UndoCategoryEvent extends Event { private static final long serialVersionUID = 1086895594328098215L; private final CategoryLabel undelete; public UndoCategoryEvent(CategoryLabel undelete) { super("undelete"); this.undelete = undelete; } public CategoryLabel getUndelete() { return undelete; } } public static class AddToCategoryEvent extends Event { private static final long serialVersionUID = -5188729058364093274L; private final CatalogEntry category; private final CatalogEntry parentCategory; public AddToCategoryEvent(CatalogEntry category, CatalogEntry parentCategory) { super("add-to-catalog"); this.category = category; this.parentCategory = parentCategory; } public CatalogEntry getCategory() { return category; } public CatalogEntry getParentCategory() { return parentCategory; } } public static class CategoryLabel { private final CatalogEntry category; private final CatalogEntry parentCategory; private final String path; private final String uuid; private boolean deleted = false; public CategoryLabel(CatalogEntry category, CatalogEntry parentCategory, String path) { this.category = category; this.parentCategory = parentCategory; this.path = path; uuid = UUID.randomUUID().toString().replace("-", ""); } public String getCategoryUUID() { return uuid; } public String getPath() { return path; } public CatalogEntry getCategory() { return category; } public CatalogEntry getParentCategory() { return parentCategory; } public boolean isDeleted() { return deleted; } public void setDeleted(boolean deleted) { this.deleted = deleted; } @Override public int hashCode() { return uuid.hashCode(); } @Override public boolean equals(Object obj) { if(this == obj) { return true; } if (obj instanceof CategoryLabel) { CategoryLabel label = (CategoryLabel)obj; return uuid.equals(label.uuid); } return false; } } }