tmf: Bug 570930: Unordered entries in BaseDataProviderTimeGraphView

Insert new entries and orphaned entries at their correct position in the
child list of their parent entry.

Change-Id: I065eb6f295ed3ffec47a22b7c6bfea6d45576570
Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/175817
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
index 4b5478d..1e8e380 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
@@ -19,6 +19,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiFunction;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -205,6 +206,7 @@
                      * families at the end
                      */
                     List<TimeGraphEntry> orphaned = new ArrayList<>();
+                    Map<Long, AtomicInteger> indexMap = new HashMap<>();
                     for (TimeGraphEntryModel entry : model.getEntries()) {
                         TimeGraphEntry uiEntry = fScopedEntries.get(scope, entry.getId());
                         if (entry.getParentId() != -1) {
@@ -213,12 +215,14 @@
                                 TimeGraphEntry parent = fScopedEntries.get(scope, entry.getParentId());
                                 if (parent != null) {
                                     // TODO: the order of children from different data providers is undefined
-                                    parent.addChild(uiEntry);
+                                    int index = indexMap.computeIfAbsent(entry.getParentId(), l -> new AtomicInteger()).getAndIncrement();
+                                    parent.addChild(index, uiEntry);
                                 } else {
                                     orphaned.add(uiEntry);
                                 }
                                 fScopedEntries.put(scope, entry.getId(), uiEntry);
                             } else {
+                                indexMap.computeIfAbsent(entry.getParentId(), l -> new AtomicInteger()).getAndIncrement();
                                 uiEntry.updateModel(entry);
                             }
                         } else {
@@ -241,10 +245,13 @@
                         fEntryIds.put(uiEntry, dataProvider, entry.getId());
                     }
                     // Find missing parents
+                    // Orphans should be inserted before non-orphans
+                    indexMap.clear();
                     for (TimeGraphEntry orphanedEntry : orphaned) {
                         TimeGraphEntry parent = fScopedEntries.get(scope, orphanedEntry.getEntryModel().getParentId());
                         if (parent != null) {
-                            parent.addChild(orphanedEntry);
+                            int index = indexMap.computeIfAbsent(parent.getEntryModel().getId(), l -> new AtomicInteger()).getAndIncrement();
+                            parent.addChild(index, orphanedEntry);
                         }
                     }
                 }