From fe55fa22f8d798e95d811212624f12aec2756c23 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 26 Feb 2019 01:11:56 +0100
Subject: [PATCH] OO-3902: fully implements position in curriculum elements

---
 .../core/gui/components/tree/MenuTree.java    |  18 +-
 .../gui/components/tree/MenuTreeItem.java     |   4 +
 .../gui/components/tree/TreePosition.java     |  19 ++
 .../editor/MoveCopySubtreeController.java     |  25 +--
 .../ui/main/EditMembershipController.java     |   2 +-
 .../modules/curriculum/CurriculumElement.java |   8 +
 .../modules/curriculum/CurriculumService.java |   3 +-
 .../manager/CurriculumElementDAO.java         | 162 +++++++++++--
 .../manager/CurriculumServiceImpl.java        |   6 +-
 .../model/CurriculumElementImpl.java          |  31 ++-
 .../curriculum/model/CurriculumImpl.java      |  20 ++
 .../restapi/CurriculumElementsWebService.java |   2 +-
 .../CurriculumElementTreeRowComparator.java   |  12 +-
 .../ui/CurriculumComposerController.java      |   4 +-
 .../curriculum/ui/CurriculumElementRow.java   |   4 +
 .../curriculum/ui/CurriculumTreeModel.java    |  94 +++++++-
 .../ui/EditCurriculumElementController.java   |   6 +-
 .../ui/MoveCurriculumElementController.java   |  53 ++++-
 .../CurriculumElementSelectionController.java |   2 +-
 ...DataCollectionConfigurationController.java |   2 +-
 ...riculumElementUserSelectionController.java |   2 +-
 .../org/olat/upgrade/OLATUpgrade_13_2_0.java  | 185 +++++++++++++++
 .../olat/upgrade/_spring/upgradeContext.xml   |   1 +
 .../upgrade/model/CurriculumElementPos.java   | 133 +++++++++++
 src/main/resources/META-INF/persistence.xml   |   1 +
 .../database/mysql/alter_13_1_x_to_13_2_0.sql |   9 +
 .../database/mysql/setupDatabase.sql          |   2 +
 .../oracle/alter_13_1_x_to_13_2_0.sql         |  10 +
 .../database/oracle/setupDatabase.sql         |   2 +
 .../postgresql/alter_13_1_x_to_13_2_0.sql     |   8 +
 .../database/postgresql/setupDatabase.sql     |   2 +
 .../manager/CurriculumElementDAOTest.java     | 212 +++++++++++++++++-
 32 files changed, 971 insertions(+), 73 deletions(-)
 rename src/main/java/org/olat/modules/curriculum/{ui => site}/CurriculumElementTreeRowComparator.java (90%)
 create mode 100644 src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java
 create mode 100644 src/main/java/org/olat/upgrade/model/CurriculumElementPos.java

diff --git a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
index 22661d76377..e9e8c47a59e 100644
--- a/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
+++ b/src/main/java/org/olat/core/gui/components/tree/MenuTree.java
@@ -438,22 +438,18 @@ public class MenuTree extends AbstractComponent {
 	public TreePosition getInsertionPosition() {
 		if(insertionPoint == null) return null;
 
-		int position;
-		TreeNode parent;
 		TreeNode node = treeModel.getNodeById(insertionPoint.getNodeId());
 		if(insertionPoint.getPosition() == Position.under) {
-			parent = node;
-			position = 0;
+			return new TreePosition(node, 0);
 		} else if(insertionPoint.getPosition() == Position.up) {
-			parent = (TreeNode)node.getParent();
-			position = node.getPosition();
+			TreeNode parent = (TreeNode)node.getParent();
+			return new TreePosition(parent, node, Position.up, node.getPosition());
 		} else if(insertionPoint.getPosition() == Position.down) {
-			parent = (TreeNode)node.getParent();
-			position = node.getPosition() + 1;
-		} else {
-			return null;
+			TreeNode parent = (TreeNode)node.getParent();
+			int position = node.getPosition() + 1;
+			return new TreePosition(parent, node, Position.down, position);
 		}
-		return new TreePosition(parent, position);
+		return null;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java b/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java
index 0d4362d6d07..331ac85e74b 100644
--- a/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java
+++ b/src/main/java/org/olat/core/gui/components/tree/MenuTreeItem.java
@@ -246,6 +246,10 @@ public class MenuTreeItem extends FormItemImpl {
 	public void setRootVisible(boolean rootVisible) {
 		treeCmp.setRootVisible(rootVisible);
 	}
+	
+	public void setInsertTool(boolean enabled) {
+		treeCmp.enableInsertTool(enabled);
+	}
 
 	public void setSelectedNode(TreeNode node) {
 		treeCmp.setSelectedNode(node);
diff --git a/src/main/java/org/olat/core/gui/components/tree/TreePosition.java b/src/main/java/org/olat/core/gui/components/tree/TreePosition.java
index b12f330ef42..a304593240c 100644
--- a/src/main/java/org/olat/core/gui/components/tree/TreePosition.java
+++ b/src/main/java/org/olat/core/gui/components/tree/TreePosition.java
@@ -25,6 +25,8 @@
 
 package org.olat.core.gui.components.tree;
 
+import org.olat.core.gui.components.tree.InsertionPoint.Position;
+
 /**
  * Description:<br>
  * 
@@ -33,6 +35,8 @@ package org.olat.core.gui.components.tree;
 public class TreePosition {
 
 	private TreeNode parent;
+	private TreeNode node;
+	private Position position;
 	private int childpos; // the position of the existing treenode to which to new
 												// node should be prepended (0 = at the beginning, also
 												// works if there are no children yet)
@@ -41,6 +45,13 @@ public class TreePosition {
 		this.parent = parent;
 		this.childpos = childpos;
 	}
+	
+	public TreePosition(TreeNode parent, TreeNode node, Position position, int childpos) {
+		this.node = node;
+		this.parent = parent;
+		this.childpos = childpos;
+		this.position = position;
+	}
 
 	/**
 	 * @return int
@@ -55,5 +66,13 @@ public class TreePosition {
 	public TreeNode getParentTreeNode() {
 		return parent;
 	}
+	
+	public TreeNode getNode() {
+		return node;
+	}
+	
+	public Position getPosition() {
+		return position;
+	}
 
 }
diff --git a/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java b/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java
index 9a7a8e74865..a960e37d7b9 100644
--- a/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java
+++ b/src/main/java/org/olat/course/editor/MoveCopySubtreeController.java
@@ -45,26 +45,23 @@ import org.olat.core.gui.control.generic.messages.MessageUIFactory;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.activity.CourseLoggingAction;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
-import org.olat.core.util.nodes.INode;
 import org.olat.core.util.tree.TreeHelper;
 import org.olat.core.util.tree.TreeVisitor;
-import org.olat.core.util.tree.Visitor;
 import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.tree.CourseEditorTreeNode;
 import org.olat.util.logging.activity.LoggingResourceable;
+
 /**
- * 
- * Description:<br>
- * TODO: guido Class Description for MoveCopySubtreeController
- * 
+ * @author: guido
  */
 public class MoveCopySubtreeController extends BasicController {
 
 	private MenuTree insertTree;
-	private Link selectButton, cancelButton;
+	private Link selectButton;
+	private Link cancelButton;
 	private InsertTreeModel insertModel;
 
 	private boolean copy;
@@ -164,13 +161,10 @@ public class MoveCopySubtreeController extends BasicController {
 
 			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);
+			TreeVisitor tv = new TreeVisitor(node -> {
+				CourseEditorTreeNode cetn = (CourseEditorTreeNode)node;
+				cetn.setDirty(true);
+			}, moveCopyFrom, true);
 			tv.visitAll();					
 			CourseFactory.saveCourseEditorTreeModel(course.getResourceableId());
 			showInfo("movecopynode.info.condmoved");
@@ -182,8 +176,7 @@ public class MoveCopySubtreeController extends BasicController {
 	
 	private CourseNode getCourseNode(TreeNode tn) {
 		CourseEditorTreeNode ctn = (CourseEditorTreeNode) tn;
-		CourseNode cn = ctn.getCourseNode();
-		return cn;
+		return ctn.getCourseNode();
 	}
 
 	private void recursiveCopy(CourseEditorTreeNode copyFrom2, CourseEditorTreeNode insertParent, int pos, boolean firstIteration, ICourse course) {		
diff --git a/src/main/java/org/olat/group/ui/main/EditMembershipController.java b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
index 936c5fda948..1bfbb839cbb 100644
--- a/src/main/java/org/olat/group/ui/main/EditMembershipController.java
+++ b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
@@ -79,8 +79,8 @@ import org.olat.modules.curriculum.CurriculumElementMembership;
 import org.olat.modules.curriculum.CurriculumElementStatus;
 import org.olat.modules.curriculum.CurriculumService;
 import org.olat.modules.curriculum.model.CurriculumElementMembershipChange;
+import org.olat.modules.curriculum.site.CurriculumElementTreeRowComparator;
 import org.olat.modules.curriculum.ui.CurriculumElementRow;
-import org.olat.modules.curriculum.ui.CurriculumElementTreeRowComparator;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.repository.RepositoryManager;
diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumElement.java b/src/main/java/org/olat/modules/curriculum/CurriculumElement.java
index b514cfbda48..7dd7c0976be 100644
--- a/src/main/java/org/olat/modules/curriculum/CurriculumElement.java
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumElement.java
@@ -78,8 +78,16 @@ public interface CurriculumElement extends CurriculumElementShort, CreateInfo, M
 	
 	public void setManagedFlags(CurriculumElementManagedFlag[] flags);
 	
+	/**
+	 * @return The position of an element as child of a parent element
+	 */
 	public Long getPos();
 	
+	/**
+	 * @return The position of a root element directly under the curriculum
+	 */
+	public Long getPosCurriculum();
+	
 	public Curriculum getCurriculum();
 	
 	public CurriculumElement getParent();
diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumService.java b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
index 831afb09678..33778826d56 100644
--- a/src/main/java/org/olat/modules/curriculum/CurriculumService.java
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
@@ -317,8 +317,9 @@ public interface CurriculumService {
 	 * 
 	 * @param elementToMove The element to move
 	 * @param newParent The new parent or null if root
+	 * @param siblingBefore The sibling before the new position or null if at the first place
 	 */
-	public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent);
+	public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent, CurriculumElement siblingBefore);
 	
 	/**
 	 * The list of members of the specified curriculum element.
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
index 62420ba63df..ffa582cfaa5 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java
@@ -61,6 +61,7 @@ import org.olat.modules.curriculum.model.CurriculumElementInfos;
 import org.olat.modules.curriculum.model.CurriculumElementMembershipImpl;
 import org.olat.modules.curriculum.model.CurriculumElementSearchInfos;
 import org.olat.modules.curriculum.model.CurriculumElementSearchParams;
+import org.olat.modules.curriculum.model.CurriculumImpl;
 import org.olat.repository.RepositoryEntryRef;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -101,6 +102,10 @@ public class CurriculumElementDAO {
 		if(parent != null) {
 			((CurriculumElementImpl)parent).getChildren().add(element);
 			dbInstance.getCurrentEntityManager().merge(parent);
+		} else {
+			element.setCurriculumParent(curriculum);
+			((CurriculumImpl)curriculum).getRootElements().add(element);
+			dbInstance.getCurrentEntityManager().merge(curriculum);
 		}
 		element.setMaterializedPathKeys(getMaterializedPathKeys(parent, element));
 		dbInstance.getCurrentEntityManager().merge(element);
@@ -150,6 +155,13 @@ public class CurriculumElementDAO {
 				.getResultList();
 	}
 	
+	/**
+	 * Calculate the materialized path from the parent element.
+	 * 
+	 * @param parent The parent element (can be null if the element is a root one)
+	 * @param element The curriculum element
+	 * @return The materialized path of the specified element
+	 */
 	private String getMaterializedPathKeys(CurriculumElement parent, CurriculumElement element) {
 		if(parent != null) {
 			String parentPathOfKeys = parent.getMaterializedPathKeys();
@@ -167,23 +179,74 @@ public class CurriculumElementDAO {
 		return dbInstance.getCurrentEntityManager().merge(element);
 	}
 	
-	public CurriculumElement move(CurriculumElement element, CurriculumElement newParentElement) {
-		CurriculumElement parentElement = element.getParent();
+	public CurriculumElement move(CurriculumElement elementToMove, CurriculumElement newParentElement, CurriculumElement siblingBefore) {
+		CurriculumElement parentElement = elementToMove.getParent();
+		CurriculumElementImpl element = (CurriculumElementImpl)elementToMove;
+		
 		if(parentElement == null && newParentElement == null) {
-			return element;//already root
-		} else if(parentElement != null && parentElement.equals(newParentElement)) {
-			return element;//same parent
+			// reorder curriculum children
+			
+			CurriculumImpl curriculum = loadCurriculunByKey(element);
+			List<CurriculumElement> rootElements = curriculum.getRootElements();
+			reorderList(element, rootElements, siblingBefore);
+			dbInstance.getCurrentEntityManager().merge(curriculum);
+		} else if(parentElement == null) {
+			// move from curriculum as root to a curriculum element
+			
+			CurriculumImpl curriculum = loadCurriculunByKey(element);
+			List<CurriculumElement> rootElements = curriculum.getRootElements();
+			element.setCurriculumParent(null);
+			rootElements.remove(element);
+			curriculum = dbInstance.getCurrentEntityManager().merge(curriculum);
+			
+			newParentElement = loadByKey(newParentElement.getKey());
+			List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren();
+			reorderList(element, newChildren, siblingBefore);
+			element.setParent(newParentElement);
+			dbInstance.getCurrentEntityManager().merge(newParentElement);	
+		} else if(newParentElement == null) {
+			// move from a curriculum element to root level
+			
+			parentElement = loadByKey(parentElement.getKey());
+			List<CurriculumElement> children = ((CurriculumElementImpl)parentElement).getChildren();
+			children.remove(element);
+			element.setParent(null);
+			dbInstance.getCurrentEntityManager().merge(parentElement);	
+			
+			CurriculumImpl curriculum = loadCurriculunByKey(element);
+			element.setCurriculumParent(curriculum);
+			List<CurriculumElement> rootElements = curriculum.getRootElements();
+			reorderList(element, rootElements, siblingBefore);
+			dbInstance.getCurrentEntityManager().merge(curriculum);	
+		} else if(parentElement.equals(newParentElement)) {
+			// reorder under the same parent curriculum element
+			
+			newParentElement = loadByKey(newParentElement.getKey());
+			List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren();
+			reorderList(element, newChildren, siblingBefore);
+			dbInstance.getCurrentEntityManager().merge(newParentElement);
+		} else {
+			// move from a curriculum element to an other
+			
+			parentElement = loadByKey(parentElement.getKey());
+			List<CurriculumElement> children = ((CurriculumElementImpl)parentElement).getChildren();
+			children.remove(element);
+			element.setParent(newParentElement);
+			dbInstance.getCurrentEntityManager().merge(parentElement);	
+			
+			newParentElement = loadByKey(newParentElement.getKey());
+			List<CurriculumElement> newChildren = ((CurriculumElementImpl)newParentElement).getChildren();
+			reorderList(element, newChildren, siblingBefore);
+			dbInstance.getCurrentEntityManager().merge(newParentElement);
 		}
 
 		String keysPath = element.getMaterializedPathKeys();
-		
 		List<CurriculumElement> descendants = getDescendants(element);
-		CurriculumElementImpl elementImpl = (CurriculumElementImpl)element;
-		elementImpl.setParent(newParentElement);
-		elementImpl.setLastModified(new Date());
-		String newKeysPath = getMaterializedPathKeys(newParentElement, elementImpl);
-		elementImpl.setMaterializedPathKeys(newKeysPath);
-		elementImpl = dbInstance.getCurrentEntityManager().merge(elementImpl);
+
+		element.setLastModified(new Date());
+		String newKeysPath = getMaterializedPathKeys(newParentElement, element);
+		element.setMaterializedPathKeys(newKeysPath);
+		element = dbInstance.getCurrentEntityManager().merge(element);
 
 		for(CurriculumElement descendant:descendants) {
 			String descendantKeysPath = descendant.getMaterializedPathKeys();
@@ -195,7 +258,44 @@ public class CurriculumElementDAO {
 			dbInstance.getCurrentEntityManager().merge(descendant);
 		}		
 		dbInstance.commit();
-		return elementImpl;
+		return element;
+	}
+	
+	private void reorderList(CurriculumElement element, List<CurriculumElement> elements, CurriculumElement siblingBefore) {
+		int currentIndex = elements.indexOf(element);
+		if(siblingBefore == null) {
+			if(currentIndex >= 0) {
+				elements.remove(element);
+			}
+			elements.add(0, element);
+		} else if(currentIndex < 0) {
+			int siblingIndex = elements.indexOf(siblingBefore) + 1;
+			if(siblingIndex >= 0 && siblingIndex < elements.size()) {
+				elements.add(siblingIndex, element);
+			} else {
+				elements.add(element);
+			}
+		} else {
+			int siblingIndex = elements.indexOf(siblingBefore) + 1;
+			int newIndex = siblingIndex;
+			if(currentIndex < siblingIndex) {
+				newIndex--;
+			}
+			elements.remove(element);
+			elements.add(newIndex, element);
+		}
+	}
+	
+	private CurriculumImpl loadCurriculunByKey(CurriculumElement element) {
+		StringBuilder sb = new StringBuilder(128);
+		sb.append("select cur from curriculum cur")
+		  .append(" where cur.key=:key");
+		
+		List<CurriculumImpl> curriculums = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), CurriculumImpl.class)
+			.setParameter("key", element.getCurriculum().getKey())
+			.getResultList();
+		return curriculums == null || curriculums.isEmpty() ? null : curriculums.get(0);
 	}
 	
 	public List<CurriculumElement> loadElements(CurriculumRef curriculum, CurriculumElementStatus[] status) {
@@ -556,6 +656,17 @@ public class CurriculumElementDAO {
 		return elements;
 	}
 	
+	public int countChildren(CurriculumElementRef curriculumElement) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select count(el.key) from curriculumelement el")
+		  .append(" where el.parent.key=:elementKey");
+		List<Long> count = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Long.class)
+				.setParameter("elementKey", curriculumElement.getKey())
+				.getResultList();
+		return count != null && !count.isEmpty() && count.get(0) != null ? count.get(0).intValue() : 0;
+	}
+	
 	/**
 	 * The method returns all the children, inclusive the marked as deleted.
 	 * 
@@ -568,13 +679,36 @@ public class CurriculumElementDAO {
 		  .append(" inner join fetch el.curriculum curriculum")
 		  .append(" inner join fetch el.group bGroup")
 		  .append(" left join fetch curriculum.organisation org")
-		  .append(" where el.parent.key=:elementKey");
+		  .append(" where el.parent.key=:elementKey")
+		  .append(" order by el.pos");
 		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), CurriculumElement.class)
 				.setParameter("elementKey", curriculumElement.getKey())
 				.getResultList();
 	}
 	
+	/**
+	 * The method returns all the children, inclusive the marked as deleted.
+	 * 
+	 * @param curriculumElement The parent element
+	 * @return A list of curriculum elements
+	 */
+	public List<CurriculumElement> getChildren(CurriculumRef curriculum) {
+		StringBuilder sb = new StringBuilder(256);
+		sb.append("select el from curriculumelement el")
+		  .append(" inner join fetch el.curriculum curriculum")
+		  .append(" inner join fetch el.group bGroup")
+		  .append(" left join fetch curriculum.organisation org")
+		  .append(" where el.curriculumParent.key=:curriculumKey")
+		  .append(" order by el.posCurriculum");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), CurriculumElement.class)
+				.setParameter("curriculumKey", curriculum.getKey())
+				.getResultList();
+	}
+	
+	
+	
 	public List<Identity> getMembersIdentity(CurriculumElementRef element, String role) {
 		StringBuilder sb = new StringBuilder(256);
 		sb.append("select ident from curriculumelement el")
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
index 44c2ce4ba07..0f4b7fe9d63 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
@@ -361,10 +361,10 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat
 	public CurriculumElement updateCurriculumElement(CurriculumElement element) {
 		return curriculumElementDao.update(element);
 	}
-
+	
 	@Override
-	public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent) {
-		return curriculumElementDao.move(elementToMove, newParent);
+	public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent, CurriculumElement siblingBefore) {
+		return curriculumElementDao.move(elementToMove, newParent, siblingBefore);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java
index 61f3fe499bf..b22f6bc4e6b 100644
--- a/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java
+++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementImpl.java
@@ -26,7 +26,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
@@ -84,6 +83,11 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable {
 	@Column(name="pos", insertable=false, updatable=false)
 	private Long pos;
 	
+	/** Only used for order by (hibernate hack) */
+	@GeneratedValue
+	@Column(name="pos_cur", insertable=false, updatable=false)
+	private Long posCurriculum;
+	
 	@Column(name="c_identifier", nullable=true, insertable=true, updatable=true)
 	private String identifier;
 	@Column(name="c_displayname", nullable=true, insertable=true, updatable=true)
@@ -120,8 +124,7 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable {
 	@JoinColumn(name="fk_parent", nullable=true, insertable=true, updatable=true)
 	private CurriculumElement parent;
 	
-	@OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="parent", fetch=FetchType.LAZY,
-			orphanRemoval=true, cascade={CascadeType.REMOVE})
+	@OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="parent", fetch=FetchType.LAZY)
 	@OrderColumn(name="pos")
 	private List<CurriculumElement> children;
 	
@@ -129,6 +132,10 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable {
 	@JoinColumn(name="fk_curriculum", nullable=true, insertable=true, updatable=true)
 	private Curriculum curriculum;
 	
+	@ManyToOne(targetEntity=CurriculumImpl.class)
+	@JoinColumn(name="fk_curriculum_parent", nullable=true, insertable=true, updatable=true)
+	private Curriculum curriculumParent;
+	
 	@ManyToOne(targetEntity=CurriculumElementTypeImpl.class,fetch=FetchType.LAZY,optional=true)
 	@JoinColumn(name="fk_type", nullable=true, insertable=true, updatable=true)
 	private CurriculumElementType type;
@@ -346,6 +353,16 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable {
 	public void setPos(Long pos) {
 		this.pos = pos;
 	}
+	
+	
+
+	public Long getPosCurriculum() {
+		return posCurriculum;
+	}
+
+	public void setPosCurriculum(Long posCurriculum) {
+		this.posCurriculum = posCurriculum;
+	}
 
 	@Override
 	public Group getGroup() {
@@ -365,6 +382,14 @@ public class CurriculumElementImpl implements CurriculumElement, Persistable {
 		this.parent = parent;
 	}
 
+	public Curriculum getCurriculumParent() {
+		return curriculumParent;
+	}
+
+	public void setCurriculumParent(Curriculum curriculumParent) {
+		this.curriculumParent = curriculumParent;
+	}
+
 	public List<CurriculumElement> getChildren() {
 		if(children == null) {
 			children = new ArrayList<>();
diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java
index 81a90fc7af4..395153824f6 100644
--- a/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java
+++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumImpl.java
@@ -19,7 +19,9 @@
  */
 package org.olat.modules.curriculum.model;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -29,6 +31,8 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderColumn;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
@@ -39,6 +43,7 @@ import org.olat.basesecurity.model.OrganisationImpl;
 import org.olat.core.id.Organisation;
 import org.olat.core.id.Persistable;
 import org.olat.modules.curriculum.Curriculum;
+import org.olat.modules.curriculum.CurriculumElement;
 import org.olat.modules.curriculum.CurriculumManagedFlag;
 
 /**
@@ -88,6 +93,10 @@ public class CurriculumImpl implements Persistable, Curriculum {
 	@ManyToOne(targetEntity=OrganisationImpl.class,fetch=FetchType.LAZY,optional=true)
 	@JoinColumn(name="fk_organisation", nullable=true, insertable=true, updatable=true)
 	private Organisation organisation;
+	
+	@OneToMany(targetEntity=CurriculumElementImpl.class, mappedBy="curriculumParent", fetch=FetchType.LAZY)
+	@OrderColumn(name="pos_cur")
+	private List<CurriculumElement> rootElements;
 
 	@Override
 	public Long getKey() {
@@ -214,6 +223,17 @@ public class CurriculumImpl implements Persistable, Curriculum {
 		this.organisation = organisation;
 	}
 
+	public List<CurriculumElement> getRootElements() {
+		if(rootElements == null) {
+			rootElements = new ArrayList<>();
+		}
+		return rootElements;
+	}
+
+	public void setRootElements(List<CurriculumElement> rootElements) {
+		this.rootElements = rootElements;
+	}
+
 	@Override
 	public int hashCode() {
 		return key == null ? 261825789 : key.hashCode();
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
index 9951ee53814..3bde07dc0b9 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementsWebService.java
@@ -274,7 +274,7 @@ public class CurriculumElementsWebService {
 		}
 		CurriculumElement savedElement = curriculumService.updateCurriculumElement(elementToSave);
 		if(move) {
-			curriculumService.moveCurriculumElement(savedElement, parentElement);
+			curriculumService.moveCurriculumElement(savedElement, parentElement, null);
 			dbInstance.commit();
 			savedElement = curriculumService.getCurriculumElement(savedElement);
 		}
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java b/src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java
similarity index 90%
rename from src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java
rename to src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java
index c09c39258e0..ebf6ebb49df 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementTreeRowComparator.java
+++ b/src/main/java/org/olat/modules/curriculum/site/CurriculumElementTreeRowComparator.java
@@ -17,15 +17,17 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.modules.curriculum.ui;
+package org.olat.modules.curriculum.site;
 
 import java.text.Collator;
 import java.util.Locale;
 
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeNodeComparator;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeTableNode;
+import org.olat.modules.curriculum.ui.CurriculumElementRow;
 
 /**
+ * This is based of the position of the elements.
  * 
  * Initial date: 9 août 2018<br>
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
@@ -52,7 +54,13 @@ public class CurriculumElementTreeRowComparator extends FlexiTreeNodeComparator
 		
 		int c = 0;
 		if(parentKey1 == null && parentKey2 == null) {
-			c = compareCurriculumElements(c1, c2);
+			Long pos1 = c1.getPosCurriculum();
+			Long pos2 = c2.getPosCurriculum();
+			if(pos1 == null || pos2 == null) {
+				c = compareNullObjects(pos1, pos2);
+			} else {
+				c = Long.compare(pos1.longValue(), pos2.longValue());
+			}
 		} else if(parentKey1 != null && parentKey1.equals(parentKey2)) {
 			Long pos1 = c1.getPos();
 			Long pos2 = c2.getPos();
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java
index d52b39eece3..bec79e86182 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumComposerController.java
@@ -84,6 +84,7 @@ import org.olat.modules.curriculum.CurriculumSecurityCallback;
 import org.olat.modules.curriculum.CurriculumService;
 import org.olat.modules.curriculum.model.CurriculumElementInfos;
 import org.olat.modules.curriculum.model.CurriculumElementMembershipChange;
+import org.olat.modules.curriculum.site.CurriculumElementTreeRowComparator;
 import org.olat.modules.curriculum.ui.CurriculumComposerTableModel.ElementCols;
 import org.olat.modules.curriculum.ui.copy.CopySettingsController;
 import org.olat.modules.curriculum.ui.event.SelectReferenceEvent;
@@ -293,9 +294,8 @@ public class CurriculumComposerController extends FormBasicController implements
 			}
 		}
 		Collections.sort(rows, new CurriculumElementTreeRowComparator(getLocale()));
-		
 		tableModel.setObjects(rows);
-		tableEl.reset(false, true, true);
+		tableEl.reset(true, true, true);
 	}
 	
 	private CurriculumElementRow forgeRow(CurriculumElementInfos element) {
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java
index 7afff278d42..ccbb3ba83e3 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementRow.java
@@ -171,6 +171,10 @@ public class CurriculumElementRow implements CurriculumElementRef, FlexiTreeTabl
 		return element.getPos();
 	}
 	
+	public Long getPosCurriculum() {
+		return element.getPosCurriculum();
+	}
+	
 	public long getNumOfResources() {
 		return numOfResources;
 	}
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java
index 4bd5b926e36..bd88521b2bc 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumTreeModel.java
@@ -19,12 +19,19 @@
  */
 package org.olat.modules.curriculum.ui;
 
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.olat.core.gui.components.tree.GenericTreeModel;
 import org.olat.core.gui.components.tree.GenericTreeNode;
+import org.olat.core.gui.components.tree.InsertionPoint.Position;
+import org.olat.core.gui.components.tree.InsertionTreeModel;
+import org.olat.core.gui.components.tree.TreeNode;
+import org.olat.core.util.nodes.INode;
+import org.olat.modules.curriculum.Curriculum;
 import org.olat.modules.curriculum.CurriculumElement;
 import org.olat.modules.curriculum.CurriculumElementRef;
 
@@ -34,15 +41,27 @@ import org.olat.modules.curriculum.CurriculumElementRef;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CurriculumTreeModel extends GenericTreeModel {
+public class CurriculumTreeModel extends GenericTreeModel implements InsertionTreeModel {
 
 	private static final long serialVersionUID = 2911319509933144413L;
 
 	public static final String LEVEL_PREFIX = "cur-el-lev-";
-
+	
+	private final List<CurriculumElement> sources;
+	
 	public CurriculumTreeModel() {
+		this(null, new ArrayList<CurriculumElement>());
+	}
+	
+	public CurriculumTreeModel(Curriculum curriculum) {
+		this(curriculum, new ArrayList<CurriculumElement>());
+	}
+
+	public CurriculumTreeModel(Curriculum curriculum, List<CurriculumElement> sources) {
 		GenericTreeNode root = new GenericTreeNode();
-		root.setTitle("ROOT");
+		String title = curriculum == null ? "ROOT" : curriculum.getDisplayName();
+		root.setTitle(title);
+		this.sources = new ArrayList<>(sources);
 		setRootNode(root);
 	}
 	
@@ -79,9 +98,78 @@ public class CurriculumTreeModel extends GenericTreeModel {
 				}
 			}
 		}
+		
+		CurriculumElementComparator comparator = new CurriculumElementComparator();
+		getRootNode().sort(comparator);
+		for(GenericTreeNode node:fieldKeyToNode.values()) {
+			node.sort(comparator);
+		}	
+	}
+	
+	@Override
+	public boolean isSource(TreeNode node) {
+		if(node instanceof GenericTreeNode) {
+			GenericTreeNode gNode = (GenericTreeNode)node;
+			return gNode.getUserObject() instanceof CurriculumElement && sources.contains(gNode.getUserObject());
+		}
+		return false;
 	}
 	
+	public boolean isInParentLine(TreeNode node) {
+		for(INode iteratorNode=node; node.getParent() != null && iteratorNode != null; iteratorNode=iteratorNode.getParent()) {
+			if(iteratorNode instanceof TreeNode && isSource((TreeNode)iteratorNode)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public Position[] getInsertionPosition(TreeNode node) {
+		Position[] positions;
+		if(isSource(node)) {
+			positions = new Position[0];
+		} else if(getRootNode() == node) {
+			positions = new Position[] { Position.under };
+		} else if(isInParentLine(node)) {
+			positions = new Position[0];
+		} else {
+			positions = new Position[] { Position.up, Position.down, Position.under };
+		}
+		return positions;
+	}
+
 	public static final String nodeKey(CurriculumElementRef element) {
 		return LEVEL_PREFIX + element.getKey();
 	}
+	
+	private static class CurriculumElementComparator implements Comparator<INode> {
+
+		@Override
+		public int compare(INode n1, INode n2) {
+			CurriculumElement o1 = (CurriculumElement)((TreeNode)n1).getUserObject();
+			CurriculumElement o2 = (CurriculumElement)((TreeNode)n2).getUserObject();
+
+			Long p1 = null;
+			Long p2 = null;
+			
+			if(o1.getParent() == null && o2.getParent() == null) {
+				p1 = o1.getPosCurriculum();
+				p2 = o2.getPosCurriculum();
+			} else if(o1.getParent() != null && o2.getParent() != null) {
+				p1 = o1.getPos();
+				p2 = o2.getPos();
+			}
+			
+			int c = 0;
+			if(p1 != null && p2 != null) {
+				c = p1.compareTo(p2);
+			} else if(p1 != null) {
+				c = -1;
+			} else if(p2 != null) {
+				c = 1;
+			}
+			return c;
+		}
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java b/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java
index 65954c38a8f..114694fc101 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/EditCurriculumElementController.java
@@ -24,6 +24,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Set;
 
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -91,6 +92,8 @@ public class EditCurriculumElementController extends FormBasicController {
 	private CurriculumElement parentElement;
 	private final CurriculumSecurityCallback secCallback;
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private CurriculumService curriculumService;
 	
@@ -375,7 +378,8 @@ public class EditCurriculumElementController extends FormBasicController {
 			element.setLectures(lectures);
 			element = curriculumService.updateCurriculumElement(element);
 		}
-
+		
+		dbInstance.commitAndCloseSession(); // need to relaod properly the tree
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
 	
diff --git a/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java b/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java
index 991caa6e1e5..ce21de00086 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/MoveCurriculumElementController.java
@@ -27,12 +27,15 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.tree.GenericTreeNode;
+import org.olat.core.gui.components.tree.InsertionPoint.Position;
 import org.olat.core.gui.components.tree.MenuTreeItem;
 import org.olat.core.gui.components.tree.TreeNode;
+import org.olat.core.gui.components.tree.TreePosition;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -54,13 +57,15 @@ import org.springframework.beans.factory.annotation.Autowired;
 public class MoveCurriculumElementController extends FormBasicController {
 	
 	private MenuTreeItem curriculumTreeEl;
-	private final CurriculumTreeModel curriculumModel = new CurriculumTreeModel();
+	private final CurriculumTreeModel curriculumModel;
 	
 	private final Curriculum curriculum;
 	private Set<CurriculumElementType> allowedTypes;
 	private List<CurriculumElement> curriculumElementsToMove;
 	private Set<TreeNode> targetableNodes = new HashSet<>();
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private CurriculumService curriculumService;
 	
@@ -69,6 +74,7 @@ public class MoveCurriculumElementController extends FormBasicController {
 		super(ureq, wControl, "move_curriculum_element");
 		this.curriculum = curriculum;
 		this.curriculumElementsToMove = new ArrayList<>(curriculumElementsToMove);
+		curriculumModel = new CurriculumTreeModel(curriculum, curriculumElementsToMove);
 		allowedTypes = getAllowedTypes();
 		
 		initForm(ureq);
@@ -80,7 +86,8 @@ public class MoveCurriculumElementController extends FormBasicController {
 		
 		curriculumTreeEl = uifactory.addTreeMultiselect("elements", null, formLayout, curriculumModel, this);
 		curriculumTreeEl.setMultiSelect(false);
-		curriculumTreeEl.setRootVisible(false);
+		curriculumTreeEl.setRootVisible(true);
+		curriculumTreeEl.setInsertTool(true);
 
 		uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
 		uifactory.addFormSubmitButton("move.element", formLayout);
@@ -229,18 +236,44 @@ public class MoveCurriculumElementController extends FormBasicController {
 		if(isParent()) {
 			showWarning("error.target.no.parent");
 		} else {
-			TreeNode selectedNode = curriculumTreeEl.getSelectedNode();
-			if(selectedNode == curriculumModel.getRootNode()) {
-				for(CurriculumElement elementToMove:curriculumElementsToMove) {
-					curriculumService.moveCurriculumElement(elementToMove, null);
+			TreePosition tp = curriculumTreeEl.getInsertionPosition();
+			TreeNode parentNode = tp.getParentTreeNode();
+			CurriculumElement newParent = (CurriculumElement)parentNode.getUserObject();
+			if(newParent == curriculumModel.getRootNode()) {
+				newParent = null; // root element
+			}
+			
+			CurriculumElement siblingBefore;
+			if(tp.getNode() == null) {
+				siblingBefore = null;
+			} else if(tp.getPosition() == Position.down) {
+				siblingBefore = (CurriculumElement)tp.getNode().getUserObject();
+			} else if(tp.getPosition() == Position.up) {
+				TreeNode selectedNode = tp.getNode();
+				int index = -1;
+				for(int i=tp.getParentTreeNode().getChildCount(); i-->0; ) {
+					if(selectedNode.equals(tp.getParentTreeNode().getChildAt(i))) {
+						index = i;
+						break;
+					}
 				}
-			} else {
-				CurriculumElement newParent = (CurriculumElement)selectedNode.getUserObject();
-				for(CurriculumElement elementToMove:curriculumElementsToMove) {
-					curriculumService.moveCurriculumElement(elementToMove, newParent);
+				
+				if(index == 0) {
+					siblingBefore = null;
+				} else {
+					INode nodeBefore = tp.getParentTreeNode().getChildAt(index -1);
+					siblingBefore = (CurriculumElement)((TreeNode)nodeBefore).getUserObject();
 				}
+			} else {
+				siblingBefore = null;
+			}
+	
+			for(CurriculumElement elementToMove:curriculumElementsToMove) {
+				curriculumService.moveCurriculumElement(elementToMove, newParent, siblingBefore);
+				dbInstance.commit();
 			}
 		}
+		dbInstance.commitAndCloseSession();
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
 }
diff --git a/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java b/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java
index 9711b9f1bd4..c6ab7bc2540 100644
--- a/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java
+++ b/src/main/java/org/olat/modules/quality/generator/ui/CurriculumElementSelectionController.java
@@ -108,7 +108,7 @@ class CurriculumElementSelectionController extends FormBasicController {
 			if (curriculum != null) {
 				List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(curriculum,
 						CurriculumElementStatus.notDeleted());
-				CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel();
+				CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(curriculum);
 				curriculumTreeModel.loadTreeModel(curriculumElements);
 				KeysValues curriculumElementKeysValues = QualityUIFactory
 						.getCurriculumElementKeysValues(curriculumTreeModel, null);
diff --git a/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java b/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java
index c3a0220a7b0..bf6605e1758 100644
--- a/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java
+++ b/src/main/java/org/olat/modules/quality/ui/DataCollectionConfigurationController.java
@@ -321,7 +321,7 @@ public class DataCollectionConfigurationController extends FormBasicController {
 				if (topicCurriculum != null) {
 					topicCurriculumEl.select(QualityUIFactory.getCurriculumKey(topicCurriculum), true);
 					List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(topicCurriculum, CurriculumElementStatus.values());
-					CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel();
+					CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(topicCurriculum);
 					curriculumTreeModel.loadTreeModel(curriculumElements);
 					KeysValues curriculumElementKeysValues = QualityUIFactory.getCurriculumElementKeysValues(curriculumTreeModel, topicCurriculumElement);
 					topicCurriculumElementEl.setKeysAndValues(curriculumElementKeysValues.getKeys(), curriculumElementKeysValues.getValues(), null);
diff --git a/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java b/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java
index 49649e550f6..2db8e642bb1 100644
--- a/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java
+++ b/src/main/java/org/olat/modules/quality/ui/wizard/AddCurriculumElementUserSelectionController.java
@@ -106,7 +106,7 @@ public class AddCurriculumElementUserSelectionController extends StepFormBasicCo
 			Curriculum curriculum = curriculumService.getCurriculum(curriculumRef);
 			if (curriculum != null) {
 				List<CurriculumElement> curriculumElements = curriculumService.getCurriculumElements(curriculum, CurriculumElementStatus.notDeleted());
-				CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel();
+				CurriculumTreeModel curriculumTreeModel = new CurriculumTreeModel(curriculum);
 				curriculumTreeModel.loadTreeModel(curriculumElements);
 				KeysValues curriculumElementKeysValues = QualityUIFactory.getCurriculumElementKeysValues(curriculumTreeModel, null);
 				curriculumElementEl.setKeysAndValues(curriculumElementKeysValues.getKeys(), curriculumElementKeysValues.getValues(), null);
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java
new file mode 100644
index 00000000000..fedb17b4817
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_13_2_0.java
@@ -0,0 +1,185 @@
+/**
+ * <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.upgrade;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.upgrade.model.CurriculumElementPos;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+
+/**
+ * 
+ * Initial date: 4 janv. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OLATUpgrade_13_2_0 extends OLATUpgrade {
+	
+	private static final String VERSION = "OLAT_13.2.0";
+	private static final String UPDATE_CURRICULUM_CHILDREN = "UPDATE CURRICULUM CHILDREN";
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public OLATUpgrade_13_2_0() {
+		super();
+	}
+	
+	@Override
+	public String getVersion() {
+		return VERSION;
+	}
+
+	@Override
+	public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+
+	@Override
+	public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
+		UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION);
+		if (uhd == null) {
+			// has never been called, initialize
+			uhd = new UpgradeHistoryData();
+		} else if (uhd.isInstallationComplete()) {
+			return false;
+		}
+		
+		boolean allOk = true;
+		allOk &= updateCurriculumElementChildren(upgradeManager, uhd);
+
+		uhd.setInstallationComplete(allOk);
+		upgradeManager.setUpgradesHistory(uhd, VERSION);
+		if(allOk) {
+			log.audit("Finished OLATUpgrade_13_2_0 successfully!");
+		} else {
+			log.audit("OLATUpgrade_13_2_0 not finished, try to restart OpenOLAT!");
+		}
+		return allOk;
+	}
+	
+	/**
+	 * Recalculate pos of children
+	 * 
+	 * @param upgradeManager The upgrade manager
+	 * @param uhd The upgrade history
+	 * @return true if successful
+	 */
+	private boolean updateCurriculumElementChildren(UpgradeManager upgradeManager, UpgradeHistoryData uhd) {
+		boolean allOk = true;
+		if (!uhd.getBooleanDataValue(UPDATE_CURRICULUM_CHILDREN)) {
+			List<CurriculumElementPos> elements = getCurriculumElements();
+			Map<Long, List<CurriculumElementPos>> parentToChildren = new HashMap<>();
+			Map<Long, List<CurriculumElementPos>> curriculumToChildren = new HashMap<>();
+			
+			// pre warm the maps
+			for(CurriculumElementPos element:elements) {
+				parentToChildren.put(element.getKey(), new ArrayList<>());
+			}
+			for(CurriculumElementPos element:elements) {
+				curriculumToChildren.put(element.getCurriculumKey(), new ArrayList<>());
+			}
+			
+			// fill the data
+			for(CurriculumElementPos element:elements) {
+				if(element.getParentKey() != null) {
+					parentToChildren.get(element.getParentKey()).add(element);
+				} else {
+					curriculumToChildren.get(element.getCurriculumKey()).add(element);
+				}
+			}
+			
+			// reorder curriculum elements
+			for(List<CurriculumElementPos> children:parentToChildren.values()) {
+				if(children.isEmpty()) continue;
+				// reorder the children
+				Collections.sort(children, new PosComparator());	
+				// assign a position
+				for(int i=0; i<children.size(); i++) {
+					children.get(i).setPos(Long.valueOf(i));
+				}
+				// merge
+				for(CurriculumElementPos child:children) {
+					dbInstance.getCurrentEntityManager().merge(child);
+				}
+				dbInstance.commit();
+			}
+			dbInstance.commitAndCloseSession();
+			
+			// reorder root elements 
+			for(List<CurriculumElementPos> children:curriculumToChildren.values()) {
+				if(children.isEmpty()) continue;
+				// reorder the roots
+				Collections.sort(children, new PosComparator());	
+				// assign a position under curriculum
+				for(int i=0; i<children.size(); i++) {
+					children.get(i).setPosCurriculum(Long.valueOf(i));
+					children.get(i).setParentCurriculumKey(children.get(i).getCurriculumKey());
+				}
+				// merge
+				for(CurriculumElementPos child:children) {
+					dbInstance.getCurrentEntityManager().merge(child);
+				}
+				dbInstance.commit();
+			}
+			dbInstance.commitAndCloseSession();
+			
+
+			uhd.setBooleanDataValue(UPDATE_CURRICULUM_CHILDREN, allOk);
+			upgradeManager.setUpgradesHistory(uhd, VERSION);
+		}
+		return allOk;
+	}
+	
+	private List<CurriculumElementPos> getCurriculumElements() {
+		String q = "select curEl from curriculumelementpos as curEl";
+		return dbInstance.getCurrentEntityManager()
+			.createQuery(q, CurriculumElementPos.class)
+			.getResultList();
+	}
+	
+	private static class PosComparator implements Comparator<CurriculumElementPos> {
+		@Override
+		public int compare(CurriculumElementPos o1, CurriculumElementPos o2) {
+			Long p1 = o1.getPos();
+			Long p2 = o2.getPos();
+			
+			int c = 0;
+			if(p1 != null && p2 != null) {
+				c = p1.compareTo(p2);
+			} else if(p1 != null) {
+				c = 1;
+			} else if(p2 != null) {
+				c = -1;
+			}
+			if(c == 0) {
+				c = o1.getKey().compareTo(o2.getKey());
+			}
+			return c;
+		}	
+	}
+}
diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
index c3090d77681..397770715be 100644
--- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
@@ -47,6 +47,7 @@
 				<bean id="upgrade_13_0_0_beta7" class="org.olat.upgrade.OLATUpgrade_13_0_0_beta7"/>
 				<bean id="upgrade_13_0_0_beta9" class="org.olat.upgrade.OLATUpgrade_13_0_0_beta9"/>
 				<bean id="upgrade_13_1_0" class="org.olat.upgrade.OLATUpgrade_13_1_0"/>
+				<bean id="upgrade_13_2_0" class="org.olat.upgrade.OLATUpgrade_13_2_0"/>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java b/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java
new file mode 100644
index 00000000000..692959490fb
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/model/CurriculumElementPos.java
@@ -0,0 +1,133 @@
+/**
+ * <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.upgrade.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.olat.core.id.Persistable;
+import org.olat.modules.curriculum.model.CurriculumElementImpl;
+
+/**
+ * Only use to rewrite the position of curriculum elements.
+ * 
+ * Initial date: 25 févr. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="curriculumelementpos")
+@Table(name="o_cur_curriculum_element")
+public class CurriculumElementPos implements Persistable {
+	
+	private static final long serialVersionUID = 547658342562646552L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Column(name="pos", insertable=true, updatable=true)
+	private Long pos;
+	@Column(name="fk_parent", nullable=true, insertable=false, updatable=false)
+	private Long parentKey;
+	
+	@Column(name="pos_cur", insertable=true, updatable=true)
+	private Long posCurriculum;
+	@Column(name="fk_curriculum", nullable=true, insertable=false, updatable=false)
+	private Long curriculumKey;
+	@Column(name="fk_curriculum_parent", nullable=true, insertable=false, updatable=true)
+	private Long parentCurriculumKey;
+	
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	public Long getPos() {
+		return pos;
+	}
+
+	public void setPos(Long pos) {
+		this.pos = pos;
+	}
+
+	public Long getParentKey() {
+		return parentKey;
+	}
+
+	public void setParentKey(Long parentKey) {
+		this.parentKey = parentKey;
+	}
+
+	public Long getPosCurriculum() {
+		return posCurriculum;
+	}
+
+	public void setPosCurriculum(Long posCurriculum) {
+		this.posCurriculum = posCurriculum;
+	}
+
+	public Long getCurriculumKey() {
+		return curriculumKey;
+	}
+
+	public void setCurriculumKey(Long curriculumKey) {
+		this.curriculumKey = curriculumKey;
+	}
+
+	public Long getParentCurriculumKey() {
+		return parentCurriculumKey;
+	}
+
+	public void setParentCurriculumKey(Long parentCurriculumKey) {
+		this.parentCurriculumKey = parentCurriculumKey;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? 28562153 : key.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof CurriculumElementImpl) {
+			CurriculumElementImpl el = (CurriculumElementImpl)obj;
+			return getKey() != null && getKey().equals(el.getKey());
+		}
+		return false;
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index d1713575036..3546993e17b 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -56,6 +56,7 @@
 		<class>org.olat.upgrade.model.InvitationUpgrade</class>
 		<class>org.olat.upgrade.model.UpgradeTaxonomyLevel</class>
 		<class>org.olat.upgrade.model.UpgradeQuestionItem</class>
+		<class>org.olat.upgrade.model.CurriculumElementPos</class>
 		<!-- End upgraders mapping -->
 
 
diff --git a/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql
index f9b111b7683..2a3e1434960 100644
--- a/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql
+++ b/src/main/resources/database/mysql/alter_13_1_x_to_13_2_0.sql
@@ -66,3 +66,12 @@ alter table o_vid_metadata add vid_url varchar(512);
 alter table o_cur_curriculum_element add c_lectures varchar(16);
 alter table o_cur_element_type add c_lectures varchar(16);
 
+
+-- curriculum element
+alter table o_cur_curriculum_element add pos_cur bigint;
+alter table o_cur_curriculum_element add fk_curriculum_parent bigint;
+alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id);
+
+
+
+
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 6cb21def5ba..28bf0d20d4d 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -2631,6 +2631,7 @@ create table o_cur_curriculum_element (
   creationdate datetime not null,
   lastmodified datetime not null,
   pos bigint,
+  pos_cur bigint,
   c_identifier varchar(64),
   c_displayname varchar(255) not null,
   c_description mediumtext,
@@ -2645,6 +2646,7 @@ create table o_cur_curriculum_element (
   fk_group bigint not null,
   fk_parent bigint,
   fk_curriculum bigint not null,
+  fk_curriculum_parentbigint not null,
   fk_type bigint,
   primary key (id)
 );
diff --git a/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql
index 495a760fcb4..2d23ecee159 100644
--- a/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql
+++ b/src/main/resources/database/oracle/alter_13_1_x_to_13_2_0.sql
@@ -63,3 +63,13 @@ alter table o_vid_metadata add vid_url varchar(512);
 -- lectures
 alter table o_cur_curriculum_element add c_lectures varchar(16);
 alter table o_cur_element_type add c_lectures varchar(16);
+
+
+-- curriculum element
+alter table o_cur_curriculum_element add pos_cur number(20);
+alter table o_cur_curriculum_element add fk_curriculum_parent number(20);
+alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id);
+create index idx_cur_el_to_pcur_idx on o_cur_curriculum_element (fk_curriculum_parent);
+
+
+
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 23d3c0ab8bf..560fa0cc9ed 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -2713,6 +2713,7 @@ create table o_cur_curriculum_element (
   creationdate date not null,
   lastmodified date not null,
   pos number(20),
+  pos_cur number(20),
   c_identifier varchar(64),
   c_displayname varchar(255) not null,
   c_description CLOB,
@@ -2727,6 +2728,7 @@ create table o_cur_curriculum_element (
   fk_group number(20) not null,
   fk_parent number(20),
   fk_curriculum number(20) not null,
+  fk_curriculum_parent number(20),
   fk_type number(20),
   primary key (id)
 );
diff --git a/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql b/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql
index 1719756473b..8917b2f3f81 100644
--- a/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql
+++ b/src/main/resources/database/postgresql/alter_13_1_x_to_13_2_0.sql
@@ -65,3 +65,11 @@ alter table o_cur_curriculum_element add c_lectures varchar(16);
 alter table o_cur_element_type add c_lectures varchar(16);
 
 
+-- curriculum element
+alter table o_cur_curriculum_element add pos_cur int8;
+alter table o_cur_curriculum_element add fk_curriculum_parent int8;
+alter table o_cur_curriculum_element add constraint cur_el_to_pcur_idx foreign key (fk_curriculum_parent) references o_cur_curriculum (id);
+create index idx_cur_el_to_pcur_idx on o_cur_curriculum_element (fk_curriculum_parent);
+
+
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 678cfbb0cc9..3352ab6ae2e 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -2657,6 +2657,7 @@ create table o_cur_curriculum_element (
   creationdate timestamp not null,
   lastmodified timestamp not null,
   pos int8,
+  pos_cur int8,
   c_identifier varchar(64),
   c_displayname varchar(255) not null,
   c_description text,
@@ -2671,6 +2672,7 @@ create table o_cur_curriculum_element (
   fk_group int8 not null,
   fk_parent int8,
   fk_curriculum int8 not null,
+  fk_curriculum_parent int8,
   fk_type int8,
   primary key (id)
 );
diff --git a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
index 24bdbb584a3..2ff51111dbe 100644
--- a/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
+++ b/src/test/java/org/olat/modules/curriculum/manager/CurriculumElementDAOTest.java
@@ -45,6 +45,7 @@ import org.olat.modules.curriculum.CurriculumRoles;
 import org.olat.modules.curriculum.CurriculumService;
 import org.olat.modules.curriculum.model.CurriculumElementImpl;
 import org.olat.modules.curriculum.model.CurriculumElementInfos;
+import org.olat.modules.curriculum.model.CurriculumImpl;
 import org.olat.repository.RepositoryEntry;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
@@ -90,6 +91,42 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 		Assert.assertEquals(type, element.getType());
 	}
 	
+	/**
+	 * Check if the root elements come in curriculum list
+	 */
+	@Test
+	public void createCurriculumElement_rootElement() {
+		Curriculum curriculum = curriculumDao.createAndPersist("Cur-for-el-1", "Curriculum for element", "Curriculum", null);
+		CurriculumElementType type = curriculumElementTypeDao.createCurriculumElementType("typ-for-cur-el-1", "Type for", "First element", "AC-234");
+		CurriculumElement root1 = curriculumElementDao.createCurriculumElement("Element-1", "1. Element", new Date(), new Date(), null,
+				type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		Assert.assertNotNull(root1);
+		dbInstance.commit();
+		curriculum = curriculumDao.loadByKey(curriculum.getKey());
+		CurriculumElement root2 = curriculumElementDao.createCurriculumElement("Element-2", "2. Element", new Date(), new Date(), null,
+				type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commit();
+		curriculum = curriculumDao.loadByKey(curriculum.getKey());
+		CurriculumElement root3 = curriculumElementDao.createCurriculumElement("Element-3", "3. Element", new Date(), new Date(), null,
+				type, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element3_1 = curriculumElementDao.createCurriculumElement("Element-2", "2. Element", new Date(), new Date(), root3,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commitAndCloseSession();
+
+		//check the curriculum to elements list
+		CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey());
+		List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements();
+		Assert.assertEquals(3, rootElements.size());
+		Assert.assertEquals(root1, rootElements.get(0));
+		Assert.assertEquals(root2, rootElements.get(1));
+		Assert.assertEquals(root3, rootElements.get(2));
+		
+		//check the element to elements list
+		List<CurriculumElement> root3Children = curriculumElementDao.getChildren(root3);
+		Assert.assertEquals(1, root3Children.size());
+		Assert.assertEquals(element3_1, root3Children.get(0));
+	}
+	
 	@Test
 	public void loadByKey() {
 		Curriculum curriculum = curriculumDao.createAndPersist("Cur-for-el-2", "Curriculum for element", "Curriculum", null);
@@ -358,7 +395,7 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 	}
 	
 	@Test
-	public void moveCurriculumElement() {
+	public void moveCurriculumElement_elementToOtherElement() {
 		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null);
 		CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-7", "7. Element", null, null, null,
 				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
@@ -375,7 +412,7 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 		dbInstance.commitAndCloseSession();
 		
 		// move element1_1 under element2
-		curriculumElementDao.move(element1_1, element2);
+		curriculumElementDao.move(element1_1, element2, null);
 		dbInstance.commit();
 		
 		// check parent line of element1_1_2
@@ -397,6 +434,177 @@ public class CurriculumElementDAOTest extends OlatTestCase {
 		Assert.assertTrue(descendants1_1.contains(element1_1_2));
 	}
 	
+	@Test
+	public void moveCurriculumElement_underSameElement() {
+		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-8", "Curriculum for element", "Curriculum", null);
+		CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-8", "8. Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-8-1-1", "8.1.1 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-8-1-2", "8.1.2 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_3 = curriculumElementDao.createCurriculumElement("Element-8-1-3", "8.1.3 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_4 = curriculumElementDao.createCurriculumElement("Element-8-1-4", "8.1.4 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_5 = curriculumElementDao.createCurriculumElement("Element-8-1-5", "8.1.5 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commitAndCloseSession();
+		
+		// move element1_1 at third posistion
+		curriculumElementDao.move(element1_2, rootElement, element1_4);
+		dbInstance.commit();
+		
+		CurriculumElementImpl element = (CurriculumElementImpl)curriculumElementDao.loadByKey(rootElement.getKey());
+		List<CurriculumElement> children = element.getChildren();
+		Assert.assertEquals(children.get(0), element1_1);
+		Assert.assertEquals(children.get(1), element1_3);
+		Assert.assertEquals(children.get(2), element1_4);
+		Assert.assertEquals(children.get(3), element1_2);
+		Assert.assertEquals(children.get(4), element1_5);
+	}
+	
+	@Test
+	public void moveCurriculumElement_underSameElement_v2() {
+		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-8", "Curriculum for element", "Curriculum", null);
+		CurriculumElement rootElement = curriculumElementDao.createCurriculumElement("Element-8", "8. Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-8-1-1", "8.1.1 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-8-1-2", "8.1.2 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_3 = curriculumElementDao.createCurriculumElement("Element-8-1-3", "8.1.3 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_4 = curriculumElementDao.createCurriculumElement("Element-8-1-4", "8.1.4 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_5 = curriculumElementDao.createCurriculumElement("Element-8-1-5", "8.1.5 Element", null, null, rootElement,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commitAndCloseSession();
+		
+		// move element1_5 at third position
+		curriculumElementDao.move(element1_5, rootElement, element1_2);
+		dbInstance.commit();
+		
+		CurriculumElementImpl element = (CurriculumElementImpl)curriculumElementDao.loadByKey(rootElement.getKey());
+		List<CurriculumElement> children = element.getChildren();
+		Assert.assertEquals(element1_1, children.get(0));
+		Assert.assertEquals(element1_2, children.get(1));
+		Assert.assertEquals(element1_5, children.get(2));
+		Assert.assertEquals(element1_3, children.get(3));
+		Assert.assertEquals(element1_4, children.get(4));
+	}
+
+	@Test
+	public void moveCurriculumElement_rootElement() {
+		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-", "Curriculum for element", "Curriculum", null);
+
+		CurriculumElement element1 = curriculumElementDao.createCurriculumElement("Element-9-1", "9.1 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element2 = curriculumElementDao.createCurriculumElement("Element-9-2", "9.2 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element3 = curriculumElementDao.createCurriculumElement("Element-9-3", "9.3 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element4 = curriculumElementDao.createCurriculumElement("Element-9-4", "9.4 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element5 = curriculumElementDao.createCurriculumElement("Element-9-5", "9.5 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commitAndCloseSession();
+		
+		// move element1_1 under element2
+		curriculumElementDao.move(element2, null, element4);
+		dbInstance.commit();
+		
+		// check parent line of element1_1_2
+		CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey());
+		List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements();
+		Assert.assertEquals(element1, rootElements.get(0));
+		Assert.assertEquals(element3, rootElements.get(1));
+		Assert.assertEquals(element4, rootElements.get(2));
+		Assert.assertEquals(element2, rootElements.get(3));
+		Assert.assertEquals(element5, rootElements.get(4));
+	}
+	
+	@Test
+	public void moveCurriculumElement_rootToElement() {
+		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null);
+		CurriculumElement rootElement1 = curriculumElementDao.createCurriculumElement("Element-10-1", "10.1 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1", "10.1.1 Element", null, null, rootElement1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1-1", "10.1.1.1 Element", null, null, element1_1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-1-2", "10.1.1.2 Element", null, null, element1_1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-2", "10.1.2 Element", null, null, rootElement1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commit();
+		Assert.assertNotNull(element1_2);
+		
+		curriculum = curriculumDao.loadByKey(curriculum.getKey());
+		CurriculumElement rootElement2 = curriculumElementDao.createCurriculumElement("Element-10-2", "10.2 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commitAndCloseSession();
+		
+		// move element1_1 under element2
+		CurriculumElement reloadedElement1_1 = curriculumElementDao.loadByKey(element1_1.getKey());
+		curriculumElementDao.move(rootElement2, reloadedElement1_1, element1_1_1);
+		dbInstance.commit();
+		
+		// check children element1_1
+		CurriculumElementImpl reloadElement1_1 = (CurriculumElementImpl)curriculumElementDao.loadByKey(element1_1.getKey());
+		List<CurriculumElement> element11children = reloadElement1_1.getChildren();
+		Assert.assertEquals(3, element11children.size());
+		Assert.assertEquals(element1_1_1, element11children.get(0));
+		Assert.assertEquals(rootElement2, element11children.get(1));
+		Assert.assertEquals(element1_1_2, element11children.get(2));
+		
+		
+		// check children curriculum
+		CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey());
+		List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements();
+		Assert.assertEquals(1, rootElements.size());
+		Assert.assertEquals(rootElement1, rootElements.get(0));
+	}
+	
+	@Test
+	public void moveCurriculumElement_elementToRoot() {
+		Curriculum curriculum = curriculumDao.createAndPersist("cur-for-el-7", "Curriculum for element", "Curriculum", null);
+		CurriculumElement rootElement1 = curriculumElementDao.createCurriculumElement("Element-10-1", "10.1 Element", null, null, null,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1", "10.1.1 Element", null, null, rootElement1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1_1 = curriculumElementDao.createCurriculumElement("Element-10-1-1-1", "10.1.1.1 Element", null, null, element1_1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1_2 = curriculumElementDao.createCurriculumElement("Element-10-1-1-2", "10.1.1.2 Element", null, null, element1_1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		CurriculumElement element1_1_3 = curriculumElementDao.createCurriculumElement("Element-10-1-1-3", "10.1.1.3 Element", null, null, element1_1,
+				null, CurriculumCalendars.disabled, CurriculumLectures.disabled, curriculum);
+		dbInstance.commit();
+
+		
+		// move element1_1 under element2
+		CurriculumElement reloadedElement1_1_3 = curriculumElementDao.loadByKey(element1_1_3.getKey());
+		curriculumElementDao.move(reloadedElement1_1_3, null, rootElement1);
+		dbInstance.commit();
+		
+		// check children element1_1
+		CurriculumElementImpl reloadElement1_1 = (CurriculumElementImpl)curriculumElementDao.loadByKey(element1_1.getKey());
+		List<CurriculumElement> element11children = reloadElement1_1.getChildren();
+		Assert.assertEquals(2, element11children.size());
+		Assert.assertEquals(element1_1_1, element11children.get(0));
+		Assert.assertEquals(element1_1_2, element11children.get(1));
+		
+		
+		// check children curriculum
+		CurriculumImpl reloadedCurriculum = (CurriculumImpl)curriculumDao.loadByKey(curriculum.getKey());
+		List<CurriculumElement> rootElements = reloadedCurriculum.getRootElements();
+		Assert.assertEquals(2, rootElements.size());
+		Assert.assertEquals(rootElement1, rootElements.get(0));
+		Assert.assertEquals(element1_1_3, rootElements.get(1));
+	}
+	
+	
+	
 	@Test
 	public void getMembersIdentity() {
 		Identity supervisor = JunitTestHelper.createAndPersistIdentityAsRndUser("cur-supervisor-1");
-- 
GitLab