From 3a64ff8f8fe1548fed89bde37a90eb6cacc24be5 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Sat, 11 Aug 2018 17:33:09 +0200
Subject: [PATCH] OO-3286: improve the sort algorithm like in the curriculum
 tree table

---
 .../ui/CurriculumElementListController.java   |   3 +
 .../ui/CurriculumElementWithViewsRow.java     |  44 ++++-
 .../ui/_content/curriculum_element_row.html   |   4 +-
 .../CurriculumElementViewsRowComparator.java  | 175 +++++++++---------
 4 files changed, 135 insertions(+), 91 deletions(-)

diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementListController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementListController.java
index 7a8ea41ca84..4acb1dffc52 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementListController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementListController.java
@@ -175,6 +175,8 @@ public class CurriculumElementListController extends FormBasicController impleme
 		VelocityContainer row = createVelocityContainer("curriculum_element_row");
 		row.setDomReplacementWrapperRequired(false); // sets its own DOM id in velocity container
 		tableEl.setRowRenderer(row, this);
+		
+		tableEl.setAndLoadPersistedPreferences(ureq, "my-curriculum-elements-" + curriculum.getKey());
 	}
 
 	@Override
@@ -270,6 +272,7 @@ public class CurriculumElementListController extends FormBasicController impleme
 		});
 		
 		Collections.sort(rows, new CurriculumElementViewsRowComparator(getLocale()));
+		
 		removeByPermissions(rows);
 		removeDeactivated(rows);
 
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementWithViewsRow.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementWithViewsRow.java
index fa277a342cb..635983501e5 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementWithViewsRow.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementWithViewsRow.java
@@ -135,10 +135,18 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
 		return repositoryEntry == null || singleEntry ? element.getIdentifier() : null;
 	}
 	
+	public String getCurriculumElementExternalId() {
+		return element == null ? null : element.getExternalId();
+	}
+	
 	public String getCurriculumElementDisplayName() {
 		return repositoryEntry == null || singleEntry ? element.getDisplayName() : null;
 	}
 	
+	public Long getCurriculumElementKey() {
+		return element == null ? null : element.getKey();
+	}
+	
 	public Date getCurriculumElementBeginDate() {
 		return element == null ? null : element.getBeginDate();
 	}
@@ -147,11 +155,21 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
 		return element == null ? null : element.getEndDate();
 	}
 	
-	public long getPosition() {
-		if(this.isRepositoryEntryOnly()) {
-			return -1l;
+	public Long getCurriculumElementPos() {
+		return element == null ? null : element.getPos();
+	}
+	
+	public String getExternalId() {
+		if(element != null && repositoryEntry != null) {
+			return element.getExternalId() + " " + repositoryEntry.getExternalId();
+		}
+		if(element != null && repositoryEntry == null) {
+			return element.getExternalId();
 		}
-		return element == null ? -1l : element.getPos();
+		if(element == null && repositoryEntry != null) {
+			return repositoryEntry.getExternalId();
+		}
+		return null;
 	}
 	
 	public String getMaterializedPathKeys() {
@@ -406,8 +424,24 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
 		if(obj instanceof CurriculumElementWithViewsRow) {
 			CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow)obj;
 			return ((element == null && row.element == null) || (element != null && element.getKey().equals(row.element.getKey())))
-					&& ((repositoryEntry == null && row.repositoryEntry == null) || (repositoryEntry != null && repositoryEntry.getKey().equals(row.repositoryEntry.getKey())));
+					&& ((repositoryEntry == null && row.repositoryEntry == null)
+							|| (repositoryEntry != null && row.repositoryEntry != null && repositoryEntry.getKey().equals(row.repositoryEntry.getKey())));
 		}
 		return false;
 	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		if(isCurriculumElementOnly()) {
+			sb.append("element[key").append(element.getKey()).append(":identifier=").append(element.getIdentifier()).append("]");
+		} else if(isRepositoryEntryOnly()) {
+			sb.append("repositoryEntry[key").append(repositoryEntry.getKey()).append(":identifier=").append(repositoryEntry.getExternalRef()).append("]");
+		} else if(isCurriculumElementWithEntry()) {
+			sb.append("composite[key").append(element.getKey()).append(":identifier=").append(element.getIdentifier()).append("]")
+			  .append("entry[key").append(repositoryEntry.getKey()).append(":identifier=").append(repositoryEntry.getExternalRef()).append("]");
+		}
+		
+		return sb.toString();
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/ui/_content/curriculum_element_row.html b/src/main/java/org/olat/modules/curriculum/ui/_content/curriculum_element_row.html
index c1137219e95..8077dccdcbd 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/_content/curriculum_element_row.html
+++ b/src/main/java/org/olat/modules/curriculum/ui/_content/curriculum_element_row.html
@@ -6,6 +6,7 @@
 			<i class=" o_icon o_icon_start o_icon-lg"></i>
 		</div>
 		<h4 class="o_title">$r.escapeHtml($row.curriculumElementDisplayName) <small>$r.escapeHtml($row.curriculumElementIdentifier)</small></h4>
+		## <h5><small>$row.externalId</small></h5>
 		
 		#if($row.curriculumElementBeginDate || $row.curriculumElementEndDate)
 			<div class="o_lifecycle #if ($row.isActive()) o_active #end">
@@ -37,7 +38,8 @@
 			#if(${row.isCurriculumElementWithEntry()})
 				<h5 class="o_title">$r.escapeHtml($row.curriculumElementDisplayName) <small>$r.escapeHtml($row.curriculumElementIdentifier)</small></h5>
 			#end
-			<h4 class="o_title">$r.render($row.getSelectLinkName()) <small>$r.escapeHtml($row.repositoryEntryExternalRef)</small></h4>
+			<h4 class="o_title">$r.render($row.getSelectLinkName()) <small>$r.escapeHtml($row.repositoryEntryExternalRef)</small>
+			## <h5><small>$row.externalId</small></h4></h5>
 
 			#if($row.authors && !$row.authors.empty)
 				<div class="o_author"><span class="text-muted">$r.translate("course.made.by")</span> $r.escapeHtml($row.authors)</div>
diff --git a/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumElementViewsRowComparator.java b/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumElementViewsRowComparator.java
index cfbf1210515..28d0469cca3 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumElementViewsRowComparator.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumElementViewsRowComparator.java
@@ -20,13 +20,10 @@
 package org.olat.modules.curriculum.ui.component;
 
 import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
 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.CurriculumElementWithViewsRow;
 
 /**
@@ -37,7 +34,7 @@ import org.olat.modules.curriculum.ui.CurriculumElementWithViewsRow;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CurriculumElementViewsRowComparator implements Comparator<CurriculumElementWithViewsRow > {
+public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator {
 
 	private final Collator collator;
 	
@@ -46,97 +43,121 @@ public class CurriculumElementViewsRowComparator implements Comparator<Curriculu
 	}
 
 	@Override
-	public int compare(CurriculumElementWithViewsRow element1, CurriculumElementWithViewsRow element2) {
-		int c = 0;
+	protected int compareNodes(FlexiTreeTableNode o1, FlexiTreeTableNode o2) {
+		if(o1 == null || o2 == null) {
+			return compareNullObjects(o1, o2);
+		}
+		
+		CurriculumElementWithViewsRow c1 = (CurriculumElementWithViewsRow)o1;
+		CurriculumElementWithViewsRow c2 = (CurriculumElementWithViewsRow)o2;
+		Long parentKey1 = c1.getParentKey();
+		Long parentKey2 = c2.getParentKey();
 		
-		List<CurriculumElementWithViewsRow> parents1 = getParentLine(element1);
-		List<CurriculumElementWithViewsRow> parents2 = getParentLine(element2);
-		if(parents1.size() == parents2.size()) {
-			c = compareParents(element1, element2);
-		} else if(parents1.size() > parents2.size()) {
-			int sharedLevel = parents2.size() - 1;
-			c = compareParents(parents1.get(sharedLevel), parents2.get(sharedLevel));
-		} else if(parents1.size() < parents2.size()) {
-			int sharedLevel = parents1.size() - 1;
-			c = compareParents(parents1.get(sharedLevel), parents2.get(sharedLevel));
+		int c = 0;
+		if(parentKey1 == null && parentKey2 == null) {
+			c = compareCurriculumElements(c1, c2);
+		} else if(parentKey1 != null && parentKey1.equals(parentKey2)) {
+			c = compareSameParent(c1, c2);
+		} else if(parentKey1 != null && parentKey2 != null) {
+			// This case is usually not possible
+			CurriculumElementWithViewsRow p1 = c1.getParent();
+			CurriculumElementWithViewsRow p2 = c2.getParent();
+			c = compareCurriculumElements(p1, p2);
+		} else {
+			// This case is usually not possible
+			c = compareDisplayName(c1, c2);
 		}
 		
 		if(c == 0) {
-			c = element1.getKey().compareTo(element2.getKey());
+			c = Long.compare(c1.getKey().longValue(), c2.getKey().longValue());
 		}
 		return c;
 	}
 	
-	private List<CurriculumElementWithViewsRow> getParentLine(CurriculumElementWithViewsRow row) {
-		List<CurriculumElementWithViewsRow> parentLine = new ArrayList<>();
-		for(CurriculumElementWithViewsRow view=row; view != null; view=view.getParent()) {
-			parentLine.add(view);
-		}
-		if(parentLine.size() > 1) {
-			Collections.reverse(parentLine);
-		}
-		return parentLine;
-	}
-
-	private int compareParents(CurriculumElementWithViewsRow element1, CurriculumElementWithViewsRow element2) {
-		CurriculumElementWithViewsRow parent1 = element1.getParent();
-		CurriculumElementWithViewsRow parent2 = element2.getParent();
-		
+	private int compareSameParent(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) {
 		int c = 0;
-		// root
-		if(parent1 == null && parent2 == null) {
-			c = compareRows(element1, element2);
-		} else if(parent1.equals(parent2)) {
-			c = compareRows(element1, element2);
+		if((c1.isCurriculumElementOnly() || c1.isCurriculumElementWithEntry()) && (c2.isCurriculumElementOnly() || c2.isCurriculumElementWithEntry())) {
+			// compare by position
+			Long pos1 = c1.getCurriculumElementPos();
+			Long pos2 = c2.getCurriculumElementPos();
+			if(pos1 == null || pos2 == null) {
+				c = compareNullObjects(pos1, pos2);
+			} else {
+				c = Long.compare(pos1.longValue(), pos2.longValue());
+			}	
+		} else if(c1.isCurriculumElementOnly() || c1.isCurriculumElementWithEntry()) {
+			c = 1;
+		} else if(c2.isCurriculumElementOnly() || c2.isCurriculumElementWithEntry()) {
+			c = -1;
 		} else {
-			c = compareParents(parent1, parent2);
-		}
-		return c;
-	}
-	
-	private int compareRows(CurriculumElementWithViewsRow element1, CurriculumElementWithViewsRow element2) {
-		Date start1 = getStartDate(element1);
-		Date start2 = getStartDate(element2);
-		int c = compareDates(start1, start2);
-		if(c == 0) {
-			String display1 = getDisplayName(element1);
-			String display2 = getDisplayName(element2);
-			c = compareStrings(display1, display2); 
+			c = compareRepositoryEntry(c1, c2);
 		}
 		return c;
 	}
 	
-	private int compareStrings(String d1, String d2) {
+	private int compareCurriculumElements(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) {
 		int c = 0;
-		if(d1 == null || d2 == null) {
-			c = compareNulls(d1, d2);
+		if(c1.getCurriculumElementBeginDate() == null || c2.getCurriculumElementBeginDate() == null) {
+			c = compareNullObjects(c1.getCurriculumElementBeginDate(), c2.getCurriculumElementBeginDate());
 		} else {
-			c = collator.compare(d1, d2);
+			c = c1.getCurriculumElementBeginDate().compareTo(c2.getCurriculumElementBeginDate());
+		}
+		
+		if(c == 0) {
+			if(c1.getCurriculumElementDisplayName() == null || c2.getCurriculumElementDisplayName() == null) {
+				c = compareNullObjects(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName());
+			} else {
+				c = collator.compare(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName());
+			}
+		}
+		
+		if(c == 0) {
+			if(c1.getCurriculumElementIdentifier() == null || c2.getCurriculumElementIdentifier() == null) {
+				c = compareNullObjects(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier());
+			} else {
+				c = collator.compare(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier());
+			}
+		}
+		
+		if(c == 0) {
+			c = Long.compare(c1.getCurriculumElementKey().longValue(), c2.getCurriculumElementKey().longValue());
 		}
 		return c;
 	}
 	
-	private int compareDates(Date d1, Date d2) {
+	private int compareRepositoryEntry(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) {
 		int c = 0;
-		if(d1 == null || d2 == null) {
-			c = compareNulls(d1, d2);
+		if(c1.getRepositoryEntryDisplayName() == null || c2.getRepositoryEntryDisplayName() == null) {
+			c = compareNullObjects(c1.getRepositoryEntryDisplayName(), c2.getRepositoryEntryDisplayName());
 		} else {
-			c = d1.compareTo(d2);
+			c = collator.compare(c1.getRepositoryEntryDisplayName(), c2.getRepositoryEntryDisplayName());
+		}
+		
+		if(c == 0) {
+			if(c1.getRepositoryEntryExternalRef() == null || c2.getRepositoryEntryExternalRef() == null) {
+				c = compareNullObjects(c1.getRepositoryEntryExternalRef(), c2.getRepositoryEntryExternalRef());
+			} else {
+				c = collator.compare(c1.getRepositoryEntryExternalRef(), c2.getRepositoryEntryExternalRef());
+			}
+		}
+		
+		if(c == 0) {
+			c = Long.compare(c1.getRepositoryEntryKey().longValue(), c2.getRepositoryEntryKey().longValue());
 		}
 		return c;
 	}
 	
-	private int compareNulls(Object o1, Object o2) {
-		if(o1 == null && o2 == null) {
-			return 0;
-		} 
-		if(o1 == null) {
-			return -1;
+	private int compareDisplayName(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) {
+		String d1 = getDisplayName(c1);
+		String d2 = getDisplayName(c2);
+		if(d1 == null || d2 == null) {
+			return compareNullObjects(d1, d2);
 		}
-		if( o2 == null) {
-			return 1;
+		int c = d1.compareTo(d2);
+		if(c == 0) {
+			
 		}
-		return 0;
+		return c;
 	}
 	
 	private String getDisplayName(CurriculumElementWithViewsRow row) {
@@ -152,20 +173,4 @@ public class CurriculumElementViewsRowComparator implements Comparator<Curriculu
 		}
 		return d;
 	}
-	
-	private Date getStartDate(CurriculumElementWithViewsRow row) {
-		if(row.isCurriculumElementOnly()) {
-			return row.getCurriculumElementBeginDate();
-		}
-		if(row.isRepositoryEntryOnly()) {
-			return row.getLifecycleStart();
-		}
-		Date d = row.getLifecycleStart();
-		if(d == null) {
-			d = row.getCurriculumElementBeginDate();
-		} else if(row.getCurriculumElementBeginDate() != null && d.after(row.getCurriculumElementBeginDate())) {
-			d = row.getCurriculumElementBeginDate();
-		}
-		return d;
-	}
 }
\ No newline at end of file
-- 
GitLab