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