001package org.openstreetmap.gui.jmapviewer.checkBoxTree;
002
003import java.awt.BorderLayout;
004import java.awt.event.MouseAdapter;
005
006import javax.swing.JFrame;
007import javax.swing.JScrollPane;
008import javax.swing.JTree;
009import javax.swing.event.TreeModelEvent;
010import javax.swing.event.TreeModelListener;
011import javax.swing.event.TreeSelectionEvent;
012import javax.swing.event.TreeSelectionListener;
013import javax.swing.tree.DefaultMutableTreeNode;
014import javax.swing.tree.DefaultTreeModel;
015
016import org.openstreetmap.gui.jmapviewer.AbstractLayer;
017import org.openstreetmap.gui.jmapviewer.Layer;
018import org.openstreetmap.gui.jmapviewer.LayerGroup;
019
020/**
021 * JTree for checkBox Tree Layers
022 * 
023 * @author galo
024 */
025public class CheckBoxTree extends JTree{
026    /** Serial Version UID */
027    private static final long serialVersionUID = 6943401106938034256L;
028    
029    private final CheckBoxNodeEditor editor;
030
031    public CheckBoxTree(AbstractLayer layer){
032        this(new CheckBoxNodeData(layer));
033    }
034    public CheckBoxTree(String rootName){
035        this(new CheckBoxNodeData(rootName));
036    }
037    public CheckBoxTree(CheckBoxNodeData root ){
038        this(new DefaultMutableTreeNode(root));
039    }
040    public CheckBoxTree(DefaultMutableTreeNode node){
041        super(new DefaultTreeModel(node));
042
043        final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
044        setCellRenderer(renderer);
045
046        editor = new CheckBoxNodeEditor(this);
047        setCellEditor(editor);
048        setEditable(true);
049        
050        // listen for changes in the model (including check box toggles)
051        getModel().addTreeModelListener(new TreeModelListener() {
052            @Override
053            public void treeNodesChanged(final TreeModelEvent e) {
054                DefaultTreeModel model = (DefaultTreeModel)e.getSource();
055                Object[] nodes = e.getChildren();
056                DefaultMutableTreeNode node;
057                if(nodes==null||nodes.length==0){
058                    node = node(model.getRoot());
059                }else{
060                    node = node(nodes[0]);
061                }
062                nodeChanged(node);
063                repaint();
064            }
065
066            @Override
067            public void treeNodesInserted(final TreeModelEvent e) {
068                //System.out.println("nodes inserted");
069            }
070
071            @Override
072            public void treeNodesRemoved(final TreeModelEvent e) {
073                //System.out.println("nodes removed");
074            }
075
076            @Override
077            public void treeStructureChanged(final TreeModelEvent e) {
078                //System.out.println("structure changed");
079            }
080        });
081    }
082    public void addNodeListener(MouseAdapter listener){
083        editor.addNodeListener(listener);
084    }
085    public static void main(final String args[]) {
086        final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new CheckBoxNodeData("Root",true));
087
088        final DefaultMutableTreeNode accessibility =
089            add(root, "Accessibility", true);
090        add(accessibility, "Move system caret with focus/selection changes", false);
091        add(accessibility, "Always expand alt text for images", true);
092        root.add(accessibility);
093
094        final DefaultMutableTreeNode browsing =
095            new DefaultMutableTreeNode(new CheckBoxNodeData("Browsing", null));
096        add(browsing, "Notify when downloads complete", true);
097        add(browsing, "Disable script debugging", true);
098        add(browsing, "Use AutoComplete", true);
099        add(browsing, "Browse in a new process", false);
100        root.add(browsing);
101
102        final CheckBoxTree tree = new CheckBoxTree(root);
103        ((DefaultMutableTreeNode)tree.getModel().getRoot()).add(new DefaultMutableTreeNode(new CheckBoxNodeData("gggg", null)));
104        ((DefaultTreeModel)tree.getModel()).reload();
105        // listen for changes in the selection
106        tree.addTreeSelectionListener(new TreeSelectionListener() {
107            @Override
108            public void valueChanged(final TreeSelectionEvent e) {
109                //System.out.println("selection changed");
110            }
111        });
112        // show the tree on screen
113        final JFrame frame = new JFrame("CheckBox Tree");
114        final JScrollPane scrollPane = new JScrollPane(tree);
115        frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
116        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
117        frame.setSize(300, 150);
118        frame.setVisible(true);
119    }
120    private static Boolean childStatus(DefaultMutableTreeNode node){
121        Boolean status = data(node.getChildAt(0)).isSelected();
122        for(int i=1; i<node.getChildCount()&&status!=null; i++){
123            if(status != data(node.getChildAt(i)).isSelected()) return null;
124        }
125        return status;
126    }
127    private static void changeParents(DefaultMutableTreeNode node){
128        if(node!=null){
129            DefaultMutableTreeNode parent = node(node.getParent());
130            if(parent!=null){
131                CheckBoxNodeData dataParent = data(parent);
132                Boolean childStatus = childStatus(parent);
133                if(dataParent.isSelected()!=childStatus){
134                    dataParent.setSelected(childStatus);
135                    changeParents(parent);
136                }
137            }
138        }
139    }
140    private static void nodeChanged(DefaultMutableTreeNode node){
141        if(node!=null){
142            changeParents(node);
143            setChildrens(node, data(node).isSelected());
144        }
145    }
146    private static void setChildrens(DefaultMutableTreeNode node, Boolean value){
147        for(int i=0; i<node.getChildCount(); i++){
148            DefaultMutableTreeNode childNode = node(node.getChildAt(i));
149            if (data(childNode).isSelected() !=data(node).isSelected()){
150                data(childNode).setSelected(data(node).isSelected());
151                setChildrens(childNode, value);
152            }
153        }
154    }
155    public DefaultMutableTreeNode rootNode(){
156        return node(getModel().getRoot());
157    }
158    public LayerGroup rootLayer(){
159        return (LayerGroup)rootData().getAbstractLayer();
160    }
161    public CheckBoxNodeData rootData(){
162        return data(rootNode());
163    }
164    private static DefaultMutableTreeNode node(Object node){
165        return (DefaultMutableTreeNode)node;
166    }
167    public static CheckBoxNodeData data(DefaultMutableTreeNode node){
168        return node==null?null:(CheckBoxNodeData)node.getUserObject();
169    }
170    private static CheckBoxNodeData data(Object node){
171        return data(node(node));
172    }
173    private static DefaultMutableTreeNode add(final DefaultMutableTreeNode parent, final String text, final boolean checked){
174        final CheckBoxNodeData data = new CheckBoxNodeData(text, checked);
175        final DefaultMutableTreeNode node = new DefaultMutableTreeNode(data);
176        parent.add(node);
177        return node;
178    }
179    public static CheckBoxNodeData createNodeData(AbstractLayer layer){
180        return new CheckBoxNodeData(layer);
181    }
182    public static DefaultMutableTreeNode createNode(AbstractLayer layer){
183        return new DefaultMutableTreeNode(createNodeData(layer));
184    }
185    /*public DefaultMutableTreeNode addLayerGroup(LayerGroup group){
186        if(group!=null){
187            if(group.getParent()==null){
188                return add(rootNode(), group);
189            }else{
190                DefaultMutableTreeNode parentGroup = searchNode(group.getParent());
191                if(parentGroup==null) parentGroup = addLayerGroup(group.getParent());
192                DefaultMutableTreeNode node = add(parentGroup, group);
193                return node;
194            }
195        }else return null;
196    }*/
197    public Layer addLayer(String name){
198        Layer layer = new Layer(name);
199        addLayer(layer);
200        return layer;
201    }
202    public DefaultMutableTreeNode addLayer(AbstractLayer layer){
203        if (layer!=null){
204            DefaultMutableTreeNode parent;
205            if(layer.getParent()==null){
206                rootLayer().add(layer);
207                parent = rootNode();
208            }else{
209                parent = searchNode(layer.getParent());
210                if(parent==null) parent=addLayer(layer.getParent());
211            }
212            return add(parent, layer);
213        }else return null;
214    }
215    public DefaultMutableTreeNode add(DefaultMutableTreeNode parent, final AbstractLayer layer){
216        layer.setVisible(data(parent).isSelected());
217        DefaultMutableTreeNode node = createNode(layer); 
218        parent.add(node);
219        ((DefaultTreeModel)getModel()).reload();
220        //System.out.println("Created node "+layer+" upper of "+data(parent));
221        return node;
222    }
223    public DefaultMutableTreeNode searchNode(AbstractLayer layer){
224        return searchNode(rootNode(), layer);
225    }
226    public DefaultMutableTreeNode searchNode(DefaultMutableTreeNode node, AbstractLayer layer){
227        CheckBoxNodeData data = CheckBoxTree.data(node);
228        if(data.getAbstractLayer() == layer) return node;
229        else{
230            DefaultMutableTreeNode found = null;
231            for(int i=0; i<node.getChildCount() && found==null; i++){
232                found = searchNode((DefaultMutableTreeNode)node.getChildAt(i), layer);
233            }
234            return found;
235        }
236    }
237}