From 37081f17d565eb0e0cc73f8f04b9fd9cb25c5e60 Mon Sep 17 00:00:00 2001
From: Simon Barner <barner@fortiss.org>
Date: Tue, 2 Sep 2014 12:47:00 +0000
Subject: [PATCH] - Add comparator that sorts rows according to hierarchy
 level. Elements within one hierarchy level are sorted by name. refs 1841

---
 .../view/GenericAnnotationView.java           | 100 ++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java
index a8ddfe832..3ad0201e5 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/GenericAnnotationView.java
@@ -21,19 +21,24 @@ import java.util.Collection;
 import java.util.Set;
 import java.util.TreeSet;
 
+import org.eclipse.emf.ecore.EObject;
 import org.eclipse.jface.viewers.ArrayContentProvider;
 import org.eclipse.jface.viewers.EditingSupport;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
+import org.fortiss.tooling.base.model.element.IModelElement;
 import org.fortiss.tooling.base.ui.annotation.AnnotationEntry;
 import org.fortiss.tooling.base.ui.annotation.editingsupport.ElementNameEditingSupport;
 import org.fortiss.tooling.base.ui.annotation.valueprovider.IAnnotationValueProvider;
+import org.fortiss.tooling.kernel.model.INamedElement;
 
 /**
  * <p>
@@ -178,6 +183,99 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
 		}
 	}
 
+	/**
+	 * Comparator that sorts rows according to hierarchy level. Elements within one hierarchy level
+	 * are sorted by name.
+	 */
+	private class HierarchicalNameComparator extends ViewerComparator {
+
+		/** Computes the level of an {@link IModelElement} in the tree */
+		private int getLevel(EObject o) {
+			int level = 0;
+			while(o.eContainer() != null) {
+				level++;
+				o = o.eContainer();
+			}
+
+			return level;
+		}
+
+		/**
+		 * Returns the ancestor of the {@link IModelElement} {@code modelElement} that is
+		 * {@code levelsUp} levels above model element in the hierarchy, or {@code null}, in case
+		 * {@code levelsUp} > depth(modelElement}.
+		 */
+		private EObject getAncestor(EObject o, int levelsUp) {
+			while(o.eContainer() != null && levelsUp > 0) {
+				o = o.eContainer();
+				levelsUp--;
+			}
+			return o;
+
+		}
+
+		/** {@inheritDoc} */
+		@Override
+		public int compare(Viewer viewer, Object o1, Object o2) {
+			if(o1 instanceof AnnotationEntry && o2 instanceof AnnotationEntry) {
+				IModelElement modelElement1 = ((AnnotationEntry)o1).getModelElement();
+				IModelElement modelElement2 = ((AnnotationEntry)o2).getModelElement();
+				int modelElement1Level = getLevel(modelElement1);
+				int modelElement2Level = getLevel(modelElement2);
+
+				EObject e1 = modelElement1;
+				EObject e2 = modelElement2;
+
+				if(modelElement1Level < modelElement2Level) {
+					// Element1 is higher than element2: Get ancestor of element2 that is at the
+					// level as the element1.
+					EObject ancestor =
+							getAncestor(modelElement2, modelElement2Level - modelElement1Level);
+
+					if(modelElement1 == ancestor) {
+						// Element1 is offspring of element2
+						return -1;
+					}
+
+					// Further comparison starts on elements at the same level
+					e2 = ancestor;
+				} else if(modelElement1Level > modelElement2Level) {
+					// Element2 is higher than element1: Get ancestor of element1 that is at the
+					// level as the element2.
+					EObject ancestor =
+							getAncestor(modelElement1, modelElement1Level - modelElement2Level);
+
+					if(modelElement2 == ancestor) {
+						// Element2 is offspring of element1
+						return 1;
+					}
+
+					// Further comparison starts on elements at the same level
+					e1 = ancestor;
+				}
+				// Find direct children of common root element of element1 and element2...
+				do {
+					if(e1.eContainer() == e2.eContainer()) {
+						break;
+					}
+					e1 = e1.eContainer();
+					e2 = e2.eContainer();
+				} while(true);
+
+				// ... and compare them by name...
+				if(e1 instanceof INamedElement && e2 instanceof INamedElement) {
+					// Elements are at the same level -> compare by name
+					return(((INamedElement)e1).getName().compareTo(((INamedElement)e2).getName()));
+				}
+			}
+
+			// ... or hash code (as a fallback ordering)
+			// int Integer.compare(int x, int y) requires JDK 1.7 which is not available
+			// on the build server
+			return new Integer(o1.hashCode()).compareTo(o2.hashCode());
+		}
+	}
+
 	/** {@inheritDoc} */
 	@Override
 	protected void update(Collection<AnnotationEntry> annotationEntries) {
@@ -249,6 +347,8 @@ public class GenericAnnotationView extends AnnotationViewPartBase {
 		table.setLinesVisible(true);
 
 		createModelElementColumn();
+
+		tableViewer.setComparator(new HierarchicalNameComparator());
 	}
 
 	/** Creates the (leading) column which displays the model elements */
-- 
GitLab