/**
* 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.Iterator;
import java.util.List;
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.StaticTextElement;
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.tree.MenuTreeEvent;
import org.olat.core.gui.components.tree.MenuTreeItem;
import org.olat.core.gui.components.tree.TreeNode;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
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.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.nodes.INode;
import org.olat.course.ICourse;
import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.StatusDescriptionHelper;
import org.olat.course.properties.CoursePropertyManager;
import org.olat.course.tree.CourseEditorTreeModel;
import org.olat.course.tree.PublishTreeModel;
import org.olat.properties.Property;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.manager.CatalogManager;
/**
* Description:<br>
*
* <P>
* Initial Date: 18.01.2008 <br>
*
* @author patrickb
*/
class PublishStep00 extends BasicStep {
private PublishProcess publishProcess;
private OLATResourceable ores;
private final boolean hasCatalog;
private final boolean hasPublishableChanges;
public PublishStep00(UserRequest ureq, CourseEditorTreeModel cetm, ICourse course) {
super(ureq);
this.ores = course;
publishProcess = PublishProcess.getInstance(course, cetm, ureq.getLocale());
CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();
CourseNode rootNode = course.getRunStructure().getRootNode();
Property prop = cpm.findCourseNodeProperty(rootNode, null, null, "catalog-choice");
if(prop == null) {
hasCatalog = false;
} else if("no".equals(prop.getStringValue())) {
hasCatalog = true;
} else {
RepositoryEntry repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, true);
hasCatalog = !CoreSpringFactory.getImpl(CatalogManager.class).getCatalogCategoriesFor(repositoryEntry).isEmpty();
}
hasPublishableChanges = publishProcess.hasPublishableChanges();
setI18nTitleAndDescr("publish.header", null);
// proceed with direct access as next step.
setNextStep(new PublishStep01(ureq, course, hasPublishableChanges, hasCatalog));
}
/**
* @see org.olat.core.gui.control.generic.wizard.Step#getInitialPrevNextFinishConfig()
*/
public PrevNextFinishConfig getInitialPrevNextFinishConfig() {
// in any case allow next or finish
//VCRP-3: add catalog entry in publish wizard
if(hasPublishableChanges || !hasCatalog){
//this means we have possible steps 00a (error messages) and 00b (warning messages)
return PrevNextFinishConfig.NEXT;
}else{
// proceed with direct access as next step.
return PrevNextFinishConfig.NEXT_FINISH;
}
}
/**
* @see org.olat.core.gui.control.generic.wizard.Step#getStepController(org.olat.core.gui.UserRequest,
* org.olat.core.gui.control.WindowControl,
* org.olat.core.gui.control.generic.wizard.StepsRunContext,
* org.olat.core.gui.components.form.flexible.impl.Form)
*/
public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext runContext, Form form) {
RepositoryEntry repoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false);
/*
* first step is to show selection tree for selecting
* prepares all data needed for next step(s)
*/
runContext.put("publishProcess", publishProcess);
//fxdiff VCRP-1,2: access control of resources
if(repoEntry.isMembersOnly()) {
runContext.put("selectedCourseAccess", RepositoryEntry.MEMBERS_ONLY);
} else {
runContext.put("selectedCourseAccess",String.valueOf(repoEntry.getAccess()));
}
return new PublishStep00Form(ureq, wControl, form, publishProcess, runContext);
}
/**
* Description:<br>
* TODO: patrickb Class Description for PublishStep00Form
*
* <P>
* Initial Date: 18.01.2008 <br>
*
* @author patrickb
*/
class PublishStep00Form extends StepFormBasicController {
private PublishProcess publishManager2;
private MenuTreeItem multiSelectTree;
private StatusDescription[] sds;
private List<StatusDescription> updateNotes;
private FormLayoutContainer fic;
private StaticTextElement errorElement;
private FormLink selectAllLink;
private FormLink uncheckallLink;
public PublishStep00Form(UserRequest ureq, WindowControl wControl, Form form, PublishProcess publishManager2, StepsRunContext runContext) {
super(ureq, wControl, form, runContext, LAYOUT_VERTICAL, null);
this.publishManager2 = publishManager2;
initForm(ureq);
}
@Override
protected void doDispose() {
// nothing to dispose
}
@SuppressWarnings("synthetic-access")
@Override
protected boolean validateFormLogic(UserRequest ureq) {
//
// create publish set
// test for errors
// errors are shown as error text for the form
//
boolean createPublishSet = true;
if(containsRunContextKey("publishSetCreatedFor")){
createPublishSet = getFromRunContext("publishSetCreated") != multiSelectTree.getSelectedKeys();
}
if(createPublishSet && publishManager2.hasPublishableChanges()){
//only add selection if changes were possible
List<String> selectedKeys = new ArrayList<>(multiSelectTree.getSelectedKeys());
for(Iterator<String> selectionIt=selectedKeys.iterator(); selectionIt.hasNext(); ) {
String ident = selectionIt.next();
TreeNode node = publishManager2.getPublishTreeModel().getNodeById(ident);
if(!publishManager2.getPublishTreeModel().isSelectable(node)) {
selectionIt.remove();
}
}
List<String> asList = new ArrayList<String>(selectedKeys);
publishManager2.createPublishSetFor(asList);
addToRunContext("publishSetCreatedFor", selectedKeys);
//
PublishSetInformations set = publishProcess.testPublishSet(getLocale());
sds = set.getWarnings();
updateNotes = set.getUpdateInfos();
addToRunContext("updateNotes", updateNotes);
//
boolean isValid = sds.length == 0;
if (isValid) {
// no error and no warnings -> return immediate
return true;
}
//sort status -> first are errors, followed by warnings
sds = StatusDescriptionHelper.sort(sds);
// assemble warnings and errors
String generalErrorTxt = null;
String errorTxt = getTranslator().translate("publish.notpossible.setincomplete");
String warningTxt = getTranslator().translate("publish.withwarnings");
String errors = "<ul>";
int errCnt = 0;
String warnings = "<ul>";
for (int i = 0; i < sds.length; i++) {
StatusDescription description = sds[i];
String nodeId = sds[i].getDescriptionForUnit();
if (nodeId == null) {
// a general error
generalErrorTxt = sds[i].getShortDescription(getLocale());
break;
}
String nodeName = publishProcess.getCourseEditorTreeModel().getCourseNode(nodeId).getShortName();
String isFor = "<b>" + nodeName + "</b><br/>";
if (description.isError()) {
errors += "<li>" + isFor + description.getShortDescription(getLocale()) + "</li>";
errCnt++;
} else if (description.isWarning()) {
warnings += "<li>" + isFor + description.getShortDescription(getLocale()) + "</li>";
}
}
warnings += "</ul>";
errors += "</ul>";
//
errorTxt += "<p/>" + errors;
warningTxt += "<p/>" + warnings;
if (generalErrorTxt != null) {
addToRunContext("STEP00.generalErrorText", generalErrorTxt);
errorElement.setValue(generalErrorTxt);
errorElement.setVisible(true);
return false;
} else if (errCnt > 0) {
addToRunContext("STEP00.errorMessage", errorTxt);
errorElement.setValue(errorTxt);
errorElement.setVisible(true);
return false;
} else /*must be true then if (warCnt > 0)*/ {
addToRunContext("STEP00.warningMessage", warningTxt);
return true;
}
} else {
// no new publish set to be calculated
// check if some error was detected before.
boolean retVal = !containsRunContextKey("STEP00.generalErrorText");
retVal = retVal && !containsRunContextKey("STEP00.erroMessage");
return retVal;
}
}
@Override
protected void formOK(UserRequest ureq) {
addToRunContext("validPublish",Boolean.valueOf(publishManager2.hasPublishableChanges()));
fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
}
@Override
protected void formNOK(UserRequest ureq) {
addToRunContext("validPublish",Boolean.FALSE);
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
if (publishManager2.hasPublishableChanges()) {
//
fic = FormLayoutContainer.createCustomFormLayout("publish", getTranslator(), this.velocity_root + "/publish.html");
formLayout.add(fic);
errorElement = uifactory.addStaticTextElement("errorElement", null, null, fic);//null > no label, null > no value
errorElement.setVisible(false);
//publish treemodel is tree model and INodeFilter at the same time
multiSelectTree = uifactory.addTreeMultiselect("seltree", null, fic, publishManager2.getPublishTreeModel(), this);
multiSelectTree.setFilter(publishManager2.getPublishTreeModel());
multiSelectTree.setRootVisible(false);
multiSelectTree.setMultiSelect(true);
selectableAll();
selectAllLink = uifactory.addFormLink("checkall", fic);
selectAllLink.setElementCssClass("o_sel_course_publish_selectall_cbb");
selectAllLink.addActionListener(FormEvent.ONCLICK);
uncheckallLink = uifactory.addFormLink("uncheckall", fic);
uncheckallLink.setElementCssClass("o_sel_course_publish_deselectall_cbb");
uncheckallLink.addActionListener(FormEvent.ONCLICK);
} else {
// set message container - telling nothing to publish.
formLayout.add(FormLayoutContainer.createCustomFormLayout("nothingtopublish", getTranslator(), this.velocity_root
+ "/nothingtopublish.html"));
}
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if (source == selectAllLink) {
selectableAll();
} else if (source == uncheckallLink) {
deselectRec(publishManager2.getPublishTreeModel().getRootNode());
} else if (source == multiSelectTree) {
if(event instanceof MenuTreeEvent) {
MenuTreeEvent mte = (MenuTreeEvent)event;
TreeNode selectedNode = publishManager2.getPublishTreeModel()
.getNodeById(mte.getIdent());
if(MenuTreeEvent.SELECT.equals(mte.getCommand())) {
selectRec(selectedNode, publishManager2.getPublishTreeModel());
} else if(MenuTreeEvent.DESELECT.equals(mte.getCommand())) {
deselectRec(selectedNode);
}
}
} else {
super.formInnerEvent(ureq, source, event);
}
}
private void selectableAll() {
selectableRec(publishManager2.getPublishTreeModel().getRootNode(), publishManager2.getPublishTreeModel());
}
private void selectableRec(TreeNode node, PublishTreeModel model) {
if(model.isSelectable(node)) {
multiSelectTree.select(node.getIdent(), true);
multiSelectTree.open(node);
}
for(int i=node.getChildCount(); i-->0; ) {
selectableRec((TreeNode)node.getChildAt(i), model);
}
}
private void selectRec(INode node, PublishTreeModel model) {
if(model.isVisible(node)) {
multiSelectTree.select(node.getIdent(), true);
}
for(int i=node.getChildCount(); i-->0; ) {
selectRec(node.getChildAt(i), model);
}
}
private void deselectRec(INode node) {
multiSelectTree.select(node.getIdent(), false);
for(int i=node.getChildCount(); i-->0; ) {
deselectRec(node.getChildAt(i));
}
}
}
}