| 1 | package be.nikiroo.utils.ui; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.LinkedList; |
| 5 | import java.util.List; |
| 6 | |
| 7 | import javax.swing.JTree; |
| 8 | import javax.swing.tree.TreeModel; |
| 9 | import javax.swing.tree.TreeNode; |
| 10 | import javax.swing.tree.TreePath; |
| 11 | |
| 12 | public class TreeSnapshot { |
| 13 | private interface NodeAction { |
| 14 | public void run(TreeNode node); |
| 15 | } |
| 16 | |
| 17 | private JTree tree; |
| 18 | private TreePath[] selectionPaths; |
| 19 | private List<TreePath> expanded; |
| 20 | |
| 21 | public TreeSnapshot(JTree tree) { |
| 22 | this.tree = tree; |
| 23 | |
| 24 | selectionPaths = tree.getSelectionPaths(); |
| 25 | if (selectionPaths == null) { |
| 26 | selectionPaths = new TreePath[0]; |
| 27 | } |
| 28 | |
| 29 | expanded = new ArrayList<TreePath>(); |
| 30 | forEach(tree, new NodeAction() { |
| 31 | @Override |
| 32 | public void run(TreeNode node) { |
| 33 | TreePath path = nodeToPath(node); |
| 34 | if (path != null) { |
| 35 | if (TreeSnapshot.this.tree.isExpanded(path)) { |
| 36 | expanded.add(path); |
| 37 | } |
| 38 | } |
| 39 | } |
| 40 | }); |
| 41 | } |
| 42 | |
| 43 | public void apply() { |
| 44 | applyTo(tree); |
| 45 | } |
| 46 | |
| 47 | public void applyTo(JTree tree) { |
| 48 | final List<TreePath> newExpanded = new ArrayList<TreePath>(); |
| 49 | final List<TreePath> newSlectionPaths = new ArrayList<TreePath>(); |
| 50 | |
| 51 | forEach(tree, new NodeAction() { |
| 52 | @Override |
| 53 | public void run(TreeNode newNode) { |
| 54 | TreePath newPath = nodeToPath(newNode); |
| 55 | if (newPath != null) { |
| 56 | for (TreePath path : selectionPaths) { |
| 57 | if (isSamePath(path, newPath)) { |
| 58 | newSlectionPaths.add(newPath); |
| 59 | if (expanded.contains(path)) { |
| 60 | newExpanded.add(newPath); |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | }); |
| 67 | |
| 68 | for (TreePath newPath : newExpanded) { |
| 69 | tree.expandPath(newPath); |
| 70 | } |
| 71 | |
| 72 | tree.setSelectionPaths(newSlectionPaths.toArray(new TreePath[0])); |
| 73 | } |
| 74 | |
| 75 | // You can override this |
| 76 | protected boolean isSamePath(TreePath oldPath, TreePath newPath) { |
| 77 | return newPath.toString().equals(oldPath.toString()); |
| 78 | } |
| 79 | |
| 80 | private void forEach(JTree tree, NodeAction action) { |
| 81 | forEach(tree.getModel(), tree.getModel().getRoot(), action); |
| 82 | } |
| 83 | |
| 84 | private void forEach(TreeModel model, Object parent, NodeAction action) { |
| 85 | if (!(parent instanceof TreeNode)) |
| 86 | return; |
| 87 | |
| 88 | TreeNode node = (TreeNode) parent; |
| 89 | |
| 90 | action.run(node); |
| 91 | int count = model.getChildCount(node); |
| 92 | for (int i = 0; i < count; i++) { |
| 93 | Object child = model.getChild(node, i); |
| 94 | forEach(model, child, action); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | private static TreePath nodeToPath(TreeNode node) { |
| 99 | List<Object> nodes = new LinkedList<Object>(); |
| 100 | if (node != null) { |
| 101 | nodes.add(node); |
| 102 | node = node.getParent(); |
| 103 | while (node != null) { |
| 104 | nodes.add(0, node); |
| 105 | node = node.getParent(); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | return nodes.isEmpty() ? null : new TreePath(nodes.toArray()); |
| 110 | } |
| 111 | |
| 112 | @Override |
| 113 | public String toString() { |
| 114 | StringBuilder builder = new StringBuilder(); |
| 115 | builder.append("Tree Snapshot of: ").append(tree).append("\n"); |
| 116 | builder.append("Selected paths:\n"); |
| 117 | for (TreePath path : selectionPaths) { |
| 118 | builder.append("\t").append(path).append("\n"); |
| 119 | } |
| 120 | builder.append("Expanded paths:\n"); |
| 121 | for (TreePath epath : expanded) { |
| 122 | builder.append("\t").append(epath).append("\n"); |
| 123 | } |
| 124 | |
| 125 | return builder.toString(); |
| 126 | } |
| 127 | } |