Improve sorting of FileDiffs

Change FileDiff.PATH_COMPARATOR to group files by directory. Give the
CommitFileDiffViewer a ViewerComparator using PATH_COMPARATOR.

As a result, FileDiffs are grouped by directory, and the order of
diffs in the DifFEditorPage agrees with the order in the
DifFEditorOutlinePage.

Change-Id: I14e1b5bece5579a87277ac4dda8ad077da86b0eb
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorPage.java
index fe72318..96de4a0 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorPage.java
@@ -17,7 +17,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -547,8 +547,9 @@
 					.addAll(asList(new RepositoryCommit(commit.getRepository(),
 							untrackedCommit).getDiffs()));
 		}
-		Collections.sort(diffResult, FileDiff.PATH_COMPARATOR);
-		return diffResult.toArray(new FileDiff[diffResult.size()]);
+		FileDiff[] result = diffResult.toArray(new FileDiff[diffResult.size()]);
+		Arrays.sort(result, FileDiff.PATH_COMPARATOR);
+		return result;
 	}
 
 	/**
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/StashEditorPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/StashEditorPage.java
index fb8430b..2ff1f51 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/StashEditorPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/StashEditorPage.java
@@ -12,7 +12,6 @@
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -155,7 +154,8 @@
 					.getRepository(), stagedCommit).getDiffs();
 			stagedDiffsResult.addAll(asList(stagedDiffs));
 		}
-		return stagedDiffsResult.toArray(new FileDiff[0]);
+		return stagedDiffsResult
+				.toArray(new FileDiff[stagedDiffsResult.size()]);
 	}
 
 	/**
@@ -178,9 +178,7 @@
 			unstagedDiffs.addAll(asList(untrackedDiffs));
 		}
 
-		Collections.sort(unstagedDiffs, FileDiff.PATH_COMPARATOR);
-
-		return unstagedDiffs.toArray(new FileDiff[0]);
+		return unstagedDiffs.toArray(new FileDiff[unstagedDiffs.size()]);
 	}
 
 	private void fillStagedDiffs(FileDiff[] diffs) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java
index a48a58b..d687d18 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitFileDiffViewer.java
@@ -54,6 +54,8 @@
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
 import org.eclipse.jgit.annotations.NonNull;
 import org.eclipse.jgit.diff.DiffEntry;
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
@@ -157,6 +159,17 @@
 
 		setLabelProvider(new FileDiffLabelProvider(dimmedForegroundRgb));
 		setContentProvider(new FileDiffContentProvider());
+		setComparator(new ViewerComparator() {
+
+			@Override
+			public int compare(Viewer viewer, Object left, Object right) {
+				if (left instanceof FileDiff && right instanceof FileDiff) {
+					return FileDiff.PATH_COMPARATOR.compare((FileDiff) left,
+							(FileDiff) right);
+				}
+				return super.compare(viewer, left, right);
+			}
+		});
 		addOpenListener(new IOpenListener() {
 			@Override
 			public void open(final OpenEvent event) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiff.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiff.java
index 29220d6..cc177f7 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiff.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/FileDiff.java
@@ -56,12 +56,23 @@
 public class FileDiff extends WorkbenchAdapter {
 
 	/**
-	 * Comparator for sorting FileDiffs based on getPath().
+	 * Comparator for sorting FileDiffs based on getPath(). Compares first the
+	 * directory part, if those are equal, the filename part.
 	 */
 	public static final Comparator<FileDiff> PATH_COMPARATOR = new Comparator<FileDiff>() {
+
 		@Override
-		public int compare(FileDiff o1, FileDiff o2) {
-			return o1.getPath().compareTo(o2.getPath());
+		public int compare(FileDiff left, FileDiff right) {
+			String leftPath = left.getPath();
+			String rightPath = right.getPath();
+			int i = leftPath.lastIndexOf('/');
+			int j = rightPath.lastIndexOf('/');
+			int p = leftPath.substring(0, i + 1)
+					.compareTo(rightPath.substring(0, j + 1));
+			if (p != 0) {
+				return p;
+			}
+			return leftPath.compareTo(rightPath);
 		}
 	};