Package org.olat.course.nodes

Source Code of org.olat.course.nodes.GenericCourseNode

/**
* 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.
* <p>
*/

package org.olat.course.nodes;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.olat.core.gui.UserRequest;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.messages.MessageUIFactory;
import org.olat.core.gui.control.generic.tabbable.TabbableController;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.nodes.GenericNode;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.course.ICourse;
import org.olat.course.condition.Condition;
import org.olat.course.condition.interpreter.ConditionErrorMessage;
import org.olat.course.condition.interpreter.ConditionExpression;
import org.olat.course.condition.interpreter.ConditionInterpreter;
import org.olat.course.editor.CourseEditorEnv;
import org.olat.course.editor.NodeConfigFormController;
import org.olat.course.editor.StatusDescription;
import org.olat.course.run.navigation.NodeRunConstructionResult;
import org.olat.course.run.userview.NodeEvaluation;
import org.olat.course.run.userview.TreeEvaluation;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.modules.ModuleConfiguration;

/**
* Description:<br>
* @author Felix Jost
* @author BPS (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
*/
public abstract class GenericCourseNode extends GenericNode implements CourseNode {
  private String type, shortTitle, longTitle, learningObjectives, displayOption;
  private ModuleConfiguration moduleConfiguration;
  private String noAccessExplanation;
  private Condition preConditionVisibility;
  private Condition preConditionAccess;
  protected transient StatusDescription[] oneClickStatusCache = null;

  /**
   * Generic course node constructor
   *
   * @param type The course node type
   *     
   *      ATTENTION:
   *      all course nodes must call updateModuleConfigDefaults(true) here
   */
  public GenericCourseNode(String type) {
    super();
    this.type = type;
    moduleConfiguration = new ModuleConfiguration();
  }

  /**
   * @see org.olat.course.nodes.CourseNode#createEditController(org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.control.WindowControl, org.olat.course.ICourse)
   *     
   *      ATTENTION:
   *      all course nodes must call updateModuleConfigDefaults(false) here
   */
  public abstract TabbableController createEditController(UserRequest ureq, WindowControl wControl, ICourse course,
      UserCourseEnvironment euce);

  /**
   * @see org.olat.course.nodes.CourseNode#createNodeRunConstructionResult(org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.control.WindowControl,
   *      org.olat.course.run.userview.UserCourseEnvironment,
   *      org.olat.course.run.userview.NodeEvaluation)
   *     
   *      ATTENTION:
   *      all course nodes must call updateModuleConfigDefaults(false) here
   */
  public abstract NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl,
      UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd);
 
  protected String getDefaultTitleOption() {
    return CourseNode.DISPLAY_OPTS_TITLE_DESCRIPTION_CONTENT;
  }

  /**
   * Default implementation of the peekview controller that returns NULL: no
   * node specific peekview information should be shown<br>
   * Override this method with a specific implementation if you have
   * something interesting to show in the peekview
   *
   * @see org.olat.course.nodes.CourseNode#createPeekViewRunController(org.olat.core.gui.UserRequest,
   *      org.olat.course.run.userview.UserCourseEnvironment,
   *      org.olat.course.run.userview.NodeEvaluation)
   */
  public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv,
      NodeEvaluation ne) {
    return null;
  }
 
  /**
   * default implementation of the previewController
   *
   * @see org.olat.course.nodes.CourseNode#createPreviewController(org.olat.core.gui.UserRequest,
   * @see org.olat.core.gui.control.WindowControl,
   * @see org.olat.course.run.userview.UserCourseEnvironment,
   * @see org.olat.course.run.userview.NodeEvaluation)
   */
  @SuppressWarnings("unused")//no userCourseEnv or NodeEvaluation needed here
  public Controller createPreviewController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
    Translator translator = Util.createPackageTranslator(GenericCourseNode.class, ureq.getLocale());
    String text = translator.translate("preview.notavailable");
    return MessageUIFactory.createInfoMessage(ureq, wControl, null, text);
  }

  /**
   * @return String
   */
  public String getLearningObjectives() {
    return learningObjectives;
  }

  /**
   * @return String
   */
  public String getLongTitle() {
    return longTitle;
  }

  /**
   * @return String
   */
  public String getShortTitle() {
    return shortTitle;
  }
 
  /**
   * allows to specify if default value should be returned in case where there is no value.
   * @param returnDefault if false: null may be returned if no value found!
   * @return String
   */
  public String getDisplayOption(boolean returnDefault) {
    if(!StringHelper.containsNonWhitespace(displayOption) && returnDefault) {
      return getDefaultTitleOption();
    }
    return displayOption;
  }
 
  /**
   * @return String with the old behavior (default value if none existing)
   */
  public String getDisplayOption() {
    return getDisplayOption(true);   
  }

  /**
   * @return String
   */
  public String getType() {
    return type;
  }

  /**
   * Sets the learningObjectives.
   *
   * @param learningObjectives The learningObjectives to set
   */
  public void setLearningObjectives(String learningObjectives) {
    this.learningObjectives = learningObjectives;
  }

  /**
   * Sets the longTitle.
   *
   * @param longTitle The longTitle to set
   */
  public void setLongTitle(String longTitle) {
    this.longTitle = longTitle;
  }

  /**
   * Sets the shortTitle.
   *
   * @param shortTitle The shortTitle to set
   */
  public void setShortTitle(String shortTitle) {
    this.shortTitle = shortTitle;
  }
 
  /**
   * Sets the display option
   * @param displayOption
   */
  public void setDisplayOption(String displayOption) {
    this.displayOption = displayOption;
  }

  /**
   * Sets the type.
   *
   * @param type The type to set
   */
  public void setType(String type) {
    this.type = type;
  }

  /**
   * @return ModuleConfiguration
   */
  public ModuleConfiguration getModuleConfiguration() {
    return moduleConfiguration;
  }

  /**
   * Sets the moduleConfiguration.
   *
   * @param moduleConfiguration The moduleConfiguration to set
   */
  public void setModuleConfiguration(ModuleConfiguration moduleConfiguration) {
    this.moduleConfiguration = moduleConfiguration;
  }

  /**
   * @see org.olat.course.nodes.CourseNode#eval(org.olat.course.condition.interpreter.ConditionInterpreter,
   *      org.olat.course.run.userview.TreeEvaluation)
   */
  public NodeEvaluation eval(ConditionInterpreter ci, TreeEvaluation treeEval) {
    // each CourseNodeImplementation has the full control over all children
    // eval.
    // default behaviour is to eval all visible children
    NodeEvaluation nodeEval = new NodeEvaluation(this);
    calcAccessAndVisibility(ci, nodeEval);
    nodeEval.build();
    treeEval.cacheCourseToTreeNode(this, nodeEval.getTreeNode());
    // only add children (coursenodes/nodeeval) when I am visible and
    // atleastOneAccessible myself
    if (nodeEval.isVisible() && nodeEval.isAtLeastOneAccessible()) {
      int childcnt = getChildCount();
      for (int i = 0; i < childcnt; i++) {
        CourseNode cn = (CourseNode) this.getChildAt(i);
        NodeEvaluation chdEval = cn.eval(ci, treeEval);
        if (chdEval.isVisible()) { // child is visible
          nodeEval.addNodeEvaluationChild(chdEval);
        }
      }
    }
    return nodeEval;
  }

  /**
   * @param ci the ConditionInterpreter as the calculating machine
   * @param nodeEval the object to write the results into
   */
  protected abstract void calcAccessAndVisibility(ConditionInterpreter ci, NodeEvaluation nodeEval);

  /**
   * @return String
   */
  public String getNoAccessExplanation() {
    return noAccessExplanation;
  }

  /**
   * Sets the noAccessExplanation.
   *
   * @param noAccessExplanation The noAccessExplanation to set
   */
  public void setNoAccessExplanation(String noAccessExplanation) {
    this.noAccessExplanation = noAccessExplanation;
  }

  /**
   * @return Condition
   */
  public Condition getPreConditionVisibility() {
    if (preConditionVisibility == null) {
      preConditionVisibility = new Condition();
    }
    preConditionVisibility.setConditionId("visibility");
    return preConditionVisibility;
  }

  /**
   * Sets the preConditionVisibility.
   *
   * @param preConditionVisibility The preConditionVisibility to set
   */
  public void setPreConditionVisibility(Condition preConditionVisibility) {
    if (preConditionVisibility == null) {
      preConditionVisibility = getPreConditionVisibility();
    }
    this.preConditionVisibility = preConditionVisibility;
    this.preConditionVisibility.setConditionId("visibility");
  }

  /**
   * @return Condition
   */
  public Condition getPreConditionAccess() {
    if (preConditionAccess == null) {
      preConditionAccess = new Condition();
    }
    preConditionAccess.setConditionId("visibility");
    return preConditionAccess;
  }

  /**
   * Generic interface implementation. May be overriden by specific node's
   * implementation.
   *
   * @see org.olat.course.nodes.CourseNode#informOnDelete(org.olat.core.gui.UserRequest,
   *      org.olat.course.ICourse)
   */
  public String informOnDelete(Locale locale, ICourse course) {
    return null;
  }

  /**
   * Generic interface implementation. May be overriden by specific node's
   * implementation.
   *
   * @see org.olat.course.nodes.CourseNode#cleanupOnDelete(org.olat.course.ICourse)
   */
  public void cleanupOnDelete(ICourse course) {
  /**
   * do nothing in default implementation
   */
  }

  /**
   * Generic interface implementation. May be overriden by specific node's
   * implementation.
   *
   * @see org.olat.course.nodes.CourseNode#archiveNodeData(java.util.Locale,
   *      org.olat.course.ICourse, java.io.File)
   */
  @SuppressWarnings("unused")//implemented by specialized node
  public void archiveNodeData(Locale locale, ICourse course, File exportDirectory, String charset) {
  // nothing to do in default implementation
  }

  /**
   * @see org.olat.course.nodes.CourseNode#exportNode(java.io.File,
   *      org.olat.course.ICourse)
   */
  @SuppressWarnings("unused")//implemented by specialized node
  public void exportNode(File exportDirectory, ICourse course) {
  // nothing to do in default implementation
  }

  /**
   * @see org.olat.course.nodes.CourseNode#importNode(java.io.File,
   *      org.olat.course.ICourse, org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.control.WindowControl)
   */
  @SuppressWarnings("unused")//implemented by specialized node
  public Controller importNode(File importDirectory, ICourse course, boolean unattendedImport, UserRequest ureq, WindowControl wControl) {
    // nothing to do in default implementation
    return null;
  }

  /**
   * @see org.olat.core.gui.ShortName#getShortName()
   */
  public String getShortName() {
    return getShortTitle();
  }
 
  /**
   * @see org.olat.course.nodes.CourseNode#createInstanceForCopy()
   */
  public CourseNode createInstanceForCopy() {
    return createInstanceForCopy(true);
  }
 
  public CourseNode createInstanceForCopy(boolean isNewTitle) {
    CourseNode copyInstance = (CourseNode) XStreamHelper.xstreamClone(this);
    copyInstance.setIdent(String.valueOf(CodeHelper.getForeverUniqueID()));
    copyInstance.setPreConditionVisibility(null);
    if (isNewTitle) {
      // FIXME:pb:ms translation for COPY OF
      String newTitle = "Copy of " + getShortTitle();
      if (newTitle.length() > NodeConfigFormController.SHORT_TITLE_MAX_LENGTH) newTitle = newTitle.substring(0,
          NodeConfigFormController.SHORT_TITLE_MAX_LENGTH - 1);
      copyInstance.setShortTitle(newTitle);
    }
    return copyInstance;
  }

  /**
   * @see java.lang.Object#toString()
   */
  public String toString() {
    return "Id: " + getIdent() + ", '" + getShortTitle() + "' " + super.toString();
  }

  /**
   * @see org.olat.course.nodes.CourseNode#getConditionExpressions()
   */
  public List<ConditionExpression> getConditionExpressions() {
    ArrayList<ConditionExpression> retVal = new ArrayList<ConditionExpression>();
    String coS = getPreConditionVisibility().getConditionExpression();
    if (coS != null && !coS.equals("")) {
      // an active condition is defined
      ConditionExpression ce = new ConditionExpression(getPreConditionVisibility().getConditionId());
      ce.setExpressionString(getPreConditionVisibility().getConditionExpression());
      retVal.add(ce);
    }
    //
    return retVal;
  }

  /**
   * must be implemented in the concrete subclasses as a translator is needed
   * for the errormessages which comes with evaluating condition expressions
   *
   * @see org.olat.course.nodes.CourseNode#isConfigValid(org.olat.course.run.userview.UserCourseEnvironment)
   */
  public abstract StatusDescription[] isConfigValid(CourseEditorEnv cev);

  /**
   * @param userCourseEnv
   * @param translatorStr
   * @return
   */
  @SuppressWarnings("static-access")//for StatusDescription.WARNING
  protected List<StatusDescription> isConfigValidWithTranslator(CourseEditorEnv cev, String translatorStr, List<ConditionExpression> condExprs) {
    List<StatusDescription> condExprsStatusDescs = new ArrayList<StatusDescription>();
    // check valid configuration without course environment
    StatusDescription first = isConfigValid();
    // check valid configuration within the course environment
    if (cev == null) {
      // course environment not configured!??
      condExprsStatusDescs.add(first);
      return condExprsStatusDescs;
    }
    /*
     * there is course editor environment, we can check further. Iterate over
     * all conditions of this course node, validate the condition expression and
     * transform the condition error message into a status description
     */
    for (int i = 0; i < condExprs.size(); i++) {
      ConditionExpression ce = condExprs.get(i);
      ConditionErrorMessage[] cems = cev.validateConditionExpression(ce);
      if (cems != null && cems.length > 0) {
        for (int j = 0; j < cems.length; j++) {
          StatusDescription sd = new StatusDescription(StatusDescription.WARNING, cems[j].errorKey, cems[j].solutionMsgKey,
              cems[j].errorKeyParams, translatorStr);
          sd.setDescriptionForUnit(getIdent());
          condExprsStatusDescs.add(sd);
        }
      }
    }
    condExprsStatusDescs.add(first);
    return condExprsStatusDescs;
  }

  /**
   * @see org.olat.course.nodes.CourseNode#explainThisDuringPublish(org.olat.core.gui.control.StatusDescription)
   */
  public StatusDescription explainThisDuringPublish(StatusDescription description) {
    if (description == null) return null;
    StatusDescription retVal = null;
    if (description.getShortDescriptionKey().equals("error.notfound.coursenodeid")) {
      retVal = description.transformTo("error.notfound.coursenodeid.publish", "error.notfound.coursenodeid.publish", null);
    } else if (description.getShortDescriptionKey().equals("error.notfound.name")) {
      retVal = description.transformTo("error.notfound.name.publish", "error.notfound.name.publish", null);
    } else if (description.getShortDescriptionKey().equals("error.notassessable.coursenodid")) {
      retVal = description.transformTo("error.notassessable.coursenodid.publish", "error.notassessable.coursenodid.publish", null);
    } else {
      // throw new OLATRuntimeException("node does not know how to translate <b
      // style='color:red'>" + description.getShortDescriptionKey()
      // + "</b> in publish env", new IllegalArgumentException());
      return description;
    }
    return retVal;
  }

  /**
   * Update the module configuration to have all mandatory configuration flags
   * set to usefull default values
   *
   * @param isNewNode true: an initial configuration is set; false: upgrading
   *          from previous node configuration version, set default to maintain
   *          previous behaviour
   *         
   * This is the workflow:
   * On every click on a entry of the navigation tree, this method will be called
   * to ensure a valid configration of the depending module. This is only done in
   * RAM. If the user clicks on that node in course editor and publishes the course
   * after that, then the updated config will be persisted to disk. Otherwise
   * everything what is done here has to be done once at every course start.
   */
  @SuppressWarnings("unused")//implemented by specialized node
  public void updateModuleConfigDefaults(boolean isNewNode) {
    /**
     *  Do NO updating here, since this method can be overwritten by all classes
     *  implementing this. This is only implemented here to avoid changing all
     *  couseNode classes which do not implement this method.
     */
  }

TOP

Related Classes of org.olat.course.nodes.GenericCourseNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.