comparison java/src/uk/ac/qmul/eecs/ccmi/checkboxtree/CheckBoxTree.java @ 3:9e67171477bc

PHANTOM Omni Heptic device release
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Wed, 25 Apr 2012 17:09:09 +0100
parents
children d66dd5880081
comparison
equal deleted inserted replaced
2:4b2f975e35fa 3:9e67171477bc
1 /*
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
3
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 package uk.ac.qmul.eecs.ccmi.checkboxtree;
20
21 import java.awt.event.MouseAdapter;
22 import java.awt.event.MouseEvent;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.util.Enumeration;
26
27 import javax.swing.JTree;
28 import javax.swing.tree.DefaultMutableTreeNode;
29 import javax.swing.tree.DefaultTreeModel;
30 import javax.swing.tree.TreePath;
31 import javax.xml.parsers.ParserConfigurationException;
32 import javax.xml.parsers.SAXParser;
33 import javax.xml.parsers.SAXParserFactory;
34
35 import org.xml.sax.SAXException;
36
37
38 /**
39 * A JTree containing {@code CheckBoxTreeNode} nodes. The tree is built according to an XML file
40 * passed as argument to the constructor.
41 * The XML file hierarchical structure reflects the structure of the tree. XML tag name can be
42 * either {@code selectable} or {@code unselectable}. The former representing tree nodes with a check
43 * box associated to it, and the latter a normal tree node, much as a {@link DefaultMutableTreeNode}.
44 * Either tags must have an attribute {@code value}, representing the name of the node which will be displayed
45 * in the tree. Here is an example of a simple XML file, representing a tree with the tree root (non selectable) having
46 * three children, the first of which has, in turn, a child. all the descendants of the root are selectable, but the
47 * first child.
48 *
49 * <pre>
50 * {@code
51 * <?xml version="1.0" encoding="utf-8"?>
52 * <unselectable value="root">
53 * <unselectable value="first child"/>
54 * <selectable value="second child"/>
55 * <selectable value "third child">
56 * <selectable value="grand child"/>
57 * </selectable>
58 * </unselectable>
59 * }
60 * </pre>
61 *
62 * @see CheckBoxTreeNode
63 */
64 @SuppressWarnings("serial")
65 public class CheckBoxTree extends JTree {
66 public CheckBoxTree(InputStream stream, SetProperties values){
67 super(new DefaultTreeModel(new DefaultMutableTreeNode()));
68 this.properties = values;
69 getAccessibleContext().setAccessibleName("tree");
70 treeModel = (DefaultTreeModel)getModel();
71 setCellRenderer(new CheckBoxTreeCellRenderer());
72 buildTree(stream);
73 /* mouse listener to toggle the selected tree node */
74 addMouseListener(new MouseAdapter(){
75 @Override
76 public void mousePressed(MouseEvent e){
77 TreePath path = getPathForLocation(e.getX(),e.getY());
78 if(path == null)
79 return;
80 CheckBoxTreeNode treeNode = (CheckBoxTreeNode)path.getLastPathComponent();
81 toggleSelection(treeNode);
82 }
83 });
84 }
85
86 /**
87 * Builds a CheckBoxTree out of an xml file passed as argument. All the nodes
88 * of the tree are marked unchecked.
89 *
90 * @param stream an input stream to an xml file
91 */
92 public CheckBoxTree(InputStream stream){
93 this(stream,null);
94 }
95
96 /* use a sax parser to build the tree, if an error occurs during the parsing it just stops */
97 private void buildTree(InputStream stream){
98 SAXParserFactory factory = SAXParserFactory.newInstance();
99 try {
100 SAXParser saxParser = factory.newSAXParser();
101 XMLHandler handler = new XMLHandler((DefaultTreeModel)getModel(),properties);
102 saxParser.parse(stream, handler);
103 } catch (IOException e) {
104 e.printStackTrace();
105 return;
106 } catch (ParserConfigurationException e) {
107 e.printStackTrace();
108 return;
109 } catch (SAXException e) {
110 e.printStackTrace();
111 return;
112 }
113 }
114
115 /**
116 * Returns a reference to the properties holding which nodes of the tree are currently checked.
117 * @return the properties or {@value null} if the constructor with no properties was used.
118 */
119 public SetProperties getProperties(){
120 return properties;
121 }
122
123 /**
124 * Toggle the check box of the tree node passed as argument. If the tree node
125 * is not a leaf, then all its descendants will get the new value it. That is,
126 * if the tree node becomes selected as a result of the call, then all the descendants
127 * will become in turn selected (regardless of their previous state). If it becomes
128 * unselected, the descendants will become unselected as well.
129 *
130 * @param treeNode the tree node to toggle
131 */
132 public void toggleSelection(CheckBoxTreeNode treeNode){
133 if(treeNode.isSelectable()){
134 boolean selection = !treeNode.isSelected();
135 treeNode.setSelected(selection);
136 if(selection)
137 properties.add(treeNode.getPathAsString());
138 else
139 properties.remove(treeNode.getPathAsString());
140 treeModel.nodeChanged(treeNode);
141 if(!treeNode.isLeaf()){
142 for( @SuppressWarnings("unchecked")
143 Enumeration<CheckBoxTreeNode> enumeration = treeNode.depthFirstEnumeration(); enumeration.hasMoreElements();){
144 CheckBoxTreeNode t = enumeration.nextElement();
145 t.setSelected(selection);
146 if(selection)
147 properties.add(t.getPathAsString());
148 else
149 properties.remove(t.getPathAsString());
150 treeModel.nodeChanged(t);
151 }
152 }
153 }
154 }
155
156 private SetProperties properties;
157 private DefaultTreeModel treeModel;
158 }