/** * Adds a path to this ParentOMatic and marks it. This might result in changes in tree that * actually tries to "optimize" the markings, and it may result in tree where the currently added * and marked path is not marked, but it's some parent is. */ public void addAndMarkPath(final String path) { final Node<Payload> currentNode = addPath(path, false); // rule A: unmark children if any if (applyRuleA) { applyRecursively( currentNode, new Function<Node<Payload>, Node<Payload>>() { @Override public Node<Payload> apply(Node<Payload> input) { input.getPayload().setMarked(false); return input; } }); } currentNode.getPayload().setMarked(true); // reorganize if needed final Node<Payload> flippedNode = reorganizeForRecursion(currentNode); // optimize tree size if asked for if (keepMarkedNodesOnly) { optimizeTreeSize(flippedNode); } }
/** * Reorganizes the tree by applying the rules to the tree from the changed node and returns a node * that was top most of the flipped ones. */ protected Node<Payload> reorganizeForRecursion(final Node<Payload> changedNode) { // rule a: if parent is marked already, do not mark the child if (applyRuleA && isParentMarked(changedNode)) { changedNode.getPayload().setMarked(false); return changedNode.getParent(); } // rule b: if this parent's all children are marked, mark parent, unmark children if (applyRuleB && isParentAllChildMarkedForRuleB(changedNode)) { changedNode.getParent().getPayload().setMarked(true); for (Node<Payload> child : changedNode.getParent().getChildren()) { child.getPayload().setMarked(false); } return changedNode.getParent(); } return changedNode; }
protected void dump(final Node<Payload> node, final int depth, final StringBuilder sb) { sb.append(Strings.repeat(" ", depth)); sb.append(node.getLabel()); sb.append(" (").append(node.getPath()).append(")"); if (node.getPayload().isMarked()) { sb.append("*"); } sb.append("\n"); for (Node<Payload> child : node.getChildren()) { dump(child, depth + 1, sb); } }
/** * Returns true if parent exists (passed in node is not ROOT), and if parent {@link * Payload#isMarked()} returns {@code true}. */ protected boolean isParentMarked(final Node<Payload> node) { final Node<Payload> parent = node.getParent(); if (parent != null) { if (parent.getPayload().isMarked()) { return true; } else { return isParentMarked(parent); } } else { return false; } }
/** * Returns true if parent exists (passed in node is not ROOT), and parent's all children are * marked (their {@link Payload#isMarked()} is {@code true} for all of them. */ protected boolean isParentAllChildMarkedForRuleB(final Node<Payload> node) { final Node<Payload> parent = node.getParent(); if (parent != null) { final List<Node<Payload>> children = parent.getChildren(); if (children.size() < 2) { return false; } for (Node<Payload> child : children) { if (!child.getPayload().isMarked()) { return false; } } return true; } else { return false; } }