--- /dev/null
+package org.simantics.modeling.requests;\r
+\r
+import java.util.ArrayDeque;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.Deque;\r
+import java.util.List;\r
+\r
+import org.eclipse.jface.viewers.IFilter;\r
+import org.simantics.scl.runtime.function.Function1;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class Nodes {\r
+\r
+ public static Collection<Node> breadthFirstFlatten(IFilter filter, Collection<Node> roots) {\r
+ Collection<Node> result = new ArrayList<Node>();\r
+ List<Node> sortedRoots = new ArrayList<Node>(roots);\r
+ Collections.sort(sortedRoots);\r
+ Deque<Node> todo = new ArrayDeque<Node>(sortedRoots);\r
+ while (!todo.isEmpty()) {\r
+ Node n = todo.removeFirst();\r
+ List<Node> sorted = new ArrayList<Node>(n.getChildren());\r
+ Collections.sort(sorted);\r
+ todo.addAll(sorted);\r
+ if (filter == null || filter.select(n))\r
+ result.add(n);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ public static Collection<Node> depthFirstFlatten(IFilter filter, Collection<Node> roots, Comparator<? super Node> comparator) {\r
+ Collection<Node> result = new ArrayList<Node>();\r
+ List<Node> sortedRoots = new ArrayList<Node>(roots);\r
+ Collections.sort(sortedRoots, comparator);\r
+ for (Node n : sortedRoots) {\r
+ depthFirstFlattenRec(filter, comparator, n, result);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private static Collection<Node> depthFirstFlattenRec(IFilter filter, Comparator<? super Node> comparator, Node n, Collection<Node> result) {\r
+ if (filter == null || filter.select(n))\r
+ result.add(n);\r
+\r
+ Collection<Node> children = n.getChildren();\r
+ if (children.isEmpty())\r
+ return result;\r
+\r
+ List<Node> sorted = new ArrayList<Node>(children);\r
+ Collections.sort(sorted, comparator);\r
+ for (Node child : sorted)\r
+ depthFirstFlattenRec(filter, comparator, child, result);\r
+\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * @param f\r
+ * function that takes the walked Node as argument and returns a\r
+ * boolean to describe whether to continue the walk or cancel the\r
+ * walk. The returned value cannot be <code>null</code>.\r
+ * @return <code>true</code> if the walk was completed or <code>false</code>\r
+ * if the walk was cancelled\r
+ */\r
+ public static boolean walkTree(Function1<Node, Boolean> filter, Collection<Node> roots) {\r
+ List<Node> sortedRoots = new ArrayList<Node>(roots);\r
+ Collections.sort(sortedRoots);\r
+ for (Node n : sortedRoots)\r
+ if (!walkTreeRec(filter, n))\r
+ return false;\r
+ return true;\r
+ }\r
+\r
+ private static boolean walkTreeRec(Function1<Node, Boolean> filter, Node n) {\r
+ if (!filter.apply(n))\r
+ return false;\r
+\r
+ Collection<Node> children = n.getChildren();\r
+ if (!children.isEmpty()) {\r
+ List<Node> sorted = new ArrayList<Node>(children);\r
+ Collections.sort(sorted);\r
+ for (Node child : sorted)\r
+ if (!walkTreeRec(filter, child))\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+}\r