private void doInsert(UserRequest ureq, TreePosition tp) {
    ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId());

    int insertPos = tp.getChildpos();
    CourseNode selectedNode = getCourseNode(tp.getParentTreeNode());
    CourseEditorTreeNode insertParent =
        course.getEditorTreeModel().getCourseEditorNodeById(selectedNode.getIdent());

    // check if insert position is within the to-be-copied tree
    if (course.getEditorTreeModel().checkIfIsChild(insertParent, moveCopyFrom)) {
      showError("movecopynode.error.overlap");
      fireEvent(ureq, Event.CANCELLED_EVENT);
    } else if (copy) { // do a copy
      // copy subtree and save model
      recursiveCopy(
          moveCopyFrom,
          insertParent,
          insertPos,
          true,
          CourseFactory.getCourseEditSession(ores.getResourceableId()));
      CourseFactory.saveCourseEditorTreeModel(course.getResourceableId());

      ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_COPIED, getClass());
      fireEvent(ureq, Event.DONE_EVENT);
    } else { // move only
      if (insertParent.getIdent().equals(moveCopyFrom.getParent().getIdent())) {
        // same parent, adjust insertPos
        if (insertPos > moveCopyFrom.getPosition()) insertPos--;
      }
      insertParent.insert(moveCopyFrom, insertPos);

      moveCopyFrom.setDirty(true);
      // mark subtree as dirty
      TreeVisitor tv =
          new TreeVisitor(
              new Visitor() {
                @Override
                public void visit(INode node) {
                  CourseEditorTreeNode cetn = (CourseEditorTreeNode) node;
                  cetn.setDirty(true);
                }
              },
              moveCopyFrom,
              true);
      tv.visitAll();
      CourseFactory.saveCourseEditorTreeModel(course.getResourceableId());
      showInfo("movecopynode.info.condmoved");

      ThreadLocalUserActivityLogger.log(CourseLoggingAction.COURSE_EDITOR_NODE_MOVED, getClass());
      fireEvent(ureq, Event.DONE_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);
   }
 }
  public MoveCopySubtreeController(
      UserRequest ureq,
      WindowControl wControl,
      OLATResourceable ores,
      CourseEditorTreeNode moveCopyFrom,
      boolean copy) {
    super(ureq, wControl);
    this.ores = ores;
    this.moveCopyFrom = moveCopyFrom;
    this.copy = copy;

    ICourse course = CourseFactory.getCourseEditSession(ores.getResourceableId());
    addLoggingResourceable(LoggingResourceable.wrap(course));
    addLoggingResourceable(LoggingResourceable.wrap(moveCopyFrom.getCourseNode()));

    insertTree = new MenuTree(null, "copy_node_selection", this);
    insertTree.enableInsertTool(true);
    insertModel = new InsertTreeModel(course.getEditorTreeModel().getRootNode(), moveCopyFrom);
    insertTree.setTreeModel(insertModel);

    VelocityContainer mainVC = createVelocityContainer("moveCopyNode");

    selectButton = LinkFactory.createButton("insertAtSelectedTreepos", mainVC, this);
    selectButton.setCustomEnabledLinkCSS("btn btn-primary");
    selectButton.setCustomDisabledLinkCSS("btn btn-default");
    selectButton.setEnabled(false);
    cancelButton = LinkFactory.createButton("cancel", mainVC, this);

    int numOfNodes = TreeHelper.totalNodeCount(insertModel.getRootNode());
    if (numOfNodes > CourseModule.getCourseNodeLimit()) {
      String msg =
          getTranslator()
              .translate(
                  "warning.containsXXXormore.nodes",
                  new String[] {
                    String.valueOf(numOfNodes),
                    String.valueOf(CourseModule.getCourseNodeLimit() + 1)
                  });
      Controller tmp = MessageUIFactory.createWarnMessage(ureq, wControl, null, msg);
      listenTo(tmp);
      mainVC.put("nodelimitexceededwarning", tmp.getInitialComponent());
    }

    mainVC.put("selection", insertTree);
    putInitialPanel(mainVC);
  }