package org.simantics.modeling.requests; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Deque; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.function.Predicate; import org.eclipse.jface.viewers.IFilter; import org.simantics.scl.runtime.function.Function1; /** * @author Tuukka Lehtonen */ public class Nodes { public static final Predicate DIAGRAM_RESOURCE_PREDICATE = n -> n.getDiagramResource() != null; public static final Predicate DIAGRAM_RESOURCE_AND_RVI_PREDICATE = n -> n.getDiagramResource() != null && n.getRVI() != null; public static Collection breadthFirstFlatten(IFilter filter, Collection roots) { Collection result = new ArrayList<>(); List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots); Deque todo = new ArrayDeque<>(sortedRoots); while (!todo.isEmpty()) { Node n = todo.removeFirst(); List sorted = new ArrayList<>(n.getChildren()); Collections.sort(sorted); todo.addAll(sorted); if (filter == null || filter.select(n)) result.add(n); } return result; } public static Collection depthFirstFlatten(IFilter filter, Collection roots, Comparator comparator) { Collection result = new ArrayList<>(); List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots, comparator); for (Node n : sortedRoots) { depthFirstFlattenRec(filter, comparator, n, result); } return result; } private static Collection depthFirstFlattenRec(IFilter filter, Comparator comparator, Node n, Collection result) { if (filter == null || filter.select(n)) result.add(n); Collection children = n.getChildren(); if (children.isEmpty()) return result; List sorted = new ArrayList<>(children); Collections.sort(sorted, comparator); for (Node child : sorted) depthFirstFlattenRec(filter, comparator, child, result); return result; } /** * @param f * function that takes the walked Node as argument and returns a * boolean to describe whether to continue the walk or cancel the * walk. The returned value cannot be null. * @return true if the walk was completed or false * if the walk was cancelled */ public static boolean walkTree(Function1 filter, Collection roots) { List sortedRoots = new ArrayList<>(roots); Collections.sort(sortedRoots); for (Node n : sortedRoots) if (!walkTreeRec(filter, n)) return false; return true; } private static boolean walkTreeRec(Function1 filter, Node n) { if (!filter.apply(n)) return false; Collection children = n.getChildren(); if (!children.isEmpty()) { List sorted = new ArrayList<>(children); Collections.sort(sorted); for (Node child : sorted) if (!walkTreeRec(filter, child)) return false; } return true; } public static boolean parentIsInSet(Set set, Node node) { for (Node n = node.getParent(); n != null; n = n.getParent()) if (set.contains(n)) return true; return false; } public static Set depthFirstFilter(Predicate filter, Collection nodes) { Set result = new TreeSet<>(Node.CASE_INSENSITIVE_COMPARATOR); for (Node n : nodes) { Node newNode = depthFirstFilterRec(filter, n, null); if (newNode != null) result.add(newNode); } return result; } public static Node depthFirstFilter(Predicate filter, Node n) { return depthFirstFilterRec(filter, n, null); } private static Node depthFirstFilterRec(Predicate filter, Node n, Node newParent) { Collection children = n.getChildren(); if (children.isEmpty()) return filter.test(n) ? n.cloneWithoutChildren(newParent) : null; Node newNode = n.cloneWithoutChildren(newParent); int childCount = 0; for (Node child : children) { Node newChild = depthFirstFilterRec(filter, child, newNode); if (newChild != null) ++childCount; } return childCount > 0 ? newNode : null; } }