/**
* <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.editor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
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.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.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.util.CSSHelper;
import org.olat.core.id.OLATResourceable;
import org.olat.core.util.vfs.MergeSource;
import org.olat.core.util.vfs.NamedContainerImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.filters.VFSItemFilter;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.CourseNodeConfiguration;
import org.olat.course.nodes.CourseNodeFactory;
import org.olat.course.nodes.sp.SPEditController;
import org.olat.course.tree.CourseEditorTreeNode;
import org.olat.modules.ModuleConfiguration;
/**
*
* Description:<br>
* Select elements from the course directory and inject these files
* as single page in the course.
* VCRP-11
*
* <P>
* Initial Date: 21 mars 2011 <br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*/
public class MultiSPController extends FormBasicController {
private FormLink selectAll;
private FormLink deselectAll;
private FormLink sameLevel;
private FormLink asChild;
private MultipleSelectionElement rootSelection;
private final Map<String,MultipleSelectionElement> identToSelectionMap = new HashMap<String,MultipleSelectionElement>();
private final List<MultipleSelectionElement> nodeSelections = new ArrayList<MultipleSelectionElement>();
private int position;
private CourseEditorTreeNode selectedNode;
private final OLATResourceable ores;
private final VFSContainer rootContainer;
public MultiSPController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
OLATResourceable ores, CourseEditorTreeNode selectedNode) {
super(ureq, wControl, "choosesps");
this.ores = ores;
this.selectedNode = selectedNode;
if(rootContainer instanceof MergeSource) {
//we cannot link to files from course elements or groups folders without single page BB update
VFSContainer realContainer = ((MergeSource)rootContainer).getRootWriteContainer();
VFSContainer namedRoot = new NamedContainerImpl(rootContainer.getName(), realContainer);
this.rootContainer = namedRoot;
} else {
this.rootContainer = rootContainer;
}
initForm(ureq);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
setFormDescription("multi.sps.desc");
if(formLayout instanceof FormLayoutContainer) {
FormLayoutContainer layoutContainer = (FormLayoutContainer)formLayout;
rootSelection = initTreeRec(0, rootContainer, layoutContainer);
layoutContainer.contextPut("nodeSelections", nodeSelections);
}
selectAll = uifactory.addFormLink("checkall", "form.checkall", null, formLayout, Link.LINK);
deselectAll = uifactory.addFormLink("uncheckall", "form.uncheckall", null, formLayout, Link.LINK);
FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("ok-cancel", getTranslator());
formLayout.add(buttonLayout);
buttonLayout.setRootForm(mainForm);
if(selectedNode.getParent() != null) {
sameLevel = uifactory.addFormLink("multi.sps.sameLevel", buttonLayout, Link.BUTTON);
}
asChild = uifactory.addFormLink("multi.sps.asChild", buttonLayout, Link.BUTTON);
uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
}
private MultipleSelectionElement initTreeRec(int level, VFSItem item, FormLayoutContainer layoutcont) {
SelectNodeObject node = new SelectNodeObject(item, UUID.randomUUID().toString(), level);
String[] singleKey = new String[]{ node.getId() };
String[] singleValue = new String[]{ node.getName() };
String[] iconCSS = new String[]{ "o_icon o_icon-fw " + node.getIconCssClass() };
MultipleSelectionElement nodeSelection = uifactory.addCheckboxesVertical("print.node.list." + nodeSelections.size(), layoutcont, singleKey, singleValue, iconCSS, 1);
nodeSelection.setLabel("multi.sps.file", null);
nodeSelection.setUserObject(node);
nodeSelection.addActionListener(FormEvent.ONCLICK);
nodeSelections.add(nodeSelection);
identToSelectionMap.put(node.getId(), nodeSelection);
layoutcont.add(nodeSelection.getComponent().getComponentName(), nodeSelection);
if(item instanceof VFSContainer) {
VFSContainer container = (VFSContainer)item;
for(VFSItem subItem:container.getItems(new MultiSPVFSItemFilter())) {
MultipleSelectionElement sel = initTreeRec(level + 1, subItem, layoutcont);
node.getChildren().add(sel);
}
}
return nodeSelection;
}
@Override
protected void doDispose() {
//
}
@Override
protected void formOK(UserRequest ureq) {
//
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(nodeSelections.contains(source)) {
MultipleSelectionElement nodeSelection = (MultipleSelectionElement)source;
if(nodeSelection.isMultiselect()) {
selectRec(nodeSelection, nodeSelection.isSelected(0));
}
} else if (source == selectAll) {
for(MultipleSelectionElement nodeSelection:nodeSelections) {
if(nodeSelection.isMultiselect() && !nodeSelection.isSelected(0)) {
SelectNodeObject treeNode = (SelectNodeObject)nodeSelection.getUserObject();
String id = treeNode.getId();
nodeSelection.select(id, true);
}
}
} else if (source == deselectAll) {
for(MultipleSelectionElement nodeSelection:nodeSelections) {
if(nodeSelection.isMultiselect() && nodeSelection.isSelected(0)) {
SelectNodeObject treeNode = (SelectNodeObject)nodeSelection.getUserObject();
String id = treeNode.getId();
nodeSelection.select(id, false);
}
}
} else if (source == asChild) {
position = -1;
ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId());
create(rootSelection, course, selectedNode.getCourseNode());
fireEvent(ureq, Event.CHANGED_EVENT);
} else if (source == sameLevel) {
ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId());
CourseEditorTreeNode parentNode = (CourseEditorTreeNode)selectedNode.getParent();
position = 0;
for(position = parentNode.getChildCount(); position-->0; ) {
if(selectedNode.getIdent().equals(parentNode.getChildAt(position).getIdent())) {
position++;
break;
}
}
create(rootSelection, course, parentNode.getCourseNode());
fireEvent(ureq, Event.CHANGED_EVENT);
} else {
super.formInnerEvent(ureq, source, event);
}
}
private void create(MultipleSelectionElement selection, ICourse course, CourseNode parentNode) {
SelectNodeObject node = (SelectNodeObject)selection.getUserObject();
if(selection.isMultiselect() && selection.isSelected(0)) {
VFSItem item = node.getItem();
CourseNode newNode = null;
if(item instanceof VFSLeaf) {
//create node
newNode = createCourseNode(item, "sp");
ModuleConfiguration moduleConfig = newNode.getModuleConfiguration();
String path = getRelativePath(item);
moduleConfig.set(SPEditController.CONFIG_KEY_FILE, path);
moduleConfig.setBooleanEntry(SPEditController.CONFIG_KEY_ALLOW_RELATIVE_LINKS, true);
} else if (item instanceof VFSContainer) {
//add structure
newNode = createCourseNode(item, "st");
}
int pos = -1;
if(position >= 0 && selectedNode.getCourseNode().getIdent().equals(parentNode.getIdent())) {
pos = position++;
}
if(pos < 0 || pos >= parentNode.getChildCount()) {
course.getEditorTreeModel().addCourseNode(newNode, parentNode);
} else {
course.getEditorTreeModel().insertCourseNodeAt(newNode, parentNode, pos);
}
if (item instanceof VFSContainer) {
parentNode = newNode;
}
}
//recurse
for(MultipleSelectionElement childElement:node.getChildren()) {
create(childElement, course, parentNode);
}
}
private CourseNode createCourseNode(VFSItem item, String type) {
CourseNodeConfiguration newNodeConfig = CourseNodeFactory.getInstance().getCourseNodeConfiguration(type);
CourseNode newNode = newNodeConfig.getInstance();
newNode.setShortTitle(item.getName());
newNode.setLearningObjectives(item.getName());
newNode.setNoAccessExplanation("You don't have access");
return newNode;
}
private String getRelativePath(VFSItem item) {
String path = "";
while(item != null && !isSameAsRootContainer(item)) {
path = "/" + item.getName() + path;
item = item.getParentContainer();
}
return path;
}
private boolean isSameAsRootContainer(VFSItem item) {
if(item instanceof VFSContainer) {
VFSContainer blocker = rootContainer;
if(blocker instanceof MergeSource) {
blocker = ((MergeSource)blocker).getRootWriteContainer();
}
return blocker.isSame(item);
}
return false;
}
/**
* @param nodeSelection The node that should be selected recursively
* @param select true: select the node and its children; false: deselect the node and its children
*/
private void selectRec(MultipleSelectionElement nodeSelection, boolean select) {
SelectNodeObject userObject = (SelectNodeObject)nodeSelection.getUserObject();
String id = userObject.getId();
if(nodeSelection.isMultiselect()) {
nodeSelection.select(id, select);
}
for(MultipleSelectionElement childSelection:userObject.getChildren()) {
selectRec(childSelection, select);
}
}
public static class SelectNodeObject {
private final int indentation;
private final VFSItem item;
private final String id;
private final List<MultipleSelectionElement> children = new ArrayList<MultipleSelectionElement>();
public SelectNodeObject(VFSItem item, String id, int indentation) {
this.id = id;
this.item = item;
this.indentation = indentation;
}
public String getIndentation() {
return Integer.toString(indentation);
}
public VFSItem getItem() {
return item;
}
public String getName() {
return item.getName();
}
public String getId() {
return id;
}
public List<MultipleSelectionElement> getChildren() {
return children;
}
public String getIconCssClass() {
if(item instanceof VFSContainer) {
return "o_filetype_folder";
}
return CSSHelper.createFiletypeIconCssClassFor(item.getName());
}
}
public static class MultiFileEvents extends Event {
private static final long serialVersionUID = -5564537741338183501L;
private final String currentPath;
private final VFSContainer currentContainer;
private final List<String> selectedFiles;
public MultiFileEvents(VFSContainer currentContainer, String currentPath, List<String> selectedFiles) {
super("multi");
this.currentContainer = currentContainer;
this.currentPath = currentPath;
this.selectedFiles = selectedFiles;
}
public String getCurrentPath() {
return currentPath;
}
public VFSContainer getCurrentContainer() {
return currentContainer;
}
public List<String> getSelectedFiles() {
return selectedFiles;
}
}
public class MultiSPVFSItemFilter implements VFSItemFilter {
@Override
public boolean accept(VFSItem vfsItem) {
String name = vfsItem.getName();
return !name.startsWith(".");
}
}
}