1

I have a tree that displays network devices. The tree is filtered such that the devices are displayed by location and device type. For example, node "Office" would have child node "Computer" and "Printer" each with devices under them.

When I select the Location Node, I would like to select all nodes under it and add it to the selectionPaths[] of my tree so that they are all highlighted. Below is my code, but I can't figure out how to get this working.

   private class DefaultDeviceTreeCellRenderer extends DefaultTreeCellRenderer {

    private JLabel label;

    DefaultDeviceTreeCellRenderer() {
        super();
        label = new JLabel();
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
            boolean leaf, int row, boolean hasFocus) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
        Object o = node.getUserObject();
        if (o instanceof DefaultDevice) {
            DefaultDevice defaultDevice = (DefaultDevice) o;
            label.setIcon(defaultDevice.getIcon());
            label.setText(defaultDevice.toString());
        } else {
            System.out.println("Cell Class= " + o.getClass());
            //Set all children of this Component as selected. 
            label.setIcon(null);
            label.setText("" + value);
            TreePath[] selectionPaths = tree.getSelectionPaths();
            if (selectionPaths == null) {
                System.out.println("Nothing Selected. ");
            } else {
                //keep current selection path
                //if there are leaf nodes, add their selection paths. 
                int i = 0;
                while (i < node.getChildCount()) {
                    //add node.getNextLeaf().getPath() to selection Paths
                    ArrayList<TreePath> arrayList = new ArrayList<>(Arrays.asList(selectionPaths));
                    arrayList.add(new TreePath(((DefaultMutableTreeNode)node.getChildAt(i)).getPath()));
                    TreePath[] toArray = arrayList.toArray(new TreePath[arrayList.size()]);
                    this.printSelectionPath(selectionPaths);
                    this.printSelectionPath(toArray);
                    // tree.setSelectionPaths(toArray);
                    i++;
                }
            }
            //  System.out.println("Selection Paths.size="+selectionPaths.length);
            // ArrayList arrayList = new ArrayList(Arrays.asList(selectionPaths));
            //  System.out.println("ChildNode Path=" + node.getPath()[a]);

        }
        label.setOpaque(true);
        if (selected) {

            label.setBackground(this.backgroundSelectionColor);
            label.setForeground(this.textSelectionColor);
        } else {
            label.setBackground(this.backgroundNonSelectionColor);
            label.setForeground(this.textNonSelectionColor);
        }
        return label;
    }

    private void printSelectionPath(TreePath[] selectionPaths) {
        System.out.println("\nTreePath:");
        for (int i = 0; i < selectionPaths.length; i++) {
            System.out.println("Selection Path= " + selectionPaths[i]);
            //TreePath treePath = new TreePath(node.getPath());
           // System.out.println("TreePath= " + treePath);
        }
}
copeg
  • 8,290
  • 19
  • 28
CoupFlu
  • 311
  • 4
  • 20
  • You should really be creating a custom TreeSelectionModel: http://docs.oracle.com/javase/7/docs/api/javax/swing/tree/TreeSelectionModel.html – ControlAltDel Jun 28 '16 at 18:57
  • Can you provide an example that would accomplish this? – CoupFlu Jun 28 '16 at 19:00
  • `I would like to select all nodes under it and add it to the selectionPaths[] of my tree so that they are all highlighted` Are you sure you want to change the view by changing the SelectionModel? Might be easier to just change the view based upon whether a parent 'Location' node exists, and is selected. – copeg Jun 28 '16 at 19:01
  • I've been racking my brain over the best way to do this. Basically if I click on anything except a 'DefaultDevice' then it will be either a 'Location' or 'Model' node. If i click either of those, I want all the nodes under them to become highlighted. – CoupFlu Jun 28 '16 at 19:05
  • I considered updating the SelectionModel from the selectionListener but this doesn't seem like the right approach. I see this behavior in other apps all the time. How is it accomplished? – CoupFlu Jun 28 '16 at 19:32
  • I think I need to override the add/remove Methods in the DefaultTreeSelectionModel to add and remove the children of each selection. Does this seem like the proper strategy? – CoupFlu Jun 29 '16 at 13:36

1 Answers1

0

I accomplished this by extending the DefaultTreeSelectionModel and modifying a few methods. Here is my Extended class.

    public static class MyTreeSelectionModel extends DefaultTreeSelectionModel {

    public MyTreeSelectionModel() {
        super();
    }

    @Override
    public void removeSelectionPath(TreePath path) {
        //remove path and its children
        Object lastPathComponent = path.getLastPathComponent();
        ArrayList<TreePath> childPaths = new ArrayList();
        if (lastPathComponent instanceof DefaultMutableTreeNode) {
            DefaultMutableTreeNode dn = (DefaultMutableTreeNode) lastPathComponent;
            this.getDecendents(dn, childPaths);
        } else {
            System.out.println("Not a DefaultMutableTreeNode");
        }
        childPaths.add(path);
        this.removeSelectionPaths(childPaths.toArray(new TreePath[childPaths.size()]));
    }

    @Override
    public void addSelectionPath(TreePath path) {
        //add the path and its children
        Object lastPathComponent = path.getLastPathComponent();
        ArrayList<TreePath> childPaths = new ArrayList();
        if (lastPathComponent instanceof DefaultMutableTreeNode) {
            DefaultMutableTreeNode dn = (DefaultMutableTreeNode) lastPathComponent;
            System.out.println("Last Path Component= " + dn);
            //get decendents
            this.getDecendents(dn, childPaths);
        } else {
            System.out.println("Not a DefaultMutableTreeNode");
        }
        childPaths.add(path);
        this.addSelectionPaths(childPaths.toArray(new TreePath[childPaths.size()]));
        // super.addSelectionPath(path); //To change body of generated methods, choose Tools | Templates.
    }

    private void getDecendents(DefaultMutableTreeNode dn, ArrayList<TreePath> childPaths) {
        Enumeration children = dn.children();
        if (children != null) {
            while (children.hasMoreElements()) {
                DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();
                System.out.println("Adding " + childNode);
                TreeNode[] path1 = childNode.getPath();
                childPaths.add(new TreePath(path1));
                getDecendents(childNode, childPaths);
            }
        }

    }

}
CoupFlu
  • 311
  • 4
  • 20