Package org.olat.course.nodes.iq

Source Code of org.olat.course.nodes.iq.IQEditController

/**
* 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.iq;

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

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.olat.basesecurity.Constants;
import org.olat.basesecurity.ManagerFactory;
import org.olat.commons.file.filechooser.FileChooseCreateEditController;
import org.olat.commons.file.filechooser.LinkChooseCreateEditController;
import org.olat.core.commons.fullWebApp.LayoutMain3ColsPreviewController;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.Form;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.link.LinkFactory;
import org.olat.core.gui.components.panel.Panel;
import org.olat.core.gui.components.tabbedpane.TabbedPane;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.ControllerEventListener;
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.tabbable.ActivateableTabbableDefaultController;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.vfs.LocalFileImpl;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.VFSConstants;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSStatus;
import org.olat.course.ICourse;
import org.olat.course.assessment.AssessmentHelper;
import org.olat.course.condition.Condition;
import org.olat.course.condition.ConditionEditController;
import org.olat.course.editor.NodeEditController;
import org.olat.course.groupsandrights.CourseGroupManager;
import org.olat.course.nodes.AbstractAccessableCourseNode;
import org.olat.course.nodes.CourseNodeFactory;
import org.olat.course.nodes.IQSELFCourseNode;
import org.olat.course.nodes.IQSURVCourseNode;
import org.olat.course.nodes.IQTESTCourseNode;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.course.tree.CourseInternalLinkTreeModel;
import org.olat.fileresource.FileResourceManager;
import org.olat.fileresource.types.SurveyFileResource;
import org.olat.fileresource.types.TestFileResource;
import org.olat.ims.qti.QTIResult;
import org.olat.ims.qti.QTIResultManager;
import org.olat.ims.qti.process.AssessmentInstance;
import org.olat.ims.qti.process.QTIHelper;
import org.olat.modules.ModuleConfiguration;
import org.olat.modules.iq.IQManager;
import org.olat.modules.iq.IQPreviewSecurityCallback;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.controllers.ReferencableEntriesSearchController;
import org.olat.repository.handlers.RepositoryHandler;
import org.olat.repository.handlers.RepositoryHandlerFactory;
import org.olat.resource.OLATResource;

/**
* Description:<BR/>
* Edit controller for the qti test, selftest and survey course node
* <P/>
* Initial Date:  Oct 13, 2004
*
* @author Felix Jost
*/
public class IQEditController extends ActivateableTabbableDefaultController implements ControllerEventListener {

  public final String PANE_TAB_IQCONFIG_XXX;
  public static final String PANE_TAB_IQCONFIG_SURV = "pane.tab.iqconfig.surv";
  public static final String PANE_TAB_IQCONFIG_SELF = "pane.tab.iqconfig.self";
  public static final String PANE_TAB_IQCONFIG_TEST = "pane.tab.iqconfig.test";
  public static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility";
  private static final String VC_CHOSENTEST = "chosentest";
  private static final String ACTION_CORRECT ="correcttest";
  /** configuration key: repository sof key reference to qti file*/
  public static final String CONFIG_KEY_REPOSITORY_SOFTKEY = "repoSoftkey";
  /** configuration key: the disclaimer text*/
  public static final String CONFIG_KEY_DISCLAIMER = "disc";
  /** configuration key: enable menu switch*/
  public static final String CONFIG_KEY_ENABLEMENU = "enableMenu";
  /** configuration key: display menu switch*/
  public static final String CONFIG_KEY_DISPLAYMENU = "displayMenu";
  /** configuration key: all questions, section titles only */
  public static final String CONFIG_KEY_RENDERMENUOPTION="renderMenu";
  /** configuration key: enable score progress switch*/
  public static final String CONFIG_KEY_SCOREPROGRESS = "displayScoreProgress";
  /** configuration key: enable cancel switch*/
  public static final String CONFIG_KEY_ENABLECANCEL = "enableCancel";
  /** configuration key: enable suspend switch*/
  public static final String CONFIG_KEY_ENABLESUSPEND = "enableSuspend";
  /** configuration key: enable question progress switch*/
  public static final String CONFIG_KEY_QUESTIONPROGRESS = "displayQuestionProgss";
  /** configuration key: enable question progress switch*/
  public static final String CONFIG_KEY_QUESTIONTITLE = "displayQuestionTitle";
  /** configuration key: question sequence: item or selection */
  public static final String CONFIG_KEY_SEQUENCE = "sequence";
  /** configuration key: mode*/
  public static final String CONFIG_KEY_TYPE = "mode";
  /** configuration key: show summary: compact or detailed */
  public static final String CONFIG_KEY_SUMMARY = "summary";
  /** configuration key: max attempts*/
  public static final String CONFIG_KEY_ATTEMPTS = "attempts";
  /** configuration key: minimal score*/
  public static final String CONFIG_KEY_MINSCORE = "minscore";
  /** configuration key: maximal score*/
  public static final String CONFIG_KEY_MAXSCORE = "maxscore";
  /** configuration key: cut value (socre > cut = passed) */
  public static final String CONFIG_KEY_CUTVALUE = "cutvalue";
  /** configuration key for the filename */
  public static final String CONFIG_KEY_FILE = "file";
  /** configuration key: should relative links like ../otherfolder/my.css be allowed? **/
  public static final String CONFIG_KEY_ALLOW_RELATIVE_LINKS = "allowRelativeLinks";
  /** configuration key: enable 'show score infos' on start page */
  public static final String CONFIG_KEY_ENABLESCOREINFO = "enableScoreInfo";
 
  public static final String CONFIG_KEY_DATE_DEPENDENT_RESULTS = "dateDependentResults";
  public static final String CONFIG_KEY_RESULTS_START_DATE = "resultsStartDate";
  public static final String CONFIG_KEY_RESULTS_END_DATE = "resultsEndDate";
  public static final String CONFIG_KEY_RESULT_ON_FINISH = "showResultsOnFinish";
  public static final String CONFIG_KEY_RESULT_ON_HOME_PAGE = "showResultsOnHomePage";
 
  private OLog log = Tracing.createLoggerFor(IQEditController.class);
  private final String[] paneKeys;

  private ModuleConfiguration moduleConfiguration;
  private Panel main;
  private VelocityContainer myContent;
 
  private IQEditForm modConfigForm; 
  private ReferencableEntriesSearchController searchController;
  private ICourse course;
  private ConditionEditController accessibilityCondContr;
  private AbstractAccessableCourseNode courseNode;
  private String type;
  private UserCourseEnvironment euce;
  private TabbedPane myTabbedPane;
  private FileChooseCreateEditController fccecontr;
  private Controller correctQTIcontroller;
  private Boolean allowRelativeLinks;
  private Link previewLink;
  private Link chooseTestButton;
  private Link changeTestButton;
  private IQEditReplaceWizard replaceWizard;
  private List<Identity> learners;
  private LayoutMain3ColsPreviewController previewLayoutCtr;
  private CloseableModalController cmc;
  private Link editTestButton;

  /**
   * Constructor for the IMS QTI edit controller for a test course node
   *
   * @param ureq The user request
   * @param wControl The window controller
   * @param course The course
   * @param courseNode The test course node
   * @param groupMgr
   * @param euce
   */
  public IQEditController(UserRequest ureq, WindowControl wControl, ICourse course, IQTESTCourseNode courseNode, CourseGroupManager groupMgr, UserCourseEnvironment euce) {
    super(ureq, wControl);
   
    this.moduleConfiguration = courseNode.getModuleConfiguration();
    //o_clusterOk by guido: save to hold reference to course inside editor
    this.course = course;
    this.courseNode = courseNode;
    this.euce = euce;
    this.type = AssessmentInstance.QMD_ENTRY_TYPE_ASSESS;
    this.PANE_TAB_IQCONFIG_XXX = PANE_TAB_IQCONFIG_TEST;
    paneKeys = new String[]{PANE_TAB_IQCONFIG_XXX,PANE_TAB_ACCESSIBILITY};
    // put some default values
    if (moduleConfiguration.get(CONFIG_KEY_ENABLECANCEL) == null)
      moduleConfiguration.set(CONFIG_KEY_ENABLECANCEL, Boolean.FALSE);
    if (moduleConfiguration.get(CONFIG_KEY_ENABLESUSPEND) == null)
      moduleConfiguration.set(CONFIG_KEY_ENABLESUSPEND, Boolean.FALSE);
    if(moduleConfiguration.get(CONFIG_KEY_RENDERMENUOPTION) == null)
      moduleConfiguration.set(CONFIG_KEY_RENDERMENUOPTION, Boolean.FALSE);
   
    init(ureq, groupMgr, wControl);
    myContent.contextPut("repEntryTitle", translate("choosenfile.test"));
    myContent.contextPut("type", this.type);
  }

  /**
   * Constructor for the IMS QTI edit controller for a self-test course node
   *
   * @param ureq The user request
   * @param wControl The window controller
   * @param course The course
   * @param courseNode The self course node
   * @param groupMgr
   * @param euce
   */
  public IQEditController(UserRequest ureq, WindowControl wControl, ICourse course, IQSELFCourseNode courseNode, CourseGroupManager groupMgr, UserCourseEnvironment euce) {
    super(ureq, wControl);
   
    this.moduleConfiguration = courseNode.getModuleConfiguration();
    this.course = course;
    this.courseNode = courseNode;
    this.euce = euce;
    this.type = AssessmentInstance.QMD_ENTRY_TYPE_SELF;
    this.PANE_TAB_IQCONFIG_XXX = PANE_TAB_IQCONFIG_SELF;
    paneKeys = new String[]{PANE_TAB_IQCONFIG_XXX,PANE_TAB_ACCESSIBILITY};
    // put some default values
    if (moduleConfiguration.get(CONFIG_KEY_ENABLECANCEL) == null)
      moduleConfiguration.set(CONFIG_KEY_ENABLECANCEL, Boolean.TRUE);
    if (moduleConfiguration.get(CONFIG_KEY_ENABLESUSPEND) == null)
      moduleConfiguration.set(CONFIG_KEY_ENABLESUSPEND, Boolean.TRUE);

    init(ureq, groupMgr, wControl);
    myContent.contextPut("repEntryTitle", translate("choosenfile.self"));
    myContent.contextPut("type", this.type);
  }

  /**
   * Constructor for the IMS QTI edit controller for a survey course node
   *
   * @param ureq The user request
   * @param wControl The window controller
   * @param course The course
   * @param courseNode The survey course node
   * @param groupMgr
   * @param euce
   */
  public IQEditController(UserRequest ureq, WindowControl wControl, ICourse course, IQSURVCourseNode courseNode, CourseGroupManager groupMgr, UserCourseEnvironment euce) {
    super(ureq, wControl);
   
    this.moduleConfiguration = courseNode.getModuleConfiguration();
    this.course = course;
    this.courseNode = courseNode;
    this.euce = euce;
    this.type = AssessmentInstance.QMD_ENTRY_TYPE_SURVEY;
    this.PANE_TAB_IQCONFIG_XXX = PANE_TAB_IQCONFIG_SURV;
    paneKeys = new String[]{PANE_TAB_IQCONFIG_XXX,PANE_TAB_ACCESSIBILITY};

    // put some default values
    if (moduleConfiguration.get(CONFIG_KEY_SCOREPROGRESS) == null){
      moduleConfiguration.set(CONFIG_KEY_SCOREPROGRESS, Boolean.FALSE);
    }
    if(moduleConfiguration.getBooleanEntry(CONFIG_KEY_ALLOW_RELATIVE_LINKS)==null){
      moduleConfiguration.setBooleanEntry(CONFIG_KEY_ALLOW_RELATIVE_LINKS,false);
    }
   
    init(ureq, groupMgr, wControl);
    myContent.contextPut("repEntryTitle", translate("choosenfile.surv"));
    myContent.contextPut("type", this.type);
    chooseTestButton.setCustomDisplayText(translate("command.createSurvey"));
  }

  private void init(UserRequest ureq, CourseGroupManager groupMgr, WindowControl wControl) {   
    main = new Panel("iqeditpanel");
   
    myContent = this.createVelocityContainer("edit");   
    chooseTestButton = LinkFactory.createButtonSmall("command.chooseRepFile", myContent, this);
    changeTestButton = LinkFactory.createButtonSmall("command.changeRepFile", myContent, this);
    modConfigForm = new IQEditForm("iqeditform", getTranslator(), moduleConfiguration);
    modConfigForm.addListener(this);
    myContent.put("iqeditform",modConfigForm);

    // fetch repository entry
    RepositoryEntry re = null;
    String repoSoftkey = (String) moduleConfiguration.get(CONFIG_KEY_REPOSITORY_SOFTKEY);
    if (repoSoftkey != null) re = getIQReference(moduleConfiguration, false);
    myContent.contextPut(VC_CHOSENTEST, re == null ? translate("no.file.chosen") : re.getDisplayname());
    if (re != null) {
      if (isEditable(ureq.getIdentity(), re)) {
        editTestButton = LinkFactory.createButtonSmall("command.editRepFile", myContent, this);
      }
      myContent.contextPut("dontRenderRepositoryButton", new Boolean(true));
      // Put values to velocity container
      myContent.contextPut(CONFIG_KEY_MINSCORE, moduleConfiguration.get(CONFIG_KEY_MINSCORE));
      myContent.contextPut(CONFIG_KEY_MAXSCORE, moduleConfiguration.get(CONFIG_KEY_MAXSCORE));
      myContent.contextPut(CONFIG_KEY_CUTVALUE, moduleConfiguration.get(CONFIG_KEY_CUTVALUE));
      previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", re.getDisplayname(), Link.NONTRANSLATED, myContent, this);
      previewLink.setCustomEnabledLinkCSS("b_preview");
      previewLink.setTitle(getTranslator().translate("command.preview"));
    }

    String disclaimer = (String) moduleConfiguration.get(CONFIG_KEY_DISCLAIMER);
    //allowRelativeLinks  = courseNode.getModuleConfiguration().getBooleanEntry(CONFIG_KEY_ALLOW_RELATIVE_LINKS);

    String legend = translate("fieldset.chosecreateeditfile");
    String target = "qti";
    allowRelativeLinks  = moduleConfiguration.getBooleanEntry(CONFIG_KEY_ALLOW_RELATIVE_LINKS);
    if(allowRelativeLinks==null){
      allowRelativeLinks=Boolean.FALSE;
    }
    fccecontr = new LinkChooseCreateEditController(ureq, wControl, disclaimer, allowRelativeLinks, course.getCourseFolderContainer(), target, legend, new CourseInternalLinkTreeModel(course.getEditorTreeModel()) );   
    this.listenTo(fccecontr);
   
    Component fcContent = fccecontr.getInitialComponent();
    myContent.put("filechoosecreateedit", fcContent);
   
    Condition accessCondition = courseNode.getPreConditionAccess();
    accessibilityCondContr = new ConditionEditController(ureq, getWindowControl(), groupMgr, accessCondition, "accessabilityConditionForm",
        AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), courseNode),euce);   
    this.listenTo(accessibilityCondContr);

    main.setContent(myContent);
    // not needed for tabbledController: setInitialComponent(main);
  }

  /**
   * @param identity
   * @param repository entry
   * @return
   */
  private boolean isEditable(Identity identity, RepositoryEntry re) {
    return (ManagerFactory.getManager().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_ADMIN)
        || RepositoryManager.getInstance().isOwnerOfRepositoryEntry(identity, re)
        || RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(re, identity));
  }

  /**
   * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
   */
  public void event(UserRequest ureq, Component source, Event event) {
    if (source == modConfigForm) { // config form action
      if (event == Form.EVNT_FORM_CANCELLED) {
        return;
      } else if (event == Form.EVNT_VALIDATION_OK) {
        moduleConfiguration.set(CONFIG_KEY_ENABLEMENU, new Boolean(modConfigForm.isEnableMenu()));
        if (modConfigForm.isEnableMenu()) {
          // user selected sequence
          moduleConfiguration.set(CONFIG_KEY_DISPLAYMENU, Boolean.TRUE); // always display menu
          moduleConfiguration.set(CONFIG_KEY_QUESTIONPROGRESS, Boolean.FALSE); // never display question progress
          moduleConfiguration.set(CONFIG_KEY_RENDERMENUOPTION, Boolean.FALSE);// render sections and questions
        } else {
          // seqauential sequence, take displayMenu and questionProgress from configured values
          moduleConfiguration.set(CONFIG_KEY_DISPLAYMENU, new Boolean(modConfigForm.isDisplayMenu()));
          moduleConfiguration.set(CONFIG_KEY_QUESTIONPROGRESS, new Boolean(modConfigForm.isDisplayQuestionProgress()));
          moduleConfiguration.set(CONFIG_KEY_RENDERMENUOPTION, modConfigForm.isMenuRenderSectionsOnly());
        }
        moduleConfiguration.set(CONFIG_KEY_SEQUENCE, modConfigForm.getSequence());
        moduleConfiguration.set(CONFIG_KEY_ENABLECANCEL, new Boolean(modConfigForm.isEnableCancel()));
        moduleConfiguration.set(CONFIG_KEY_ENABLESUSPEND, new Boolean(modConfigForm.isEnableSuspend()));
        moduleConfiguration.set(CONFIG_KEY_QUESTIONTITLE, new Boolean(modConfigForm.isDisplayQuestionTitle()));
        // Only tests and selftests have summaries and score progress
        if (!type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY)) {
          moduleConfiguration.set(CONFIG_KEY_SUMMARY, modConfigForm.getSummary());
          moduleConfiguration.set(CONFIG_KEY_SCOREPROGRESS, new Boolean(modConfigForm.isDisplayScoreProgress()));
          moduleConfiguration.set(CONFIG_KEY_ENABLESCOREINFO, new Boolean(modConfigForm.isEnableScoreInfo()));
          moduleConfiguration.set(CONFIG_KEY_DATE_DEPENDENT_RESULTS, new Boolean(modConfigForm.isShowResultsDateDependent()));
          moduleConfiguration.set(CONFIG_KEY_RESULTS_START_DATE, modConfigForm.getShowResultsStartDate());
          moduleConfiguration.set(CONFIG_KEY_RESULTS_END_DATE, modConfigForm.getShowResultsEndDate());
          moduleConfiguration.set(CONFIG_KEY_RESULT_ON_FINISH, modConfigForm.isShowResultsAfterFinishTest());
          moduleConfiguration.set(CONFIG_KEY_RESULT_ON_HOME_PAGE, modConfigForm.isShowResultsOnHomePage());
        }
        // Only tests have a limitation on number of attempts
        if (type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS)) {
          moduleConfiguration.set(CONFIG_KEY_ATTEMPTS, modConfigForm.getAttempts());
        }       
       
        fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
        return;
      }
    } else if (source == myContent) {
      if(event.getCommand().equals(ACTION_CORRECT)){
        /* FIXME:pb:remove this elseif code, as the use case "correct" is started from details view only
         * - check if the test is in use at the moment
         * - check if already results exist
         * - check if test is referenced from other courses
         */
        String repoSoftKey = (String)moduleConfiguration.get(CONFIG_KEY_REPOSITORY_SOFTKEY);
        RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(repoSoftKey,false);
        if(re==null){
          //not found
        }else{
          RepositoryHandler typeToEdit = RepositoryHandlerFactory.getInstance().getRepositoryHandler(re);
          OLATResourceable ores = re.getOlatResource();
          correctQTIcontroller = typeToEdit.getEditorController(ores, ureq, this.getWindowControl());
          this.getWindowControl().pushToMainArea(correctQTIcontroller.getInitialComponent());         
          this.listenTo(correctQTIcontroller);
        }
      }
    } else if (source == previewLink){
      // handle preview
      if (previewLayoutCtr != null) previewLayoutCtr.dispose();
      Controller previewController = IQManager.getInstance().createIQDisplayController(moduleConfiguration, new IQPreviewSecurityCallback(), ureq, getWindowControl(), course
          .getResourceableId().longValue(), courseNode.getIdent());
      previewLayoutCtr = new LayoutMain3ColsPreviewController(ureq, getWindowControl(), null, null, previewController.getInitialComponent(), null);
      previewLayoutCtr.addDisposableChildController(previewController);
      previewLayoutCtr.activate();
     
    } else if (source == chooseTestButton){// initiate search controller
      if (type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY)) {
        searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq,
            SurveyFileResource.TYPE_NAME, translate("command.chooseSurvey"));
      } else { // test and selftest use same repository resource type
        searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq,
            TestFileResource.TYPE_NAME, translate("command.chooseTest"));
      }     
      this.listenTo(searchController);
      cmc = new CloseableModalController(getWindowControl(), translate("close"), searchController.getInitialComponent(), true, translate("command.chooseRepFile"));
      cmc.activate();
    }
    else if (source == changeTestButton) {//change associated test
      if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SELF)) {//selftest
        String[] types = new String[]{TestFileResource.TYPE_NAME};
        searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq, types, translate("command.chooseTest"));
        cmc = new CloseableModalController(getWindowControl(), translate("close"), searchController.getInitialComponent());
        this.listenTo(searchController);
      } else if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS) | type.equals(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY)) {//test, survey
        String[] types;
        if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS)) {//test
          types = new String[]{TestFileResource.TYPE_NAME};
        } else {//survey
          types = new String[]{SurveyFileResource.TYPE_NAME};
        }
        RepositoryEntry re = courseNode.getReferencedRepositoryEntry();
        //look if there are PASSED entries in changelog
        //if yes create archive of results and all users can be notified about the changed test configuration
        String repositorySoftKey = (String) courseNode.getModuleConfiguration().get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
        Long repKey = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(repositorySoftKey, true).getKey();
        List<QTIResult> results = QTIResultManager.getInstance().selectResults(course.getResourceableId(), courseNode.getIdent(), repKey, 1);
        // test was passed from an user
        boolean passed = (results != null && results.size() > 0) ? true : false;
        // test was started and not passed
        // it exists partly results for this test
        List<Identity> identitiesWithQtiSerEntry = IQManager.getInstance().getIdentitiesWithQtiSerEntry(course.getResourceableId(), courseNode.getIdent());
        if(passed || identitiesWithQtiSerEntry.size() > 0) {
          learners = new ArrayList<Identity>();
          for(QTIResult result : results) {
            Identity identity = result.getResultSet().getIdentity();
            if(identity != null && !learners.contains(identity)) learners.add(identity);
          }
          // add identities with qti.ser entry
          for (Identity identity : identitiesWithQtiSerEntry) {
            if(!learners.contains(identity)) learners.add(identity);
          }
          replaceWizard = new IQEditReplaceWizard(ureq, getWindowControl(), course, courseNode, types, learners, results, identitiesWithQtiSerEntry.size());
          replaceWizard.addControllerListener(this);
          cmc = new CloseableModalController(getWindowControl(), translate("close"), replaceWizard.getInitialComponent());
        } else {
          if(type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS)) {//test         
            searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq, types, translate("command.chooseTest"));
          } else {//survey
            searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq, types, translate("command.chooseSurvey"));
          }
          this.listenTo(searchController);
          cmc = new CloseableModalController(getWindowControl(), translate("close"), searchController.getInitialComponent());
        }
      }
      cmc.activate();
    }
    else if (source == editTestButton) {
      CourseNodeFactory.getInstance().launchReferencedRepoEntryEditor(ureq, courseNode);
    }
  }
 
  /**
   * @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)
   */
  public void event(UserRequest urequest, Controller source, Event event) {
    if (source.equals(searchController)) {
      if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
        // repository search controller done       
        cmc.deactivate();
        RepositoryEntry re = searchController.getSelectedEntry();
        doIQReference(urequest, re);
      }
    } else if (source == accessibilityCondContr) {
      if (event == Event.CHANGED_EVENT) {
        Condition cond = accessibilityCondContr.getCondition();
        courseNode.setPreConditionAccess(cond);
        fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
      }
    } else if (source == fccecontr) {
      if (event == FileChooseCreateEditController.FILE_CHANGED_EVENT) {
          String chosenFile = fccecontr.getChosenFile();
          if (chosenFile != null){
              moduleConfiguration.set(CONFIG_KEY_DISCLAIMER, fccecontr.getChosenFile());
          }
          else {
              moduleConfiguration.remove(CONFIG_KEY_DISCLAIMER);
          }
        fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
      } else if (event == FileChooseCreateEditController.ALLOW_RELATIVE_LINKS_CHANGED_EVENT) {
        allowRelativeLinks = fccecontr.getAllowRelativeLinks();
        courseNode.getModuleConfiguration().setBooleanEntry(CONFIG_KEY_ALLOW_RELATIVE_LINKS, allowRelativeLinks.booleanValue());
        fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
      }
    } else if (source == correctQTIcontroller){
      if(event == Event.DONE_EVENT){       
        //getWindowControl().pop();       
      }
    } else if (source == replaceWizard) {
      if(event == Event.CANCELLED_EVENT) {
        cmc.deactivate();
      } else if(event == Event.DONE_EVENT) {
        cmc.deactivate();
        String repositorySoftKey = (String) moduleConfiguration.get(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
        Long repKey = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(repositorySoftKey, true).getKey();
        QTIResultManager.getInstance().deleteAllResults(course.getResourceableId(), courseNode.getIdent(), repKey);
        removeIQReference(moduleConfiguration);
        VFSStatus isDeleted = IQManager.getInstance().removeQtiSerFiles(course.getResourceableId(), courseNode.getIdent());
        if (!isDeleted.equals(VFSConstants.YES)) {
          // couldn't removed qtiser files
          log.warn("Couldn't removed course node folder! Course resourceable id: " + course.getResourceableId() + ", Course node ident: " + courseNode.getIdent());
        }
        doIQReference(urequest, replaceWizard.getSelectedRepositoryEntry());
      }
    }
  }
 
  private void doIQReference(UserRequest urequest, RepositoryEntry re) {
    // repository search controller done       
    if (re != null) {
      if (CoordinatorManager.getCoordinator().getLocker().isLocked(re.getOlatResource(), null)) {           
        this.showError("error.entry.locked");
      } else {
        setIQReference(re, moduleConfiguration);
        previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", re.getDisplayname(), Link.NONTRANSLATED, myContent, this);
        previewLink.setCustomEnabledLinkCSS("b_preview");
        previewLink.setTitle(getTranslator().translate("command.preview"));
        myContent.contextPut("dontRenderRepositoryButton", new Boolean(true));
        // If of type test, get min, max, cut - put in module config and push
        // to velocity
        if (type.equals(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS)) {
          updateModuleConfigFromQTIFile(re.getOlatResource());
          // Put values to velocity container
          myContent.contextPut(CONFIG_KEY_MINSCORE, moduleConfiguration.get(CONFIG_KEY_MINSCORE));
          myContent.contextPut(CONFIG_KEY_MAXSCORE, moduleConfiguration.get(CONFIG_KEY_MAXSCORE));
          myContent.contextPut(CONFIG_KEY_CUTVALUE, moduleConfiguration.get(CONFIG_KEY_CUTVALUE));
        }
        if (isEditable(urequest.getIdentity(), re)) {
          editTestButton = LinkFactory.createButtonSmall("command.editRepFile", myContent, this);
        }
        fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
      }
    }
  }

  /**
   * @see org.olat.core.gui.control.generic.tabbable.TabbableDefaultController#addTabs(org.olat.core.gui.components.TabbedPane)
   */
  public void addTabs(TabbedPane tabbedPane) {
    myTabbedPane = tabbedPane;
    tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate("condition.accessibility.title")));
    //PANE_TAB_IQCONFIG_XXX is set during construction time
    tabbedPane.addTab(translate(PANE_TAB_IQCONFIG_XXX), main);
  }

  /**
   * Ge the qti file soft key repository reference
   * @param config
   * @param strict
   * @return RepositoryEntry
   */
  public static RepositoryEntry getIQReference(ModuleConfiguration config, boolean strict) {
    if (config == null) {
      if (strict) throw new AssertException("missing config in IQ");
      else return null;
    }
    String repoSoftkey = (String) config.get(CONFIG_KEY_REPOSITORY_SOFTKEY);
    if (repoSoftkey == null) {
      if (strict) throw new AssertException("invalid config when being asked for references");
      else return null;
    }
    RepositoryManager rm = RepositoryManager.getInstance();
    return rm.lookupRepositoryEntryBySoftkey(repoSoftkey, strict);
  }

  /**
   * Set the referenced repository entry.
   *
   * @param re
   * @param moduleConfiguration
   */
  public static void setIQReference(RepositoryEntry re, ModuleConfiguration moduleConfiguration) {
    moduleConfiguration.set(CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey());
  }
 
  /**
   * Remove the reference to the repository entry.
   *
   * @param moduleConfiguration
   */
  public static void removeIQReference(ModuleConfiguration moduleConfiguration) {
    moduleConfiguration.remove(IQEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
  }

  /**
   * Update the module configuration from the qti file: read min/max/cut values
   * @param res
   */
  public void updateModuleConfigFromQTIFile(OLATResource res) {
    FileResourceManager frm = FileResourceManager.getInstance();
    File unzippedRoot = frm.unzipFileResource(res);
    //with VFS FIXME:pb:c: remove casts to LocalFileImpl and LocalFolderImpl if no longer needed.
    VFSContainer vfsUnzippedRoot = new LocalFolderImpl(unzippedRoot);
    VFSItem vfsQTI = vfsUnzippedRoot.resolve("qti.xml");
    if (vfsQTI==null){
      throw new AssertException("qti file did not exist even it should be guaranteed by repositor check-in "
          + ((LocalFileImpl)vfsQTI).getBasefile().getAbsolutePath());
    }
    //ensures that InputStream is closed in every case.
    Document doc = QTIHelper.getDocument((LocalFileImpl)vfsQTI);
    if(doc == null){
      //error reading qti file (existence check was made before)
      throw new AssertException("qti file could not be read " + ((LocalFileImpl)vfsQTI).getBasefile().getAbsolutePath());
    }
    // Extract min, max and cut value
    Float minValue = null, maxValue = null, cutValue = null;
    Element decvar = (Element) doc.selectSingleNode("questestinterop/assessment/outcomes_processing/outcomes/decvar");
    if (decvar != null) {
      Attribute minval = decvar.attribute("minvalue");
      if (minval != null) {
        String mv = minval.getValue();
        try {
          minValue = new Float(Float.parseFloat(mv));
        } catch (NumberFormatException e1) {
          // if not correct in qti file -> ignore
        }
      }
      Attribute maxval = decvar.attribute("maxvalue");
      if (maxval != null) {
        String mv = maxval.getValue();
        try {
          maxValue = new Float(Float.parseFloat(mv));
        } catch (NumberFormatException e1) {
          // if not correct in qti file -> ignore
        }
      }
      Attribute cutval = decvar.attribute("cutvalue");
      if (cutval != null) {
        String cv = cutval.getValue();
        try {
          cutValue = new Float(Float.parseFloat(cv));
        } catch (NumberFormatException e1) {
          // if not correct in qti file -> ignore
        }
      }
    }
    // Put values to module configuration
    moduleConfiguration.set(CONFIG_KEY_MINSCORE, minValue);
    moduleConfiguration.set(CONFIG_KEY_MAXSCORE, maxValue);
    moduleConfiguration.set(CONFIG_KEY_CUTVALUE, cutValue);
  }

  /**
   * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
   */
  protected void doDispose() {
    //child controllers registered with listenTo() get disposed in BasicController
    if (previewLayoutCtr != null) {
      previewLayoutCtr.dispose();
      previewLayoutCtr = null;
    }
  }
 
  public String[] getPaneKeys() {
    return paneKeys;
  }

  public TabbedPane getTabbedPane() {
    return myTabbedPane;
  }


}
TOP

Related Classes of org.olat.course.nodes.iq.IQEditController

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.