annotate java/src/uk/ac/qmul/eecs/ccmi/checkboxtree/CheckBoxTree.java @ 8:ea7885bd9bff tip

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