/** * */ package cz.cuni.mff.peckam.java.origamist.gui.editor; import java.util.List; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import cz.cuni.mff.peckam.java.origamist.model.Operation; import cz.cuni.mff.peckam.java.origamist.model.OperationContainer; import cz.cuni.mff.peckam.java.origamist.utils.MutableHashMap; /** * The tree that displays operations. * * @author Martin Pecka */ public class OperationsTree extends JTree { /** */ private static final long serialVersionUID = 6867603232306832702L; /** The map that maps operations to their corresponding tree nodes. */ protected MutableHashMap<Operation, DefaultMutableTreeNode> nodesForOperations = new MutableHashMap<Operation, DefaultMutableTreeNode>(); { setRootVisible(false); setShowsRootHandles(true); setSelectionModel(new DefaultTreeSelectionModel()); getSelectionModel().setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); } /** * */ public OperationsTree() { super(); } /** * @param newModel */ public OperationsTree(TreeModel newModel) { super(newModel); } /** * @param root */ public OperationsTree(TreeNode root) { super(root); } /** * Get the tree model that represents the given list of operations. * * @param operations The operations to be represented. * @return The tree model representing the given operations. */ public TreeModel getModelForOperations(List<Operation> operations) { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); root.setAllowsChildren(true); createOperationsStructure(root, operations); return new DefaultTreeModel(root); } /** * Recursively add the given list of operations under the given root. * * @param root The tree node to add the operations under. * @param operations The operations to add. */ protected void createOperationsStructure(DefaultMutableTreeNode root, List<Operation> operations) { if (operations != null) { for (Operation o : operations) { DefaultMutableTreeNode node = createNode(o); node.setAllowsChildren(false); root.add(node); if (o instanceof OperationContainer) { node.setAllowsChildren(true); createOperationsStructure(node, ((OperationContainer) o).getOperations()); } } } } /** * Create the node for the given operation. * * @param operation The operation to create the node for. * @return The node. */ protected DefaultMutableTreeNode createNode(Operation operation) { DefaultMutableTreeNode node = new DefaultMutableTreeNode(operation); if (operation instanceof OperationContainer) { node.setAllowsChildren(true); } else { node.setAllowsChildren(false); } nodesForOperations.put(operation, node); return node; } /** * Remove the given operation from this tree. * * @param operation The operation to remove. */ public void removeOperation(Operation operation) { MutableTreeNode node = nodesForOperations.forcedGet(operation); if (node != null) { nodesForOperations.forcedRemove(operation); ((DefaultTreeModel) getModel()).removeNodeFromParent(node); repaint(); } } /** * Add the operation under the tree's top level (just under the single root). * * @param operation The operation to add. */ public void addTopLevelOperation(Operation operation) { DefaultMutableTreeNode root = (DefaultMutableTreeNode) getModel().getRoot(); DefaultMutableTreeNode node = createNode(operation); ((DefaultTreeModel) getModel()).insertNodeInto(node, root, root.getChildCount()); addSelectionPath(new TreePath(node.getPath())); repaint(); } /** * Return the node that holds the given operation. * * @param operation The operation to find node for. * @return The node for the operation. */ public TreeNode getNodeForOperation(Operation operation) { return nodesForOperations.forcedGet(operation); } /** * Scroll the tree so that the given operation's node is visible. * <p> * Only works if the tree is under a {@link javax.swing.JScrollPane}. * * @param operation The operation to make visible. */ public void scrollToOperation(Operation operation) { DefaultMutableTreeNode node = nodesForOperations.forcedGet(operation); if (node != null) scrollPathToVisible(new TreePath(node.getPath())); } /** * Force recomputing of the cached cell heights. */ public void recomputeHeights() { // changing the model is one of the easiest ways to recompute the cell heights TreeModel model = getModel(); int[] selected = getSelectionRows(); setModel(new DefaultTreeModel(null)); setModel(model); setSelectionRows(selected); } }