Bug 578643 - visual stable Sort Order in Progress View

never let a new job pop up above an already shown one.

Change-Id: Ife1d803ceaae857f199179fbfd4b255c6843778d
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.ui/+/190578
Tested-by: Platform Bot <platform-bot@eclipse.org>
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManagerUtil.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManagerUtil.java
index 6e912c5..8256270 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManagerUtil.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManagerUtil.java
@@ -18,6 +18,8 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.QualifiedName;
 import org.eclipse.core.runtime.jobs.Job;
@@ -49,6 +51,10 @@
 public class ProgressManagerUtil {
 
 	static class ProgressViewerComparator extends ViewerComparator {
+		private final HashMap<Object, Integer> lastIndexes = new HashMap<>();
+		private final Comparator<Object> byIndex = Comparator.comparing(lastIndexes::get,
+				Comparator.nullsLast(Integer::compare)); // makes visual sort order stable
+
 		@Override
 		@SuppressWarnings({ "rawtypes", "unchecked" })
 		public int compare(Viewer testViewer, Object e1, Object e2) {
@@ -60,18 +66,18 @@
 			/*
 			 * https://bugs.eclipse.org/371354
 			 *
-			 * This ordering is inherently unstable, since it relies on modifiable
-			 * properties of the elements: E.g. the default implementation in JobTreeElement
-			 * compares getDisplayString(), many of whose implementations use
-			 * getPercentDone().
-			 *
 			 * JavaSE 7+'s TimSort introduced a breaking change: It now throws a new
 			 * IllegalArgumentException for bad comparators. Workaround is to retry a few
 			 * times.
 			 */
 			for (int retries = 3; retries > 0; retries--) {
 				try {
-					Arrays.sort(elements, (a, b) -> ProgressViewerComparator.this.compare(viewer, a, b));
+					Arrays.sort(elements,
+							byIndex.thenComparing((a, b) -> ProgressViewerComparator.this.compare(viewer, a, b)));
+					lastIndexes.clear();
+					for (int i = 0; i < elements.length; i++) {
+						lastIndexes.put(elements[i], i);
+					}
 					return; // success
 				} catch (IllegalArgumentException e) {
 					// retry